代码之家  ›  专栏  ›  技术社区  ›  user193464

团结纳瓦伊陷入困境

  •  1
  • user193464  · 技术社区  · 6 年前

    我正试图在unity engine中开发一种与光子网络系统一起工作的人工智能。它应该相当简单:它向一个随机的玩家跑去,直到他和玩家之间达到5个单位的距离,然后它以稍慢的速度行走,直到到达玩家的前面。然后他发起攻击。到目前为止还不错,但有时,当AI与玩家之间的距离达到5个单位时,它会被卡住。我在网上尝试了几次修复,但都没有效果。 以下是代码:

    using System.Collections;
    using System.Collections.Generic;
    using UnityEngine;
    using UnityEngine.AI;
    
    [RequireComponent(typeof(NavMeshAgent))]
    [RequireComponent(typeof(Rigidbody))]
    [RequireComponent(typeof(Animator))]
    [RequireComponent(typeof(PhotonView))]
    [RequireComponent(typeof(PhotonTransformView))]
    public class EnemyAI : Photon.MonoBehaviour {
    
        NavMeshAgent agent;
        Animator anim;
    
        PlayerController target;
        [Header("Base settings")]
        [SerializeField]
        float health = 100f, damage, timeBetweenAttacks = 5f;
    
        [Space]
        [Header("Enemy Ragdoll")]
        [SerializeField]
        GameObject ragdoll;
    
        AudioSource emotAud, stepAud;
    
        [Space]
        [SerializeField]
        [Header("Audio")]
        List<AudioClip> attackingAuds;
    
        [Space]
        [Header("Sunete pasi")]
        [SerializeField]
        List<AudioClip> stepAuds;
    
        [Space]
        [Header("Alte optiuni")]
        [SerializeField]
        float distantaLaCareIncepeSaMearga = 5f, walkSpeed = .5f, runSpeed = 3.5f;
    
        bool dead, walking;
    
        PhotonView killer;
    
        float nextAttackTime;
    
        // Use this for initialization
        void Start () {
            emotAud = gameObject.AddComponent<AudioSource>();
            stepAud = gameObject.AddComponent<AudioSource>();
    
            emotAud.spatialBlend = 1;
            emotAud.maxDistance = 7;
    
            stepAud.spatialBlend = 1;
            stepAud.maxDistance = 7;
    
            emotAud.playOnAwake = false;
            stepAud.playOnAwake = false;
    
            dead = false;
            target = null;
            agent = GetComponent<NavMeshAgent>();
            anim = GetComponent<Animator>();
            killer = null;
        }
    
        // Update is called once per frame
        void Update () {
            if (photonView.isMine)
            {
    
                if (walking)
                {
                    agent.speed = walkSpeed;
                }
                else
                {
                    agent.speed = runSpeed;
                }
    
                if (health <= 0)
                {
                    if (!dead)
                    {
                        dead = true;
                        photonView.RPC("die", PhotonTargets.AllBuffered);
                    }
                }
    
                if (!target)
                {
                    if (!PhotonNetwork.offlineMode)
                    {
                        nextAttackTime = (float)PhotonNetwork.room.CustomProperties["remainTime"];
                    }
                    else
                    {
                        nextAttackTime = 0f;
                    }
    
                    PlayerController[] controllers = FindObjectsOfType<PlayerController>();
                    int randCh = Random.Range(0, controllers.Length);
    
                    if (controllers.Length > 0)
                    {
                        target = controllers[randCh];
                    }
                    anim.SetFloat("move", 0);
    
                }
                else
                {
    
                    if (Vector3.Distance(transform.position, target.gameObject.transform.position) > 1.8f)
                    {
                        if (Vector3.Distance(transform.position, target.gameObject.transform.position) > distantaLaCareIncepeSaMearga)
                        {
                            walking = false;
                        }
                        else
                        {
                            walking = true;
                        }
    
                        anim.SetBool("walking", walking);
                        anim.SetFloat("move", 1);
    
                        //print("Active: " + agent.isActiveAndEnabled + " Pend: " + agent.pathPending + " Has path: " + agent.hasPath);
    
                        if (agent.isActiveAndEnabled)
                        {
                            if (!agent.pathPending)
                            {
                                agent.SetDestination(target.gameObject.transform.position - transform.forward * 1.2f);
                            }
                        }
                    }
                    else
                    {
                        if (!PhotonNetwork.offlineMode)
                        {
                            if (nextAttackTime >= (float)PhotonNetwork.room.CustomProperties["remainTime"])
                            {
                                anim.SetTrigger("attack");
                                nextAttackTime -= timeBetweenAttacks;
                            }
                            else
                            {
                                anim.SetFloat("move", 0);
                            }
                        }
                        else
                        {
                            if (nextAttackTime <= 0f)
                            {
                                anim.SetTrigger("attack");
                                nextAttackTime += timeBetweenAttacks;
                            }
                            else
                            {
                                nextAttackTime -= Time.deltaTime;
                                anim.SetFloat("move", 0);
                            }
                        }
                    }
                }
            }
        }
    
        void OnDrawGizmosSelected()
        {
            if (target)
            {
                Gizmos.color = Color.blue;
                Gizmos.DrawSphere(agent.destination, 1);
            }
        }
    
        [PunRPC]
        void die()
        {
            if (killer)
            {
                killer.gameObject.GetComponent<PlayerController>().kill();
            }
    
            if (attackingAuds.Count > 0)
            {
                emotAud.clip = attackingAuds[Random.Range(0, attackingAuds.Count - 1)];
                emotAud.Play();
            }
    
            gameObject.GetComponent<CapsuleCollider>().enabled = false;
            Instantiate(ragdoll, transform.position, transform.rotation);
            Destroy(this.gameObject);
        }
    
        public void attack()
        {
            if (target && target.health >= 0)
            {
                if (Vector3.Distance(target.gameObject.transform.position, transform.position) <= 2f)
                {
                    target.doDamage(damage);
                    if (target.health <= 0)
                    {
                        target.photonView.RPC("die", PhotonTargets.All, true);
                    }
                }
            }
        }
    
        void OnCollisionEnter(Collision col)
        {
            if (col.gameObject.tag.Contains("Bullet"))
            {
                killer = col.gameObject.GetComponent<Magic_Bullet>().owner;
                target = killer.gameObject.GetComponent<PlayerController>();
                photonView.RPC("takeDamage", PhotonTargets.AllBuffered, col.gameObject.GetComponent<Magic_Bullet>().damage);
                PhotonNetwork.Destroy(col.gameObject);
            }
        }
    
        [PunRPC]
        void takeDamage(float dmg)
        {
            health -= dmg;
        }
    
        public void step()
        {
            stepAud.clip = stepAuds[Random.Range(0, stepAuds.Count - 1)];
            stepAud.Play();
        }
    
    }
    

    我做错了什么?

    1 回复  |  直到 6 年前
        1
  •  3
  •   Hesamom    6 年前

    你的更新功能中有一个地狱般的if-else,这让我们所有人都很头疼, 相反,尝试使用scriptableobject(作为unity官方教程)或需要硬编码的协同程序实现一个简单的FSM,这是不推荐的。

    https://unity3d.com/learn/tutorials/topics/navigation/finite-state-ai-delegate-pattern