Commit 1b628ef6 authored by Rogerborg's avatar Rogerborg

Expose the target scene nodes of collision response animators. Setting the...

Expose the target scene nodes of collision response animators.  Setting the target forces an update of its last position.  This allows a setPosition() to take effect without being blocked by the collision geometry.  Added comments to this effect, a unit test, and some unrelated !node checks in all the animators' animateNode() methods.

git-svn-id: svn://svn.code.sf.net/p/irrlicht/code/trunk@1957 dfc29bdd-3216-0410-991c-e03cc46cb475
parent 9bc11201
...@@ -1082,7 +1082,9 @@ namespace scene ...@@ -1082,7 +1082,9 @@ namespace scene
ISceneManager::createTriangleSelector(); ISceneManager::createTriangleSelector();
\param sceneNode: SceneNode which should be manipulated. After you added this animator \param sceneNode: SceneNode which should be manipulated. After you added this animator
to the scene node, the scene node will not be able to move through walls and is to the scene node, the scene node will not be able to move through walls and is
affected by gravity. affected by gravity. If you need to teleport the scene node to a new position without
it being effected by the collision geometry, then call sceneNode->setPosition(); then
animator->setTargetNode(sceneNode);
\param ellipsoidRadius: Radius of the ellipsoid with which collision detection and \param ellipsoidRadius: Radius of the ellipsoid with which collision detection and
response is done. If you have got a scene node, and you are unsure about response is done. If you have got a scene node, and you are unsure about
how big the radius should be, you could use the following code to determine how big the radius should be, you could use the following code to determine
...@@ -1091,8 +1093,8 @@ namespace scene ...@@ -1091,8 +1093,8 @@ 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, as an acceleration in \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 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. 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
......
...@@ -13,14 +13,19 @@ namespace scene ...@@ -13,14 +13,19 @@ namespace scene
{ {
//! Special scene node animator for doing automatic collision detection and response. //! Special scene node animator for doing automatic collision detection and response.
/** This scene node animator can be attached to any scene node /** This scene node animator can be attached to any single scene node
modifying it in that way, that it cannot move through walls of the and will then prevent it from moving through specified collision geometry
world, is influenced by gravity and acceleration. This animator is (e.g. walls and floors of the) world, as well as having it fall under gravity.
useful for example for first person shooter games. Attach it for This animator provides a simple implementation of first person shooter cameras.
example to a first person shooter camera, and the camera will behave as Attach it to a camera, and the camera will behave as the player control in a
the player control in a first person shooter game: The camera stops and first person shooter game: The camera stops and slides at walls, walks up stairs,
slides at walls, walks up stairs, falls down if there is no floor under falls down if there is no floor under it, and so on.
it, and so on. */
The animator will treat any change in the position of its target scene
node as movement, including a setPosition(), as movement. If you want to
teleport the target scene node manually to a location without it being effected
by collision geometry, then call setTargetNode(node) after calling node->setPosition().
*/
class ISceneNodeAnimatorCollisionResponse : public ISceneNodeAnimator class ISceneNodeAnimatorCollisionResponse : public ISceneNodeAnimator
{ {
public: public:
...@@ -92,6 +97,17 @@ namespace scene ...@@ -92,6 +97,17 @@ namespace scene
//! Get the current triangle selector containing all triangles for collision detection. //! Get the current triangle selector containing all triangles for collision detection.
virtual ITriangleSelector* getWorld() const = 0; virtual ITriangleSelector* getWorld() const = 0;
//! Set the single node that this animator will act on.
/** \param node The new target node. Setting this will force the animator to update
its last target position for the node, allowing setPosition() to teleport
the node through collision geometry. */
virtual void setTargetNode(ISceneNode * node) = 0;
//! Gets the single node that this animator is acting on.
/** \return The node that this animator is acting on. */
virtual ISceneNode* getTargetNode(void) const = 0;
}; };
......
...@@ -96,7 +96,7 @@ bool CSceneNodeAnimatorCameraFPS::OnEvent(const SEvent& evt) ...@@ -96,7 +96,7 @@ bool CSceneNodeAnimatorCameraFPS::OnEvent(const SEvent& evt)
void CSceneNodeAnimatorCameraFPS::animateNode(ISceneNode* node, u32 timeMs) void CSceneNodeAnimatorCameraFPS::animateNode(ISceneNode* node, u32 timeMs)
{ {
if (node->getType() != ESNT_CAMERA) if (!node || node->getType() != ESNT_CAMERA)
return; return;
ICameraSceneNode* camera = static_cast<ICameraSceneNode*>(node); ICameraSceneNode* camera = static_cast<ICameraSceneNode*>(node);
......
...@@ -41,7 +41,7 @@ CSceneNodeAnimatorCameraMaya::~CSceneNodeAnimatorCameraMaya() ...@@ -41,7 +41,7 @@ CSceneNodeAnimatorCameraMaya::~CSceneNodeAnimatorCameraMaya()
//! It is possible to send mouse and key events to the camera. Most cameras //! It is possible to send mouse and key events to the camera. Most cameras
//! may ignore this input, but camera scene nodes which are created for //! may ignore this input, but camera scene nodes which are created for
//! example with scene::ISceneManager::addMayaCameraSceneNode or //! example with scene::ISceneManager::addMayaCameraSceneNode or
//! scene::ISceneManager::addMeshViewerCameraSceneNode, may want to get this input //! scene::ISceneManager::addMeshViewerCameraSceneNode, may want to get this input
//! for changing their position, look at target or whatever. //! for changing their position, look at target or whatever.
...@@ -90,7 +90,7 @@ void CSceneNodeAnimatorCameraMaya::animateNode(ISceneNode *node, u32 timeMs) ...@@ -90,7 +90,7 @@ void CSceneNodeAnimatorCameraMaya::animateNode(ISceneNode *node, u32 timeMs)
//Alt + LM + MM = Dolly forth/back in view direction (speed % distance camera pivot - max distance to pivot) //Alt + LM + MM = Dolly forth/back in view direction (speed % distance camera pivot - max distance to pivot)
//Alt + MM = Move on camera plane (Screen center is about the mouse pointer, depending on move speed) //Alt + MM = Move on camera plane (Screen center is about the mouse pointer, depending on move speed)
if (node->getType() != ESNT_CAMERA) if (!node || node->getType() != ESNT_CAMERA)
return; return;
ICameraSceneNode* camera = static_cast<ICameraSceneNode*>(node); ICameraSceneNode* camera = static_cast<ICameraSceneNode*>(node);
...@@ -157,13 +157,13 @@ void CSceneNodeAnimatorCameraMaya::animateNode(ISceneNode *node, u32 timeMs) ...@@ -157,13 +157,13 @@ void CSceneNodeAnimatorCameraMaya::animateNode(ISceneNode *node, u32 timeMs)
} }
else else
{ {
translate += tvectX * (TranslateStart.X - MousePos.X)*TranslateSpeed + translate += tvectX * (TranslateStart.X - MousePos.X)*TranslateSpeed +
tvectY * (TranslateStart.Y - MousePos.Y)*TranslateSpeed; tvectY * (TranslateStart.Y - MousePos.Y)*TranslateSpeed;
} }
} }
else if (Translating) else if (Translating)
{ {
translate += tvectX * (TranslateStart.X - MousePos.X)*TranslateSpeed + translate += tvectX * (TranslateStart.X - MousePos.X)*TranslateSpeed +
tvectY * (TranslateStart.Y - MousePos.Y)*TranslateSpeed; tvectY * (TranslateStart.Y - MousePos.Y)*TranslateSpeed;
OldTarget = translate; OldTarget = translate;
Translating = false; Translating = false;
...@@ -235,7 +235,7 @@ void CSceneNodeAnimatorCameraMaya::allKeysUp() ...@@ -235,7 +235,7 @@ void CSceneNodeAnimatorCameraMaya::allKeysUp()
//! Sets the rotation speed //! Sets the rotation speed
void CSceneNodeAnimatorCameraMaya::setRotateSpeed(f32 speed) void CSceneNodeAnimatorCameraMaya::setRotateSpeed(f32 speed)
{ {
RotateSpeed = speed; RotateSpeed = speed;
} }
...@@ -275,7 +275,7 @@ f32 CSceneNodeAnimatorCameraMaya::getZoomSpeed() const ...@@ -275,7 +275,7 @@ f32 CSceneNodeAnimatorCameraMaya::getZoomSpeed() const
ISceneNodeAnimator* CSceneNodeAnimatorCameraMaya::createClone(ISceneNode* node, ISceneManager* newManager) ISceneNodeAnimator* CSceneNodeAnimatorCameraMaya::createClone(ISceneNode* node, ISceneManager* newManager)
{ {
CSceneNodeAnimatorCameraMaya * newAnimator = CSceneNodeAnimatorCameraMaya * newAnimator =
new CSceneNodeAnimatorCameraMaya(CursorControl, RotateSpeed, ZoomSpeed, TranslateSpeed); new CSceneNodeAnimatorCameraMaya(CursorControl, RotateSpeed, ZoomSpeed, TranslateSpeed);
return newAnimator; return newAnimator;
} }
......
...@@ -137,12 +137,9 @@ ITriangleSelector* CSceneNodeAnimatorCollisionResponse::getWorld() const ...@@ -137,12 +137,9 @@ ITriangleSelector* CSceneNodeAnimatorCollisionResponse::getWorld() const
void CSceneNodeAnimatorCollisionResponse::animateNode(ISceneNode* node, u32 timeMs) void CSceneNodeAnimatorCollisionResponse::animateNode(ISceneNode* node, u32 timeMs)
{ {
if (node != Object) if (node != Object)
{
setNode(node); setNode(node);
return;
}
if (!World) if(!Object || !World)
return; return;
u32 diff = timeMs - LastTime; u32 diff = timeMs - LastTime;
......
...@@ -15,7 +15,7 @@ namespace scene ...@@ -15,7 +15,7 @@ namespace scene
//! Special scene node animator for doing automatic collision detection and response. //! Special scene node animator for doing automatic collision detection and response.
/** This scene node animator can be attached to any scene node modifying it in that /** This scene node animator can be attached to any scene node modifying it in that
way, that it cannot move through walls of the world, is influenced by gravity and way, that it cannot move through walls of the world, is influenced by gravity and
acceleration. This animator is useful for example for first person shooter acceleration. This animator is useful for example for first person shooter
games. Attach it for example to a first person shooter camera, and the camera will games. Attach it for example to a first person shooter camera, and the camera will
behave as the player control in a first person shooter game: The camera stops and behave as the player control in a first person shooter game: The camera stops and
slides at walls, walks up stairs, falls down if there is no floor under it, and so on. slides at walls, walks up stairs, falls down if there is no floor under it, and so on.
...@@ -26,7 +26,7 @@ namespace scene ...@@ -26,7 +26,7 @@ namespace scene
//! constructor //! constructor
CSceneNodeAnimatorCollisionResponse(ISceneManager* scenemanager, CSceneNodeAnimatorCollisionResponse(ISceneManager* scenemanager,
ITriangleSelector* world, ISceneNode* object, ITriangleSelector* world, ISceneNode* object,
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,-100.0f,0),
const core::vector3df& ellipsoidTranslation = core::vector3df(0,0,0), const core::vector3df& ellipsoidTranslation = core::vector3df(0,0,0),
...@@ -41,7 +41,7 @@ namespace scene ...@@ -41,7 +41,7 @@ namespace scene
virtual bool isFalling() const; virtual bool isFalling() const;
//! 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.
virtual void setEllipsoidRadius(const core::vector3df& radius); virtual void setEllipsoidRadius(const core::vector3df& radius);
//! Returns the radius of the ellipsoid with which the collision detection and //! Returns the radius of the ellipsoid with which the collision detection and
...@@ -82,13 +82,19 @@ namespace scene ...@@ -82,13 +82,19 @@ namespace scene
//! Returns type of the scene node animator //! Returns type of the scene node animator
virtual ESCENE_NODE_ANIMATOR_TYPE getType() const { return ESNAT_COLLISION_RESPONSE; } virtual ESCENE_NODE_ANIMATOR_TYPE getType() const { return ESNAT_COLLISION_RESPONSE; }
//! Creates a clone of this animator. //! Creates a clone of this animator.
/** Please note that you will have to drop /** Please note that you will have to drop
(IReferenceCounted::drop()) the returned pointer after calling (IReferenceCounted::drop()) the returned pointer after calling
this. */ this. */
virtual ISceneNodeAnimator* createClone(ISceneNode* node, ISceneManager* newManager=0); virtual ISceneNodeAnimator* createClone(ISceneNode* node, ISceneManager* newManager=0);
//! Set the single node that this animator will act on.
virtual void setTargetNode(ISceneNode * node) { setNode(node); }
//! Gets the single node that this animator is acting on.
virtual ISceneNode* getTargetNode(void) const { return Object; }
private: private:
void setNode(ISceneNode* node); void setNode(ISceneNode* node);
...@@ -100,7 +106,7 @@ namespace scene ...@@ -100,7 +106,7 @@ namespace scene
core::vector3df LastPosition; core::vector3df LastPosition;
core::triangle3df RefTriangle; core::triangle3df RefTriangle;
ITriangleSelector* World; ITriangleSelector* World;
ISceneNode* Object; ISceneNode* Object;
ISceneManager* SceneManager; ISceneManager* SceneManager;
......
...@@ -30,6 +30,9 @@ inline s32 CSceneNodeAnimatorFollowSpline::clamp(s32 idx, s32 size) ...@@ -30,6 +30,9 @@ inline s32 CSceneNodeAnimatorFollowSpline::clamp(s32 idx, s32 size)
//! animates a scene node //! animates a scene node
void CSceneNodeAnimatorFollowSpline::animateNode(ISceneNode* node, u32 timeMs) void CSceneNodeAnimatorFollowSpline::animateNode(ISceneNode* node, u32 timeMs)
{ {
if(!node)
return;
const u32 pSize = Points.size(); const u32 pSize = Points.size();
if (pSize==0) if (pSize==0)
return; return;
......
...@@ -53,6 +53,9 @@ void CSceneNodeAnimatorTexture::clearTextures() ...@@ -53,6 +53,9 @@ void CSceneNodeAnimatorTexture::clearTextures()
//! animates a scene node //! animates a scene node
void CSceneNodeAnimatorTexture::animateNode(ISceneNode* node, u32 timeMs) void CSceneNodeAnimatorTexture::animateNode(ISceneNode* node, u32 timeMs)
{ {
if(!node)
return;
if (Textures.size()) if (Textures.size())
{ {
const u32 t = (timeMs-StartTime); const u32 t = (timeMs-StartTime);
......
...@@ -54,6 +54,7 @@ int main(int argumentCount, char * arguments[]) ...@@ -54,6 +54,7 @@ int main(int argumentCount, char * arguments[])
extern bool md2Animation(void); extern bool md2Animation(void);
extern bool b3dAnimation(void); extern bool b3dAnimation(void);
extern bool guiDisabledMenu(void); extern bool guiDisabledMenu(void);
extern bool collisionResponseAnimator(void);
typedef struct _STest typedef struct _STest
{ {
...@@ -65,7 +66,11 @@ int main(int argumentCount, char * arguments[]) ...@@ -65,7 +66,11 @@ int main(int argumentCount, char * arguments[])
static const STest tests[] = static const STest tests[] =
{ {
TEST(disambiguateTextures), // Run this first, since it validates the WD. // Note that to interactively debug a test, you will generally want to move it
// (temporarily) to the beginning of the list, since each test runs in its own
// process.
TEST(collisionResponseAnimator),
TEST(disambiguateTextures), // Normally you should run this first, since it validates the working directory.
TEST(exports), TEST(exports),
TEST(testVector3d), TEST(testVector3d),
TEST(testVector2d), TEST(testVector2d),
......
...@@ -8,9 +8,9 @@ ...@@ -8,9 +8,9 @@
#include <assert.h> #include <assert.h>
#include <stdarg.h> #include <stdarg.h>
#if defined(_MSC_VER) && !defined(NDEBUG) #if defined(TESTING_ON_WINDOWS)
#include <windows.h> #include <windows.h> // For OutputDebugString()
#endif // #if defined(_MSC_VER) && !defined(NDEBUG) #endif // #if defined(TESTING_ON_WINDOWS)
using namespace irr; using namespace irr;
...@@ -247,7 +247,7 @@ void logTestString(const char * format, ...) ...@@ -247,7 +247,7 @@ void logTestString(const char * format, ...)
(void)fflush(logFile); (void)fflush(logFile);
} }
#if defined(_MSC_VER) && !defined(NDEBUG) #if defined(TESTING_ON_WINDOWS)
OutputDebugStringA(logString); OutputDebugStringA(logString);
#endif // #if defined(_MSC_VER) && !defined(NDEBUG) #endif // #if defined(TESTING_ON_WINDOWS)
} }
...@@ -4,6 +4,10 @@ ...@@ -4,6 +4,10 @@
#include "irrlicht.h" #include "irrlicht.h"
#if defined(_WIN32) || defined(_WIN64) || defined(WIN32) || defined(WIN64) || defined(_WIN32_WCE)
#define TESTING_ON_WINDOWS
#endif
//! Compare two files //! Compare two files
/** \param fileName1 The first file for comparison. /** \param fileName1 The first file for comparison.
\param fileName1 The second file for comparison. \param fileName1 The second file for comparison.
......
Test suite pass at GMT Fri Dec 12 10:58:58 2008 Test suite pass at GMT Tue Dec 16 14:56:26 2008
...@@ -39,6 +39,7 @@ ...@@ -39,6 +39,7 @@
</Linker> </Linker>
<Unit filename="b3dAnimation.cpp" /> <Unit filename="b3dAnimation.cpp" />
<Unit filename="disambiguateTextures.cpp" /> <Unit filename="disambiguateTextures.cpp" />
<Unit filename="collisionResponseAnimator.cpp" />
<Unit filename="drawPixel.cpp" /> <Unit filename="drawPixel.cpp" />
<Unit filename="exports.cpp" /> <Unit filename="exports.cpp" />
<Unit filename="fast_atof.cpp" /> <Unit filename="fast_atof.cpp" />
......
...@@ -173,6 +173,10 @@ ...@@ -173,6 +173,10 @@
RelativePath=".\b3dAnimation.cpp" RelativePath=".\b3dAnimation.cpp"
> >
</File> </File>
<File
RelativePath=".\collisionResponseAnimator.cpp"
>
</File>
<File <File
RelativePath=".\disambiguateTextures.cpp" RelativePath=".\disambiguateTextures.cpp"
> >
...@@ -206,11 +210,11 @@ ...@@ -206,11 +210,11 @@
> >
</File> </File>
<File <File
RelativePath=".\softwareDevice.cpp" RelativePath=".\planeMatrix.cpp"
> >
</File> </File>
<File <File
RelativePath=".\planeMatrix.cpp" RelativePath=".\softwareDevice.cpp"
> >
</File> </File>
<File <File
......
...@@ -169,6 +169,10 @@ ...@@ -169,6 +169,10 @@
RelativePath=".\b3dAnimation.cpp" RelativePath=".\b3dAnimation.cpp"
> >
</File> </File>
<File
RelativePath=".\collisionResponseAnimator.cpp"
>
</File>
<File <File
RelativePath=".\disambiguateTextures.cpp" RelativePath=".\disambiguateTextures.cpp"
> >
......
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