Продолжение статьи Введение в Nebula 2: Mangalore. В данном продолжении рассказывается как создавать анимированные объекты, как управлять ими с помощью клавиатуры и как делать для них collision detection.
В этой части статьи мы рассмотрим как работать с анимированными графическими объектами, как управлять объектами при помощи клавиатуры, как делать статические препятствия.
Итак, пора нам уже добавить в наш мир какое-нибудь прямоходячее существо. В мангалоре подобные существа называются актерами. В дальнейшем мы будем экпериментировать над "актером" kila. Копируем все ресурсы, которые связаны с этим объектом (смотрите скрипт kila.n2) из папки небулы в папку нашего проекта. Теперь настраиваем анимации. Открываем в Microsoft Excel 2003 таблицу anims.xml. В этой таблице связываются состояние актера с какой-либо из его анимаций. Добавляем столбец kila. У нашего актера только одна анимация. Поэтому напротив всех трех состояний вводим название анимации "one". Переходим к программному коду. Добавляем в наш главный класс TutorialApp функцию SetupPlayer. Опять также создаем entity, но теперь вместо graphics property создаем и крепим к entity ActorGraphicsProperty. Через атрибут AnimSet указываем название столбца в таблице anims.xml, который соответствует актеру (у нас это kila). Чтобы переключиться на другую анимацию надо послать для entity сообщение Message::GfxSetAnimation. Также теперь отбираем свойство ChaseCameraProperty у ящика и ставим его нашему актеру. В итоге код функции SetupPlayer.
Не забываем добавить вызов SetupPlayer в функцию Open. Компилируем и запускаем. На экране мы видим шагающего актера, мимо пролетает ящик, а где то в дали земля. Давайте сделаем, чтобы наш актер тоже не висел в воздухе. Создаем свойство ActorPhysicsProperty и добавляем его нашему актеру. Это свойство отличается от обыкновенного PhysicsProperty тем, что оно всегда создает вокруг нашего актера капсуль, при чем для любого объекта создается капсуль с одними и теме же размерами, и который при симулировании физики всегда ориентирован вдоль оси Y и никогда не может завалиться на бок. Также это свойство используется для ragdoll. Ragdoll настраивается через файл композита (как это сделать смотрите файл compositeloader.cpp), который передается entity для ActorPhysicsProperty через атрибут Physics. Нам это свойство не совсем нравится, потому что нельзя изменить параметры капсуля. Поэтому создаем свое свойство ActorPhysicsProperty2, которое наследует ActorPhysicsProperty. Наше свойство будет отличаться только тем, что оно будет брать соответствующие атрибуты и создавать капсуль нужного нам размера.
Добавляем ActorPhysicsProperty2 для нашего entity. Компилируем и запускаем. К сожалению, наш актер по-прежнему стоит на месте и падать не собирается. Нажимаем на F2, чтобы убедится, что нашему актеру присоединен физический объект. Как мы видим он синего цвета, т.е он выключен. Возможно вы скажите, что надо включить физику, точно так же как мы это делали для ящика. Но, к сожалению, это не помогает. После пошаговой отладки я выяснил, что постоянно блокирует нашего актера работа функций Physics::CharEntity::OnStepBefore и Physics::CharEntity::CheckGround. Посмотрев на эти функции, я понял, что физика включится, только после того как мы начнем управлять нашим актером. Не знаю в чем была задумка разработчиков, но при данных обстоятельствах нам всегда надо будет размещать актера возле земли. И неизвестно как будет вести себя актер, допустим, когда он попадет в яму. Если игрок, управляющий актером перестанет давать команды движения, то наш актер зависнет в воздухе.
Ладно, смиримся пока с этим обстоятельством. Давайте сделаем управление актером. Создаем свойство PlayerInputProperty, которое наследует InputProperty. По названиям тут все понятно что к чему. Это свойство будет перехватывать сообщения, которые посылает клавиатура и мышь. Обрабатывая, эти сообщения мы будем посылать сообщения нашему актеру, чтобы он соответствующим образом двигался. Помните я говорил, что, чтобы изменить состояние какого-либо объекта, то ему надо послать соответствующее сообщение. Сообщения обрабатывают property, поэтому смотрите программный код того или иного property и вы узнаете какие сообщения оно обрабатывает и что при этом менятеся.
playerinputproperty.h
#ifndef PLAYERINPUTPROPERTY_H
#define PLAYERINPUTPROPERTY_H
#include<properties/inputproperty.h>namespace Properties
{
class PlayerInputProperty: public InputProperty
{
DeclareRtti;
DeclareFactory(PlayerInputProperty);
public:
PlayerInputProperty();
~PlayerInputProperty();
/// setup default entity attributesvoid SetupDefaultAttributes();
/// called when input focus is gainedvoid OnObtainFocus();
/// called when input focus is lostvoid OnLoseFocus();
bool Accepts(Message::Msg *msg);
void HandleMessage(Message::Msg *msg);
};
RegisterFactory(PlayerInputProperty);
}
#endif