Commit 2c203d84 authored by Rogerborg's avatar Rogerborg

https://sourceforge.net/tracker2/index.php?func=detail&aid=2498791&group_id=74339&atid=540678

Expose the collision result position in ISceneNodeAnimatorCollisionResponse, to give more information to the user app.  Thanks again to garritg.

git-svn-id: svn://svn.code.sf.net/p/irrlicht/code/trunk@2120 dfc29bdd-3216-0410-991c-e03cc46cb475
parent a4171705
......@@ -28,7 +28,7 @@ namespace scene
\param animator: Collision response animator in which the collision occurred. You can call
this animator's methods to find the node, collisionPoint and/or collision triangle.
\retval true if the collision was handled in the animator. The animator's target
node will *not* be moved to the collision point, but will instead move directly
node will *not* be stopped at the collision point, but will instead move fully
to the location that triggered the collision check.
\retval false if the collision was not handled in the animator. The animator's
target node will be moved to the collision position.
......@@ -141,6 +141,13 @@ namespace scene
//! Returns the last triangle that caused a collision
virtual const core::triangle3df & getCollisionTriangle() const = 0;
//! Returns the position that the target node will be moved to, unless the collision is consumed in a callback).
/**
If you have a collision callback registered, and it consumes the collision, then the
node will ignore the collision and will not stop at this position. Instead, it will
move fully to the position that caused the collision to occur. */
virtual const core::vector3df & getCollisionResultPosition(void) const = 0;
//! Sets a callback interface which will be called if a collision occurs.
/** \param callback: collision callback handler that will be called when a collision
occurs. Set this to 0 to disable the callback.
......
// Copyright (C) 2002-2009 Nikolaus Gebhardt
// This file is part of the "Irrlicht Engine".
// For conditions of distribution and use, see copyright notice in irrlicht.h
#include "CSceneNodeAnimatorCollisionResponse.h"
#include "ISceneCollisionManager.h"
#include "ISceneManager.h"
#include "ICameraSceneNode.h"
#include "os.h"
namespace irr
{
namespace scene
{
//! constructor
CSceneNodeAnimatorCollisionResponse::CSceneNodeAnimatorCollisionResponse(
ISceneManager* scenemanager,
ITriangleSelector* world, ISceneNode* object,
const core::vector3df& ellipsoidRadius,
const core::vector3df& gravityPerSecond,
const core::vector3df& ellipsoidTranslation,
f32 slidingSpeed)
: Radius(ellipsoidRadius), Gravity(gravityPerSecond), Translation(ellipsoidTranslation),
World(world), Object(object), SceneManager(scenemanager), LastTime(0),
SlidingSpeed(slidingSpeed), Falling(false), IsCamera(false),
AnimateCameraTarget(true), CollisionOccurred(false),
CollisionCallback(0)
{
#ifdef _DEBUG
setDebugName("CSceneNodeAnimatorCollisionResponse");
#endif
if (World)
World->grab();
setNode(Object);
}
//! destructor
CSceneNodeAnimatorCollisionResponse::~CSceneNodeAnimatorCollisionResponse()
{
if (World)
World->drop();
if (CollisionCallback)
CollisionCallback->drop();
}
//! Returns if the attached scene node is falling, which means that
//! there is no blocking wall from the scene node in the direction of
//! the gravity.
bool CSceneNodeAnimatorCollisionResponse::isFalling() const
{
_IRR_IMPLEMENT_MANAGED_MARSHALLING_BUGFIX;
return Falling;
}
//! Sets the radius of the ellipsoid with which collision detection and
//! response is done.
void CSceneNodeAnimatorCollisionResponse::setEllipsoidRadius(
const core::vector3df& radius)
{
Radius = radius;
}
//! Returns the radius of the ellipsoid with wich the collision detection and
//! response is done.
core::vector3df CSceneNodeAnimatorCollisionResponse::getEllipsoidRadius() const
{
return Radius;
}
//! Sets the gravity of the environment.
void CSceneNodeAnimatorCollisionResponse::setGravity(const core::vector3df& gravity)
{
Gravity = gravity;
}
//! Returns current vector of gravity.
core::vector3df CSceneNodeAnimatorCollisionResponse::getGravity() const
{
return Gravity;
}
// Copyright (C) 2002-2009 Nikolaus Gebhardt
// This file is part of the "Irrlicht Engine".
// For conditions of distribution and use, see copyright notice in irrlicht.h
#include "CSceneNodeAnimatorCollisionResponse.h"
#include "ISceneCollisionManager.h"
#include "ISceneManager.h"
#include "ICameraSceneNode.h"
#include "os.h"
namespace irr
{
namespace scene
{
//! constructor
CSceneNodeAnimatorCollisionResponse::CSceneNodeAnimatorCollisionResponse(
ISceneManager* scenemanager,
ITriangleSelector* world, ISceneNode* object,
const core::vector3df& ellipsoidRadius,
const core::vector3df& gravityPerSecond,
const core::vector3df& ellipsoidTranslation,
f32 slidingSpeed)
: Radius(ellipsoidRadius), Gravity(gravityPerSecond), Translation(ellipsoidTranslation),
World(world), Object(object), SceneManager(scenemanager), LastTime(0),
SlidingSpeed(slidingSpeed), Falling(false), IsCamera(false),
AnimateCameraTarget(true), CollisionOccurred(false),
CollisionCallback(0)
{
#ifdef _DEBUG
setDebugName("CSceneNodeAnimatorCollisionResponse");
#endif
if (World)
World->grab();
setNode(Object);
}
//! destructor
CSceneNodeAnimatorCollisionResponse::~CSceneNodeAnimatorCollisionResponse()
{
if (World)
World->drop();
if (CollisionCallback)
CollisionCallback->drop();
}
//! Returns if the attached scene node is falling, which means that
//! there is no blocking wall from the scene node in the direction of
//! the gravity.
bool CSceneNodeAnimatorCollisionResponse::isFalling() const
{
_IRR_IMPLEMENT_MANAGED_MARSHALLING_BUGFIX;
return Falling;
}
//! Sets the radius of the ellipsoid with which collision detection and
//! response is done.
void CSceneNodeAnimatorCollisionResponse::setEllipsoidRadius(
const core::vector3df& radius)
{
Radius = radius;
}
//! Returns the radius of the ellipsoid with wich the collision detection and
//! response is done.
core::vector3df CSceneNodeAnimatorCollisionResponse::getEllipsoidRadius() const
{
return Radius;
}
//! Sets the gravity of the environment.
void CSceneNodeAnimatorCollisionResponse::setGravity(const core::vector3df& gravity)
{
Gravity = gravity;
}
//! Returns current vector of gravity.
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)
{
Translation = translation;
}
//! Returns the translation of the ellipsoid for collision detection.
core::vector3df CSceneNodeAnimatorCollisionResponse::getEllipsoidTranslation() const
{
return Translation;
}
//! Sets a triangle selector holding all triangles of the world with which
//! the scene node may collide.
void CSceneNodeAnimatorCollisionResponse::setWorld(ITriangleSelector* newWorld)
{
Falling = false;
LastTime = os::Timer::getTime();
if (World)
World->drop();
World = newWorld;
if (World)
World->grab();
}
//! Returns the current triangle selector containing all triangles for
//! collision detection.
ITriangleSelector* CSceneNodeAnimatorCollisionResponse::getWorld() const
{
return World;
}
void CSceneNodeAnimatorCollisionResponse::animateNode(ISceneNode* node, u32 timeMs)
{
CollisionOccurred = false;
if (node != Object)
setNode(node);
if(!Object || !World)
return;
u32 diff = timeMs - LastTime;
LastTime = timeMs;
core::vector3df pos = Object->getPosition();
core::vector3df vel = pos - LastPosition;
FallingVelocity += Gravity * (f32)diff * 0.001f;
CollisionTriangle = RefTriangle;
CollisionPoint = core::vector3df();
core::vector3df force = vel + FallingVelocity;
const core::vector3df nullVector ( 0.f, 0.f, 0.f );
if ( force != nullVector )
{
// TODO: divide SlidingSpeed by frame time
bool f = false;
pos = SceneManager->getSceneCollisionManager()->getCollisionResultPosition(
World, LastPosition-Translation,
Radius, vel, CollisionTriangle, CollisionPoint, f, SlidingSpeed, FallingVelocity);
CollisionOccurred = (CollisionTriangle != RefTriangle);
pos += Translation;
if (f)//CollisionTriangle == RefTriangle)
{
Falling = true;
}
else
{
Falling = false;
FallingVelocity.set(0, 0, 0);
}
bool collisionConsumed = false;
if (CollisionOccurred && CollisionCallback)
collisionConsumed = CollisionCallback->onCollision(*this);
if(!collisionConsumed)
Object->setPosition(pos);
}
// move camera target
if (AnimateCameraTarget && IsCamera)
{
const core::vector3df pdiff = Object->getPosition() - LastPosition - vel;
ICameraSceneNode* cam = (ICameraSceneNode*)Object;
cam->setTarget(cam->getTarget() + pdiff);
}
LastPosition = Object->getPosition();
}
void CSceneNodeAnimatorCollisionResponse::setNode(ISceneNode* node)
{
Object = node;
if (Object)
{
LastPosition = Object->getPosition();
IsCamera = (Object->getType() == ESNT_CAMERA);
}
LastTime = os::Timer::getTime();
}
//! Writes attributes of the scene node animator.
void CSceneNodeAnimatorCollisionResponse::serializeAttributes(io::IAttributes* out, io::SAttributeReadWriteOptions* options) const
{
out->addVector3d("Radius", Radius);
out->addVector3d("Gravity", Gravity);
out->addVector3d("Translation", Translation);
out->addBool("AnimateCameraTarget", AnimateCameraTarget);
}
//! Reads attributes of the scene node animator.
void CSceneNodeAnimatorCollisionResponse::deserializeAttributes(io::IAttributes* in, io::SAttributeReadWriteOptions* options)
{
Radius = in->getAttributeAsVector3d("Radius");
Gravity = in->getAttributeAsVector3d("Gravity");
Translation = in->getAttributeAsVector3d("Translation");
AnimateCameraTarget = in->getAttributeAsBool("AnimateCameraTarget");
}
ISceneNodeAnimator* CSceneNodeAnimatorCollisionResponse::createClone(ISceneNode* node, ISceneManager* newManager)
{
if (!newManager) newManager = SceneManager;
CSceneNodeAnimatorCollisionResponse * newAnimator =
new CSceneNodeAnimatorCollisionResponse(newManager, World, Object, Radius, (Gravity * 1000.0f), Translation,
SlidingSpeed);
return newAnimator;
}
void CSceneNodeAnimatorCollisionResponse::setCollisionCallback(ICollisionCallback* callback)
{
if (CollisionCallback)
CollisionCallback->drop();
CollisionCallback = callback;
if (CollisionCallback)
CollisionCallback->grab();
}
} // end namespace scene
} // end namespace irr
}
//! Sets the translation of the ellipsoid for collision detection.
void CSceneNodeAnimatorCollisionResponse::setEllipsoidTranslation(const core::vector3df &translation)
{
Translation = translation;
}
//! Returns the translation of the ellipsoid for collision detection.
core::vector3df CSceneNodeAnimatorCollisionResponse::getEllipsoidTranslation() const
{
return Translation;
}
//! Sets a triangle selector holding all triangles of the world with which
//! the scene node may collide.
void CSceneNodeAnimatorCollisionResponse::setWorld(ITriangleSelector* newWorld)
{
Falling = false;
LastTime = os::Timer::getTime();
if (World)
World->drop();
World = newWorld;
if (World)
World->grab();
}
//! Returns the current triangle selector containing all triangles for
//! collision detection.
ITriangleSelector* CSceneNodeAnimatorCollisionResponse::getWorld() const
{
return World;
}
void CSceneNodeAnimatorCollisionResponse::animateNode(ISceneNode* node, u32 timeMs)
{
CollisionOccurred = false;
if (node != Object)
setNode(node);
if(!Object || !World)
return;
u32 diff = timeMs - LastTime;
LastTime = timeMs;
CollisionResultPosition = Object->getPosition();
core::vector3df vel = CollisionResultPosition - LastPosition;
FallingVelocity += Gravity * (f32)diff * 0.001f;
CollisionTriangle = RefTriangle;
CollisionPoint = core::vector3df();
CollisionResultPosition = core::vector3df();
core::vector3df force = vel + FallingVelocity;
const core::vector3df nullVector ( 0.f, 0.f, 0.f );
if ( force != nullVector )
{
// TODO: divide SlidingSpeed by frame time
bool f = false;
CollisionResultPosition
= SceneManager->getSceneCollisionManager()->getCollisionResultPosition(
World, LastPosition-Translation,
Radius, vel, CollisionTriangle, CollisionPoint, f, SlidingSpeed, FallingVelocity);
CollisionOccurred = (CollisionTriangle != RefTriangle);
CollisionResultPosition += Translation;
if (f)//CollisionTriangle == RefTriangle)
{
Falling = true;
}
else
{
Falling = false;
FallingVelocity.set(0, 0, 0);
}
bool collisionConsumed = false;
if (CollisionOccurred && CollisionCallback)
collisionConsumed = CollisionCallback->onCollision(*this);
if(!collisionConsumed)
Object->setPosition(CollisionResultPosition);
}
// move camera target
if (AnimateCameraTarget && IsCamera)
{
const core::vector3df pdiff = Object->getPosition() - LastPosition - vel;
ICameraSceneNode* cam = (ICameraSceneNode*)Object;
cam->setTarget(cam->getTarget() + pdiff);
}
LastPosition = Object->getPosition();
}
void CSceneNodeAnimatorCollisionResponse::setNode(ISceneNode* node)
{
Object = node;
if (Object)
{
LastPosition = Object->getPosition();
IsCamera = (Object->getType() == ESNT_CAMERA);
}
LastTime = os::Timer::getTime();
}
//! Writes attributes of the scene node animator.
void CSceneNodeAnimatorCollisionResponse::serializeAttributes(io::IAttributes* out, io::SAttributeReadWriteOptions* options) const
{
out->addVector3d("Radius", Radius);
out->addVector3d("Gravity", Gravity);
out->addVector3d("Translation", Translation);
out->addBool("AnimateCameraTarget", AnimateCameraTarget);
}
//! Reads attributes of the scene node animator.
void CSceneNodeAnimatorCollisionResponse::deserializeAttributes(io::IAttributes* in, io::SAttributeReadWriteOptions* options)
{
Radius = in->getAttributeAsVector3d("Radius");
Gravity = in->getAttributeAsVector3d("Gravity");
Translation = in->getAttributeAsVector3d("Translation");
AnimateCameraTarget = in->getAttributeAsBool("AnimateCameraTarget");
}
ISceneNodeAnimator* CSceneNodeAnimatorCollisionResponse::createClone(ISceneNode* node, ISceneManager* newManager)
{
if (!newManager) newManager = SceneManager;
CSceneNodeAnimatorCollisionResponse * newAnimator =
new CSceneNodeAnimatorCollisionResponse(newManager, World, Object, Radius, (Gravity * 1000.0f), Translation,
SlidingSpeed);
return newAnimator;
}
void CSceneNodeAnimatorCollisionResponse::setCollisionCallback(ICollisionCallback* callback)
{
if (CollisionCallback)
CollisionCallback->drop();
CollisionCallback = callback;
if (CollisionCallback)
CollisionCallback->grab();
}
} // end namespace scene
} // end namespace irr
......@@ -104,6 +104,8 @@ namespace scene
//! Returns the last triangle that caused a collision.
virtual const core::triangle3df & getCollisionTriangle() const { return CollisionTriangle; }
virtual const core::vector3df & getCollisionResultPosition(void) const { return CollisionResultPosition; }
//! Sets a callback interface which will be called if a collision occurs.
/** \param callback: collision callback handler that will be called when a collision
occurs. Set this to 0 to disable the callback.
......@@ -134,6 +136,7 @@ namespace scene
bool CollisionOccurred;
core::vector3df CollisionPoint;
core::triangle3df CollisionTriangle;
core::vector3df CollisionResultPosition;
ICollisionCallback* CollisionCallback;
};
......
......@@ -24,12 +24,21 @@ public:
if(collisionPoint != ExpectedCollisionPoint)
{
logTestString("*** Error: expected %f %f %f\n",
logTestString("*** Error: collision point, expected %f %f %f\n",
ExpectedCollisionPoint.X, ExpectedCollisionPoint.Y, ExpectedCollisionPoint.Z);
expectedCollisionCallbackPositions = false;
assert(false);
}
const vector3df & nodePosition = animator.getCollisionResultPosition();
if(nodePosition != ExpectedNodePosition)
{
logTestString("*** Error: result position, expected %f %f %f\n",
ExpectedNodePosition.X, ExpectedNodePosition.Y, ExpectedNodePosition.Z);
expectedCollisionCallbackPositions = false;
assert(false);
}
if(animator.getTargetNode() != ExpectedTarget)
{
logTestString("*** Error: wrong node\n");
......@@ -40,10 +49,14 @@ public:
return ConsumeNextCollision;
}
void setNextExpectedCollision(ISceneNode* target, const vector3df& point, bool consume)
void setNextExpectedCollision(ISceneNode* target,
const vector3df& expectedPoint,
const vector3df& expectedPosition,
bool consume)
{
ExpectedTarget = target;
ExpectedCollisionPoint = point;
ExpectedCollisionPoint = expectedPoint;
ExpectedNodePosition = expectedPosition;
ConsumeNextCollision = consume;
}
......@@ -51,6 +64,7 @@ private:
ISceneNode * ExpectedTarget;
vector3df ExpectedCollisionPoint;
vector3df ExpectedNodePosition;
bool ConsumeNextCollision;
};
......@@ -108,7 +122,10 @@ bool collisionResponseAnimator(void)
// Try to move both nodes to the right of the wall.
// This one should be stopped by its animator.
testNode1->setPosition(vector3df(50, 0,0));
collisionCallback.setNextExpectedCollision(testNode1, vector3df(-5.005f, 0, 0), false);
collisionCallback.setNextExpectedCollision(testNode1,
vector3df(-5.005f, 0, 0),
vector3df(-15.005f, 0, 0),
false);
// Whereas this one, by forcing the animator to update its target node, should be
// able to pass through the wall. (In <=1.6 it was stopped by the wall even if
......@@ -141,7 +158,10 @@ bool collisionResponseAnimator(void)
testNode2->setPosition(vector3df(-50, 0, 0));
// We'll consume this collision, so the node will actually move all the way through.
collisionCallback.setNextExpectedCollision(testNode2, vector3df(5.005f, 0, 0), true);
collisionCallback.setNextExpectedCollision(testNode2,
vector3df(5.005f, 0, 0),
vector3df(15.005f, 0, 0),
true);
device->run();
smgr->drawAll();
......@@ -154,7 +174,10 @@ bool collisionResponseAnimator(void)
}
// Now we'll try to move it back to the right and allow it to be stopped.
collisionCallback.setNextExpectedCollision(testNode2, vector3df(-5.005f, 0, 0), false);
collisionCallback.setNextExpectedCollision(testNode2,
vector3df(-5.005f, 0, 0),
vector3df(-15.005f, 0, 0),
false);
testNode2->setPosition(vector3df(50, 0, 0));
device->run();
......
Test suite pass at GMT Thu Jan 22 09:54:41 2009
Test suite pass at GMT Thu Jan 22 10:10:45 2009
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment