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; }
|
|
| |