Творец. День третий. Командный центр

Хо-хо, товарищи! Центр обеспечения техподдержки уполномочен заявить: мы руководим всем миром. Вот так! А кто-то всё ещё косится в сторону Белого дома... Не-а, ни в коем разе. Запомните: the keyboard and the mouse are rulezzz of the world. Сплюньте.

Для управления в компьютерных играх иногда ещё используют джойстик. Правда, нынче – только в авиасимуляторах и близлежащих с ними жанрах. GLScene способен и на такую гимнастику, однако к чему нам эти проблемы? Нам вполне хватит клавиатуры и мышки. Моя дырявая память мне подсказывает, что в «Мегабайте» под номером 37’2007, я уже говорил о добавлении модуля Keyboard в раздел Uses проекта Delphi.

Open Клавиатура
В комплекте GLScene какой-то отдельной демо-программки для клавиатуры и мышки я не нашёл. Да и к чему? Управление объе-ктами и так необходимо почти в любом 3D-приложении. Какие особенности работы с клавиатурой и мышкой в движке GLScene? Да никаких. Элементарность и удобство – вот, похоже, и всё.
Компонента, отвечающего за клавиатуру, в составе GLScene нет – достаточно просто добавить заветное слово Keyboard в раздел Uses, после чего станет доступна процедура IskeyDown, проверяющая нажатие клавиш. С мышкой интереснее: для работы с ней используется компонент GLUserInterface. В его свойствах мы можем поиграться с инвертированием по осям X и Y, задать максимальный-минимальный угол поворота и... собственно, всё. Однако GLUserInterface отказывается работать без основного компонента GLNavigator. А вот его возможности гораздо шире. GLNavigator – это компонент управления перемещением какого-либо объекта – к примеру, камерой, символизирующей собой ГлавГероя, или каким-нибудь вполне материальным объектом. В нашем случае, это Player, за выполнение обязанностей которого, как вы помните, у нас отвечает товарищ GLActor.

Центр уполномочен заявить
Добавляем на форму GLNavigator и назначаем значение Player.UseVirtualUp=True, во вкладке VirtualUp: X=0, Y=1, Z=0. Теперь управляем Player`ом так (перемещение вперёд):

GLNavigator1.MoveForward(3*deltatime);

Если укажем в скобках отрицательное значение, то Player побежит назад. Deltatime – это константа для каждого компьютера, что-то вроде усредняющего значения. Если вы не будете использовать эту функцию, то на Pentium-133 наш Player будет двигаться медленнее черепахи, а на процессорах уровня Athlon64 3000+ – носиться со скоростью света.
Весь код управления игроком будем писать в процедуре GLCadencer1Progress (именно там используется константа deltatime). Также не забывайте о том, что мы можем теперь анимировать нашего GLActor. Если вы всё сделали правильно, следуя рекомендациям прошлой статьи, то теперь можете указывать текущую анимацию для Player.
Вот как реализовал это я. В процедуру GLCadencer1Progress добавил локальную переменную anim типа string. Безо всяких условий, я решил, что anim:='stand', после чего начал проверять нажатие различных клавиш по принципу:

if IsKeyDown(VK_LEFT) then
 begin
  GLNavigator1.StrafeHorizontal(-3*deltatime);
  anim:='run';
 end;

И в конце концов, я стал указывать для Player`а анимацию anim:

if Player.CurrentAnimationanim
 then
  begin
   Player.SwitchToAnimation(anim);
   Weapon.Synchronize(Player);
  end;

А куда идти-то?
Проверок клавиш я сделал две: для VK_LEFT и VK_RIGHT (это обычные клавиатурные стрелки). Когда нажимаются эти клавиши, то Player смещается на определённое положение влево-вправо и запускается анимация run. Также стоит вспомнить о том, что в идеале Player должен смотреть в ту сторону, куда он бежит. Эти обязанности я возложил на игрока. Пусть он мышкой указывает, куда должен смотреть Player:

if X<Player.Position.X+470
 then Player.RollAngle:=0
 else Player.RollAngle:=–180;

(эта строчка прописывается в процедуре GLSceneViewer1MouseMove).
Теперь насчёт камеры. Вариантов может быть два: либо вы устанавливаете камеру в неподвижное положение – при этом полностью обозревается весь уровень, – либо указываете GLCamera1 потомком для Player и… стоп! Если вы произведёте такие манипуляции, то с камерой произойдёт необъяснимое – в лучшем случае, просто поменяется угол обзора. А дело вот в чём. Если вы назначаете потомком какой-либо объект, то он получает в наследство свойства Up.X, Up.Y, Up.Z. Эти свойства – что-то вроде локальной системы координат, для которой тело отсчёта – это сам объект. Если вы щёлкнете по трём точкам напротив свойства Up объекта Player, то откроется окно «XYZ editor». Собственно говоря, вы сможете указать здесь инвертность по какой-либо из осей. Например, установили вы инвертность по оси Y. Теперь при увеличении значения координаты по этой оси тело будет двигаться не вверх, а вниз. Чувствуете, чем пахнет? Мы задавали координаты камеры, исходя из её локальной системы координат. А тут – нате вам: они вдруг перемешались. Поэтому если хотите, чтобы камера всюду ходила за Player, добавьте в процедуру GLCadencer1Progress следующий код:

GLCamera1.Position.X:=Player.Position.X;
GLCamera1.Position.Y:=Player.Position.Y;

«Лопай, что дают» (по Чехову)
Если вам совсем лень печатать весь приведённый в статье код, зайдите на наш форум, в раздел «Файловый архив». Там выложены ссылки на исходный код и уже скомпилированную версию описанной в цикле игрушки.
Кстати, там же вы можете предложить свой вариант названия разрабатываемого проекта.


Рекомендуем почитать: