← к содержанию

Урок 14. Включаем интерактивность

Наверное, вы и так давно догадались, что я немного англофоб :). Слово «интерактивность» мне не нравится (для тех, кому так же, как и мне, оно кажется кривым и непонятным, скажу что оно получилось от английского слова interactionвзаимодействие), но, к сожалению, именно этим словом компьютерные учебники называют процесс взаимодействия человека с программой. Типа, нажми на кнопку – получишь какую-то реакцию программы на это нажатие. До сих пор вся интерактивность наших примеров сводилась к нажатию клавиши Ecs для выхода из программы. В этом уроке добавим возможность «полетать» по нашей сцене.

За обработку событий, таких как нажатие клавиши на клавиатуре, движение мышью или каких-то событий окна в DDD отвечает модуль ddd.zavisimost.sobytija_SDL2. Модули в каталоге zavisimost (пока) не документированы, так что этот (и следующий) урок можно считать неким вариантом документации к модулю обработки событий. В этом модуле определены (на момент написания урока) четыре класса, каждый является классом-потомком предыдущего.

Самый базовый класс ОбработчикСобытий, хоть и не является абстрактным, но по факту его нельзя считать рабочим, в нём не определено ни одного события, только функции, отвечающие за регистрацию/разрегистрацию событий.

Его потомок МинимальныйОбработчикСобытий – это уже вполне действующий класс, в нём определены и зарегестрированы функции обработки событий окна. Если бы он был подключен по-умолчанию, то все предыдущие уроки-примеры работали бы так же, только не действовал бы выход по клавише Esc. Этот класс рекомендуется в качестве базового для создания обработчика событий в любой сколько-нибудь крупной программе, где пользователь сам будет решать, как должна действовать та или иная клавиша или кнопка мыши (или даже переопределять это поведение в настройках).

Следующий класс СтандартныйОбработчикСобытий добавляет к предыдущему единственную функциональность — выход из программы по клавише Esc. Этот класс включен в DDD по-умолчанию.

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

  1. Откройте модуль scena.d и добавьте перед объявлением функции сцена объявление ещё одной переменной модуля – нашего обработчика событий:

ОбработчикСобытийСДвижением обработчик_событий;
  1. Перейдите в начало функции сцена и добавьте первой строкой создание обработчика:

    обработчик_событий = new ОбработчикСобытийСДвижением();
  1. Теперь нам нужно указать библиотеке DDD использовать этот обработчик событий. Это мы делаем через менеджер:

    менеджер.задать_обработчик_событий(обработчик_событий);
  1. В принципе, при некотором способе организации графической библиотеки этого было бы достаточно: создали новый объект событий и подключили его, чего ещё надо? Но подход в DDD слегка отличается. Если сейчас запустить программу, то она будет работать как минимум не хуже, чем со стандартным обработчиком. Но вот новой функциональности так и не появится, «летать» по сцене мы не сможем. Если говорить конкретнее, то события нажатия клавиш и движения мыши срабатывать будут, но вот на Место, к которому присоединена камера, это не повлияет. Так сделано сознательно, потому что всё это должно быть частью обновления сцены, а функция обновление_сцены объявляется пользователем и находится у него (и в нашем модуле scena.d она таки есть!). Т.е. ещё раз: надо самостоятельно обновить Место, к которому присоединена камера, в функции обновление_сцены. Каких-то сложных телодвижений для этого не требуется, надо всего-то вызвать один метод обработчика событий. Перейдите к функции обновление_сцены и добавьте туда строку:

обработчик_событий.события_в_обновлении_сцены(менеджер, длительность_кадра);

Теперь, обработчик событий, имея в своём распоряжении значение длительности кадра и ссылку на менеджер (а через него на объект менеджер.место_камеры) сможет переместить и повернуть эту камеру требуемым образом. В каком-либо сложном приложении/игре пользователь может решить выполнить некие дополнительные действия с камерой перед вызовом этой функции, или вообще её не вызывать, а сделать всё самостоятельно. Так что это сделано для большей гибкости.

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


  2. Многие привыкли в играх управлять с помощью клавиш WASD, а не стрелками, и класс ОбработчикСобытийСДвижением такое управление допускает. У его конструктора есть необязательный (т. е., имеющий значение по-умолчанию) строковый параметр кнопки_управления. Если в него передать строку "WASD", то камера будет управляться этими клавишами, а если "стрелки и WASD", то, соответственно, и так и так. Для примера поменяйте конструктор на:

    обработчик_событий = new ОбработчикСобытийСДвижением("стрелки и WASD");

И сможете управлять камерой обоими способами.

Если сильно приблизиться к самолётику, то можно увидеть действие плоскости ближнего отсечения, о котором говорилось в предыдущем уроке – ближняя часть самолётика будет отрезаться. Чтобы этого не происходило в настоящей игре, вам понадобится самостоятельно каким-то образом «обрабатывать столкновения» с объектами и не подпускать камеру слишком близко к ним.