Beispiel #1
0
	void FunnelPlanner::computeCrossing( float radius, const Vector2 & startPos, PortalPath * path, size_t startPortal ) {
		assert( path->getPortalCount() > 0 && "Funnel planner should only be applied to PortalPaths with at least one portal" );
		FunnelApex apex( startPortal - 1, startPos );	// if startPortal is zero, this should go to all 1s...i.e. -1 > all other size_t values
		
		const WayPortal * portal = path->getPortal( startPortal );
		Vector2 pLeft( portal->getLeft( radius ) );
		Vector2 pRight( portal->getRight( radius ) );
		Vector2 dirLeft( pLeft - apex._pos );
		Vector2 dirRight( pRight - apex._pos );
	#ifdef SIMPLE_FUNNEL
		FunnelEdge funnelLeft( startPortal, dirLeft );
		FunnelEdge funnelRight( startPortal, dirRight );
		size_t currPortal = startPortal + 1;
		const size_t PORTAL_COUNT = path->getPortalCount();
		while ( currPortal < PORTAL_COUNT ) {
			portal = path->getPortal( currPortal );
			pLeft.set( portal->getLeft( radius ) );
			pRight.set( portal->getRight( radius ) );
			dirLeft.set( pLeft - apex._pos );
			dirRight.set( pRight - apex._pos );

			// test left side of the funnel
			if ( funnelRight.isOnRight( dirLeft ) ) {
				// the portal's funnel is on the right of the current funnel
				Vector2 oldApex = apex._pos;
				Vector2 newApex = funnelRight._dir + apex._pos;
				//if ( apex._id != -1 && apex._id < currPortal ) {
					path->setWaypoints( apex._id + 1, funnelRight._id + 1, newApex, norm( funnelRight._dir ) );
				//}
				apex.set( funnelRight._id, newApex );
				currPortal = funnelRight._id + 1;

				portal = path->getPortal( currPortal );
				pLeft.set( portal->getLeft( radius ) );
				pRight.set( portal->getRight( radius ) );
				dirLeft.set( pLeft - apex._pos );
				dirRight.set( pRight - apex._pos );
				funnelLeft.set( currPortal, dirLeft );
				funnelRight.set( currPortal, dirRight );
				++currPortal;
				
				continue;
			} else if ( funnelLeft.isOnRight( dirLeft ) ) {
				funnelLeft.set( currPortal, dirLeft );
			}

			// test right side of the funnel
			if ( funnelLeft.isOnLeft( dirRight ) ) {
				// the portal's funnel is on the left of the current funnel
				Vector2 oldApex = apex._pos;
				Vector2 newApex = funnelLeft._dir + apex._pos;
				//if ( apex._id != -1 && apex._id < currPortal ) {
					path->setWaypoints( apex._id + 1, funnelLeft._id + 1, newApex, norm( funnelLeft._dir ) );
				//}
				apex.set( funnelLeft._id, newApex );
				currPortal = funnelLeft._id + 1;

				portal = path->getPortal( currPortal );
				pLeft.set( portal->getLeft( radius ) );
				pRight.set( portal->getRight( radius ) );
				dirLeft.set( pLeft - apex._pos );
				dirRight.set( pRight - apex._pos );
				funnelLeft.set( currPortal, dirLeft );
				funnelRight.set( currPortal, dirRight );
				++currPortal;
				
				continue;
			} else if ( funnelRight.isOnLeft( dirRight ) ) {
				funnelRight.set( currPortal, dirRight );
			}
			++currPortal;
		}

		// Now handle goal
		const Vector2 goalPt = path->getGoalCentroid();
		Vector2 goalDir( goalPt - apex._pos );

		if ( funnelLeft.isOnLeft( goalDir ) ) {
			// The goal point is on the left side of the funnel
			if ( apex._id != -1 && apex._id < PORTAL_COUNT ) {
				path->setWaypoints( apex._id + 1, PORTAL_COUNT, apex._pos + funnelLeft._dir, norm( funnelLeft._dir ) );
			}
		} else if ( funnelRight.isOnRight( goalDir ) ) {
			// The goal point is on the right side of the funnel
			if ( apex._id != -1 && apex._id < PORTAL_COUNT ) {
				path->setWaypoints( apex._id + 1, PORTAL_COUNT, apex._pos + funnelRight._dir, norm( funnelRight._dir ) );
			}
		} 

		if ( apex._id + 1 < PORTAL_COUNT ) {
			path->setWaypoints( (size_t)apex._id + 1, (size_t)PORTAL_COUNT, goalPt, norm( goalPt - apex._pos ) );
		}

	#else
		_left.push_back( FunnelEdge( startPortal - 1, startPortal, dirLeft, startPos ) );
		_right.push_back( FunnelEdge( startPortal - 1, startPortal, dirRight, startPos ) );
		const size_t PORTAL_COUNT = path->getPortalCount();
		for ( size_t i = startPortal + 1; i < PORTAL_COUNT; ++i ) {
			portal = path->getPortal( i );

			// investigate the left point
			pLeft.set( portal->getLeft( radius ) );			
			bool apexMoved = false;
			while ( !_right.empty() ) {
				std::list< FunnelEdge >::iterator itr = _right.begin();
				Vector2 dir = pLeft - itr->_origin;
				if ( itr->isOnRight( dir ) ) {
					apexMoved = true;
					Vector2 newApex = itr->_origin + itr->_dir;
					path->setWaypoints( itr->_id + 1, itr->_endID + 1, newApex, norm( itr->_dir ) );
					apex.set( itr->_endID, newApex );
					_right.pop_front();
				} else {
					break;
				}
			}
			if ( apexMoved ) {
				_left.clear();
				_left.push_back( FunnelEdge( apex._id, i, pLeft - apex._pos, apex._pos ) );
			} else {
				std::list< FunnelEdge >::reverse_iterator itr = _left.rbegin();
				while ( ! _left.empty() ) {
					Vector2 dir = pLeft - itr->_origin;
					if ( itr->isOnRight( dir ) ) {
						_left.pop_back();
						itr = _left.rbegin();
					} else {
						break;
					}
				}
				if ( _left.empty() ) {
					_left.push_back( FunnelEdge( apex._id, i, pLeft - apex._pos, apex._pos ) );
				} else {
					Vector2 origin( itr->_origin + itr->_dir );
					_left.push_back( FunnelEdge( itr->_endID, i, pLeft - origin, origin ) );
				}
			}

			// investigate the right point
			pRight.set( portal->getRight( radius ) );
			apexMoved = false;
			while ( !_left.empty() ) {
				std::list< FunnelEdge >::iterator itr = _left.begin();
				Vector2 dir = pRight - itr->_origin;
				if ( itr->isOnLeft( dir ) ) {
					apexMoved = true;
					Vector2 newApex = itr->_origin + itr->_dir;
					path->setWaypoints( itr->_id + 1, itr->_endID + 1, newApex, norm( itr->_dir ) );
					apex.set( itr->_endID, newApex );
					_left.pop_front();
				} else {
					break;
				}
			}
			if ( apexMoved ) {
				_right.clear();
				_right.push_back( FunnelEdge( apex._id, i, pRight - apex._pos, apex._pos ) );
			} else {
				std::list< FunnelEdge >::reverse_iterator itr = _right.rbegin();
				while ( ! _right.empty() ) {
					Vector2 dir = pRight - itr->_origin;
					if ( itr->isOnLeft( dir ) ) {
						_right.pop_back();
						itr = _right.rbegin();
					} else {
						break;
					}
				}
				if ( _right.empty() ) {
					_right.push_back( FunnelEdge( apex._id, i, pRight - apex._pos, apex._pos ) );
				} else {
					Vector2 origin( itr->_origin + itr->_dir );
					_right.push_back( FunnelEdge( itr->_endID, i, pRight - origin, origin ) );
				}
			}
		}
		// handle the goal
		const Vector2 goalPt = path->getGoalCentroid();
		Vector2 goalDir;

		bool apexMoved = false;
		while ( !_left.empty() ) {
			std::list< FunnelEdge >::iterator itr = _left.begin();
			goalDir.set( goalPt - itr->_origin );
			if ( itr->isOnLeft( goalDir ) ) {
				apexMoved = true;
				Vector2 newApex = itr->_origin + itr->_dir;
				apex.set( itr->_endID, newApex );
				path->setWaypoints( itr->_id + 1, itr->_endID + 1, newApex, norm( itr->_dir ) );
				_left.pop_front();
			} else {
				break;
			}
		}
		if ( apexMoved ) {
			goalDir.set( goalPt - apex._pos );
			path->setWaypoints( apex._id + 1, PORTAL_COUNT, goalPt, norm( goalDir ) );
		} else {
			// apexMoved is already false -- it is the only way to reach this branch
			while ( !_right.empty() ) {
				std::list< FunnelEdge >::iterator itr = _right.begin();
				goalDir.set( goalPt - itr->_origin );
				if ( itr->isOnRight( goalDir ) ) {
					apexMoved = true;
					Vector2 newApex = itr->_origin + itr->_dir;
					apex.set( itr->_endID, newApex );
					path->setWaypoints( itr->_id + 1, itr->_endID + 1, newApex, norm( itr->_dir ) );
					_right.pop_front();
				} else {
					break;
				}
			}

			goalDir.set( goalPt - apex._pos );
			path->setWaypoints( apex._id + 1, PORTAL_COUNT, goalPt, norm( goalDir ) );

		}
	#endif	// SIMPLE_FUNNEL
	}
Beispiel #2
0
//----------------------------------------------------------------------------
void CHomingMissile::UpdateCruiseMissile(float frameTime)
{

	IRenderer* pRenderer = gEnv->pRenderer;
	IRenderAuxGeom* pGeom = pRenderer->GetIRenderAuxGeom();
	float color[4] = {1,1,1,1};
	const static float step = 15.f;  
	float y = 20.f;    

	bool bDebug = g_pGameCVars->i_debug_projectiles > 0;

	if (m_targetId)
	{
		IEntity* pTarget = gEnv->pEntitySystem->GetEntity(m_targetId);
		if (pTarget)
		{
			AABB box;
			pTarget->GetWorldBounds(box);
			SetDestination( box.GetCenter() );

			//if (bDebug)
				//pRenderer->Draw2dLabel(5.0f, y+=step, 1.5f, color, false, "Target Entity: %s", pTarget->GetName());
		}    
	}
	else 
	{
		// update destination pos from weapon
		static IItemSystem* pItemSystem = g_pGame->GetIGameFramework()->GetIItemSystem();
		IItem* pItem = pItemSystem->GetItem(m_weaponId);
		if (pItem && pItem->GetIWeapon())
		{
			const Vec3& dest = pItem->GetIWeapon()->GetDestination();
			SetDestination( dest );

			//if (bDebug)
				//pRenderer->Draw2dLabel(5.0f, y+=step, 1.5f, color, false, "Weapon Destination: (%.1f %.1f %.1f)", dest.x, dest.y, dest.z);
		}
	}

	pe_status_dynamics status;
	if (!GetEntity()->GetPhysics()->GetStatus(&status))
		return;

	float currentSpeed = status.v.len();
	Vec3 currentPos = GetEntity()->GetWorldPos();
	Vec3 goalDir(ZERO);

	if (!m_destination.IsZero())
	{

		if((currentPos-m_destination).len2()<(m_detonationRadius*m_detonationRadius))
		{
			Explode(true, true, m_destination, -status.v.normalized(), status.v, m_targetId);
			return;
		}

		if (bDebug)
			pGeom->DrawCone(m_destination, Vec3(0,0,-1), 2.5f, 7.f, ColorB(255,0,0,255));

		float heightDiff = (m_cruiseAltitude-m_alignAltitude) - currentPos.z;

		if (!m_isCruising && heightDiff * sgn(status.v.z) > 0.f)
		{
			// if heading towards align altitude (but not yet reached) accelerate to max speed    
			if (bDebug)
				pRenderer->Draw2dLabel(5.0f,  y+=step,   1.5f, color, false, "[HomingMissile] accelerating (%.1f / %.1f)", currentSpeed, m_maxSpeed);    
		}
		else if (!m_isCruising && heightDiff * sgnnz(status.v.z) < 0.f && (status.v.z<0 || status.v.z>0.25f))
		{
			// align to cruise
			if (currentSpeed != 0)
			{
				goalDir = status.v;
				goalDir.z = 0;
				goalDir.normalize();
			}    

			if (bDebug)
				pRenderer->Draw2dLabel(5.0f,  y+=step, 1.5f, color, false, "[HomingMissile] aligning"); 
		}
		else
		{
			if (bDebug)
				pRenderer->Draw2dLabel(5.0f,  y+=step, 1.5f, color, false, "[HomingMissile] cruising..."); 

			// cruise
			m_isCruising = true;

			if (!m_destination.IsZero())
			{
				float groundDistSq = m_destination.GetSquaredDistance2D(currentPos);
				float distSq = m_destination.GetSquaredDistance(currentPos);
				float descendDistSq = sqr(m_descendDistance);

				if (m_isDescending || groundDistSq <= descendDistSq)
				{
					if (bDebug)
						pRenderer->Draw2dLabel(5.0f,  y+=step, 1.5f, color, false, "[HomingMissile] descending!"); 

					if (distSq != 0)
						goalDir = (m_destination - currentPos).normalized();
					else 
						goalDir.zero();

					m_isDescending = true;
				}              
				else
				{
					Vec3 airPos = m_destination;
					airPos.z = currentPos.z;          
					goalDir = airPos - currentPos;
					if (goalDir.len2() != 0)
						goalDir.Normalize();
				}    
			}
		}
	}  

	float desiredSpeed = currentSpeed;
	if (currentSpeed < m_maxSpeed-0.1f)
	{
		desiredSpeed = min(m_maxSpeed, desiredSpeed + m_accel*frameTime);
	}

	Vec3 currentDir = status.v.GetNormalizedSafe(FORWARD_DIRECTION);
	Vec3 dir = currentDir;

	if (!goalDir.IsZero())
	{ 
		float cosine = max(min(currentDir.Dot(goalDir), 0.999f), -0.999f);
		float goalAngle = RAD2DEG(acos_tpl(cosine));
		float maxAngle = m_turnSpeed * frameTime;

		if (bDebug)
		{ 
			pGeom->DrawCone( currentPos, goalDir, 0.4f, 12.f, ColorB(255,0,0,255) );
			pRenderer->Draw2dLabel(5.0f,  y+=step, 1.5f, color, false, "[HomingMissile] goalAngle: %.2f", goalAngle); 

		}

		if (goalAngle > maxAngle+0.05f)    
			dir = (Vec3::CreateSlerp(currentDir, goalDir, maxAngle/goalAngle)).normalize();
		else //if (goalAngle < 0.005f)
			dir = goalDir;
	}

	pe_action_set_velocity action;
	action.v = dir * desiredSpeed;
	GetEntity()->GetPhysics()->Action(&action);

	if (bDebug)
	{
		pGeom->DrawCone( currentPos, dir, 0.4f, 12.f, ColorB(128,128,0,255) );  
		pRenderer->Draw2dLabel(5.0f,  y+=step, 1.5f, color, false, "[HomingMissile] currentSpeed: %.1f (max: %.1f)", currentSpeed, m_maxSpeed); 
	}
}
Beispiel #3
0
	void PortalPath::setPreferredDirection( const Agents::BaseAgent * agent, float headingCos, Agents::PrefVelocity & pVel ) {
		const size_t PORTAL_COUNT = _route->getPortalCount();
		Vector2 dir;
		if ( _currPortal >= PORTAL_COUNT ) {
			// assume that the path is clear
			// TODO: See GoalVC
			_goal->setDirections( agent->_pos, agent->_radius, pVel );
			
			// speed
			Vector2 goalPoint = pVel.getTarget();
			Vector2 disp = goalPoint - agent->_pos;
			const float distSq = absSq( disp );
			float speed = agent->_prefSpeed;

			if ( distSq <= 0.0001f ) {
				// I've basically arrived -- speed should be zero.
				speed = 0.f;
			} else {
				const float speedSq = speed * speed;
				const float TS_SQD = SIM_TIME_STEP * SIM_TIME_STEP;
				if ( distSq / speedSq < TS_SQD ) {
					// The distance is less than I would travel in a single time step.
					speed = sqrtf( distSq ) / SIM_TIME_STEP;
				}
			}
			pVel.setSpeed( speed );
		} else {
			const WayPortal * portal = _route->getPortal( _currPortal );
			Vector2 goalDir( _waypoints[ _currPortal ] - agent->_pos );
			float dist = abs( goalDir );
			// If the displacement to the next way point is large enough
			//	(i.e., not essentially zero), use it, otherwise, peek
			//	into the next waypoint.
			//
			//	The goal is to always provide a goalDir to the portal
			//	that is well-defined and unit-length.
			bool bigEnough = dist >= EPS;
			if ( bigEnough ) {
				goalDir /= dist;
				if ( goalDir * _headings[ _currPortal ] < headingCos ) {
					// Heading has deviated too far recompute crossing
					FunnelPlanner planner;
					planner.computeCrossing( agent->_radius, agent->_pos, this, _currPortal );
					goalDir = _waypoints[ _currPortal ] - agent->_pos;
					dist = abs( goalDir );
					if ( bigEnough = ( dist >= EPS ) ) {
						goalDir /= dist;
					}
				}
			} 
			if ( ! bigEnough ) {
				// simply cross the wayportal perpendicularly
				//goalDir.set( portal->getCrossingDir( agent->_pos ) );
				if ( _currPortal + 1 < getPortalCount() ) {
					// calculate w.r.t. next waypoint
					goalDir = norm( _waypoints[ _currPortal + 1 ] - agent->_pos );
				} else {
					// calculate w.r.t. goal
					Vector2 gp;
					_goal->getTargetPoint( gp, agent->_radius );
					goalDir = norm( gp - agent->_pos );
				}
			}
			assert( abs( goalDir ) > EPS && "Providing a goal direction that is too small" );
			
			pVel.setTarget( _waypoints[ _currPortal ] );
			portal->setPreferredDirection( agent->_pos, agent->_radius, goalDir, pVel );
		}
	}
Beispiel #4
0
//-----------------------------------------------------------------------------
void CHomingMissile::UpdateControlledMissile(float frameTime)
{
	bool isServer = gEnv->bServer;
	bool isClient = gEnv->bClient;

	CActor *pClientActor=0;
	if (gEnv->bClient)
		pClientActor=static_cast<CActor *>(g_pGame->GetIGameFramework()->GetClientActor());
	bool isOwner = ((!m_ownerId && isServer) || (isClient && pClientActor && (pClientActor->GetEntityId() == m_ownerId) && pClientActor->IsPlayer()));

	IRenderer* pRenderer = gEnv->pRenderer;
	IRenderAuxGeom* pGeom = pRenderer->GetIRenderAuxGeom();
	float color[4] = {1,1,1,1};
	const static float step = 15.f;  
	float y = 20.f;    

	bool bDebug = g_pGameCVars->i_debug_projectiles > 0;

	if (isOwner || isServer)
	{
		//If there's a target, follow the target
		if(isServer)
		{
			if (m_targetId)
			{
				if (m_lockedTimer>0.0f)
					m_lockedTimer=m_lockedTimer-frameTime;
				else
				{
					// If we are here, there's a target
					IEntity* pTarget = gEnv->pEntitySystem->GetEntity(m_targetId);
					if (pTarget)
					{
						AABB box;
						pTarget->GetWorldBounds(box);
						Vec3 finalDes = box.GetCenter();
						SetDestination(finalDes);
						//SetDestination( box.GetCenter() );

						if (bDebug)
							pRenderer->Draw2dLabel(5.0f, y+=step, 1.5f, color, false, "Target Entity: %s", pTarget->GetName());
					}

					m_lockedTimer+=0.05f;
				}
			}
			else if(m_autoControlled)
				return;
		} 

		if (m_controlled && !m_autoControlled && isOwner && !m_targetId)
		{
			//Check if the weapon is still selected
			CWeapon *pWeapon = GetWeapon();

			if(!pWeapon || !pWeapon->IsSelected())
				return;

			if (m_controlledTimer>0.0f)
				m_controlledTimer=m_controlledTimer-frameTime;
			else if (pClientActor && pClientActor->IsPlayer()) 	//Follow the crosshair
			{
				if (IMovementController *pMC=pClientActor->GetMovementController())
				{
					Vec3 eyePos(ZERO);
					Vec3 eyeDir(ZERO);

					IVehicle* pVehicle = pClientActor->GetLinkedVehicle();
					if(!pVehicle)
					{
						SMovementState state;
						pMC->GetMovementState(state);

						eyePos = state.eyePosition;
						eyeDir = state.eyeDirection;
					}
					else
					{	
						SViewParams viewParams;
						pVehicle->UpdateView(viewParams, pClientActor->GetEntityId());

						eyePos = viewParams.position;
						eyeDir = viewParams.rotation * Vec3(0,1,0);
						//eyeDir = (viewParams.targetPos - viewParams.position).GetNormalizedSafe();
					}

					int pierceability=7;

					if (IPhysicalEntity *pPE=GetEntity()->GetPhysics())
					{
						if (pPE->GetType()==PE_PARTICLE)
						{
							pe_params_particle pp;

							if (pPE->GetParams(&pp))
								pierceability=pp.iPierceability;
						}
					}

					static const int objTypes = ent_all;
					static const int flags = (geom_colltype_ray << rwi_colltype_bit) | rwi_colltype_any | (pierceability & rwi_pierceability_mask) | (geom_colltype14 << rwi_colltype_bit);

					IPhysicalWorld* pWorld = gEnv->pPhysicalWorld;
					static IPhysicalEntity* pSkipEnts[10];
					int numSkip = CSingle::GetSkipEntities(pWeapon, pSkipEnts, 10);

					ray_hit hit;
					int hits = 0;

					float range=m_maxTargetDistance;
					hits = pWorld->RayWorldIntersection(eyePos + 1.5f*eyeDir, eyeDir*range, objTypes, flags, &hit, 1, pSkipEnts, numSkip);
					
					while (hits)
					{
						if (gEnv->p3DEngine->RefineRayHit(&hit, eyeDir*range))
							break;

						eyePos = hit.pt+eyeDir*0.003f;
						range -= hit.dist+0.003f;

						hits = pWorld->RayWorldIntersection(eyePos, eyeDir*range, objTypes, flags, &hit, 1, pSkipEnts, numSkip);
					}

					DestinationParams params;

					if(hits)
						params.pt=hit.pt;
					else
						params.pt=(eyePos+m_maxTargetDistance*eyeDir);	//Some point in the sky...

					GetGameObject()->InvokeRMI(SvRequestDestination(), params, eRMI_ToServer);

					if (bDebug)
					{
						pRenderer->Draw2dLabel(5.0f, y+=step, 1.5f, color, false, "PlayerView eye direction: %.3f %.3f %.3f", eyeDir.x, eyeDir.y, eyeDir.z);
						pRenderer->Draw2dLabel(5.0f, y+=step, 1.5f, color, false, "PlayerView Target: %.3f %.3f %.3f", hit.pt.x, hit.pt.y, hit.pt.z);
						pRenderer->GetIRenderAuxGeom()->DrawCone(m_destination, Vec3(0,0,-1), 2.5f, 7.f, ColorB(255,0,0,255));
					}
				}

				m_controlledTimer+=0.0f;
			}
		}
	}

	//This code is shared by both modes above (auto and controlled)
	if(!m_destination.IsZero())
	{
		pe_status_dynamics status;
		if (!GetEntity()->GetPhysics()->GetStatus(&status))
		{
			CryLogAlways("couldn't get physics status!");
			return;
		}

		pe_status_pos pos;
		if (!GetEntity()->GetPhysics()->GetStatus(&pos))
		{
			CryLogAlways("couldn't get physics pos!");
			return;
		}

		float currentSpeed = status.v.len();

		if (currentSpeed>0.001f)
		{
			Vec3 currentVel = status.v;
			Vec3 currentPos = pos.pos;
			Vec3 goalDir(ZERO);

			assert(!_isnan(currentSpeed));
			assert(!_isnan(currentVel.x) && !_isnan(currentVel.y) && !_isnan(currentVel.z));

			//Just a security check
			if((currentPos-m_destination).len2()<(m_detonationRadius*m_detonationRadius))
			{
				Explode(true, true, m_destination, -currentVel.normalized(), currentVel, m_targetId);

				return;
			}

			goalDir = m_destination - currentPos;
			goalDir.Normalize();

			//Turn more slowly...
			currentVel.Normalize();

			if(bDebug)
			{

				pRenderer->Draw2dLabel(50,55,2.0f,color,false, "  Destination: %.3f, %.3f, %.3f",m_destination.x,m_destination.y,m_destination.z);
				pRenderer->Draw2dLabel(50,80,2.0f,color,false, "  Current Dir: %.3f, %.3f, %.3f",currentVel.x,currentVel.y,currentVel.z);
				pRenderer->Draw2dLabel(50,105,2.0f,color,false,"  Goal    Dir: %.3f, %.3f, %.3f",goalDir.x,goalDir.y,goalDir.z);
			}

			float cosine = currentVel.Dot(goalDir);
			cosine = CLAMP(cosine,-1.0f,1.0f);
			float totalAngle = RAD2DEG(cry_acosf(cosine));

			assert(totalAngle>=0);

			if (cosine<0.99)
			{
				float maxAngle = m_turnSpeed*frameTime;
				if (maxAngle>totalAngle)
					maxAngle=totalAngle;
				float t=(maxAngle/totalAngle)*m_lazyness;

				assert(t>=0.0 && t<=1.0);

				goalDir = Vec3::CreateSlerp(currentVel, goalDir, t);
				goalDir.Normalize();
			}

			if(bDebug)
				pRenderer->Draw2dLabel(50,180,2.0f,color,false,"Corrected Dir: %.3f, %.3f, %.3f",goalDir.x,goalDir.y,goalDir.z);

			pe_action_set_velocity action;
			action.v = goalDir * currentSpeed;
			GetEntity()->GetPhysics()->Action(&action);
		}
	}
}