Шаблон команда

Tulenber 29 May, 2020 ⸱ Beginner ⸱ 4 min ⸱ 2019.3.14f1 ⸱

Добавим ещё один шаблон в нашу копилку и посмотрим, что из себя представляет шаблон “Команда”.

Управление - это неотъемлемая часть игры. Исключите управление и в лучшем случае игра превратится в кино. Хотя в последнее время даже кино начинает предоставлять возможность управления происходящим на экране, например “Чёрное зеркало: Брандашмыг” или “Мозаика” Стивена Содерберга. Базовое создание управления в игре, как и практически любая вещь в программировании, не представляет из себя чего-то сложного. Всего лишь нужно вставить вызов функции, которая проверяет клик по левой кнопке мышки и вот вы настроили выстрел. Потом вызвали другую функцию и, по нажатию кнопки пробел на клавиатуре, ваш персонаж уже прыгает. Ещё дюжина вызовов размазанных по всему коду и можно выходить в продакшн. Добавить в игру настройку действий? В iOs появилась возможность использования Xbox/DualShock контроллеров и хорошо бы добавить их поддержку? Игру нужно портировать на консоль? Нет мы так не договаривались. В общем, понятно, что простая задача всегда может превратиться в сложную из-за небольшого изменения требований, а сгладить рост сложности, в случае с настройкой управления, поможет шаблон “Команда”.

Теория

Официальное описание шаблона гласит, что команда представляет собой объект-обёртку над вызовом. Этот подход позволяет легко передавать команды между объектами, перенастраивать их поведение, а также создавать из них последовательности. Для более глубокого знакомства с теоретической частью можно обратиться к этой главе из книги Роберта Нистрома или этой статье.

Сравнение со стратегиями

По своей сути и базовой реализации команды очень похожи на стратегии, которые мы рассмотрели в прошлой статье цикла о шаблонах, но их использование различается масштабом и областью применения. Команда превращает разнородные действия в объекты, в результате чего появляется свобода действия с ними, например, отмена операции. Стратегия же обычно описывает изменение внутреннего поведения конкретной сущности.

Последовательности команд

Объекты команд позволяют легко создавать из них последовательности, что можно использовать для поддержки отмены/возврата действий по шагам, всё, что вам нужно, это дополнить объект команды данными об обратных действиях. Это не очень применимо к экшен играм, однако, может пригодиться в пошаговой стратегии или создании редактора для настроек каких-либо игровых элементов.

Практика

В качестве практического примера воспользуемся наработками из предыдущей статьи о стратегиях и добавим управление магом, применив шаблон команд. Создадим 3 команды: использование заклинания, переключение между заклинаниями, а также создание противника.

Реализация

  1. Базовый класс команды:
1
2
3
4
5
// Базовый класс команды
public abstract class Command
{
    public abstract void Execute();
}
  1. Команды:
  1. Использование заклинания:
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
// Команда использования заклинания
public class FireSpellCommand : Command
{
    private Mage _mage = null;

    public FireSpellCommand(Mage mage)
    {
        _mage = mage;
    }
    
    public override void Execute()
    {
        _mage.FireSpell();
    }
}
  1. Переключение заклинания:
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
// Команда изменения заклинания
public class ChangeSpellCommand : Command
{
    private Mage _mage = null;

    public ChangeSpellCommand(Mage mage)
    {
        _mage = mage;
    }
    
    public override void Execute()
    {
        _mage.ChangeSpell();
    }
}
  1. Создание противника:
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
// Команда создания противника
public class SpawnEnemyCommand : Command
{
    private EnemyHandler _enemyHandler;

    public SpawnEnemyCommand(EnemyHandler enemyHandler)
    {
        _enemyHandler = enemyHandler;
    }
    
    public override void Execute()
    {
        _enemyHandler.SpawnEnemy();
    }
}
  1. Управление командами:
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
using UnityEngine;

public class InputHandler : MonoBehaviour
{
    // Управляющие магом и противником объекты
    public Mage mage = null;
    public EnemyHandler enemyHandler = null;

    // Привязка действий к командам
    private Command _leftMouseClick = null;
    private Command _rightMouseClick = null;
    private Command _spaceKeyboardPush = null;

    // Start is called before the first frame update
    void Start()
    {
        // Создание команд
        _leftMouseClick = new FireSpellCommand(mage);
        _rightMouseClick = new SpawnEnemyCommand(enemyHandler);
        _spaceKeyboardPush = new ChangeSpellCommand(mage);
        
    }

    // Update is called once per frame
    void Update()
    {
        // Клик левой кнопки мышки
        if (Input.GetMouseButtonDown(0))
        {
            _leftMouseClick.Execute();
        }

        // Клик правой кнопки мышки
        if (Input.GetMouseButtonDown(1))
        {
            _rightMouseClick.Execute();
        }

        // Нажатие кнопки пробел
        if (Input.GetKeyDown(KeyCode.Space))
        {
            _spaceKeyboardPush.Execute();
        }
    }
}

Результат

Как несложно заметить действия были абстрагированы от вызывающего их кода, что упростит создание настроек или расширение методов управления.

Заключение

Мы живём в такое время, когда мобильные устройства, помимо стандартного и зачастую неудобного управления через тачскир, получают поддержку полноценных игровых(и не только) контроллеров, да и выпуск игры редко происходит только на одной платформе. А настройка управления всегда была элементом проявления дружелюбности к игроку. Для облегчения борьбы с этими вызовами вполне подходит рассмотренный нами шаблон команд. Однако не забывайте, что злоупотребление шаблонами может превратить ваш код в лазанью. Пока! =)



Privacy policyCookie policyTerms of service
Tulenber 2020