Search Unity

Unintended Shared Variables in FSM States

Discussion in 'Scripting' started by SpaceTako, Mar 2, 2020.

  1. SpaceTako

    SpaceTako

    Joined:
    Feb 15, 2018
    Posts:
    6
    I'm trying to create a simple state machine for my AI but am encountering an issue in my wander state. The issue comes from trying to set the currentPosition variable of the gameobjects currently in my Wander state
    Code (CSharp):
    1. if (haveCurrentPosition == false)
    2.             {
    3.                 haveCurrentPosition = true;
    4.                 Debug.Log("Owners name is : " + stateController.ourSelf.name);
    5.                 currentPosition = stateController.ourSelf.position;
    6.             }
    in a MonoBehaviour version of this code I made, this code runs fine and each game object gets its own independent current position value. In the Abstract class version made for the state machine each gameobject shares the current position value. How would I be able to obtain an independent value for each of my game objects so that they all have their own paths to travel opposed to all going to the same destination?
    All of the AI sharing a SINGLE path in the FSM abstract class version

    Independent Paths for each AI in the MonoBehaviour

    and the rest of my code just in case its needed

    States Base Class
    Code (CSharp):
    1. public abstract class FSMState : ScriptableObject
    2. {
    3.     public abstract void EnterState(StateController stateController);
    4.     public abstract void RunState(StateController stateController);
    5.     public abstract void ExitState(StateController stateController);
    6. }
    Wander State
    Code (CSharp):
    1. public class FlyingWanderState : FSMState
    2. {
    3.     public FSMState transitionState;
    4.     public float speed;
    5.     [SerializeField] float distanceToBeginChase;
    6.     [Header("Wander Distance Range")]
    7.     [SerializeField] float minWanderDistance;
    8.     [SerializeField] float maxWanderDistance;
    9.  
    10.     bool isCalculatingMovement;
    11.     bool haveCurrentPosition;
    12.     Vector3 wanderDirection;
    13.     Vector3 currentPosition;
    14.     float wanderDistance;
    15.  
    16.     //BUG thery're all sharing the same current position leading to the buggy behavior im seeing
    17.     public override void EnterState(StateController stateController)
    18.     {
    19.         stateController.ourSelf.GetComponent<NavMeshAgent>().enabled = false;
    20.         ResetRNG();
    21.     }
    22.  
    23.     public override void RunState(StateController stateController)
    24.     {
    25.         FindAPositionToWanderTo(stateController);
    26.         //transitions
    27.         float distanceToPlayer = Vector3.Distance(stateController.ourSelf.position, stateController.player.position);
    28.         if (distanceToPlayer < distanceToBeginChase)
    29.         {
    30.             stateController.ChangeState(transitionState);
    31.         }
    32.     }
    33.     public override void ExitState(StateController stateController)
    34.     {
    35.         stateController.ourSelf.GetComponent<NavMeshAgent>().enabled = true;
    36.         ResetRNG();
    37.     }
    38.  
    39.     int GenerateMultiplier()
    40.     {
    41.         if (Random.value < 0.5f)
    42.             return -1;
    43.         else
    44.             return 1;
    45.     }
    46.  
    47.     void FindAPositionToWanderTo(StateController stateController)
    48.     {
    49.         if (isCalculatingMovement == true)
    50.         {
    51.             wanderDirection = new Vector3(Random.Range(0, 1) * GenerateMultiplier(), Random.Range(0, 1) * GenerateMultiplier(), Random.Range(0, 1) * GenerateMultiplier());
    52.             if (wanderDirection == Vector3.zero)
    53.             {
    54.                 wanderDirection = new Vector3(Random.Range(.1f, 1) * GenerateMultiplier(), Random.Range(.1f, 1) * GenerateMultiplier(), Random.Range(.1f, 1) * GenerateMultiplier());
    55.             }
    56.             wanderDirection.Normalize();
    57.  
    58.             wanderDistance = Random.Range(minWanderDistance, maxWanderDistance);
    59.             isCalculatingMovement = false;
    60.         }
    61.         else
    62.         {
    63.             if (haveCurrentPosition == false)
    64.             {
    65.                 haveCurrentPosition = true;
    66.                 Debug.Log("Owners name is : " + stateController.ourSelf.name);
    67.                 currentPosition = stateController.ourSelf.position;
    68.             }
    69.  
    70.             Ray destinationCheck = new Ray(currentPosition, wanderDirection);
    71.             Debug.DrawRay(currentPosition, wanderDirection * wanderDistance, Color.black);
    72.  
    73.             if (Physics.Raycast(destinationCheck, out var hitInfo, wanderDistance))
    74.             {
    75.                 isCalculatingMovement = true;
    76.             }
    77.             else
    78.             {
    79.                 //we can move to our new position
    80.                 Vector3 destination = currentPosition + (wanderDirection * wanderDistance);
    81.                 Debug.Log("Current Position is : " + currentPosition);
    82.                 Debug.DrawLine(currentPosition, destination, Color.cyan);
    83.                 stateController.ourSelf.position = Vector3.MoveTowards(stateController.ourSelf.position, destination, Time.deltaTime * speed);
    84.                 if (stateController.ourSelf.position == destination)
    85.                 {
    86.                     ResetRNG();
    87.                 }
    88.             }
    89.         }
    90.     }
    91.  
    92.     void ResetRNG()
    93.     {
    94.         isCalculatingMovement = true;
    95.         haveCurrentPosition = false;
    96.     }
    State Controller
    Code (CSharp):
    1. public class StateController : MonoBehaviour
    2. {
    3.     //all the variables needed to make the ai run
    4.     public FSMState currentState;
    5.     public NavMeshAgent navMesh;
    6.     public Transform player;
    7.     public bool isInit;
    8.     public Transform ourSelf;
    9.  
    10.     private FSMState previousState;
    11.  
    12.     private void Awake()
    13.     {
    14.         navMesh = this.GetComponent<NavMeshAgent>();
    15.         player = GameObject.FindGameObjectWithTag("Player").transform;
    16.         previousState = currentState;
    17.         ourSelf = this.transform;
    18.     }
    19.  
    20.     void Start()
    21.     {
    22.         InitalizeState(currentState);
    23.     }
    24.  
    25.     void Update()
    26.     {
    27.         //find out if our state has changed
    28.         if(previousState != currentState && isInit == false)
    29.         {
    30.             //a change has occured
    31.             InitalizeState(currentState);
    32.         }
    33.         //run the state
    34.         currentState.RunState(this);
    35.     }
    36.  
    37.     public void ChangeState(FSMState newState)
    38.     {
    39.         previousState = currentState;
    40.         //clean out the state
    41.         currentState.ExitState(this);
    42.         currentState = newState;
    43.         isInit = false; //new state needs to be initalized
    44.     }
    45.  
    46.     public void InitalizeState(FSMState state)
    47.     {
    48.         isInit = true;
    49.         state.EnterState(this);
    50.     }
    51. }