P
P
password222021-04-13 21:02:59
Unity
password22, 2021-04-13 21:02:59

I can't find a bug in the implementation of the State pattern (StateMachine)?

Good evening. How it should work: characters spawn on my stage (Character.cs), I click one at a time, it goes into the selected state, then I click on the place and it goes there. BUT. They all go to the same place! That is, I click on one, then on the place, and they all go there.

I studied all the code, double-checked everything I could, but I could not figure it out. Perhaps some knowledge is not enough.

Scripts:
1. StateMachine - stores the current state
2. State - an abstract class, states are inherited from it
3. SelectState - the state of the selected character
4. UnselectState the state of the NOT selected character
5. Character - the

StateMachine object itself (1)

public class StateMachine
{
    public State CurrentState { get; private set; }


    public void Initialize(State startingState)
    {
        CurrentState = startingState;
        startingState.Enter();
    }

    public void ChangeState(State newState)
    {
        CurrentState.Exit();

        CurrentState = newState;
        newState.Enter();
    }
}


State (2)

public abstract class State
{
    protected Character character;
    protected StateMachine stateMachine;

    protected State(Character _character, StateMachine _stateMachine)
    {
        character = _character;
        stateMachine = _stateMachine;
    }

    public virtual void Enter(){}
    public virtual void HandleInput(){}
    public virtual void Exit() {}

    public void ForEveryone(){}
}


Select State (3)

public class SelectState : State
{
    public SelectState(Character character, StateMachine stateMachine) : base(character, stateMachine) { }

    public override void HandleInput()
    {
        base.HandleInput();

        if (Input.GetMouseButtonDown(0))
        {
            var hit = character.Ray();

            character.agent.SetDestination(hit.point);
            character.stateMachine.ChangeState(character.unselect);
        }
    }

}


UnselectState(4)

public class UnselectedState : State
{
    public UnselectedState(Character character, StateMachine stateMachine) : base(character, stateMachine) { }

    public override void HandleInput()
    {
        base.HandleInput();

        if (Input.GetMouseButtonDown(0))
        {
            var hit = character.Ray();

            if (hit.collider.gameObject.tag == "Agent") character.stateMachine.ChangeState(character.select);
            else return;
        }
    }

}


character (5)

public class Character : MonoBehaviour, IPooledObject //интерфейс для пулинга персонажей
{
    [NonSerialized] public StateMachine stateMachine;
    [NonSerialized] public SelectState select;
    [NonSerialized] public UnselectedState unselect;

    [NonSerialized] public NavMeshAgent agent;

    public void OnObjectSpawn() //персонажи спавнятся из пула. В этот момент они создаются
    {
        stateMachine = new StateMachine();
        select = new SelectState(this, stateMachine);
        unselect = new UnselectedState(this, stateMachine);

        stateMachine.Initialize(unselect); //выбираем изначальное состояние

        agent = GetComponent<NavMeshAgent>();
    }

    public void Update()
    {
        stateMachine.CurrentState.HandleInput();
    }


    public RaycastHit Ray()
    {
        RaycastHit hit;
        Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);

        if (Physics.Raycast(ray, out hit, Mathf.Infinity)) return hit;
        return hit;
    }

}


I would be glad for any help or hint where to dig! Thanks

Answer the question

In order to leave comments, you need to log in

1 answer(s)
T
twobomb, 2021-04-14
@password22

public GameObject[] goArray;

        public void Awake(){
            foreach (var go in goArray)
                go.GetComponent<Character>().isSelected = false;
        }

        public GameObject selected{//Вернет выделенного персонажа, если нет такого то null
            get{
                foreach (var go in goArray)
                    if (go.GetComponent<Character>().isSelected)
                        return go;
                return null;
            }
        }

        public void Update(){
            if (Input.GetMouseButtonDown(0)){
                var hit = Ray();
                if (hit.collider.gameObject.tag == "Agent"){
                    var _ch = hit.collider.gameObject.GetComponent<Character>();
                    if(selected != null)
                        selected.isSelected = false;
                    _ch.isSelected = true;

                } else if (hit.collider.gameObject.tag == "Ground"){
                    if(selected != null)
                        selected.GetComponent<Character>().agent.SetDestination(hit.point);
                }
                else if (selected != null)
                        selected.isSelected = false;
            }
        }

Didn't find what you were looking for?

Ask your question

Ask a Question

731 491 924 answers to any question