diff --git a/changes.txt b/changes.txt index 683c13bb..11e48479 100644 --- a/changes.txt +++ b/changes.txt @@ -1,5 +1,7 @@ Changes in version 1.5 (... 2008) + - Significant internal change to the way that FPS camera jump speed and collision response animator gravity interact. The behaviour is now much more realistic, but it will require you to adjust your jump speed and gravity. + - Renamed IGUIElement::setRelativePosition(const core::rect& r) to IGUIElement::setRelativePositionProportional(), as it has radically different functionality from setRelativePosition(const core::rect& r) - Added IGUIElement::setRelativePosition(const core::position2di & position) to set a new position while retaining the existing height and width. diff --git a/examples/07.Collision/main.cpp b/examples/07.Collision/main.cpp index 63979847..526c00f4 100644 --- a/examples/07.Collision/main.cpp +++ b/examples/07.Collision/main.cpp @@ -95,14 +95,14 @@ int main() We add a first person shooter camera to the scene for being able to move in the quake 3 level like in tutorial 2. But this, time, we add a special animator to the camera: A Collision Response animator. This - thing modifies the scene node to which it is attached to in that way, - that it may no more move through walls and is affected by gravity. The + animator modifies the scene node to which it is attached to in order to + prevent it moving through walls, and to add gravity to it. The only thing we have to tell the animator is how the world looks like, - how big the scene node is, how gravity and so on. After the collision - response animator is attached to the camera, we do not have to do - anything more for collision detection, anything is done automaticly, + how big the scene node is, how much gravity to apply and so on. After the + collision response animator is attached to the camera, we do not have to do + anything more for collision detection, anything is done automatically, all other collision detection code below is for picking. And please - note another cool feature: The collsion response animator can be + note another cool feature: The collision response animator can be attached also to all other scene nodes, not only to cameras. And it can be mixed with other scene node animators. In this way, collision detection and response in the Irrlicht engine is really, really easy. @@ -115,26 +115,29 @@ int main() case it is the camera. The third defines how big the object is, it is the radius of an ellipsoid. Try it out and change the radius to smaller values, the camera will be able to move closer to walls after this. The - next parameter is the direction and speed of gravity. You could set it - to (0,0,0) to disable gravity. And the last value is just a - translation: Without this, the ellipsoid with which collision detection - is done would be around the camera, and the camera would be in the - middle of the ellipsoid. But as human beings, we are used to have our + next parameter is the direction and speed of gravity. We'll set it to + (0, -10, 0), which approximates to realistic gravity, assuming that our + units are metres. You could set it to (0,0,0) to disable gravity. And the + last value is just a translation: Without this, the ellipsoid with which + collision detection is done would be around the camera, and the camera would + be in the middle of the ellipsoid. But as human beings, we are used to have our eyes on top of the body, with which we collide with our world, not in the middle of it. So we place the scene node 50 units over the center of the ellipsoid with this parameter. And that's it, collision detection works now. */ + // Set a jump speed of 3 units per second, which gives a fairly realistic jump + // when used with the gravity of (0, -10, 0) in the collision response animator. scene::ICameraSceneNode* camera = - smgr->addCameraSceneNodeFPS(0, 100.0f, 300.0f, -1, 0, 0, true); + smgr->addCameraSceneNodeFPS(0, 100.0f, 300.0f, -1, 0, 0, true, 3.f); camera->setPosition(core::vector3df(-100,50,-150)); if (selector) { scene::ISceneNodeAnimator* anim = smgr->createCollisionResponseAnimator( selector, camera, core::vector3df(30,50,30), - core::vector3df(0,-3,0), + core::vector3df(0,-10,0), core::vector3df(0,50,0)); camera->addAnimator(anim); anim->drop(); diff --git a/examples/Demo/CDemo.cpp b/examples/Demo/CDemo.cpp index e555eefa..ddaedf5c 100644 --- a/examples/Demo/CDemo.cpp +++ b/examples/Demo/CDemo.cpp @@ -324,13 +324,13 @@ void CDemo::switchToNextScene() keyMap[8].Action = EKA_JUMP_UP; keyMap[8].KeyCode = KEY_KEY_J; - camera = sm->addCameraSceneNodeFPS(0, 100.0f, 400.0f, -1, keyMap, 9, false, 0.f); + camera = sm->addCameraSceneNodeFPS(0, 100.0f, 400.0f, -1, keyMap, 9, false, 3.f); camera->setPosition(core::vector3df(108,140,-140)); scene::ISceneNodeAnimatorCollisionResponse* collider = sm->createCollisionResponseAnimator( metaSelector, camera, core::vector3df(25,50,25), - core::vector3df(0, quakeLevelMesh ? -2.5f : 0.0f,0), + core::vector3df(0, quakeLevelMesh ? -10.f : 0.0f,0), core::vector3df(0,45,0), 0.005f); camera->addAnimator(collider); diff --git a/include/ISceneManager.h b/include/ISceneManager.h index 37d0385c..53a9f813 100644 --- a/include/ISceneManager.h +++ b/include/ISceneManager.h @@ -1086,9 +1086,9 @@ namespace scene const core::aabbox3d& box = yourSceneNode->getBoundingBox(); core::vector3df radius = box.MaxEdge - box.getCenter(); \endcode - \param gravityPerSecond: Sets the gravity of the environment. A good example value would be - core::vector3df(0,-100.0f,0) for letting gravity affect all object to - fall down. For bigger gravity, make increase the length of the vector. + \param gravityPerSecond: Sets the gravity of the environment, as an acceleration in + units per second per second. If your units are equivalent to metres, then + core::vector3df(0,-10.0f,0) would give an approximately realistic gravity. You can disable gravity by setting it to core::vector3df(0,0,0). \param ellipsoidTranslation: By default, the ellipsoid for collision detection is created around the center of the scene node, which means that the ellipsoid surrounds @@ -1102,7 +1102,7 @@ namespace scene virtual ISceneNodeAnimatorCollisionResponse* createCollisionResponseAnimator( ITriangleSelector* world, ISceneNode* sceneNode, const core::vector3df& ellipsoidRadius = core::vector3df(30,60,30), - const core::vector3df& gravityPerSecond = core::vector3df(0,-100.0f,0), + const core::vector3df& gravityPerSecond = core::vector3df(0,-10.0f,0), const core::vector3df& ellipsoidTranslation = core::vector3df(0,0,0), f32 slidingValue = 0.0005f) = 0; diff --git a/include/ISceneNodeAnimatorCollisionResponse.h b/include/ISceneNodeAnimatorCollisionResponse.h index 53c0283b..e7ad068c 100644 --- a/include/ISceneNodeAnimatorCollisionResponse.h +++ b/include/ISceneNodeAnimatorCollisionResponse.h @@ -63,6 +63,11 @@ namespace scene //! \return Gravity vector. */ virtual core::vector3df getGravity() const = 0; + //! 'Jump' the animator, by adding a jump speed opposite to its gravity + /** \param jumpSpeed The initial speed of the jump; the velocity will be opposite + to this animator's gravity vector. */ + virtual void jump(f32 jumpSpeed) = 0; + //! Set translation of the collision ellipsoid. /** By default, the ellipsoid for collision detection is created around the center of the scene node, which means that diff --git a/source/Irrlicht/CSceneNodeAnimatorCameraFPS.cpp b/source/Irrlicht/CSceneNodeAnimatorCameraFPS.cpp index 50cafea9..59dc2ee7 100644 --- a/source/Irrlicht/CSceneNodeAnimatorCameraFPS.cpp +++ b/source/Irrlicht/CSceneNodeAnimatorCameraFPS.cpp @@ -8,6 +8,7 @@ #include "Keycodes.h" #include "ICursorControl.h" #include "ICameraSceneNode.h" +#include "ISceneNodeAnimatorCollisionResponse.h" namespace irr { @@ -199,9 +200,26 @@ void CSceneNodeAnimatorCameraFPS::animateNode(ISceneNode* node, u32 timeMs) if (CursorKeys[EKA_STRAFE_RIGHT]) pos -= strafevect * timeDiff * MoveSpeed; - // jumping ( needs a gravity , else it's a fly to the World-UpVector ) + // For jumping, we find the collision response animator attached to our camera + // and if it's not falling, we tell it to jump. if (CursorKeys[EKA_JUMP_UP]) - pos += camera->getUpVector() * timeDiff * JumpSpeed; + { + const core::list & animators = camera->getAnimators(); + core::list::ConstIterator it = animators.begin(); + while(it != animators.end()) + { + if(ESNAT_COLLISION_RESPONSE == (*it)->getType()) + { + ISceneNodeAnimatorCollisionResponse * collisionResponse = + static_cast(*it); + + if(!collisionResponse->isFalling()) + collisionResponse->jump(JumpSpeed); + } + + it++; + } + } // write translation camera->setPosition(pos); diff --git a/source/Irrlicht/CSceneNodeAnimatorCollisionResponse.cpp b/source/Irrlicht/CSceneNodeAnimatorCollisionResponse.cpp index bf5e4e53..8dba9425 100644 --- a/source/Irrlicht/CSceneNodeAnimatorCollisionResponse.cpp +++ b/source/Irrlicht/CSceneNodeAnimatorCollisionResponse.cpp @@ -21,8 +21,8 @@ CSceneNodeAnimatorCollisionResponse::CSceneNodeAnimatorCollisionResponse( const core::vector3df& gravityPerSecond, const core::vector3df& ellipsoidTranslation, f32 slidingSpeed) -: Radius(ellipsoidRadius), Gravity(gravityPerSecond / 1000.0f), Translation(ellipsoidTranslation), - World(world), Object(object), SceneManager(scenemanager), +: Radius(ellipsoidRadius), Gravity(gravityPerSecond), Translation(ellipsoidTranslation), + World(world), Object(object), SceneManager(scenemanager), FallingVelocity(0.f), SlidingSpeed(slidingSpeed), Falling(false), IsCamera(false), AnimateCameraTarget(true) { @@ -85,6 +85,13 @@ core::vector3df CSceneNodeAnimatorCollisionResponse::getGravity() const return Gravity; } +//! 'Jump' the animator, by adding a jump speed opposite to its gravity +void CSceneNodeAnimatorCollisionResponse::jump(f32 jumpSpeed) +{ + FallingVelocity -= (core::vector3df(Gravity).normalize()) * jumpSpeed; + Falling = true; +} + //! Sets the translation of the ellipsoid for collision detection. void CSceneNodeAnimatorCollisionResponse::setEllipsoidTranslation(const core::vector3df &translation) @@ -108,8 +115,6 @@ void CSceneNodeAnimatorCollisionResponse::setWorld(ITriangleSelector* newWorld) Falling = false; LastTime = os::Timer::getTime(); - FallStartTime = LastTime; - if (World) World->drop(); @@ -148,18 +153,11 @@ void CSceneNodeAnimatorCollisionResponse::animateNode(ISceneNode* node, u32 time core::vector3df pos = Object->getPosition(); core::vector3df vel = pos - LastPosition; - //g = Gravity * (f32)((timeMs - FallStartTime) * diff); - - f32 dt = 1.f; - if (Falling) - { - dt = f32 ( ( timeMs - FallStartTime ) * diff ); - } - core::vector3df g = Gravity * dt; + FallingVelocity += Gravity * (f32)diff * 0.001f; core::triangle3df triangle = RefTriangle; - core::vector3df force = vel + g; + core::vector3df force = vel + FallingVelocity; const core::vector3df nullVector ( 0.f, 0.f, 0.f ); @@ -170,19 +168,19 @@ void CSceneNodeAnimatorCollisionResponse::animateNode(ISceneNode* node, u32 time bool f = false; pos = SceneManager->getSceneCollisionManager()->getCollisionResultPosition( World, LastPosition-Translation, - Radius, vel, triangle, f, SlidingSpeed, g); + Radius, vel, triangle, f, SlidingSpeed, FallingVelocity); pos += Translation; if (f)//triangle == RefTriangle) { - if (!Falling) - FallStartTime = timeMs; - Falling = true; } else + { Falling = false; + FallingVelocity.set(0, 0, 0); + } Object->setPosition(pos); } @@ -209,7 +207,6 @@ void CSceneNodeAnimatorCollisionResponse::setNode(ISceneNode* node) } LastTime = os::Timer::getTime(); - FallStartTime = LastTime; } //! Writes attributes of the scene node animator. diff --git a/source/Irrlicht/CSceneNodeAnimatorCollisionResponse.h b/source/Irrlicht/CSceneNodeAnimatorCollisionResponse.h index 8f9ae404..348eae20 100644 --- a/source/Irrlicht/CSceneNodeAnimatorCollisionResponse.h +++ b/source/Irrlicht/CSceneNodeAnimatorCollisionResponse.h @@ -51,6 +51,9 @@ namespace scene //! Sets the gravity of the environment. virtual void setGravity(const core::vector3df& gravity); + //! 'Jump' the animator, by adding a jump speed opposite to its gravity + virtual void jump(f32 jumpSpeed); + //! Returns current vector of gravity. virtual core::vector3df getGravity() const; @@ -93,13 +96,13 @@ namespace scene core::vector3df LastPosition; core::vector3df Radius; core::vector3df Gravity; + core::vector3df FallingVelocity; // In the direction of Gravity. core::vector3df Translation; ITriangleSelector* World; ISceneNode* Object; ISceneManager* SceneManager; u32 LastTime; - u32 FallStartTime; f32 SlidingSpeed; bool Falling; bool IsCamera;