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)
- 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)
- 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
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();

View File

@ -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);

View File

@ -1086,9 +1086,9 @@ namespace scene
const core::aabbox3d<f32>& 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;

View File

@ -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

View File

@ -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<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
camera->setPosition(pos);

View File

@ -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.

View File

@ -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;