main.cpp 8.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266
  1. /** Example 004 Movement
  2. This tutorial shows how to move and animate SceneNodes. The
  3. basic concept of SceneNodeAnimators is shown as well as manual
  4. movement of nodes using the keyboard. We'll demonstrate framerate
  5. independent movement, which means moving by an amount dependent
  6. on the duration of the last run of the Irrlicht loop.
  7. Example 19.MouseAndJoystick shows how to handle other input than keyboard.
  8. As always, include the header files, use the irr namespace,
  9. and tell the linker to link with the .lib file.
  10. */
  11. #ifdef _MSC_VER
  12. #pragma comment(lib, "Irrlicht.lib")
  13. #endif
  14. #include <irrlicht.h>
  15. #include "driverChoice.h"
  16. #include "exampleHelper.h"
  17. using namespace irr;
  18. /*
  19. To receive events like mouse and keyboard input, or GUI events like
  20. "button has been clicked", we need an object which is derived from the
  21. irr::IEventReceiver object. There is only one method to override:
  22. irr::IEventReceiver::OnEvent(). This method will be called by the engine once
  23. when an event happens. What we really want to know is whether a key is being
  24. held down, and so we will remember the current state of each key.
  25. */
  26. class MyEventReceiver : public IEventReceiver
  27. {
  28. public:
  29. // This is the one method that we have to implement
  30. virtual bool OnEvent(const SEvent& event)
  31. {
  32. // Remember whether each key is down or up
  33. if (event.EventType == irr::EET_KEY_INPUT_EVENT)
  34. KeyIsDown[event.KeyInput.Key] = event.KeyInput.PressedDown;
  35. /*
  36. Always return false by default. If you return true you tell the engine
  37. that you handled this event completely and the Irrlicht should not
  38. process it any further. So for example if you return true for all
  39. EET_KEY_INPUT_EVENT events then Irrlicht would not pass on key-events
  40. to it's GUI system.
  41. */
  42. return false;
  43. }
  44. // This is used to check whether a key is being held down
  45. virtual bool IsKeyDown(EKEY_CODE keyCode) const
  46. {
  47. return KeyIsDown[keyCode];
  48. }
  49. MyEventReceiver()
  50. {
  51. for (u32 i=0; i<KEY_KEY_CODES_COUNT; ++i)
  52. KeyIsDown[i] = false;
  53. }
  54. private:
  55. // We use this array to store the current state of each key
  56. bool KeyIsDown[KEY_KEY_CODES_COUNT];
  57. };
  58. /*
  59. The event receiver for keeping the pressed keys is ready, the actual responses
  60. will be made inside the render loop, right before drawing the scene. So lets
  61. create an irr::IrrlichtDevice and the scene node we want to move. We also
  62. create some additional scene nodes to show different possibilities to move and
  63. animate scene nodes.
  64. */
  65. int main()
  66. {
  67. // ask user for driver
  68. video::E_DRIVER_TYPE driverType=driverChoiceConsole();
  69. if (driverType==video::EDT_COUNT)
  70. return 1;
  71. /*
  72. Create the event receiver. Take care that the pointer to it has to
  73. stay valid as long as the IrrlichtDevice uses it. Event receivers are not
  74. reference counted.
  75. */
  76. MyEventReceiver receiver;
  77. // create device
  78. IrrlichtDevice* device = createDevice(driverType,
  79. core::dimension2d<u32>(640, 480), 16, false, false, false, &receiver);
  80. if (device == 0)
  81. return 1; // could not create selected driver.
  82. video::IVideoDriver* driver = device->getVideoDriver();
  83. scene::ISceneManager* smgr = device->getSceneManager();
  84. const io::path mediaPath = getExampleMediaPath();
  85. /*
  86. Create the node which will be moved with the WSAD keys. We create a
  87. sphere node, which is a built-in geometry primitive. We place the node
  88. at (0,0,30) and assign a texture to it to let it look a little bit more
  89. interesting. Because we have no dynamic lights in this scene we disable
  90. lighting for each model (otherwise the models would be black).
  91. */
  92. scene::ISceneNode * sphereNode = smgr->addSphereSceneNode();
  93. if (sphereNode)
  94. {
  95. sphereNode->setPosition(core::vector3df(0,0,30));
  96. sphereNode->setMaterialTexture(0, driver->getTexture(mediaPath + "wall.bmp"));
  97. sphereNode->setMaterialFlag(video::EMF_LIGHTING, false);
  98. }
  99. /*
  100. Now we create another node, movable using a scene node animator. Scene
  101. node animators modify scene nodes and can be attached to any scene node
  102. like mesh scene nodes, billboards, lights and even camera scene nodes.
  103. Scene node animators are not only able to modify the position of a
  104. scene node, they can also animate the textures of an object for
  105. example. We create a cube scene node and attach a 'fly circle' scene
  106. node animator to it, letting this node fly around our sphere scene node.
  107. */
  108. scene::ISceneNode* cubeNode = smgr->addCubeSceneNode();
  109. if (cubeNode)
  110. {
  111. cubeNode->setMaterialTexture(0, driver->getTexture(mediaPath + "t351sml.jpg"));
  112. cubeNode->setMaterialFlag(video::EMF_LIGHTING, false);
  113. scene::ISceneNodeAnimator* anim =
  114. smgr->createFlyCircleAnimator(core::vector3df(0,0,30), 20.0f);
  115. if (anim)
  116. {
  117. cubeNode->addAnimator(anim);
  118. anim->drop();
  119. }
  120. }
  121. /*
  122. The last scene node we add is a b3d model of a walking ninja. Is shows the
  123. use of a 'fly straight' animator to move the node between two points.
  124. */
  125. scene::IAnimatedMeshSceneNode* ninjaNode =
  126. smgr->addAnimatedMeshSceneNode(smgr->getMesh(mediaPath + "ninja.b3d"));
  127. if (ninjaNode)
  128. {
  129. scene::ISceneNodeAnimator* anim =
  130. smgr->createFlyStraightAnimator(core::vector3df(100,0,60),
  131. core::vector3df(-100,0,60), 3500, true);
  132. if (anim)
  133. {
  134. ninjaNode->addAnimator(anim);
  135. anim->drop();
  136. }
  137. /*
  138. To make the model look right we disable lighting, set the
  139. frames between which the animation should loop, rotate the
  140. model around 180 degrees, and adjust the animation speed and
  141. the texture. To set the correct animation (frames and speed), we
  142. would also be able to just call
  143. "ninjaNode->setMD2Animation(scene::EMAT_RUN)" for the 'run'
  144. animation instead of "setFrameLoop" and "setAnimationSpeed",
  145. But that only works with MD2 animations, while this can be used to
  146. start other animations. For MD2 it's usually good advice not to use
  147. hardcoded frame-numbers...
  148. */
  149. ninjaNode->setMaterialFlag(video::EMF_LIGHTING, false);
  150. ninjaNode->setFrameLoop(0, 13);
  151. ninjaNode->setAnimationSpeed(15);
  152. // ninjaNode->setMD2Animation(scene::EMAT_RUN);
  153. ninjaNode->setScale(core::vector3df(2.f,2.f,2.f));
  154. ninjaNode->setRotation(core::vector3df(0,-90,0));
  155. // ninjaNode->setMaterialTexture(0, driver->getTexture(mediaPath + "sydney.bmp"));
  156. }
  157. /*
  158. To be able to look at and move around in this scene, we create a first
  159. person shooter style camera and make the mouse cursor invisible.
  160. */
  161. smgr->addCameraSceneNodeFPS();
  162. device->getCursorControl()->setVisible(false);
  163. /*
  164. Add a colorful irrlicht logo
  165. */
  166. device->getGUIEnvironment()->addImage(
  167. driver->getTexture(mediaPath + "irrlichtlogoalpha2.tga"),
  168. core::position2d<s32>(10,20));
  169. /*
  170. Lets draw the scene and also write the current frames per second and the
  171. name of the driver to the caption of the window.
  172. */
  173. int lastFPS = -1;
  174. // In order to do framerate independent movement, we have to know
  175. // how long it was since the last frame
  176. u32 then = device->getTimer()->getTime();
  177. // This is the movement speed in units per second.
  178. const f32 MOVEMENT_SPEED = 5.f;
  179. while(device->run())
  180. {
  181. // Work out a frame delta time.
  182. const u32 now = device->getTimer()->getTime();
  183. const f32 frameDeltaTime = (f32)(now - then) / 1000.f; // Time in seconds
  184. then = now;
  185. /* Check if keys W, S, A or D are being held down, and move the
  186. sphere node around respectively. */
  187. core::vector3df nodePosition = sphereNode->getPosition();
  188. if(receiver.IsKeyDown(irr::KEY_KEY_W))
  189. nodePosition.Y += MOVEMENT_SPEED * frameDeltaTime;
  190. else if(receiver.IsKeyDown(irr::KEY_KEY_S))
  191. nodePosition.Y -= MOVEMENT_SPEED * frameDeltaTime;
  192. if(receiver.IsKeyDown(irr::KEY_KEY_A))
  193. nodePosition.X -= MOVEMENT_SPEED * frameDeltaTime;
  194. else if(receiver.IsKeyDown(irr::KEY_KEY_D))
  195. nodePosition.X += MOVEMENT_SPEED * frameDeltaTime;
  196. sphereNode->setPosition(nodePosition);
  197. driver->beginScene(video::ECBF_COLOR | video::ECBF_DEPTH, video::SColor(255,113,113,133));
  198. smgr->drawAll(); // draw the 3d scene
  199. device->getGUIEnvironment()->drawAll(); // draw the gui environment (the logo)
  200. driver->endScene();
  201. int fps = driver->getFPS();
  202. if (lastFPS != fps)
  203. {
  204. core::stringw tmp(L"Movement Example - Irrlicht Engine [");
  205. tmp += driver->getName();
  206. tmp += L"] fps: ";
  207. tmp += fps;
  208. device->setWindowCaption(tmp.c_str());
  209. lastFPS = fps;
  210. }
  211. }
  212. /*
  213. In the end, delete the Irrlicht device.
  214. */
  215. device->drop();
  216. return 0;
  217. }
  218. /*
  219. That's it. Compile and play around with the program.
  220. **/