MerGC_Team | Дата: Четверг, 03.04.2014, 18:19 | Сообщение # 1 |
Веселый админ
Группа: Администраторы
Сообщений: 32
Статус: Оффлайн
| Этот туториал построен на уроке №04 Движение в котором показано, как обрабатывать клавиатурные события в IrrLicht Engine. Здесь мы научимся обрабатывать события мыши и джойстика, если у вас подключен джойстик и имеется поддержка джойстика. В настоящее время такая поддержка встроена в Windows, Linux и SDL устройства. Код #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;
Так же как мы делали в примере №04 Движение, мы сохраняем последние состояния мыши и первого джойстика, обновляем данные как только получаем события.. Код class MyEventReceiver : public IEventReceiver { public: // Создаём структуру для записи состояний мыши struct SMouseState { core::position2di Position; bool LeftButtonDown; SMouseState() : LeftButtonDown(false) { } } MouseState;
// Это единственный метод, который мы должны переопределить virtual bool OnEvent(const SEvent& event) { // Запомнить состояния мыши if (event.EventType == irr::EET_MOUSE_INPUT_EVENT) { switch(event.MouseInput.Event) { case EMIE_LMOUSE_PRESSED_DOWN: MouseState.LeftButtonDown = true; break;
case EMIE_LMOUSE_LEFT_UP: MouseState.LeftButtonDown = false; break;
case EMIE_MOUSE_MOVED: MouseState.Position.X = event.MouseInput.X; MouseState.Position.Y = event.MouseInput.Y; break;
default: // Мы не будем обрабатывать колёсико мыши break; } }
// Состояние каждого подключенного джойстика направляется сюда // при каждом шаге главного цикла движка Irrlicht Engine // сохраняем состояние первого джойстика, игнорируем другие джойстики. // Это на текущий момент поддерживается только в Windows и Linux. if (event.EventType == irr::EET_JOYSTICK_INPUT_EVENT && event.JoystickEvent.Joystick == 0) { JoystickState = event.JoystickEvent; }
return false; }
const SEvent::SJoystickEvent & GetJoystickState(void) const { return JoystickState; }
const SMouseState & GetMouseState(void) const { return MouseState; }
MyEventReceiver() { }
private: SEvent::SJoystickEvent JoystickState; };
Обработчик событий для сохранения нажатых кнопок готов, актуальные ответы получальщика могут быть использованы внутри цикла рендеринга перед отрисовкой сцены. Так что давайте просто создадим 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; // не удалось создать выбранный драйвер.
core::array< SJoystickInfo > joystickInfo; // если поддержка джойстика имеется if(device->activateJoysticks(joystickInfo)) { std::cout << "Joystick support is enabled and " << joystickInfo.size() << " joystick(s) are present." << std::endl;
for(u32 joystick = 0; joystick < joystickInfo.size(); ++joystick) { std::cout << "Joystick " << joystick << ":" << std::endl; std::cout << "tName: '" << joystickInfo[joystick].Name.c_str() << "'" << std::endl; std::cout << "tAxes: " << joystickInfo[joystick].Axes << std::endl; std::cout << "tButtons: " << joystickInfo[joystick].Buttons << std::endl;
std::cout << "tHat is: ";
switch(joystickInfo[joystick].PovHat) { case SJoystickInfo::POV_HAT_PRESENT: std::cout << "present" << std::endl; break;
case SJoystickInfo::POV_HAT_ABSENT: std::cout << "absent" << std::endl; break;
case SJoystickInfo::POV_HAT_UNKNOWN: default: std::cout << "unknown" << std::endl; break; } } } else // джойстик не поддерживается { std::cout << "Joystick support is not enabled." << std::endl; }
core::stringw tmp = L"Irrlicht Joystick Example ("; tmp += joystickInfo.size(); tmp += " joysticks)"; device->setWindowCaption(tmp.c_str());
video::IVideoDriver* driver = device->getVideoDriver(); scene::ISceneManager* smgr = device->getSceneManager();
Мы создадим стрелку(3д модель), ось которой будет представлять импровизированную ручку джойстика и реагировать на отклонения реального джойстика, вдобавок эта "ручка" будет перемещаться вслед за указателем мыши. Код scene::ISceneNode * node = smgr->addMeshSceneNode( smgr->addArrowMesh( "Arrow", video::SColor(255, 255, 0, 0), video::SColor(255, 0, 255, 0), 16,16, 2.f, 1.3f, 0.1f, 0.6f ) ); node->setMaterialFlag(video::EMF_LIGHTING, false);
scene::ICameraSceneNode * camera = smgr->addCameraSceneNode(); camera->setPosition(core::vector3df(0, 0, -10));
// Как и в примере 04, мы сделаем движение независимым от частоты кадров. 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;
bool movedWithJoystick = false; core::vector3df nodePosition = node->getPosition();
if(joystickInfo.size() > 0) { f32 moveHorizontal = 0.f; // Диапазон от -1.f (полное влево) до +1.f (полное вправо) f32 moveVertical = 0.f; // от -1.f (полное вниз) до +1.f (полное вверх).
const SEvent::SJoystickEvent & joystickData = receiver.GetJoystickState();
// Мы получаем полный аналог диапазона осей(т.е. текущий наклон джойстика), и таким // образом, можем определить мёртвую зону. Это эмпирическое значение, так как // некоторые джойстики могут дрожать или ползать вокруг центральной точки больше других. // Мы используем диапазон 5% как мёртвую зону, но в целом было бы неплохо, если бы вы // представили пользователю опциональную возможность изменять этот параметр. const f32 DEAD_ZONE = 0.05f;
moveHorizontal = (f32)joystickData.Axis[SEvent::SJoystickEvent::AXIS_X] / 32767.f; if(fabs(moveHorizontal) < DEAD_ZONE) moveHorizontal = 0.f;
moveVertical = (f32)joystickData.Axis[SEvent::SJoystickEvent::AXIS_Y] / -32767.f; if(fabs(moveVertical) < DEAD_ZONE) moveVertical = 0.f;
// Информация о POV(Point of View) шляпки(т.е. шляпки-манипулятора дж.) // на данный момент поддерживается только в Windows, но значение // устанавливается в 65535 если это не поддерживается так что мы можем // проверить этот диапазон. const u16 povDegrees = joystickData.POV / 100; if(povDegrees < 360) { if(povDegrees > 0 && povDegrees < 180) moveHorizontal = 1.f; else if(povDegrees > 180) moveHorizontal = -1.f;
if(povDegrees > 90 && povDegrees < 270) moveVertical = -1.f; else if(povDegrees > 270 || povDegrees < 90) moveVertical = +1.f; }
if(!core::equals(moveHorizontal, 0.f) || !core::equals(moveVertical, 0.f)) { nodePosition.X += MOVEMENT_SPEED * frameDeltaTime * moveHorizontal; nodePosition.Y += MOVEMENT_SPEED * frameDeltaTime * moveVertical; movedWithJoystick = true; } }
// Если нода-стрелка не перемещается джойстиком, она должна следовать за курсором мыши. if(!movedWithJoystick) { // Создать луч на курсор мыши. core::line3df ray = smgr->getSceneCollisionManager()->getRayFromScreenCoordinates( receiver.GetMouseState().Position, camera);
// И построим пересечение луча с плоскостью обращённой к камере, // расположенной вокруг ноды(короче нода расположена на этой плоскости // так как плоскость строится в позиции ноды). core::plane3df plane(nodePosition, core::vector3df(0, 0, -1)); core::vector3df mousePosition; if(plane.getIntersectionWithLine(ray.start, ray.getVector(), mousePosition)) { // Теперь мы имеем позицию мыши в 3d пространстве двигаем ноду к этой позиции. core::vector3df toMousePosition(mousePosition - nodePosition); const f32 availableMovement = MOVEMENT_SPEED * frameDeltaTime;
if(toMousePosition.getLength() <= availableMovement) nodePosition = mousePosition; // Прыгнуть к финальной позиции else // иначе двигаться к ней nodePosition += toMousePosition.normalize() * availableMovement; } }
node->setPosition(nodePosition);
// Включает/выключает освещение в зависимости от того нажата ли левая кнопка мыши. node->setMaterialFlag(video::EMF_LIGHTING, receiver.GetMouseState().LeftButtonDown);
driver->beginScene(true, true, video::SColor(255,113,113,133)); smgr->drawAll(); // отрисовать 3d сцену driver->endScene(); }
В конце, освободить устройство Иррлихта. Код device->drop();
return 0; }
Это все.
|
|
| |