123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313 |
- /** Example 019 Mouse and Joystick
- This tutorial builds on example 04.Movement which showed how to
- handle keyboard events in Irrlicht. Here we'll handle mouse events
- and joystick events, if you have a joystick connected and a device
- that supports joysticks. These are currently Windows, Linux and SDL
- devices.
- */
- #ifdef _MSC_VER
- #pragma comment(lib, "Irrlicht.lib")
- #endif
- #include <irrlicht.h>
- #include "driverChoice.h"
- using namespace irr;
- /*
- Just as we did in example 04.Movement with keys, we'll store the latest state of the
- mouse and the first joystick, updating them as we receive events.
- Note that instead of working with events we could work with CursorControl, aka
- device->getCursorControl(), to get the current mouse state.
- With events you get every mouse movement since the last device->run(),
- while CursorControl will always return the current state at the moment you check it.
- CursorControl will be able to get cursor positions even if the mouse is outside the
- active Window, while the behavior of mouse-events for this is a bit system dependent
- and also can be influenced by system calls for mouse-grabbing.
- Events tend to work on more devices (especially mobile devices) where CursorControl might
- not be available. Also on some systems (X11) checking the mouse position with CursorControl
- can be rather slow compared to events.
- Often it depends a bit on the type of game which solution is preferable, just be aware
- that you have some choice for this.
- */
- class MyEventReceiver : public IEventReceiver
- {
- public:
- // We'll create a struct to record info on the mouse state
- struct SMouseState
- {
- core::position2di Position;
- bool LeftButtonDown;
- bool WasMouseMoved;
- SMouseState() : LeftButtonDown(false), WasMouseMoved(false) { }
- } MouseState;
- // This is the one method that we have to implement
- virtual bool OnEvent(const SEvent& event)
- {
- // Remember the mouse state
- 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;
- MouseState.WasMouseMoved = true;
- break;
- default:
- // We won't use the wheel
- break;
- }
- }
- // The state of each connected joystick is sent to us
- // once every run() of the Irrlicht device. Store the
- // state of the first joystick, ignoring other joysticks.
- 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;
- }
- void ResetMouseMoved()
- {
- MouseState.WasMouseMoved = false;
- }
- private:
- SEvent::SJoystickEvent JoystickState;
- };
- /*
- The event receiver for remembering the events is ready, the actual responses
- will be made inside the render loop, right before drawing the scene. So lets
- just create an irr::IrrlichtDevice and the scene node we want to move.
- */
- int main()
- {
- // ask user for driver
- video::E_DRIVER_TYPE driverType=driverChoiceConsole();
- if (driverType==video::EDT_COUNT)
- return 1;
- // create device
- MyEventReceiver receiver;
- IrrlichtDevice* device = createDevice(driverType,
- core::dimension2d<u32>(640, 480), 16, false, false, false, &receiver);
- if (device == 0)
- return 1; // could not create selected driver.
- /*
- Joysticks have to be activated to generate events.
- So lets's do that and also print out some info to the console
- about all the joysticks we found and can use.
- */
- 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;
- }
- // Set some window caption text
- 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();
- /*
- We'll create an arrow mesh and move it around either with the joystick axis/hat,
- or make it follow the mouse pointer. */
- 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));
- // As in example 04, we'll use framerate independent movement.
- u32 then = device->getTimer()->getRealTime();
- const f32 MOVEMENT_SPEED = 5.f;
- // Ignore all events which happened until now.
- // Like mouse events triggered while we chose our driver.
- device->clearSystemMessages();
- while(device->run())
- {
- // Work out a frame delta time.
- const u32 now = device->getTimer()->getRealTime();
- const f32 frameDeltaTime = (f32)(now - then) / 1000.f; // Time in seconds
- then = now;
- bool movedWithJoystick = false;
- core::vector3df nodePosition = node->getPosition();
- if(joystickInfo.size() > 0) // if we have at least one joystick
- {
- f32 moveHorizontal = 0.f; // Range is -1.f for full left to +1.f for full right
- f32 moveVertical = 0.f; // -1.f for full down to +1.f for full up.
- const SEvent::SJoystickEvent & joystickData = receiver.GetJoystickState();
- // We receive the full analog range of the axes, and so have to implement our
- // own dead zone. This is an empirical value, since some joysticks have more
- // jitter or creep around the center point than others. We'll use 5% of the
- // range as the dead zone, but generally you would want to give the user the
- // option to change this.
- 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 hat info is only currently supported on Windows, but the value is
- // guaranteed to be 65535 if it's not supported, so we can check its range.
- 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;
- // We only go back to following mouse when it moves again
- receiver.ResetMouseMoved();
- }
- }
- // If the arrow node isn't being moved with the joystick, then have it follow the mouse cursor.
- if (!movedWithJoystick && receiver.GetMouseState().WasMouseMoved)
- {
- // Create a ray through the mouse cursor.
- core::line3df ray = smgr->getSceneCollisionManager()->getRayFromScreenCoordinates(
- receiver.GetMouseState().Position, camera);
- // And intersect the ray with a plane around the node facing towards the camera.
- core::plane3df plane(nodePosition, core::vector3df(0, 0, -1));
- core::vector3df mousePosition;
- if(plane.getIntersectionWithLine(ray.start, ray.getVector(), mousePosition))
- {
- // We now have a mouse position in 3d space; move towards it.
- core::vector3df toMousePosition(mousePosition - nodePosition);
- const f32 availableMovement = MOVEMENT_SPEED * frameDeltaTime;
- if(toMousePosition.getLength() <= availableMovement)
- {
- nodePosition = mousePosition; // Jump to the final position
- }
- else
- {
- nodePosition += toMousePosition.normalize() * availableMovement; // Move towards it
- }
- }
- }
- node->setPosition(nodePosition);
- // Turn lighting on and off depending on whether the left mouse button is down.
- node->setMaterialFlag(video::EMF_LIGHTING, receiver.GetMouseState().LeftButtonDown);
- driver->beginScene(video::ECBF_COLOR | video::ECBF_DEPTH, video::SColor(255,113,113,133));
- smgr->drawAll(); // draw the 3d scene
- driver->endScene();
- }
- /*
- In the end, delete the Irrlicht device.
- */
- device->drop();
- return 0;
- }
- /*
- **/
|