首页 文章

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

提问于
浏览
0

我想从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飞到gem,调用方法,飞回 and have all the gems in the trigger stored in a queue 因为当触发器中有多个gem时,AI必须排队 .


所以这是一个 update ,我试图让追随者收集宝石时将它们存储在我的列表中

public class PlayerFollower:Ai {private List collectablesToCollect = new List(); //将范围内的所有宝石存储在此处私有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 回答

  • 1

    这就是我要做的事情:

    您在Gem( Collectable )上有代码,而您的代码在Collecting-AI( PlayerFollower )上 .

    PlayerFollower 需要一个代表其搜索半径的 Trigger ,它需要一个代表其物理位置的对撞机 . 还将AI放在自己的物理层上 . 您的收藏品需要相同的设置,但我建议您将 Trigger 设置在与AI相同的层上,而碰撞应该与世界相同(因此您可以触摸它,但AI会通过) .

    每当一个对象进入 PlayerFollowerPlayerFollower 时,其组件类型为 Collectable ,就将其存储在 List<Collectable> 中 . 每当一个对象退出_544390_的_544390_,其组件类型为 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);
            }
        }
    }
    

相关问题