1
/** Example 019 Mouse and Joystick
3
This tutorial builds on example 04.Movement which showed how to
4
handle keyboard events in Irrlicht. Here we'll handle mouse events
5
and joystick events, if you have a joystick connected and a device
6
that supports joysticks. These are currently Windows, Linux and SDL
11
// We'll define this to stop MSVC complaining about sprintf().
12
#define _CRT_SECURE_NO_WARNINGS
13
#pragma comment(lib, "Irrlicht.lib")
17
#include "driverChoice.h"
22
Just as we did in example 04.Movement, we'll store the latest state of the
23
mouse and the first joystick, updating them as we receive events.
25
class MyEventReceiver : public IEventReceiver
28
// We'll create a struct to record info on the mouse state
31
core::position2di Position;
33
SMouseState() : LeftButtonDown(false) { }
36
// This is the one method that we have to implement
37
virtual bool OnEvent(const SEvent& event)
39
// Remember the mouse state
40
if (event.EventType == irr::EET_MOUSE_INPUT_EVENT)
42
switch(event.MouseInput.Event)
44
case EMIE_LMOUSE_PRESSED_DOWN:
45
MouseState.LeftButtonDown = true;
48
case EMIE_LMOUSE_LEFT_UP:
49
MouseState.LeftButtonDown = false;
52
case EMIE_MOUSE_MOVED:
53
MouseState.Position.X = event.MouseInput.X;
54
MouseState.Position.Y = event.MouseInput.Y;
58
// We won't use the wheel
63
// The state of each connected joystick is sent to us
64
// once every run() of the Irrlicht device. Store the
65
// state of the first joystick, ignoring other joysticks.
66
// This is currently only supported on Windows and Linux.
67
if (event.EventType == irr::EET_JOYSTICK_INPUT_EVENT
68
&& event.JoystickEvent.Joystick == 0)
70
JoystickState = event.JoystickEvent;
76
const SEvent::SJoystickEvent & GetJoystickState(void) const
81
const SMouseState & GetMouseState(void) const
92
SEvent::SJoystickEvent JoystickState;
97
The event receiver for keeping the pressed keys is ready, the actual responses
98
will be made inside the render loop, right before drawing the scene. So lets
99
just create an irr::IrrlichtDevice and the scene node we want to move. We also
100
create some other additional scene nodes, to show that there are also some
101
different possibilities to move and animate scene nodes.
105
// ask user for driver
106
video::E_DRIVER_TYPE driverType=driverChoiceConsole();
107
if (driverType==video::EDT_COUNT)
111
MyEventReceiver receiver;
113
IrrlichtDevice* device = createDevice(driverType,
114
core::dimension2d<u32>(640, 480), 16, false, false, false, &receiver);
117
return 1; // could not create selected driver.
120
core::array<SJoystickInfo> joystickInfo;
121
if(device->activateJoysticks(joystickInfo))
123
std::cout << "Joystick support is enabled and " << joystickInfo.size() << " joystick(s) are present." << std::endl;
125
for(u32 joystick = 0; joystick < joystickInfo.size(); ++joystick)
127
std::cout << "Joystick " << joystick << ":" << std::endl;
128
std::cout << "\tName: '" << joystickInfo[joystick].Name.c_str() << "'" << std::endl;
129
std::cout << "\tAxes: " << joystickInfo[joystick].Axes << std::endl;
130
std::cout << "\tButtons: " << joystickInfo[joystick].Buttons << std::endl;
132
std::cout << "\tHat is: ";
134
switch(joystickInfo[joystick].PovHat)
136
case SJoystickInfo::POV_HAT_PRESENT:
137
std::cout << "present" << std::endl;
140
case SJoystickInfo::POV_HAT_ABSENT:
141
std::cout << "absent" << std::endl;
144
case SJoystickInfo::POV_HAT_UNKNOWN:
146
std::cout << "unknown" << std::endl;
153
std::cout << "Joystick support is not enabled." << std::endl;
156
core::stringw tmp = L"Irrlicht Joystick Example (";
157
tmp += joystickInfo.size();
158
tmp += " joysticks)";
159
device->setWindowCaption(tmp.c_str());
161
video::IVideoDriver* driver = device->getVideoDriver();
162
scene::ISceneManager* smgr = device->getSceneManager();
165
We'll create an arrow mesh and move it around either with the joystick axis/hat,
166
or make it follow the mouse pointer. */
167
scene::ISceneNode * node = smgr->addMeshSceneNode(
168
smgr->addArrowMesh( "Arrow",
169
video::SColor(255, 255, 0, 0),
170
video::SColor(255, 0, 255, 0),
176
node->setMaterialFlag(video::EMF_LIGHTING, false);
178
scene::ICameraSceneNode * camera = smgr->addCameraSceneNode();
179
camera->setPosition(core::vector3df(0, 0, -10));
181
// As in example 04, we'll use framerate independent movement.
182
u32 then = device->getTimer()->getTime();
183
const f32 MOVEMENT_SPEED = 5.f;
187
// Work out a frame delta time.
188
const u32 now = device->getTimer()->getTime();
189
const f32 frameDeltaTime = (f32)(now - then) / 1000.f; // Time in seconds
192
bool movedWithJoystick = false;
193
core::vector3df nodePosition = node->getPosition();
195
if(joystickInfo.size() > 0)
197
f32 moveHorizontal = 0.f; // Range is -1.f for full left to +1.f for full right
198
f32 moveVertical = 0.f; // -1.f for full down to +1.f for full up.
200
const SEvent::SJoystickEvent & joystickData = receiver.GetJoystickState();
202
// We receive the full analog range of the axes, and so have to implement our
203
// own dead zone. This is an empirical value, since some joysticks have more
204
// jitter or creep around the center point than others. We'll use 5% of the
205
// range as the dead zone, but generally you would want to give the user the
206
// option to change this.
207
const f32 DEAD_ZONE = 0.05f;
210
(f32)joystickData.Axis[SEvent::SJoystickEvent::AXIS_X] / 32767.f;
211
if(fabs(moveHorizontal) < DEAD_ZONE)
212
moveHorizontal = 0.f;
215
(f32)joystickData.Axis[SEvent::SJoystickEvent::AXIS_Y] / -32767.f;
216
if(fabs(moveVertical) < DEAD_ZONE)
219
// POV hat info is only currently supported on Windows, but the value is
220
// guaranteed to be 65535 if it's not supported, so we can check its range.
221
const u16 povDegrees = joystickData.POV / 100;
224
if(povDegrees > 0 && povDegrees < 180)
225
moveHorizontal = 1.f;
226
else if(povDegrees > 180)
227
moveHorizontal = -1.f;
229
if(povDegrees > 90 && povDegrees < 270)
231
else if(povDegrees > 270 || povDegrees < 90)
235
if(!core::equals(moveHorizontal, 0.f) || !core::equals(moveVertical, 0.f))
237
nodePosition.X += MOVEMENT_SPEED * frameDeltaTime * moveHorizontal;
238
nodePosition.Y += MOVEMENT_SPEED * frameDeltaTime * moveVertical;
239
movedWithJoystick = true;
243
// If the arrow node isn't being moved with the joystick, then have it follow the mouse cursor.
244
if(!movedWithJoystick)
246
// Create a ray through the mouse cursor.
247
core::line3df ray = smgr->getSceneCollisionManager()->getRayFromScreenCoordinates(
248
receiver.GetMouseState().Position, camera);
250
// And intersect the ray with a plane around the node facing towards the camera.
251
core::plane3df plane(nodePosition, core::vector3df(0, 0, -1));
252
core::vector3df mousePosition;
253
if(plane.getIntersectionWithLine(ray.start, ray.getVector(), mousePosition))
255
// We now have a mouse position in 3d space; move towards it.
256
core::vector3df toMousePosition(mousePosition - nodePosition);
257
const f32 availableMovement = MOVEMENT_SPEED * frameDeltaTime;
259
if(toMousePosition.getLength() <= availableMovement)
260
nodePosition = mousePosition; // Jump to the final position
262
nodePosition += toMousePosition.normalize() * availableMovement; // Move towards it
266
node->setPosition(nodePosition);
268
// Turn lighting on and off depending on whether the left mouse button is down.
269
node->setMaterialFlag(video::EMF_LIGHTING, receiver.GetMouseState().LeftButtonDown);
271
driver->beginScene(true, true, video::SColor(255,113,113,133));
272
smgr->drawAll(); // draw the 3d scene
277
In the end, delete the Irrlicht device.