git-svn-id: svn://svn.code.sf.net/p/irrlicht/code/trunk@6000 dfc29bdd-3216-0410-991c-e03cc46cb475
		
			
				
	
	
		
			311 lines
		
	
	
		
			8.0 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			311 lines
		
	
	
		
			8.0 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
| // Copyright (C) 2002-2012 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), CollisionNode(0), CollisionCallback(0),
 | |
| 	Falling(false), IsCamera(false), AnimateCameraTarget(true), CollisionOccurred(false),
 | |
| 	FirstUpdate(true)
 | |
| {
 | |
| 	#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
 | |
| {
 | |
| 	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;
 | |
| 	FirstUpdate = true;
 | |
| }
 | |
| 
 | |
| 
 | |
| //! Returns the radius of the ellipsoid with which 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;
 | |
| 	FirstUpdate = true;
 | |
| }
 | |
| 
 | |
| 
 | |
| //! 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)
 | |
| {
 | |
| 	if (newWorld)
 | |
| 		newWorld->grab();
 | |
| 
 | |
| 	if (World)
 | |
| 		World->drop();
 | |
| 
 | |
| 	World = newWorld;
 | |
| 
 | |
| 	FirstUpdate = true;
 | |
| }
 | |
| 
 | |
| 
 | |
| //! 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;
 | |
| 
 | |
| 	// trigger reset
 | |
| 	if ( timeMs == 0 )
 | |
| 	{
 | |
| 		FirstUpdate = true;
 | |
| 		timeMs = LastTime;
 | |
| 	}
 | |
| 
 | |
| 	if ( FirstUpdate )
 | |
| 	{
 | |
| 		LastPosition = Object->getPosition();
 | |
| 		Falling = false;
 | |
| 		LastTime = timeMs;
 | |
| 		FallingVelocity.set ( 0, 0, 0 );
 | |
| 
 | |
| 		FirstUpdate = false;
 | |
| 	}
 | |
| 
 | |
| 	const f32 diffSec = (f32)(timeMs - LastTime)*0.001f;
 | |
| 	LastTime = timeMs;
 | |
| 
 | |
| 	CollisionResultPosition = Object->getPosition();
 | |
| 	core::vector3df vel = CollisionResultPosition - LastPosition;
 | |
| 
 | |
| 	FallingVelocity += Gravity * diffSec;
 | |
| 
 | |
| 	CollisionTriangle = RefTriangle;
 | |
| 	CollisionPoint = core::vector3df();
 | |
| 	CollisionResultPosition = core::vector3df();
 | |
| 	CollisionNode = 0;
 | |
| 
 | |
| 	// core::vector3df force = vel + FallingVelocity;
 | |
| 
 | |
| 	if ( AnimateCameraTarget )
 | |
| 	{
 | |
| 		// TODO: divide SlidingSpeed by frame time
 | |
| 
 | |
| 		bool f = false;
 | |
| 		CollisionResultPosition
 | |
| 			= SceneManager->getSceneCollisionManager()->getCollisionResultPosition(
 | |
| 				World, LastPosition-Translation,
 | |
| 				Radius, vel, CollisionTriangle, CollisionPoint, f,
 | |
| 				CollisionNode, SlidingSpeed, FallingVelocity*diffSec);
 | |
| 
 | |
| 		CollisionOccurred = (CollisionTriangle != RefTriangle);
 | |
| 
 | |
| 		CollisionResultPosition += Translation;
 | |
| 
 | |
| 		if ( diffSec > 0 )	// don't change the state when there was no time
 | |
| 		{
 | |
| 			if (f)//CollisionTriangle == RefTriangle)
 | |
| 			{
 | |
| 				Falling = true;
 | |
| 			}
 | |
| 			else
 | |
| 			{
 | |
| 				if ( CollisionOccurred )	// f can also happen to be false when FallingVelocity was already 0 (p.e. at top of a jump)
 | |
| 					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
 | |
| {
 | |
| 	ISceneNodeAnimatorCollisionResponse::serializeAttributes(out, options);
 | |
| 
 | |
| 	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)
 | |
| {
 | |
| 	ISceneNodeAnimatorCollisionResponse::deserializeAttributes(in, options);
 | |
| 
 | |
| 	Radius = in->getAttributeAsVector3d("Radius", Radius);
 | |
| 	Gravity = in->getAttributeAsVector3d("Gravity", Gravity);
 | |
| 	Translation = in->getAttributeAsVector3d("Translation", Translation);
 | |
| 	AnimateCameraTarget = in->getAttributeAsBool("AnimateCameraTarget", AnimateCameraTarget);
 | |
| }
 | |
| 
 | |
| 
 | |
| ISceneNodeAnimator* CSceneNodeAnimatorCollisionResponse::createClone(ISceneNode* node, ISceneManager* newManager)
 | |
| {
 | |
| 	if (!newManager) newManager = SceneManager;
 | |
| 
 | |
| 	CSceneNodeAnimatorCollisionResponse * newAnimator =
 | |
| 		new CSceneNodeAnimatorCollisionResponse(newManager, World, Object, Radius,
 | |
| 				Gravity, Translation, SlidingSpeed);
 | |
| 	newAnimator->cloneMembers(this);
 | |
| 	return newAnimator;
 | |
| }
 | |
| 
 | |
| void CSceneNodeAnimatorCollisionResponse::setCollisionCallback(ICollisionCallback* callback)
 | |
| {
 | |
| 	if ( CollisionCallback == callback )
 | |
| 		return;
 | |
| 
 | |
| 	if (CollisionCallback)
 | |
| 		CollisionCallback->drop();
 | |
| 
 | |
| 	CollisionCallback = callback;
 | |
| 
 | |
| 	if (CollisionCallback)
 | |
| 		CollisionCallback->grab();
 | |
| }
 | |
| 
 | |
| //! Should the Target react on collision ( default = true )
 | |
| void CSceneNodeAnimatorCollisionResponse::setAnimateTarget ( bool enable )
 | |
| {
 | |
| 	AnimateCameraTarget = enable;
 | |
| 	FirstUpdate = true;
 | |
| }
 | |
| 
 | |
| //! Should the Target react on collision ( default = true )
 | |
| bool CSceneNodeAnimatorCollisionResponse::getAnimateTarget () const
 | |
| {
 | |
| 	return AnimateCameraTarget;
 | |
| }
 | |
| 
 | |
| } // end namespace scene
 | |
| } // end namespace irr
 | |
| 
 |