1

我正在尝试在统一引擎中开发一种与光子网络系统一起使用的 AI。它应该相当简单:它跑向一个随机玩家,直到他与玩家之间的距离达到 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();
    }

}

我究竟做错了什么?

4

1 回答 1

3

好吧,你的更新函数中有一个 if else 的地狱,这让我们所有人都头疼,相反,尝试使用 scriptableobject(作为统一官方教程)或 Coroutines 实现一个简单的 FSM,这需要硬编码,不推荐。

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

于 2018-05-20T22:55:17.320 回答