irrlicht/source/Irrlicht/CSceneNodeAnimatorCollision...

238 lines
5.6 KiB
C++

// Copyright (C) 2002-2008 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 / 1000.0f), Translation(ellipsoidTranslation),
World(world), Object(object), SceneManager(scenemanager),
SlidingSpeed(slidingSpeed), Falling(false), IsCamera(false), AnimateCameraTarget(true)
{
#ifdef _DEBUG
setDebugName("CSceneNodeAnimatorCollisionResponse");
#endif
if (World)
World->grab();
setNode(Object);
}
//! destructor
CSceneNodeAnimatorCollisionResponse::~CSceneNodeAnimatorCollisionResponse()
{
if (World)
World->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;
}
//! 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();
FallStartTime = LastTime;
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)
{
if (node != Object)
{
setNode(node);
return;
}
if (!World)
return;
u32 diff = timeMs - LastTime;
LastTime = timeMs;
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;
core::triangle3df triangle = RefTriangle;
core::vector3df force = vel + g;
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, triangle, f, SlidingSpeed, g);
pos += Translation;
if (f)//triangle == RefTriangle)
{
if (!Falling)
FallStartTime = timeMs;
Falling = true;
}
else
Falling = false;
Object->setPosition(pos);
}
// move camera target
if (AnimateCameraTarget && IsCamera)
{
const core::vector3df diff = Object->getPosition() - LastPosition - vel;
ICameraSceneNode* cam = (ICameraSceneNode*)Object;
cam->setTarget(cam->getTarget() + diff);
}
LastPosition = Object->getPosition();
}
void CSceneNodeAnimatorCollisionResponse::setNode(ISceneNode* node)
{
Object = node;
if (Object)
{
LastPosition = Object->getPosition();
IsCamera = (Object->getType() == ESNT_CAMERA);
}
LastTime = os::Timer::getTime();
FallStartTime = LastTime;
}
//! 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");
}
} // end namespace scene
} // end namespace irr