我想从Spyro创建一个像Sparx这样的追随者AI。你可以在这个视频中看到这些机制
https://youtu.be/2DicrivJ2xc?t=5
Sparx寻找地面上的宝石,飞向它们并飞回Spyro。当飞向他们时,宝石也开始飞向玩家。所以Sparx正在收集宝石。
我已经创建了让宝石飞向玩家的功能。假设我称这种方法为
StartMovingToPlayer();
Sparx将在他的剧本中从gem中调用此方法。
public class PlayerFollower : Ai
{
private void OnTriggerEnter(Collider col) // something entered the trigger
{
Collectable collectable = col.GetComponent<Collectable>(); // try to get the collectable script
if (collectable != null) // is it a collectable?
collectable.StartMovingToPlayer(); // make it move to the player
}
}
所以我的问题是,如何让AI飞向宝石,调用方法,飞回并将触发器中的所有宝石存储在队列中,因为当有超过在触发器中有一个宝石,AI必须排队。
所以这是更新,我试图让关注者收集宝石时将它们存储在我的列表中
public class PlayerFollower:艾 { private List collectablesToCollect = new List(); //将范围内的所有宝石存储在此处 private bool isCollecting = false; //是目前收集宝石的追随者? 私人浮动运动速度= 10; //收集速度
private void Update()
{
if (CollectablesInRange()) // any gems in range?
{
if (!isCollecting) // collecting queued?
MoveToCollectable(); // collect it
}
else
{
// follow the player
}
}
private void OnTriggerEnter(Collider col)
{
Collectable collectable = col.GetComponent<Collectable>(); // get the gem
if (collectable != null) // is the object a gem?
{
if (!collectable.GetMovementState()) // got the gem already collected?
collectablesToCollect.Add(collectable); // add it to the queue
}
}
private void OnTriggerExit(Collider col)
{
Collectable collectable = col.GetComponent<Collectable>();
if (collectable != null)
collectablesToCollect.Remove(collectable); // remove it from the queue
}
private void MoveToCollectable() // start collecting
{
isCollecting = true;
if (CollectablesInRange())
{
Collectable collectable = collectablesToCollect.First(); just look for one gem
Vector3 defaultPosition = transform.position;
transform.position = Vector3.MoveTowards(transform.position, collectable.GetCollectablePosition(), movementSpeed * Time.deltaTime); // move to the gem
collectable.StartMovingToPlayer(); // call the gems movement
transform.position = Vector3.MoveTowards(transform.position, defaultPosition, movementSpeed * Time.deltaTime); // move back to the player
collectablesToCollect.Remove(collectable); // remove it from the queue
isCollecting = false;
if (CollectablesInRange()) // collect again, when the list is not empty
MoveToCollectable();
}
}
private bool CollectablesInRange()
{
return collectablesToCollect.Count > 0; // are there any gems in range?
}
}
答案 0 :(得分:1)
这就是我要做的事情:
您在Gem(Collectable
)上有代码,而您的代码在您的Collecting-AI(PlayerFollower
)上。
PlayerFollower
需要一个代表其搜索半径的Trigger
,它需要一个代表其物理位置的对撞机。还将AI放在自己的物理层上。你的收藏品需要相同的设置,但我建议你将Trigger
设置在与AI相同的层上,而碰撞应该与世界相同(所以你可以触摸它,但AI通过通过)。
每当某个对象进入Trigger
PlayerFollower
的{{1}}组件Collectable
时,就会将其存储在List<Collectable>
中。每当对象退出Trigger
PlayerFollower
的{{1}}组件Collectable
时,就会从列表中删除它。这就是你如何追踪可以收集和不收集的东西。
现在,当一个对象进入Trigger
并被添加时,您将检查是否有当前目标要移动到,如果没有,则将添加的对象设置为目标。
当您的AI进入另一个对象的触发器时,此对象会触发OnTriggerEnter
并识别AI。它在AI上调用一个方法,声明它现在被收集并且可能设置一个布尔值,可以从其他对象读取到true
,说明它现在已经被收集而不再是世界的一部分了。
此方法从列表中删除对象并搜索下一个目标(在列表中)。当什么都找不到时,它就会回到播放器并等待收集下一个对象。
AI的可能(未经测试)实施:
public class PlayerFollower : AI
{
List<Collectable> possibleTargets = new List<Collectable>();
Collectable target;
void OnTriggerEnter(Collider other)
{
Collectable collectable = other.GetComponent<Collectable>();
if (collectable != null && !collectable.Collected)
{
possibleTargets.Add(collectable);
SetNextTarget();
}
}
public void Collect(Collectable collectable)
{
possibleTargets.Remove(collectable);
SetNextTarget();
}
void SetNextTarget()
{
target = null;
for(int i = 0; i < possibleTargets.Count; i++)
if(!possibleTargets[i].Collected)
{
target = possibleTargets[i];
return;
}
}
}
Gem的可能(未经测试)实施:
public class Collectable : MonoBehaviour
{
private bool collected;
public bool Collected { get { return collected; } }
void OnTriggerEnter(Collider other)
{
PlayerFollower ai = other.GetComponent<PlayerFollower>();
if (ai != null)
{
collected = true;
ai.Collect(this);
}
}
}