Перевод Example 004 Movement
Автор: Кукуй Кукуев
Ну что я могу здесь вам сказать?
Следующим делом планирую перевести урок Example 012 Terrain Rendering... если звёзды нашлют вдохновение. В этом уроке есть 2 замечательные фишки: как ставить Скибокс и Скидоме и как делать территорию для игры по карте высот(heightmap). Заодно расскажу где брать скибоксы и с помощью чего генерировать свою карту высот для уровня и для последующего встраивания в Иррлихт.
Ну а пока:
/** Example 004 Movement(Пример 004 Движение) Этот туториал покажет как передвигать и анимировать SceneNodes. Покажет основную концепцию SceneNodeAnimators(аниматоров узлов сцены) и то как передвигать узлы сцены используя клавиатуру. Мы продемонстрируем расчёт частоты кадров в главном цикле Иррлихта и как с его помощью сделать независимое движение, что означает настройку зависимости от того как давно был запущен основной цикл иррлихта последний раз.(т.е. расчёт фактора deltaTime) (http://en.wikipedia.org/wiki/Delta_time) А пример 19.MouseAndJoystick покажет как настроить управление с помощью этих устройств. Как всегда, Я извлекаю заголовки, включаю пространство имён irr, и связывают проект с .lib файлом. */ #ifdef _MSC_VER //Мы так же определяем этот дефайн, чтобы MSVC //не жаловался на sprintf(). #define _CRT_SECURE_NO_WARNINGS #pragma comment(lib, "Irrlicht.lib") #endif #include <irrlicht.h> #include "driverChoice.h" using namespace irr; /* Чтобы получить событие от мыши или клавиатуры, или событие GUI, такие как "OK кнопка была нажата", нам необходим объект: irr::IEventReceiver object. Существует только один метод класса, виртуальный и переопределяемый в: irr::IEventReceiver::OnEvent(). Реагирующий на возникновение событий. Ведь мы действительно должны знать - является ли кнопка в данный момент нажатой, и как мы будем проверять текущее состояние всех клавиш. */ class MyEventReceiver : public IEventReceiver { public: //Это тот самый единственный метод, который получает события //и который необходимо переопределить virtual bool OnEvent( const SEvent& event) { //Если произошло событие, затрагивающее //клавиатуру, записать по индексу клавиши //в массиве true/false = зажата/нет 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<KEY_KEY_CODES_COUNT; ++i) KeyIsDown[i] = false; } private: // Мы используем этот массив для хранения текущего значения каждой клавиши bool KeyIsDown[KEY_KEY_CODES_COUNT]; }; /* Получальщик событий для получения и сохранения нажатых клавиш готов, фактически нажатия будут доступны внутри цикла рендеринга, ещё перед отрисовкой сцены. Итак, давайте просто создадим: irr::IrrlichtDevice и узел сцены, который мы хотим передвигать. Мы так же создадим ряд дополнительных узлов сцены, чтобы показать какие существуют возможности для передвижения и анимации узлов сцены. */ int main( ) { //Спросить пользователя про драйвер video::E_DRIVER_TYPE driverType=driverChoiceConsole( ); if ( driverType==video::EDT_COUNT) return 1; //Создать устройство MyEventReceiver receiver; IrrlichtDevice* device = createDevice( driverType, core::dimension2d<u32>( 640, 480), 16, false, false, false, &receiver); if ( device == 0) return 1; // устройство не удалось создать с таким драйвером. video::IVideoDriver* driver = device->getVideoDriver( ); scene::ISceneManager* smgr = device->getSceneManager( ); /* Создаём узел, который может быть перемещён нажатием кнопок 'W','S','A','D'. Мы создадим узел-сферу, которая является геометрическим примитивом. Мы установим узел в координаты (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); } /* Теперь мы создаём другой узел, движимый с помощью АНИМАТОРА узлов сцены. Аниматоры узлов сцены динамически изменяют узлы сцены и могут быть присоединены к любому узлу сцены как, например, к сетке узла сцены, биллбоардам(картинкам всегда повёрнутым к пользователю), к источникам свети и даже к узлу камеры сцены. Аниматор узла сцены не только в состоянии изменять положение узла сцены, они так же могут анимировать, например, текстуры объекта! Мы создадим куб-узел сцены и присоединим к нему аниматор по названию: 'fly circle'(летать по кругу), заставляя этот узел летать вокруг узла нашей сферы. */ 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( ); } } /* Последний узел сцены мы добавляем, чтобы посмотреть возможности анимирования b3d модели в узле сцены, которая использует аниматор 'полёт прямо' для движения между точками. */ 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( ); } /* Для того, чтобы модель была видна мы отключаем освещение, устанавливаем фрейм(кадр) между которыми анимация должна проигрывать свой цикл, поворачиваем модель на 180 градусов, и настраиваем скорость анимации и текстуры. Чтобы правильно установить анимацию (кадры(фреймы) и скорость), мы просто можем вызывать: "anms->setMD2Animation(scene::EMAT_RUN)" для 'запуска' анимации, а не "setFrameLoop" и "setAnimationSpeed", ведь это работает только с MD2 анимациями. Но теперь вы знаете как работать и с другими видами анимации. И хороший совет - НЕ используйте жёсткое задание номеров фреймов(frame-numbers) в коде... */ anms->setMaterialFlag( video::EMF_LIGHTING, false); anms->setFrameLoop( 0, 13); anms->setAnimationSpeed( 15); // anms->setMD2Animation(scene::EMAT_RUN); anms->setScale( core::vector3df( 2.f,2.f,2.f)); anms->setRotation( core::vector3df( 0,-90,0)); // anms->setMaterialTexture(0, driver->getTexture("../../media/sydney.bmp")); } /* Чтобы иметь возможность видеть и перемещаться по сцене, мы создаём камеру в стиле FPS(first person shooter) и делаем курсор мыши невидимым. */ smgr->addCameraSceneNodeFPS( ); device->getCursorControl( )->setVisible( false); /* Добавим красочный логотип Иррлихта */ device->getGUIEnvironment( )->addImage( driver->getTexture( "../../media/irrlichtlogoalpha2.tga"), core::position2d<s32>( 10,20)); gui::IGUIStaticText* diagnostics = device->getGUIEnvironment( )->addStaticText( L"", core::rect<s32>( 10, 10, 400, 20)); diagnostics->setOverrideColor( video::SColor( 255, 255, 255, 0)); /* Мы сделали всё необходимое для отрисовки. Мы так же напишем кол-во кадров в секунду(frames per second,FPS)и имя драйвера в заголовке окна. */ int lastFPS = -1; //Для того, чтобы сделать частоту кадров независимой от //движения(т.е. чтобы сделать игровой процесс независимым от //быстродействия железа), мы должны знать, как давно //сменился последний фрейм(высчитать фактор //дельтатайм = deltaTime, разность во времени между //текущим кадром рисуемым движком и предыдущим) u32 then = device->getTimer( )->getTime( ); //Это скорость передвижения в секунду. const f32 MOVEMENT_SPEED = 5.f; while( device->run( )) { //Рассчёт DeltaTime. const 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( ); // нарисовать 3d сцену device->getGUIEnvironment( )->drawAll( ); // нарисовать GUI (логотип движка) 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; } /* Вот и всё. Откомпилируйте и поиграйте с программой. **/
12 августа 2010