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 ...@@ -28,7 +28,7 @@ namespace scene
\param animator: Collision response animator in which the collision occurred. You can call \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. 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 \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. to the location that triggered the collision check.
\retval false if the collision was not handled in the animator. The animator's \retval false if the collision was not handled in the animator. The animator's
target node will be moved to the collision position. target node will be moved to the collision position.
...@@ -141,6 +141,13 @@ namespace scene ...@@ -141,6 +141,13 @@ namespace scene
//! Returns the last triangle that caused a collision //! Returns the last triangle that caused a collision
virtual const core::triangle3df & getCollisionTriangle() const = 0; 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. //! Sets a callback interface which will be called if a collision occurs.
/** \param callback: collision callback handler that will be called when a collision /** \param callback: collision callback handler that will be called when a collision
occurs. Set this to 0 to disable the callback. occurs. Set this to 0 to disable the callback.
......
// Copyright (C) 2002-2009 Nikolaus Gebhardt // Copyright (C) 2002-2009 Nikolaus Gebhardt
// This file is part of the "Irrlicht Engine". // This file is part of the "Irrlicht Engine".
// For conditions of distribution and use, see copyright notice in irrlicht.h // For conditions of distribution and use, see copyright notice in irrlicht.h
#include "CSceneNodeAnimatorCollisionResponse.h" #include "CSceneNodeAnimatorCollisionResponse.h"
#include "ISceneCollisionManager.h" #include "ISceneCollisionManager.h"
#include "ISceneManager.h" #include "ISceneManager.h"
#include "ICameraSceneNode.h" #include "ICameraSceneNode.h"
#include "os.h" #include "os.h"
namespace irr namespace irr
{ {
namespace scene namespace scene
{ {
//! constructor //! constructor
CSceneNodeAnimatorCollisionResponse::CSceneNodeAnimatorCollisionResponse( CSceneNodeAnimatorCollisionResponse::CSceneNodeAnimatorCollisionResponse(
ISceneManager* scenemanager, ISceneManager* scenemanager,
ITriangleSelector* world, ISceneNode* object, ITriangleSelector* world, ISceneNode* object,
const core::vector3df& ellipsoidRadius, const core::vector3df& ellipsoidRadius,
const core::vector3df& gravityPerSecond, const core::vector3df& gravityPerSecond,
const core::vector3df& ellipsoidTranslation, const core::vector3df& ellipsoidTranslation,
f32 slidingSpeed) f32 slidingSpeed)
: Radius(ellipsoidRadius), Gravity(gravityPerSecond), Translation(ellipsoidTranslation), : Radius(ellipsoidRadius), Gravity(gravityPerSecond), Translation(ellipsoidTranslation),
World(world), Object(object), SceneManager(scenemanager), LastTime(0), World(world), Object(object), SceneManager(scenemanager), LastTime(0),
SlidingSpeed(slidingSpeed), Falling(false), IsCamera(false), SlidingSpeed(slidingSpeed), Falling(false), IsCamera(false),
AnimateCameraTarget(true), CollisionOccurred(false), AnimateCameraTarget(true), CollisionOccurred(false),
CollisionCallback(0) CollisionCallback(0)
{ {
#ifdef _DEBUG #ifdef _DEBUG
setDebugName("CSceneNodeAnimatorCollisionResponse"); setDebugName("CSceneNodeAnimatorCollisionResponse");
#endif #endif
if (World) if (World)
World->grab(); World->grab();
setNode(Object); setNode(Object);
} }
//! destructor //! destructor
CSceneNodeAnimatorCollisionResponse::~CSceneNodeAnimatorCollisionResponse() CSceneNodeAnimatorCollisionResponse::~CSceneNodeAnimatorCollisionResponse()
{ {
if (World) if (World)
World->drop(); World->drop();
if (CollisionCallback) if (CollisionCallback)
CollisionCallback->drop(); CollisionCallback->drop();
} }
//! Returns if the attached scene node is falling, which means that //! Returns if the attached scene node is falling, which means that
//! there is no blocking wall from the scene node in the direction of //! there is no blocking wall from the scene node in the direction of
//! the gravity. //! the gravity.
bool CSceneNodeAnimatorCollisionResponse::isFalling() const bool CSceneNodeAnimatorCollisionResponse::isFalling() const
{ {
_IRR_IMPLEMENT_MANAGED_MARSHALLING_BUGFIX; _IRR_IMPLEMENT_MANAGED_MARSHALLING_BUGFIX;
return Falling; return Falling;
} }
//! Sets the radius of the ellipsoid with which collision detection and //! Sets the radius of the ellipsoid with which collision detection and
//! response is done. //! response is done.
void CSceneNodeAnimatorCollisionResponse::setEllipsoidRadius( void CSceneNodeAnimatorCollisionResponse::setEllipsoidRadius(
const core::vector3df& radius) const core::vector3df& radius)
{ {
Radius = radius; Radius = radius;
} }
//! Returns the radius of the ellipsoid with wich the collision detection and //! Returns the radius of the ellipsoid with wich the collision detection and
//! response is done. //! response is done.
core::vector3df CSceneNodeAnimatorCollisionResponse::getEllipsoidRadius() const core::vector3df CSceneNodeAnimatorCollisionResponse::getEllipsoidRadius() const
{ {
return Radius; return Radius;
} }
//! Sets the gravity of the environment. //! Sets the gravity of the environment.
void CSceneNodeAnimatorCollisionResponse::setGravity(const core::vector3df& gravity) void CSceneNodeAnimatorCollisionResponse::setGravity(const core::vector3df& gravity)
{ {
Gravity = gravity; Gravity = gravity;
} }
//! Returns current vector of gravity. //! Returns current vector of gravity.
core::vector3df CSceneNodeAnimatorCollisionResponse::getGravity() const core::vector3df CSceneNodeAnimatorCollisionResponse::getGravity() const
{ {
return Gravity; return Gravity;
} }
//! 'Jump' the animator, by adding a jump speed opposite to its gravity //! 'Jump' the animator, by adding a jump speed opposite to its gravity
void CSceneNodeAnimatorCollisionResponse::jump(f32 jumpSpeed) void CSceneNodeAnimatorCollisionResponse::jump(f32 jumpSpeed)
{ {
FallingVelocity -= (core::vector3df(Gravity).normalize()) * jumpSpeed; FallingVelocity -= (core::vector3df(Gravity).normalize()) * jumpSpeed;
Falling = true; 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)
{ {
Translation = translation; Translation = translation;
} }
//! Returns the translation of the ellipsoid for collision detection. //! Returns the translation of the ellipsoid for collision detection.
core::vector3df CSceneNodeAnimatorCollisionResponse::getEllipsoidTranslation() const core::vector3df CSceneNodeAnimatorCollisionResponse::getEllipsoidTranslation() const
{ {
return Translation; return Translation;
} }
//! Sets a triangle selector holding all triangles of the world with which //! Sets a triangle selector holding all triangles of the world with which
//! the scene node may collide. //! the scene node may collide.
void CSceneNodeAnimatorCollisionResponse::setWorld(ITriangleSelector* newWorld) void CSceneNodeAnimatorCollisionResponse::setWorld(ITriangleSelector* newWorld)
{ {
Falling = false; Falling = false;
LastTime = os::Timer::getTime(); LastTime = os::Timer::getTime();
if (World) if (World)
World->drop(); World->drop();
World = newWorld; World = newWorld;
if (World) if (World)
World->grab(); World->grab();
} }
//! Returns the current triangle selector containing all triangles for //! Returns the current triangle selector containing all triangles for
//! collision detection. //! collision detection.
ITriangleSelector* CSceneNodeAnimatorCollisionResponse::getWorld() const ITriangleSelector* CSceneNodeAnimatorCollisionResponse::getWorld() const
{ {
return World; return World;
} }
void CSceneNodeAnimatorCollisionResponse::animateNode(ISceneNode* node, u32 timeMs) void CSceneNodeAnimatorCollisionResponse::animateNode(ISceneNode* node, u32 timeMs)
{ {
CollisionOccurred = false; CollisionOccurred = false;
if (node != Object) if (node != Object)
setNode(node); setNode(node);
if(!Object || !World) if(!Object || !World)
return; return;
u32 diff = timeMs - LastTime; u32 diff = timeMs - LastTime;
LastTime = timeMs; LastTime = timeMs;
core::vector3df pos = Object->getPosition(); CollisionResultPosition = Object->getPosition();
core::vector3df vel = pos - LastPosition; core::vector3df vel = CollisionResultPosition - LastPosition;
FallingVelocity += Gravity * (f32)diff * 0.001f; FallingVelocity += Gravity * (f32)diff * 0.001f;
CollisionTriangle = RefTriangle; CollisionTriangle = RefTriangle;
CollisionPoint = core::vector3df(); CollisionPoint = core::vector3df();
CollisionResultPosition = core::vector3df();
core::vector3df force = vel + FallingVelocity;
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 );
if ( force != nullVector )
{ if ( force != nullVector )
// TODO: divide SlidingSpeed by frame time {
// TODO: divide SlidingSpeed by frame time
bool f = false;
pos = SceneManager->getSceneCollisionManager()->getCollisionResultPosition( bool f = false;
World, LastPosition-Translation, CollisionResultPosition
Radius, vel, CollisionTriangle, CollisionPoint, f, SlidingSpeed, FallingVelocity); = SceneManager->getSceneCollisionManager()->getCollisionResultPosition(
World, LastPosition-Translation,
CollisionOccurred = (CollisionTriangle != RefTriangle); Radius, vel, CollisionTriangle, CollisionPoint, f, SlidingSpeed, FallingVelocity);
pos += Translation; CollisionOccurred = (CollisionTriangle != RefTriangle);
if (f)//CollisionTriangle == RefTriangle) CollisionResultPosition += Translation;
{
Falling = true; if (f)//CollisionTriangle == RefTriangle)
} {
else Falling = true;
{ }
Falling = false; else
FallingVelocity.set(0, 0, 0); {
} Falling = false;
FallingVelocity.set(0, 0, 0);
bool collisionConsumed = false; }
if (CollisionOccurred && CollisionCallback) bool collisionConsumed = false;
collisionConsumed = CollisionCallback->onCollision(*this);
if (CollisionOccurred && CollisionCallback)
if(!collisionConsumed) collisionConsumed = CollisionCallback->onCollision(*this);
Object->setPosition(pos);
} if(!collisionConsumed)
Object->setPosition(CollisionResultPosition);
// move camera target }
if (AnimateCameraTarget && IsCamera)
{ // move camera target
const core::vector3df pdiff = Object->getPosition() - LastPosition - vel; if (AnimateCameraTarget && IsCamera)
ICameraSceneNode* cam = (ICameraSceneNode*)Object; {
cam->setTarget(cam->getTarget() + pdiff); const core::vector3df pdiff = Object->getPosition() - LastPosition - vel;
} ICameraSceneNode* cam = (ICameraSceneNode*)Object;
cam->setTarget(cam->getTarget() + pdiff);
LastPosition = Object->getPosition(); }
}
LastPosition = Object->getPosition();
}
void CSceneNodeAnimatorCollisionResponse::setNode(ISceneNode* node)
{
Object = node; void CSceneNodeAnimatorCollisionResponse::setNode(ISceneNode* node)
{
if (Object) Object = node;
{
LastPosition = Object->getPosition(); if (Object)
IsCamera = (Object->getType() == ESNT_CAMERA); {
} LastPosition = Object->getPosition();
IsCamera = (Object->getType() == ESNT_CAMERA);
LastTime = os::Timer::getTime(); }
}
LastTime = os::Timer::getTime();
}
//! Writes attributes of the scene node animator.
void CSceneNodeAnimatorCollisionResponse::serializeAttributes(io::IAttributes* out, io::SAttributeReadWriteOptions* options) const
{ //! Writes attributes of the scene node animator.
out->addVector3d("Radius", Radius); void CSceneNodeAnimatorCollisionResponse::serializeAttributes(io::IAttributes* out, io::SAttributeReadWriteOptions* options) const
out->addVector3d("Gravity", Gravity); {
out->addVector3d("Translation", Translation); out->addVector3d("Radius", Radius);
out->addBool("AnimateCameraTarget", AnimateCameraTarget); 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)
{ //! Reads attributes of the scene node animator.
Radius = in->getAttributeAsVector3d("Radius"); void CSceneNodeAnimatorCollisionResponse::deserializeAttributes(io::IAttributes* in, io::SAttributeReadWriteOptions* options)
Gravity = in->getAttributeAsVector3d("Gravity"); {
Translation = in->getAttributeAsVector3d("Translation"); Radius = in->getAttributeAsVector3d("Radius");
AnimateCameraTarget = in->getAttributeAsBool("AnimateCameraTarget"); Gravity = in->getAttributeAsVector3d("Gravity");
} Translation = in->getAttributeAsVector3d("Translation");
AnimateCameraTarget = in->getAttributeAsBool("AnimateCameraTarget");
}
ISceneNodeAnimator* CSceneNodeAnimatorCollisionResponse::createClone(ISceneNode* node, ISceneManager* newManager)
{
if (!newManager) newManager = SceneManager; ISceneNodeAnimator* CSceneNodeAnimatorCollisionResponse::createClone(ISceneNode* node, ISceneManager* newManager)
{
CSceneNodeAnimatorCollisionResponse * newAnimator = if (!newManager) newManager = SceneManager;
new CSceneNodeAnimatorCollisionResponse(newManager, World, Object, Radius, (Gravity * 1000.0f), Translation,
SlidingSpeed); CSceneNodeAnimatorCollisionResponse * newAnimator =
new CSceneNodeAnimatorCollisionResponse(newManager, World, Object, Radius, (Gravity * 1000.0f), Translation,
return newAnimator; SlidingSpeed);
}
return newAnimator;
void CSceneNodeAnimatorCollisionResponse::setCollisionCallback(ICollisionCallback* callback) }
{
if (CollisionCallback) void CSceneNodeAnimatorCollisionResponse::setCollisionCallback(ICollisionCallback* callback)
CollisionCallback->drop(); {
if (CollisionCallback)
CollisionCallback = callback; CollisionCallback->drop();
if (CollisionCallback) CollisionCallback = callback;
CollisionCallback->grab();
} if (CollisionCallback)
CollisionCallback->grab();
} // end namespace scene }
} // end namespace irr
} // end namespace scene
} // end namespace irr
...@@ -104,6 +104,8 @@ namespace scene ...@@ -104,6 +104,8 @@ namespace scene
//! Returns the last triangle that caused a collision. //! Returns the last triangle that caused a collision.
virtual const core::triangle3df & getCollisionTriangle() const { return CollisionTriangle; } 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. //! Sets a callback interface which will be called if a collision occurs.
/** \param callback: collision callback handler that will be called when a collision /** \param callback: collision callback handler that will be called when a collision
occurs. Set this to 0 to disable the callback. occurs. Set this to 0 to disable the callback.
...@@ -134,6 +136,7 @@ namespace scene ...@@ -134,6 +136,7 @@ namespace scene
bool CollisionOccurred; bool CollisionOccurred;
core::vector3df CollisionPoint; core::vector3df CollisionPoint;
core::triangle3df CollisionTriangle; core::triangle3df CollisionTriangle;
core::vector3df CollisionResultPosition;
ICollisionCallback* CollisionCallback; ICollisionCallback* CollisionCallback;
}; };
......
...@@ -24,12 +24,21 @@ public: ...@@ -24,12 +24,21 @@ public:
if(collisionPoint != ExpectedCollisionPoint) 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); ExpectedCollisionPoint.X, ExpectedCollisionPoint.Y, ExpectedCollisionPoint.Z);
expectedCollisionCallbackPositions = false; expectedCollisionCallbackPositions = false;
assert(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) if(animator.getTargetNode() != ExpectedTarget)
{ {
logTestString("*** Error: wrong node\n"); logTestString("*** Error: wrong node\n");
...@@ -40,10 +49,14 @@ public: ...@@ -40,10 +49,14 @@ public:
return ConsumeNextCollision; 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; ExpectedTarget = target;
ExpectedCollisionPoint = point; ExpectedCollisionPoint = expectedPoint;
ExpectedNodePosition = expectedPosition;
ConsumeNextCollision = consume; ConsumeNextCollision = consume;
} }
...@@ -51,6 +64,7 @@ private: ...@@ -51,6 +64,7 @@ private:
ISceneNode * ExpectedTarget; ISceneNode * ExpectedTarget;
vector3df ExpectedCollisionPoint; vector3df ExpectedCollisionPoint;
vector3df ExpectedNodePosition;
bool ConsumeNextCollision; bool ConsumeNextCollision;
}; };
...@@ -108,7 +122,10 @@ bool collisionResponseAnimator(void) ...@@ -108,7 +122,10 @@ bool collisionResponseAnimator(void)
// Try to move both nodes to the right of the wall. // Try to move both nodes to the right of the wall.
// This one should be stopped by its animator. // This one should be stopped by its animator.
testNode1->setPosition(vector3df(50, 0,0)); 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 // 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 // able to pass through the wall. (In <=1.6 it was stopped by the wall even if
...@@ -141,7 +158,10 @@ bool collisionResponseAnimator(void) ...@@ -141,7 +158,10 @@ bool collisionResponseAnimator(void)
testNode2->setPosition(vector3df(-50, 0, 0)); testNode2->setPosition(vector3df(-50, 0, 0));
// We'll consume this collision, so the node will actually move all the way through. // 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(); device->run();
smgr->drawAll(); smgr->drawAll();
...@@ -154,7 +174,10 @@ bool collisionResponseAnimator(void) ...@@ -154,7 +174,10 @@ bool collisionResponseAnimator(void)
} }
// Now we'll try to move it back to the right and allow it to be stopped. // 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)); testNode2->setPosition(vector3df(50, 0, 0));
device->run(); 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