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.

git-svn-id: svn://svn.code.sf.net/p/irrlicht/code/trunk@1811 dfc29bdd-3216-0410-991c-e03cc46cb475
master
Rogerborg 2008-11-22 23:41:11 +00:00
parent f7dfda9f1f
commit a83051f62e
8 changed files with 68 additions and 40 deletions

View File

@ -1,5 +1,7 @@
Changes in version 1.5 (... 2008) 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<f32>& r) to IGUIElement::setRelativePositionProportional(), as it has radically different functionality from setRelativePosition(const core::rect<s32>& r) - Renamed IGUIElement::setRelativePosition(const core::rect<f32>& r) to IGUIElement::setRelativePositionProportional(), as it has radically different functionality from setRelativePosition(const core::rect<s32>& r)
- Added IGUIElement::setRelativePosition(const core::position2di & position) to set a new position while retaining the existing height and width. - Added IGUIElement::setRelativePosition(const core::position2di & position) to set a new position while retaining the existing height and width.

View File

@ -95,14 +95,14 @@ int main()
We add a first person shooter camera to the scene for being able to 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 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 special animator to the camera: A Collision Response animator. This
thing modifies the scene node to which it is attached to in that way, animator modifies the scene node to which it is attached to in order to
that it may no more move through walls and is affected by gravity. The 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, 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 how big the scene node is, how much gravity to apply and so on. After the
response animator is attached to the camera, we do not have to do collision response animator is attached to the camera, we do not have to do
anything more for collision detection, anything is done automaticly, anything more for collision detection, anything is done automatically,
all other collision detection code below is for picking. And please 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 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 be mixed with other scene node animators. In this way, collision
detection and response in the Irrlicht engine is really, really easy. 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 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 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 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 next parameter is the direction and speed of gravity. We'll set it to
to (0,0,0) to disable gravity. And the last value is just a (0, -10, 0), which approximates to realistic gravity, assuming that our
translation: Without this, the ellipsoid with which collision detection units are metres. You could set it to (0,0,0) to disable gravity. And the
is done would be around the camera, and the camera would be in the last value is just a translation: Without this, the ellipsoid with which
middle of the ellipsoid. But as human beings, we are used to have our 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 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 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 of the ellipsoid with this parameter. And that's it, collision
detection works now. 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 = 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)); camera->setPosition(core::vector3df(-100,50,-150));
if (selector) if (selector)
{ {
scene::ISceneNodeAnimator* anim = smgr->createCollisionResponseAnimator( scene::ISceneNodeAnimator* anim = smgr->createCollisionResponseAnimator(
selector, camera, core::vector3df(30,50,30), selector, camera, core::vector3df(30,50,30),
core::vector3df(0,-3,0), core::vector3df(0,-10,0),
core::vector3df(0,50,0)); core::vector3df(0,50,0));
camera->addAnimator(anim); camera->addAnimator(anim);
anim->drop(); anim->drop();

View File

@ -324,13 +324,13 @@ void CDemo::switchToNextScene()
keyMap[8].Action = EKA_JUMP_UP; keyMap[8].Action = EKA_JUMP_UP;
keyMap[8].KeyCode = KEY_KEY_J; 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)); camera->setPosition(core::vector3df(108,140,-140));
scene::ISceneNodeAnimatorCollisionResponse* collider = scene::ISceneNodeAnimatorCollisionResponse* collider =
sm->createCollisionResponseAnimator( sm->createCollisionResponseAnimator(
metaSelector, camera, core::vector3df(25,50,25), 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); core::vector3df(0,45,0), 0.005f);
camera->addAnimator(collider); camera->addAnimator(collider);

View File

@ -1086,9 +1086,9 @@ namespace scene
const core::aabbox3d<f32>& box = yourSceneNode->getBoundingBox(); const core::aabbox3d<f32>& box = yourSceneNode->getBoundingBox();
core::vector3df radius = box.MaxEdge - box.getCenter(); core::vector3df radius = box.MaxEdge - box.getCenter();
\endcode \endcode
\param gravityPerSecond: Sets the gravity of the environment. A good example value would be \param gravityPerSecond: Sets the gravity of the environment, as an acceleration in
core::vector3df(0,-100.0f,0) for letting gravity affect all object to units per second per second. If your units are equivalent to metres, then
fall down. For bigger gravity, make increase the length of the vector. 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). 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 \param ellipsoidTranslation: By default, the ellipsoid for collision detection is created around
the center of the scene node, which means that the ellipsoid surrounds the center of the scene node, which means that the ellipsoid surrounds
@ -1102,7 +1102,7 @@ namespace scene
virtual ISceneNodeAnimatorCollisionResponse* createCollisionResponseAnimator( virtual ISceneNodeAnimatorCollisionResponse* createCollisionResponseAnimator(
ITriangleSelector* world, ISceneNode* sceneNode, ITriangleSelector* world, ISceneNode* sceneNode,
const core::vector3df& ellipsoidRadius = core::vector3df(30,60,30), 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), const core::vector3df& ellipsoidTranslation = core::vector3df(0,0,0),
f32 slidingValue = 0.0005f) = 0; f32 slidingValue = 0.0005f) = 0;

View File

@ -63,6 +63,11 @@ namespace scene
//! \return Gravity vector. */ //! \return Gravity vector. */
virtual core::vector3df getGravity() const = 0; 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. //! Set translation of the collision ellipsoid.
/** By default, the ellipsoid for collision detection is /** By default, the ellipsoid for collision detection is
created around the center of the scene node, which means that created around the center of the scene node, which means that

View File

@ -8,6 +8,7 @@
#include "Keycodes.h" #include "Keycodes.h"
#include "ICursorControl.h" #include "ICursorControl.h"
#include "ICameraSceneNode.h" #include "ICameraSceneNode.h"
#include "ISceneNodeAnimatorCollisionResponse.h"
namespace irr namespace irr
{ {
@ -199,9 +200,26 @@ void CSceneNodeAnimatorCameraFPS::animateNode(ISceneNode* node, u32 timeMs)
if (CursorKeys[EKA_STRAFE_RIGHT]) if (CursorKeys[EKA_STRAFE_RIGHT])
pos -= strafevect * timeDiff * MoveSpeed; 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]) if (CursorKeys[EKA_JUMP_UP])
pos += camera->getUpVector() * timeDiff * JumpSpeed; {
const core::list<ISceneNodeAnimator*> & animators = camera->getAnimators();
core::list<ISceneNodeAnimator*>::ConstIterator it = animators.begin();
while(it != animators.end())
{
if(ESNAT_COLLISION_RESPONSE == (*it)->getType())
{
ISceneNodeAnimatorCollisionResponse * collisionResponse =
static_cast<ISceneNodeAnimatorCollisionResponse *>(*it);
if(!collisionResponse->isFalling())
collisionResponse->jump(JumpSpeed);
}
it++;
}
}
// write translation // write translation
camera->setPosition(pos); camera->setPosition(pos);

View File

@ -21,8 +21,8 @@ CSceneNodeAnimatorCollisionResponse::CSceneNodeAnimatorCollisionResponse(
const core::vector3df& gravityPerSecond, const core::vector3df& gravityPerSecond,
const core::vector3df& ellipsoidTranslation, const core::vector3df& ellipsoidTranslation,
f32 slidingSpeed) f32 slidingSpeed)
: Radius(ellipsoidRadius), Gravity(gravityPerSecond / 1000.0f), Translation(ellipsoidTranslation), : Radius(ellipsoidRadius), Gravity(gravityPerSecond), Translation(ellipsoidTranslation),
World(world), Object(object), SceneManager(scenemanager), World(world), Object(object), SceneManager(scenemanager), FallingVelocity(0.f),
SlidingSpeed(slidingSpeed), Falling(false), IsCamera(false), AnimateCameraTarget(true) SlidingSpeed(slidingSpeed), Falling(false), IsCamera(false), AnimateCameraTarget(true)
{ {
@ -85,6 +85,13 @@ core::vector3df CSceneNodeAnimatorCollisionResponse::getGravity() const
return Gravity; 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. //! Sets the translation of the ellipsoid for collision detection.
void CSceneNodeAnimatorCollisionResponse::setEllipsoidTranslation(const core::vector3df &translation) void CSceneNodeAnimatorCollisionResponse::setEllipsoidTranslation(const core::vector3df &translation)
@ -108,8 +115,6 @@ void CSceneNodeAnimatorCollisionResponse::setWorld(ITriangleSelector* newWorld)
Falling = false; Falling = false;
LastTime = os::Timer::getTime(); LastTime = os::Timer::getTime();
FallStartTime = LastTime;
if (World) if (World)
World->drop(); World->drop();
@ -148,18 +153,11 @@ void CSceneNodeAnimatorCollisionResponse::animateNode(ISceneNode* node, u32 time
core::vector3df pos = Object->getPosition(); core::vector3df pos = Object->getPosition();
core::vector3df vel = pos - LastPosition; core::vector3df vel = pos - LastPosition;
//g = Gravity * (f32)((timeMs - FallStartTime) * diff); FallingVelocity += Gravity * (f32)diff * 0.001f;
f32 dt = 1.f;
if (Falling)
{
dt = f32 ( ( timeMs - FallStartTime ) * diff );
}
core::vector3df g = Gravity * dt;
core::triangle3df triangle = RefTriangle; core::triangle3df triangle = RefTriangle;
core::vector3df force = vel + g; core::vector3df force = vel + FallingVelocity;
const core::vector3df nullVector ( 0.f, 0.f, 0.f ); const core::vector3df nullVector ( 0.f, 0.f, 0.f );
@ -170,19 +168,19 @@ void CSceneNodeAnimatorCollisionResponse::animateNode(ISceneNode* node, u32 time
bool f = false; bool f = false;
pos = SceneManager->getSceneCollisionManager()->getCollisionResultPosition( pos = SceneManager->getSceneCollisionManager()->getCollisionResultPosition(
World, LastPosition-Translation, World, LastPosition-Translation,
Radius, vel, triangle, f, SlidingSpeed, g); Radius, vel, triangle, f, SlidingSpeed, FallingVelocity);
pos += Translation; pos += Translation;
if (f)//triangle == RefTriangle) if (f)//triangle == RefTriangle)
{ {
if (!Falling)
FallStartTime = timeMs;
Falling = true; Falling = true;
} }
else else
{
Falling = false; Falling = false;
FallingVelocity.set(0, 0, 0);
}
Object->setPosition(pos); Object->setPosition(pos);
} }
@ -209,7 +207,6 @@ void CSceneNodeAnimatorCollisionResponse::setNode(ISceneNode* node)
} }
LastTime = os::Timer::getTime(); LastTime = os::Timer::getTime();
FallStartTime = LastTime;
} }
//! Writes attributes of the scene node animator. //! Writes attributes of the scene node animator.

View File

@ -51,6 +51,9 @@ namespace scene
//! Sets the gravity of the environment. //! Sets the gravity of the environment.
virtual void setGravity(const core::vector3df& gravity); 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. //! Returns current vector of gravity.
virtual core::vector3df getGravity() const; virtual core::vector3df getGravity() const;
@ -93,13 +96,13 @@ namespace scene
core::vector3df LastPosition; core::vector3df LastPosition;
core::vector3df Radius; core::vector3df Radius;
core::vector3df Gravity; core::vector3df Gravity;
core::vector3df FallingVelocity; // In the direction of Gravity.
core::vector3df Translation; core::vector3df Translation;
ITriangleSelector* World; ITriangleSelector* World;
ISceneNode* Object; ISceneNode* Object;
ISceneManager* SceneManager; ISceneManager* SceneManager;
u32 LastTime; u32 LastTime;
u32 FallStartTime;
f32 SlidingSpeed; f32 SlidingSpeed;
bool Falling; bool Falling;
bool IsCamera; bool IsCamera;