Скрипт затрагивает только один игровой объект

Делая конечный автомат AI «игрой», у меня есть 3 состояния «Движение», «Бой» и «Вид». Все они работают очень хорошо, теперь я делаю бег (кстати, если у кого-то есть хорошие ссылки на учебники или информацию, которая у них есть под рукой, мне бы это понравилось) состояние, поэтому я хочу сделать все три предыдущих состояния в их Idle режим. Который отлично работает, когда у меня есть 1 AI. Как только я поставлю остальные (сейчас их всего 6), это все равно повлияет только на 1, но затем через некоторое время он «отпустит», я думаю, это лучший термин для сценария, и он просто вернется к трем предполагаемым состояниям. бездействовать. Я думаю, что в моем сценарии Coin я говорю найти, и я думаю, что это должно быть что-то еще, я просто не уверен, правильно ли это, но основан на моем предыдущем опыте, который обычно имеет место с Unity. Я опубликую некоторый код, но вот некоторая информация, которая может помочь вашим глазам, поскольку вам не нужно читать все:

-У меня есть логическое значение, настроенное в моем AIClass, которое является ложным, пока один из моих игровых объектов не столкнется с «монетой», а монета — это просто игровой объект, который я поместил в свою игру, чтобы проверить поведение моего ИИ. Когда это логическое значение верно, в моем обновлении в моем AIClass (извините, это в самом низу скрипта, вы можете прокрутить вниз, но мне пришлось поместить другой код на тот случай, если я что-то делал в этом, чтобы вызвать мою проблему.) Это устанавливает состояние MovementState в Idle, CombatState в Idle и ViewState в Idle.

-Кроме того, когда это логическое значение равно false, это единственный раз, когда происходит вызов перехода состояний. Например, обычно ИИ будет искать игрока, если найдет его, то подойдет к нему, а если окажется на определенном расстоянии, то выстрелит. Довольно просто. Перемещение между этими состояниями происходит в конце каждого IENumerator, когда вызывается «NextMovementState()», «NextCombatState()» или «NextViewState()». Поэтому, когда логическое значение истинно, их никогда не следует вызывать, останавливая ИИ от перехода в другое состояние, кроме Idle (в то, в котором он установлен, когда логическое значение истинно в обновлении).

И это прекрасно работает, когда у меня в игре только 1 ИИ.

CoinScript.cs

using UnityEngine;
using System.Collections;

public class CoinScript : MonoBehaviour {

    private AIClass a;
    // Use this for initialization
    void Start () {
        a = GameObject.Find ("Enemy").GetComponent<AIClass>();
    }

    // Update is called once per frame
    void Update () {

    }

    void OnCollisionEnter(Collision collision)
    {
        if (collision.collider)
        {
            if(collision.gameObject.tag == "Enemy" || collision.gameObject.tag == "EnemyProjectile")
            {
                Physics.IgnoreCollision(rigidbody.collider,collision.collider);
                //Debug.Log ("Enemy");
            }
            if(collision.gameObject.tag == "Player")
            {
                Debug.Log ("triggered!");
                a.fleeBool = true;
                Destroy(gameObject);
            }
        }
    }
}

AIClass.cs

using UnityEngine;
using System.Collections;

public class AIClass : MonoBehaviour
{
    public NavMeshAgent agent;

    //Ammo in gun before reloading is required
    public int ammo = 30;
    public int maxAmmo = 30;
    //Number of bullets a gun fires in sequence on 1 trigger pull
    public int chamber = 3;
    public int maxChamber = 3;
    //Pause between bursts or mouse presses, set to 0 for fully automatic
    public double chamberTime = 120;
    //How fast a gun fires in RPS
    public int fireRate = 7;
    public int fireTimer = 0;
    //How fast a gun can reload
    public int reloadTime = 3;
    public int reloadTimer = 0;
    //Number of bullets fired per shot
    public int bulletsFired = 1;
    public GameObject bulletClone;

    //Acceptable degrees as to which the AI will begin firing at its target
    public int firingAngle = 5;
    //Vision cone of degrees to left and right
    public int visionAngle = 35;
    public int visionDistance = 100;
    public int vRotationSpeed = 3;
    public int vIdleTimer = 0;
    public int vIdleTime = 300;
    public int searchTimer = 0;
    public int searchTime = 300;

    public int mIdleTimer = 0;
    public int mIdleTime = 300;


    public bool isFocusedOnPlayer = false;
    public bool seesPlayer = false;
    //
    public bool fleeBool;
    public bool flee;
    public enum MovementState
    {
        MSearch,
        MMoving,
        MIdle,
    }
    public enum CombatState
    {
        CFiring,
        CReloading,
        CIdle,
    }
    public enum ViewState
    {
        VSearch,
        VFocus,
        VIdle,
    }

    public enum FleeState
    {
        FSearch,
        FMoving,
        FIdle
    }
    public CombatState combatState;
    public ViewState viewState;
    public MovementState movementState;
    public FleeState fleeState;

    //Search state (knows where player is and will head to the player's location)
    IEnumerator MSearchState ()
    {   
        mIdleTimer = 0;
        int stuckTimer = 0;

        while (movementState == MovementState.MSearch)
        {
            //I've arrived at my location, if idle too long, then go back to idle state
            if(Vector3.Distance(transform.position,agent.destination) < 3)
                mIdleTimer++;
            //I'm stuck and haven't moved in a while, go back to idle state
            if(agent.velocity.magnitude < 1)
                stuckTimer++;
            if(seesPlayer || mIdleTimer > mIdleTime + 200 || stuckTimer > 300)
            {
                agent.destination = transform.position;
                movementState = MovementState.MIdle;
            }
            yield return 0;
        }
        if (!flee) {
                        NextMovementState();
                }

    }
    //Wander state
    IEnumerator MMovingState ()
    {   
        while (movementState == MovementState.MMoving)
        {
            //Wander code... Create a random angle and convert it to radians
            float randomAngle = (float)(3.14/180)*Random.Range(0,360);
            //Normalize direction vector, as we will be using it to calculate where we place the circle
            Vector3 tempV = agent.velocity;
            Vector3.Normalize (tempV);
            //Using our relative position, 5 units in front of us. Use the generated angle to find the point on the circle that we want to go to
            agent.destination =  transform.position + tempV * 3 + new Vector3(Mathf.Cos (randomAngle)*3,0,Mathf.Sin (randomAngle)*3);
            //Check to see if we are within the arena bounds, if not, push our projected vector back inside
            if(agent.destination.x > 24)
                agent.destination = agent.destination + new Vector3(-7,0,0);
            if(agent.destination.x < -24)
                agent.destination = agent.destination + new Vector3(7,0,0);
            if(agent.destination.z > 24)
                agent.destination = agent.destination + new Vector3(0,0,-7);
            if(agent.destination.z < -24)
                agent.destination = agent.destination + new Vector3(0,0,7);

            if(seesPlayer)
            {
                agent.destination = transform.position;
                movementState = MovementState.MIdle;
            }
            yield return 0;
        }
        if (!flee) {
                        NextMovementState ();
                }
    }
    //Not moving, if I don't see the player for awhile, then go wander
    IEnumerator MIdleState ()
    {   
        mIdleTimer = 0;
        while (movementState == MovementState.MIdle)
        {
            if(seesPlayer)
                mIdleTimer = 0;
            else
                mIdleTimer++;
            if(mIdleTimer > mIdleTime + Random.Range (-100,100))
                movementState = MovementState.MMoving;
            yield return 0;
        }
        if (!flee) {
                        NextMovementState ();
                }
    }
    //Visual search state, randomly look around and check to see if we see the player
    IEnumerator VSearchState ()
    {   
        Transform target = GameObject.FindWithTag ("Player").transform;
        Vector3 targetPosition = target.position;
        while (viewState == ViewState.VSearch)
        {
            searchTimer--;
            //Vision Cone calculation
            Vector3 targetDir = target.position - transform.position;
            Vector3 forward = transform.forward;
            float angle = Vector3.Angle(targetDir, forward);
            //If player is within vision cone then proceed
            if (angle < visionAngle)
            {
                //Check to see if there are any object between player and myself
                RaycastHit hit;
                if (Physics.Raycast(transform.position, targetDir, out hit))
                {
                    if(hit.transform == target)
                    {
                        seesPlayer = true;
                        viewState = ViewState.VFocus;
                    }
                }
            }
            //Look in another direction
            if(searchTimer < 0)
            {
                searchTimer = searchTime + Random.Range (-100,100);
                targetPosition = new Vector3(Random.Range (-100,100),transform.position.y,Random.Range (-100,100));
            }
            transform.rotation = Quaternion.Slerp(transform.rotation,Quaternion.LookRotation(targetPosition - transform.position), vRotationSpeed*Time.deltaTime);

            yield return 0;
        }
        if (!flee) {
                        NextViewState ();
                }
    }
    //Focus on player
    IEnumerator VFocusState ()
    {   
        Transform target = GameObject.FindWithTag ("Player").transform;
        while (viewState == ViewState.VFocus)
        {
            //Vision Cone calculation
            Vector3 targetDir = target.position - transform.position;
            Vector3 forward = transform.forward;
            float angle = Vector3.Angle(targetDir, forward);
            if (angle > visionAngle)
                viewState = ViewState.VIdle;
            else
            {
                RaycastHit hit;
                //Check if there are any objects in the way
                if (Physics.Raycast(transform.position, targetDir, out hit))
                {
                    if(hit.transform == target)
                    {
                        //Tell other AI where player is
                        GameObject[] objArray = GameObject.FindGameObjectsWithTag ("Enemy");
                        AIClass[] enemyArray = new AIClass[objArray.Length];
                        for(int i = 0; i < enemyArray.Length; i++)
                        {
                            enemyArray[i] = (AIClass)objArray[i].GetComponent(typeof(AIClass));
                            if(i >= enemyArray.Length/2)
                                enemyArray[i].agent.destination = target.position;
                            else
                                enemyArray[i].agent.destination = target.position + target.forward*5;
                            enemyArray[i].movementState = MovementState.MSearch;
                        }
                        seesPlayer = true;
                        transform.rotation = Quaternion.Slerp(transform.rotation,Quaternion.LookRotation(target.position - transform.position), vRotationSpeed*Time.deltaTime);
                        //Check to see player is within sights of the gun
                        if (angle < firingAngle)
                            isFocusedOnPlayer = true;
                        else
                            isFocusedOnPlayer = false;
                    }
                    else
                    {
                        //I no longer see the player
                        seesPlayer = false;
                        viewState = ViewState.VIdle;
                        isFocusedOnPlayer = false;
                    }
                }
            }
            yield return 0;
        }
        if (!flee) {
                        NextViewState ();
                }
    }
    //Visual idle state, basically the ai is just looking forward
    IEnumerator VIdleState ()
    {   
        vIdleTimer = 0;
        Transform target = GameObject.FindWithTag ("Player").transform;
        while (viewState == ViewState.VIdle)
        {
            //Vision cone calculation
            vIdleTimer++;
            Vector3 targetDir = target.position - transform.position;
            Vector3 forward = transform.forward;
            float angle = Vector3.Angle(targetDir, forward);
            //Check to see if there is an object is between the ai and the player
            if (angle < visionAngle)
            {
                RaycastHit hit;
                if (Physics.Raycast(transform.position, targetDir, out hit))
                {
                    if(hit.transform == target)
                    {
                        seesPlayer = true;
                        viewState = ViewState.VFocus;
                    }
                }
            }
            if(vIdleTimer > vIdleTime)
                viewState = ViewState.VSearch;
            yield return 0;
        }
        if (!flee) {
                        NextViewState ();
                }
    }
    //Firing gun state
    IEnumerator CFiringState ()
    {   
        while (combatState == CombatState.CFiring)
        {
            if(!isFocusedOnPlayer)
                combatState = CombatState.CIdle;
            fireTimer--;
            if(ammo > 0)
            {
                if(chamber > 0)
                {
                    if(fireTimer <= 0)
                    {
                        for(int i = 0; i < bulletsFired;i++)
                        {
                            GameObject temp = (GameObject) Instantiate (bulletClone,transform.position + transform.forward,transform.rotation);
                            temp.rigidbody.AddForce(transform.forward*500);
                        }
                        fireTimer = 60 / fireRate;
                        ammo--;
                        chamber--;
                    }
                }
                else
                {
                    chamber = maxChamber;
                    fireTimer = (int)(60/chamberTime);
                }
            }
            else
            {
                combatState = CombatState.CReloading;
            }
            yield return 0;
        }
        if (!flee) {
                        NextCombatState ();
                }
    }

    IEnumerator CReloadingState ()
    {
        reloadTimer = reloadTime * 60;
        while (combatState == CombatState.CReloading)
        {
            reloadTimer--;
            if(reloadTimer <= 0)
            {
                ammo = maxAmmo;
                combatState = CombatState.CIdle;
            }
            yield return 0;
        }
        if (!flee) {
                        NextCombatState ();
                }
    }

    IEnumerator CIdleState ()
    {   
        while (combatState == CombatState.CIdle)
        {
            if(isFocusedOnPlayer)
                combatState = CombatState.CFiring;
            yield return 0;
        }
        if (!flee) {
                        NextCombatState ();
                }
    }

    void Start ()
    {
        fleeBool = false;
        flee = false;
        NextCombatState();
        NextViewState();
        NextMovementState();
    }
    void NextMovementState()
    {   
        string methodName = movementState.ToString() + "State";
        System.Reflection.MethodInfo info = GetType().GetMethod(methodName, System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance);
        StartCoroutine((IEnumerator)info.Invoke(this, null));
    }
    void NextCombatState ()
    {
        string methodName = combatState.ToString() + "State";
        System.Reflection.MethodInfo info = GetType().GetMethod(methodName, System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance);
        StartCoroutine((IEnumerator)info.Invoke(this, null));
    }
    void NextViewState ()
    {
        string methodName = viewState.ToString() + "State";
        System.Reflection.MethodInfo info = GetType().GetMethod(methodName, System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance);
        StartCoroutine((IEnumerator)info.Invoke(this, null));
    }

    void NextFleeState()
    {
        string methodName = viewState.ToString() + "State";
        System.Reflection.MethodInfo info = GetType().GetMethod(methodName, System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance);
        StartCoroutine((IEnumerator)info.Invoke(this, null));
    }

    void Update()
    {
        Debug.DrawLine(transform.position, transform.position+transform.forward*5, Color.red);
        if (fleeBool == true) 
        {
            flee = true;
        }

        if (flee == true) 
        {
            Debug.Log ("flee is true");
            combatState = CombatState.CIdle;
            movementState = MovementState.MIdle;
            viewState = ViewState.VIdle;
            Debug.Log ("End of idles");
        }
    }

}

person Community    schedule 28.02.2014    source источник
comment
Я действительно думаю, что проблема в том, что я говорю GameObject.Find(Enemy) и, просмотрев документацию Unity, думаю, что находит только один. Итак, чтобы сузить мой вопрос, я действительно думаю, что это проблема, и мне интересно, как я могу сделать это, но с каждым ИИ.   -  person    schedule 28.02.2014


Ответы (2)


Вы можете использовать GameObject.FindObjectsOfType() или GameObject.FindGameObjectsWithTag

person Shredder2500    schedule 28.02.2014

вы можете сделать это, сохранив весь AIClass в массиве, а затем зациклив его, чтобы он стал конкретным, поэтому каждый враг может быть затронут

AIClass[] AIObject = GameObject.Find("Enemy").GetComponents<AIClass>();  
foreach(AIClass a in AIObject ){  
 //do something with a
}

он должен работать.

person Julio Andryanto    schedule 25.06.2015