Как правильно разделять движение и ввод?

Как правильно организовать движение игрока с использованием InputController и класса Person? Как лучше передавать данные о вводе из InputController в метод move класса Person?
  • 16 января 2024 г. 14:30
Ответы на вопрос 2
Для того чтобы правильно разделить движение и ввод, полезно использовать принципы проектирования программного обеспечения, такие как разделение ответственности (Separation of Concerns) и инверсия зависимостей (Dependency Inversion).

Вот один из возможных способов организации кода:

1. `InputController` занимается только обработкой пользовательского ввода и не должен знать, что делается с этой информацией. Его задача — определить, какие действия хочет совершить пользователь, и сгенерировать соответствующие сигналы или команды.

2. `Person` (игровой персонаж) содержит методы для перемещения и другой логики поведения, но не знает о существовании `InputController`.

3. Создайте промежуточный слой (например, `PlayerController`, `GameplayController` или даже `EventSystem`), который будет получать команды от `InputController` и вызывать соответствующие методы в `Person`.

Пример кода на C# с использованием Unity3D (псевдокод):

```csharp
// Класс, который обрабатывает ввод пользователя
public class InputController : MonoBehaviour
{
    public event Action<Vector2> OnMoveInput;

    void Update()
    {
        Vector2 moveInput = new Vector2(Input.GetAxis("Horizontal"), Input.GetAxis("Vertical"));
        if (moveInput != Vector2.zero)
        {
            OnMoveInput?.Invoke(moveInput); // Вызываем событие с текущим вектором движения
        }
    }
}

// Класс игрока
public class Person
{
    // Метод для обработки движения
    public void Move(Vector2 direction)
    {
        // Здесь ваш код для движения, например, изменение положения transform
        transform.Translate(direction * speed * Time.deltaTime);
    }
}

// Класс контроллера персонажа, который связывает InputController и Person
public class PlayerController : MonoBehaviour
{
    private InputController inputController;
    private Person person;

    void Awake()
    {
        inputController = GetComponent<InputController>();
        person = GetComponent<Person>();
        inputController.OnMoveInput += HandleMoveInput; // Подписываемся на событие
    }

    // Обработчик события ввода движения
    private void HandleMoveInput(Vector2 input)
    {
        person.Move(input); // Передаем ввод в метод Move класса Person
    }
    
    void OnDestroy()
    {
        inputController.OnMoveInput -= HandleMoveInput; // Отписываемся от события при уничтожении объекта
    }
}
```

Такая структура позволяет вам легко изменять способ получения ввода (например, для других платформ или устройств ввода), не затрагивая класс `Person`. Кроме того, `Person` не зависит от конкретных реализаций ввода данных, что делает этот класс более модульным и удобным для тестирования.

Когда вы связываете всё вместе в Unity, вы просто добавляете эти компоненты (скрипты) на один игровой объект (GameObject), который представляет игрока. Компонент `PlayerController` служит связующим звеном между вводом пользователя и логикой движения персонажа.
В InputController держишь ссылку на Person . 
Когда происходит ввод, то просто вызываешь нужный метод у твоего Person
Похожие вопросы