password22
@password22

Не могу найти ошибку в реализации паттерна «Состояние» (StateMachine)?

Добрый вечер. Как ведь должно работать: у меня на сцене спавнятся персонажи (Character.cs), я жму по одному, он переходит в состояние выбранного, затем жму на место и он идет туда. НО. Они все идут в одно место! То есть я жму на одного, затем на место, а они все идут туда.

Я изучил весь код, перепроверил все что только можно, но так и не смог разобраться. Возможно, недостаточно каких-то знаний.

Скрипты:
1. StateMachine - хранит текущее состояние
2. State - абстрактный класс, от него наследуются состояния
3. SelectState - состояние выбранного character
4. UnselectStateсостояние НЕ выбранного character
5. Character - сам объект

StateMachine (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(){}
}


SelectState (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;
    }

}


Буду рад любой помощи или подсказке, куда копать! Спасибо
  • Вопрос задан
  • 97 просмотров
Решения вопроса 1
twobomb
@twobomb
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;
            }
        }
Ответ написан
Пригласить эксперта
Ответы на вопрос 1
DanceM
@DanceM Куратор тега Unity
Кто хочет -ищет способ, кто не хочет -ищет причину
Если я правильно понял, то у каждого персонажа СВОЯ машина StateMachine, свой SelectState, и каждому он по клику мыши отправляет точку, куда идти. Вот все и идут.
Ответ написан
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Войти через центр авторизации
Похожие вопросы