[ Новые сообщения · Участники · Правила форума · Поиск · RSS ]
  • Страница 1 из 1
  • 1
Форум » Игровые движки » IrrLicht Engine » Туториал №4: Движение (сложность: легкий)
Туториал №4: Движение (сложность: легкий)
MerGC_TeamДата: Суббота, 01.03.2014, 12:20 | Сообщение # 1
Веселый админ
Группа: Администраторы
Сообщений: 32
Статус: Оффлайн
Тема данного туторила – перемещение узлов(нод) сцены с помощью клавиатуры, аниматоров и анимирование узлов. Попутно, этот туториал пример того, как можно ограничить число кадров в секунду, т.е скорость движения объектов на сцене будет относительна времени.

Как обычно, подключаем заголовочный файл движка IrrLicht, объявляем пространство имен ‘irr’ включенным.

Код
#include <irrlicht.h>
#include "driverChoice.h"
using namespace irr;


Для обработки таких событий как события мыши, клавиатуры, пользовательского интерфейса необходимо реализовать класс унаследованный от irr::IEventReceiver и переопределить его метод irr::IEventReceiver::OnEvent(), потом мы создадим объект на основе своего класса, “сообщим” про него движку, а движок, в свою очередь, каждый раз когда в нем возникает событие, будет вызываеть наш обработчик OnEvent.

Код
class MyEventReceiver : public IEventReceiver
{
public:
// наш собственный обработчик событий
virtual bool OnEvent(const SEvent& event)
{
// просто запоминаем состояние любой клавиши - нажата/отжата
if (event.EventType == irr::EET_KEY_INPUT_EVENT)
KeyIsDown[event.KeyInput.Key] = event.KeyInput.PressedDown;
return false;
}
   
// метод возвращающий состояние для запрошенной клавиши
virtual bool IsKeyDown(EKEY_CODE keyCode) const
{
return KeyIsDown[keyCode];
}
   
//конструктор, в цикле сбрасываем статус для всех клавиш
MyEventReceiver()
{
for (u32 i=0; i KeyIsDown[i] = false;
}
   
private:
// массив для хранения статусов клавиш
bool KeyIsDown[KEY_KEY_CODES_COUNT];
};


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

Код
int main()
{
// спрашиваем у пользователя при запуске про драйвер (OpenGL, DirectX и т.п.)
video::E_DRIVER_TYPE driverType=driverChoiceConsole();
// выходим из приложения, если драйвер не выбран
if (driverType==video::EDT_COUNT) return 1;
// создаем наш обработчик событий
MyEventReceiver receiver;
// при создании движка, сообщаем про наш обработчик, см. последний параметр.
IrrlichtDevice* device = createDevice(driverType, core::dimension2du(640, 480),
16, false, false, false, &receiver);
if (device == 0) return 1; // ошибка создания движка, выходим.
   
// вспомогательные указатели
video::IVideoDriver* driver = device->getVideoDriver();
scene::ISceneManager* smgr = device->getSceneManager();


Создаем узел, который будет реагировать на нажатие клавиш WASD. Это будет сфера, созданная с помощью встроенной функции. Разместим ее в координатах (0,0,30) и текстурируем ее. Т.к. на сцене нет динамических источников света, то для всех материалов привязываемых к узлам сцены отключаем обработку освещения, иначе они все будут абсолютно черными.

Код
scene::ISceneNode * node = smgr->addSphereSceneNode(); // создаем на сцене сферу
if (node)
{
// позиционирем сферу
node->setPosition(core::vector3df(0,0,30));
// текстурируем сферу
node->setMaterialTexture(0, driver->getTexture("../../media/wall.bmp"));
//отключаем обработку освещения для материала
node->setMaterialFlag(video::EMF_LIGHTING, false);
}


Теперь создаем другой узел(ноду), который будет двигать аниматор. Аниматоры могут влиять на узлы(ноды) сцены к которым привязаны, такие как: 3d модели, билборды, источники света, камеры. Аниматоры могут влиять на практически любые характеристики узла, т.е. не только двигать, но и масштабировать объекты, анимировать текстуры и тп. Мы создадим куб и привяжем к нему аниматор который заставит летать его по кругу.

Код
scene::ISceneNode* n = smgr->addCubeSceneNode(); // создаем на сцене куб
if (n)
{
// текстурируем куб
n->setMaterialTexture(0, driver->getTexture("../../media/t351sml.jpg"));
n->setMaterialFlag(video::EMF_LIGHTING, false); // отключаем обработку освещения
// позиционировать не будем, т.к. его спозиционирует
// аниматор, созданный в следующей строке
scene::ISceneNodeAnimator* anim = smgr->createFlyCircleAnimator(
core::vector3df(0,0,30), 20.0f);
if (anim)
{
n->addAnimator(anim);
anim->drop();
}
}


И еще один узел на сцене, к которой мы прицепим 3d модель ниндзи и аниматор движения по прямой меж двух точек.

Код
scene::IAnimatedMeshSceneNode* anms = smgr->addAnimatedMeshSceneNode(
smgr->getMesh("../../media/ninja.b3d"));
if (anms)
{
scene::ISceneNodeAnimator* anim = smgr->createFlyStraightAnimator(
core::vector3df(100,0,60), core::vector3df(-100,0,60), 3500, true);
if (anim)
{
anms->addAnimator(anim);
anim->drop();
}


Чтобы ниндзя не был памятником, который аниматор доставляет из точки А в точку Б, мы дадим указание на проигрывание анимационного набора фреймов модели, отвечающего за бег. Чтобы правильно сориентировать модель, развернем ее на 90 градусов и чуть-чуть отмаштабируем. Если бы мы использовали модель .md2 вместо .b3d, то и для задания диапазона фремов вместо setFrameLoop() и setAnimationSpeed() можно было бы вызвать “anms->setMD2Animation(scene::EMAT_RUN)”, т.к. для моделей из Quake2 в движке есть предопределенные константы.

Код
anms->setMaterialFlag(video::EMF_LIGHTING, false);
anms->setFrameLoop(0, 13); // фреймы модели с 0 по 13 изображают бег
anms->setAnimationSpeed(15); //скорость проигрывания анимации
//anms->setMD2Animation(scene::EMAT_RUN); //если бы модель была типа .md2
anms->setScale(core::vector3df(2.f,2.f,2.f)); // маштабируем в 2 раза по XYZ осям
anms->setRotation(core::vector3df(0,-90,0)); // поворачиваем на 90 град. вокруг Y
//anms->setMaterialTexture(0, driver->getTexture("../../media/sydney.bmp"));
}


Чтобы перемещаться по сцене самостоятельно, добавив на нее FPS камеру… ну и спрячем указатель мыши за ненадобностью.

Код
smgr->addCameraSceneNodeFPS();
device->getCursorControl()->setVisible(false);


Для красоты “приклеим” логотипчик движка IrrLicht

Код
device->getGUIEnvironment()->addImage(driver->getTexture(
"../../media/irrlichtlogoalpha2.tga"),
core::position2d(10,20));</p>
gui::IGUIStaticText* diagnostics = device->getGUIEnvironment()->addStaticText(
L"", core::rect(10, 10, 400, 20));
diagnostics->setOverrideColor(video::SColor(255, 255, 255, 0));


Вот практически и все, дело за отрисовкой.

Код
int lastFPS = -1;
// чтобы сделать жизнь сцены независимой от частоты кадров(фреймрейта)
// мы должны знать время прошедшее с момента отрисовки последнего фрейма
u32 then = device->getTimer()->getTime();
// расстояние покрываемое объектами в секунду.
f32 MOVEMENT_SPEED = 5.f;
while(device->run())
{
// ищем разницу во времени
u32 now = device->getTimer()->getTime();
const f32 frameDeltaTime = (f32)(now - then) / 1000.f; // в секундах
then = now;


Проверяем нажаты ли клавиши W, S, A, D. Если да, то двигаем сферу.

Код
// получаем текущую позицию сферы
core::vector3df nodePosition = node->getPosition();
// двигаем текущую позицию вперед или назад
if(receiver.IsKeyDown(irr::KEY_KEY_W)) nodePosition.Y +=
MOVEMENT_SPEED * frameDeltaTime;
else if(receiver.IsKeyDown(irr::KEY_KEY_S)) nodePosition.Y -=
MOVEMENT_SPEED * frameDeltaTime;
   
// двигаем ее текущую позицию вправо или влево
if(receiver.IsKeyDown(irr::KEY_KEY_A)) nodePosition.X -=
MOVEMENT_SPEED * frameDeltaTime;
else if(receiver.IsKeyDown(irr::KEY_KEY_D)) nodePosition.X +=
MOVEMENT_SPEED * frameDeltaTime;
   
node->setPosition(nodePosition); // применяем измененную позицию обратно к сфере
   
driver->beginScene(true, true, video::SColor(255,113,113,133));
   
smgr->drawAll(); // рисуем объекты на сцене
device->getGUIEnvironment()->drawAll(); // рисуем объекыт интерфейса
   
driver->endScene();
   
int fps = driver->getFPS();
   
if (lastFPS != fps)
{
core::stringw tmp(L"Movement Example - Irrlicht Engine ["); // строка заголовока
tmp += driver->getName(); // к которому приплюсовываем имя драйвера
tmp += L"] fps: "; // и количество рисуемых кадров в секунду
tmp += fps;
   
device->setWindowCaption(tmp.c_str()); // устанавливаем заголовок
lastFPS = fps;
}
}


Ну и как всегда, по завершению главного цикла удаляем корневой объект(движок):

Код
device->drop();
return 0;
}
 
Форум » Игровые движки » IrrLicht Engine » Туториал №4: Движение (сложность: легкий)
  • Страница 1 из 1
  • 1
Поиск: