将AI移动到收集器,调用方法并在Unity中飞回

时间:2017-09-10 19:35:49

标签: c# unity3d

我想从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?
}

}

1 个答案:

答案 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);
        }
    }
}