示例#1
0
void gkAuxRenderer::AuxRenderSkeleton( const Vec3& from, const Vec3& to, ColorF& color /*= ColorF(1.0,1.0,1.0,1.0)*/, float radius /*= 0.05f*/, bool ignoreZ /*= false */ )
{
	Vec3 dir = to - from;
	Vec3 dirInPlane = Vec3::CreateProjection(Vec3(0,0,1), dir.GetNormalized());
	if (dirInPlane.IsEquivalent(Vec3(0,0,0)))
	{
		dirInPlane = Vec3::CreateProjection(Vec3(1,0,0), dir.GetNormalized());
	}

	float len = dir.GetLength();
	dirInPlane.Normalize();
	dirInPlane *= radius * len;

	Vec3 dirInPlane1 = dirInPlane.GetRotated(dir.GetNormalized(), DEG2RAD(120.0f));
	Vec3 dirInPlane2 = dirInPlane.GetRotated(dir.GetNormalized(), DEG2RAD(-120.0f));

	Vec3 jointPt = from + dir.GetNormalized() * len * 0.8f;

	AuxRender3DLine(from, jointPt + dirInPlane, color, true);
	AuxRender3DLine(from, jointPt + dirInPlane1, color, true);
	AuxRender3DLine(from, jointPt + dirInPlane2, color, true);

	AuxRender3DLine(to, jointPt + dirInPlane, ColorF(1,0,0,1), true);
	AuxRender3DLine(to, jointPt + dirInPlane1, ColorF(1,0,0,1), true);
	AuxRender3DLine(to, jointPt + dirInPlane2, ColorF(1,0,0,1), true);

	AuxRender3DLine(jointPt + dirInPlane, jointPt + dirInPlane2, ColorF(1,0,0,1), true);
	AuxRender3DLine(jointPt + dirInPlane1, jointPt + dirInPlane2, ColorF(1,0,0,1), true);
	AuxRender3DLine(jointPt + dirInPlane, jointPt + dirInPlane1, ColorF(1,0,0,1), true);



}
void CIntersectionAssistanceUnit::DebugUpdate() const
{
    if(g_pGameCVars->pl_pickAndThrow.intersectionAssistDebugEnabled)
        {
            IEntity* pEntity = gEnv->pEntitySystem->GetEntity(m_subjectEntityId);
            if(pEntity)
                {
                    IPhysicalEntity *pPhysical = pEntity->GetPhysics();
                    if(pPhysical)
                        {
                            const float fFontSize = 1.2f;
                            float drawColor[4] = {1.0f, 1.0f, 1.0f, 1.0f};

                            string sMsg(string().Format(" Entity ID: [%d]", m_subjectEntityId));
                            sMsg += string().Format("\n Entity Name: [%s]", pEntity->GetName());

                            sMsg += string().Format("\n EmbedTimer: [%.3f]", m_embedTimer);
                            sMsg += string().Format("\n EmbedState: [%s]",(m_embedState == eES_None) ? "NONE" : (m_embedState == eES_Evaluating) ? "EVALUATING" : (m_embedState == eES_ReEvaluating) ? "REEVALUATING" : (m_embedState == eES_NotEmbedded) ? "NOT EMBEDDED" : (m_embedState == eES_Embedded) ? "EMBEDDED" : "UNKNOWN");

                            Vec3 vCurrTrans = m_entityStartingWPos - pEntity->GetWorldPos();
                            sMsg += string().Format("\n Translation: < %.3f, %.3f, %.3f >", vCurrTrans.x, vCurrTrans.y, vCurrTrans.z );
                            sMsg += string().Format("\n Trans magnitude: < %.3f >", vCurrTrans.GetLength() );
                            sMsg += string().Format("\n Trans per sec: < %.3f >", vCurrTrans.GetLength() / g_pGameCVars->pl_pickAndThrow.intersectionAssistTimePeriod );

                            sMsg += string().Format("\n Collision count: %u", m_collisionCount );

                            // RENDER
                            Vec3 vDrawPos = pEntity->GetWorldPos() + Vec3(0.0f,0.0f,0.6f);
                            gEnv->pRenderer->DrawLabelEx(vDrawPos, fFontSize, drawColor, true, true, sMsg.c_str());

                            // Box
                            pe_params_bbox bbox;
                            if(pPhysical->GetParams(&bbox))
                                {
                                    ColorB colDefault = ColorB( 127,127,127 );
                                    ColorB embedded = ColorB(255, 0, 0);
                                    ColorB notEmbedded = ColorB(0, 255, 0);

                                    gEnv->pRenderer->GetIRenderAuxGeom()->DrawAABB( AABB(bbox.BBox[0],bbox.BBox[1]), Matrix34(IDENTITY), false, (m_embedState == eES_Embedded) ? embedded : (m_embedState == eES_NotEmbedded) ? notEmbedded : colDefault, eBBD_Faceted);
                                }
                        }
                }

        }
}
示例#3
0
Quat QuatFromSourceToTarget( const Vec3& source, const Vec3& target )
{
    Vec3 s = source.GetNormalized();
    Vec3 t = target.GetNormalized();

    Vec3 c = s.GetCrossProduct( t );
    Real d = s.GetDotProduct( t );

    // check if vectors are the same
    if ( Equals( d, Real( 1 ), REAL_EPSILON * 3 ) )
    {
        // set to no rotation and return
        return Quat::ZERO;
    }

    // check for 180 degree rotation
    Real clen = c.GetLength();
    if ( clen <= REAL_EPSILON )
    {
        // pick an axis to rotate around
        Vec3 r = Vec3::UNIT_Y.GetCrossProduct( source );
        Real rlen = r.GetLength();

        if ( rlen <= REAL_EPSILON )
        {
            // bad luck, pick another axis
            r = Vec3::UNIT_X.GetCrossProduct( source );
            rlen = r.GetLength();
        }

        // normalize, set rotation and return
        r /= rlen;
        return QuatFromAxisAngle( r, Radian( REAL_PI ) );
    }

    // normalize c
    c /= clen;

    // get angle and set quaternion
    Real a = acos( d ) * Real( 0.5 );
    Real sa = sin( a );

    return Quat( cos( a ), c.X() * sa, c.Y() * sa, c.Z() * sa );
}
示例#4
0
//====================================================================
// DebugDrawArrow
//====================================================================
void CAIDebugRenderer::DrawArrow(const Vec3& vPos, const Vec3& vLength, float fWidth, const ColorB& color)
{
	Vec3 points[7];
	Vec3 tris[5 * 3];

	float	len = vLength.GetLength();
	if (len < 0.0001f)
		return;

	float	headLen = fWidth * 2.0f;
	float	headWidth = fWidth * 2.0f;

	if (headLen > len * 0.8f)
		headLen = len * 0.8f;

	Vec3	vDir(vLength/len);
	Vec3	norm(vLength.y, -vLength.x, 0);
	norm.NormalizeSafe();

	Vec3	end(vPos + vLength);
	Vec3	start(vPos);

	unsigned int n = 0;
	points[n++] = end;
	points[n++] = end - vDir * headLen - norm * headWidth/2;
	PREFAST_SUPPRESS_WARNING(6386)
	points[n++] = end - vDir * headLen - norm * fWidth/2;
	points[n++] = end - vDir * headLen + norm * fWidth/2;
	points[n++] = end - vDir * headLen + norm * headWidth/2;
	points[n++] = start - norm * fWidth/2;
	points[n++] = start + norm * fWidth/2;

	n = 0;
	tris[n++] = points[0];
	tris[n++] = points[1];
	tris[n++] = points[2];

	tris[n++] = points[0];
	tris[n++] = points[2];
	tris[n++] = points[3];

	tris[n++] = points[0];
	tris[n++] = points[3];
	tris[n++] = points[4];

	tris[n++] = points[2];
	tris[n++] = points[5];
	tris[n++] = points[6];

	tris[n++] = points[2];
	tris[n++] = points[6];
	tris[n++] = points[3];

	DrawTriangles(tris, n, color);
}
示例#5
0
Quat QuatFromExponentialMap( const Vec3& v )
{
    Radian angle( v.GetLength() );

    if ( angle > std::numeric_limits<Real>::epsilon() )
    {
        return QuatFromAxisAngle( v / angle, angle );
    }
    else
    {
        return Quat::ZERO;
    }
}
void CIntersectionAssistanceUnit::UpdateCheckingForObjectEmbed(const float dt)
{
    if(IsClientResponsibleForSubjectEntity())
        {
            if(m_embedTimer > 0.0f)
                {
                    m_embedTimer -= dt;
                    if(m_embedTimer < 0.0f)
                        {
                            IEntity* pEntity = gEnv->pEntitySystem->GetEntity(m_subjectEntityId);
                            if(pEntity)
                                {

                                    // Make our decision, is this object stuck?
                                    Vec3 translation = m_entityStartingWPos - pEntity->GetWorldPos();
                                    const float transPerSec = translation.GetLength() / g_pGameCVars->pl_pickAndThrow.intersectionAssistTimePeriod;
                                    const float countsPerSec  = m_collisionCount / g_pGameCVars->pl_pickAndThrow.intersectionAssistTimePeriod;

                                    if( countsPerSec >= g_pGameCVars->pl_pickAndThrow.intersectionAssistCollisionsPerSecond &&
                                            transPerSec <= g_pGameCVars->pl_pickAndThrow.intersectionAssistTranslationThreshold )
                                        {
                                            OnDetectObjectEmbedded();
                                        }
                                    else
                                        {
                                            // Are we still suspicious?
                                            if(countsPerSec >= g_pGameCVars->pl_pickAndThrow.intersectionAssistCollisionsPerSecond)
                                                {
                                                    // The object moved a fair distance, but its getting an awful lot of high penetration collision events - Test a while longer
                                                    BeginCheckingForObjectEmbed();
                                                    m_embedState = eES_ReEvaluating;
                                                }
                                            else
                                                {
                                                    m_embedState = eES_NotEmbedded;
                                                }
                                        }
                                }
                        }
                }
        }

#ifndef _RELEASE
    DebugUpdate();
#endif //#ifndef _RELEASE
}
示例#7
0
void CBoidBug::UpdateBugsBehavior( float dt,SBoidContext &bc )
{
	if (cry_random(0, 9) == 0)
	{
		// Randomally modify heading vector.
		m_heading.x += Boid::Frand()*0.2f*bc.factorAlignment; // Used as random movement.
		m_heading.y += Boid::Frand()*0.2f*bc.factorAlignment;
		m_heading.z += Boid::Frand()*0.1f*bc.factorAlignment;
		m_heading = m_heading.GetNormalized();
		if (bc.behavior == EBUGS_DRAGONFLY)
			m_speed = bc.MinSpeed + (bc.MaxSpeed - bc.MinSpeed)*Boid::Frand();
	}

	// Avoid player.
	Vec3 fromPlayerVec = Vec3( m_pos.x-bc.playerPos.x, m_pos.y-bc.playerPos.y, 0 );
	if ((fromPlayerVec).GetLengthSquared() < BUGS_SCARE_DISTANCE*BUGS_SCARE_DISTANCE) // 2 meters.
	{
		float d = (BUGS_SCARE_DISTANCE - fromPlayerVec.GetLength());
		m_accel += 5.0f * fromPlayerVec * d;
	}

	// Maintain average speed.
	float targetSpeed = (bc.MaxSpeed + bc.MinSpeed)/2;
	m_accel -= m_heading*(m_speed-targetSpeed)*0.5f;

	//m_accel = (m_targetPos - m_pos)*bc.factorAttractToOrigin;

	if (m_pos.z < bc.terrainZ+bc.MinHeight)
	{
		m_accel.z = (bc.terrainZ+bc.MinHeight-m_pos.z)*bc.factorAttractToOrigin;
	}
	else if (m_pos.z > bc.terrainZ+bc.MaxHeight)
	{
		m_accel.z = -(m_pos.z-bc.terrainZ+bc.MinHeight)*bc.factorAttractToOrigin;
	}
	else
	{
		// Always try to accelerate in direction oposite to current in Z axis.
		m_accel.z += -m_heading.z * 0.2f;
	}
}
示例#8
0
//------------------------------------------------------------------------
void CProjectile::SetVelocity(const Vec3 &pos, const Vec3 &dir, const Vec3 &velocity, float speedScale)
{
	if (!m_pPhysicalEntity)
		return;

	Vec3 totalVelocity = (dir * m_pAmmoParams->speed * speedScale) + velocity;

	if (m_pPhysicalEntity->GetType()==PE_PARTICLE)
	{
		pe_params_particle particle;
		particle.heading = totalVelocity.GetNormalized();
		particle.velocity = totalVelocity.GetLength();

		m_pPhysicalEntity->SetParams(&particle);
	}
	else if (m_pPhysicalEntity->GetType()==PE_RIGID)
	{
		pe_action_set_velocity vel;
		vel.v = totalVelocity;

		m_pPhysicalEntity->Action(&vel);
	}
}
	virtual void ProcessEvent( EFlowEvent event,SActivationInfo *pActInfo )
	{
		switch (event)
		{
			case eFE_Activate:
			{
				// update destination only if dynamic update is enabled. otherwise destination is read on Start/Reset only
				if (m_bActive && IsPortActive(pActInfo, IN_DEST) && GetPortBool(pActInfo, IN_DYN_DEST) == true)
				{
					ReadDestinationPosFromInput( pActInfo );
					if (m_valueType==VT_TIME)
						CalcSpeedFromTimeInput( pActInfo );
				}
				if (m_bActive && IsPortActive(pActInfo, IN_VALUE))
				{
					ReadSpeedFromInput( pActInfo ); 
				}
				if (IsPortActive(pActInfo, IN_START))
				{
					Start( pActInfo );
				}
				if (IsPortActive(pActInfo, IN_STOP))
				{
					pActInfo->pGraph->SetRegularlyUpdated( pActInfo->myID, false );
					if (m_bActive)
					{
						ActivateOutput(pActInfo, OUT_DONE, true);
						m_bActive = false;
					}
					ActivateOutput(pActInfo, OUT_STOP, true);
				}

				// we dont support dynamic change of those inputs
				assert( !IsPortActive(pActInfo, IN_COORDSYS) );
				assert( !IsPortActive(pActInfo, IN_VALUETYPE) );

				break;
			}

			case eFE_Initialize:
			{
				m_bActive = false;
				m_position = ZERO;
				m_coorSys = (ECoordSys)GetPortInt( pActInfo, IN_COORDSYS );
				m_valueType = (EValueType)GetPortInt(pActInfo, IN_VALUETYPE);
				IEntity *pEnt = pActInfo->pEntity;
				if(pEnt)
					m_position = pEnt->GetWorldPos();
				ActivateOutput(pActInfo, OUT_CURRENT, m_position);  // i dont see a sense for this, but lets keep it for now
				pActInfo->pGraph->SetRegularlyUpdated( pActInfo->myID, false );
				break;
			}

			case eFE_Update:
			{
				IEntity *pEnt = pActInfo->pEntity;
			  if (!pEnt)
				{
					pActInfo->pGraph->SetRegularlyUpdated( pActInfo->myID, false );
					break;
				}

				// Use physics velocity updates, unless the entity is parented in another entity space and not rigid.
				IPhysicalEntity* pPhysEnt = pEnt->GetPhysics();
				if( pPhysEnt && (pEnt->GetParent()!=NULL || pPhysEnt->GetType() == PE_STATIC) )
				{
					pPhysEnt = NULL;
				}

				if (m_stopping)
				{
					m_stopping = false;
					pActInfo->pGraph->SetRegularlyUpdated( pActInfo->myID, false );

					if( pPhysEnt == NULL )
					{
						SetPos(pActInfo, m_destination);
					}

					m_bActive = false;
					break;
				}
				
				if (!m_bActive) break;
				float time = gEnv->pTimer->GetFrameStartTime().GetSeconds();
				float timeDifference = time - m_lastFrameTime; 
				m_lastFrameTime = time;

					// note - if there's no physics then this will be the same, but if the platform is moved through physics, then
					//        we have to get back the actual movement - this maybe framerate dependent.
				m_position = pActInfo->pEntity->GetPos();

				// let's compute the movement vector now
				Vec3 oldPosition = m_position;

				if(m_bForceFinishAsTooNear || m_position.IsEquivalent(m_destination, 0.01f))
				{
					m_position = m_destination;
					oldPosition = m_destination;
					ActivateOutput(pActInfo, OUT_DONE, true);
					ActivateOutput(pActInfo, OUT_FINISH, true);
					SetPos(pActInfo, m_position); // for finishing we have to make a manual setpos even if there is physics involved, to make sure the entity will be where it should.
					if (pPhysEnt)
					{
						pe_action_set_velocity setVel;
						setVel.v = ZERO;
						pPhysEnt->Action( &setVel );

						m_stopping = true;
					}
					else
					{
						pActInfo->pGraph->SetRegularlyUpdated( pActInfo->myID, false );
						m_bActive = false;
					}
				}
				else
				{
					Vec3 direction = m_destination - m_position;
					float distance = direction.GetLength();
					Vec3 directionAndSpeed = direction.normalized();

					// ease-area calcs
					float distanceForEaseOutCalc = distance + m_easeOutDistance * EASE_MARGIN_FACTOR;
					if (distanceForEaseOutCalc < m_easeOutDistance)	// takes care of m_easeOutDistance being 0
					{
						directionAndSpeed *= distanceForEaseOutCalc / m_easeOutDistance;
					}
					else  // init code makes sure both eases dont overlap, when the movement is time defined. when it is speed defined, only ease out is applied if they overlap. 
					{
						if (m_easeInDistance>0.f)
						{
							Vec3 vectorFromStart = m_position - m_startPos;
							float distanceFromStart = vectorFromStart.GetLength();
							float distanceForEaseInCalc = distanceFromStart + m_easeInDistance * EASE_MARGIN_FACTOR;
							if (distanceForEaseInCalc < m_easeInDistance)
							{
								directionAndSpeed *= distanceForEaseInCalc / m_easeInDistance;
							}
						}
					}

					directionAndSpeed *= (m_topSpeed * timeDifference);

					if(direction.GetLength() < directionAndSpeed.GetLength())
					{
						m_position = m_destination;
						m_bForceFinishAsTooNear = true;
					}
					else
						m_position += directionAndSpeed;
				}
				ActivateOutput(pActInfo, OUT_CURRENT, m_position);
				if (pPhysEnt == NULL)
				{
					SetPos(pActInfo, m_position);
				}
				else
				{
					pe_action_set_velocity setVel;
					float rTimeStep = timeDifference>0.000001f ? 1.f / timeDifference : 0.0f;
					setVel.v = (m_position - oldPosition) * rTimeStep;  
					pPhysEnt->Action( &setVel );
				}
				break;
			}
		};
	};
示例#10
0
void CPlayerStateUtil::CalculateGroundOrJumpMovement( const CPlayer& player, const SActorFrameMovementParams &movement, const bool bigWeaponRestrict, Vec3 &move )
{
	const bool isPlayer = player.IsPlayer();
	const float totalMovement = fabsf(movement.desiredVelocity.x) + fabsf(movement.desiredVelocity.y);
	const bool moving = (totalMovement > FLT_EPSILON);

	if (moving)
	{	
		Vec3 desiredVelocityClamped = movement.desiredVelocity;
		const float desiredVelocityMag = desiredVelocityClamped.GetLength();

		const float invDesiredVelocityMag = 1.0f / desiredVelocityMag;

		float strafeMul;

		if (bigWeaponRestrict)
		{
			strafeMul = g_pGameCVars->pl_movement.nonCombat_heavy_weapon_strafe_speed_scale;
		}
		else
		{
			strafeMul = g_pGameCVars->pl_movement.strafe_SpeedScale;
		}

		float backwardMul = 1.0f;

		desiredVelocityClamped = desiredVelocityClamped * (float)__fsel(-(desiredVelocityMag - 1.0f), 1.0f, invDesiredVelocityMag);

		//going back?
		if (isPlayer)	//[Mikko] Do not limit backwards movement when controlling AI.
		{
			backwardMul = (float)__fsel(desiredVelocityClamped.y, 1.0f, LERP(backwardMul, player.m_params.backwardMultiplier, -desiredVelocityClamped.y));
		}

		NETINPUT_TRACE(player.GetEntityId(), backwardMul);
		NETINPUT_TRACE(player.GetEntityId(), strafeMul);

		const Quat oldBaseQuat = player.GetEntity()->GetWorldRotation(); // we cannot use m_baseQuat: that one is already updated to a new orientation while desiredVelocity was relative to the old entity frame
		move += oldBaseQuat.GetColumn0() * desiredVelocityClamped.x * strafeMul * backwardMul;
		move += oldBaseQuat.GetColumn1() * desiredVelocityClamped.y * backwardMul;
	}

	//ai can set a custom sprint value, so dont cap the movement vector
	if (movement.sprint<=0.0f)
	{
		//cap the movement vector to max 1
		float moveModule(move.len());

		//[Mikko] Do not limit backwards movement when controlling AI, otherwise it will disable sprinting.
		if (isPlayer)
		{
			move /= (float)__fsel(-(moveModule - 1.0f), 1.0f, moveModule);
		}

		NETINPUT_TRACE(player.GetEntityId(), moveModule);
	}

	//player movement don't need the m_frameTime, its handled already in the physics
	float scale = player.GetStanceMaxSpeed(player.GetStance());
	move *= scale;
	NETINPUT_TRACE(player.GetEntityId(), scale);

	if (isPlayer)
	{
		const bool  isCrouching = ((player.m_actions & ACTION_CROUCH) != 0);
		AdjustMovementForEnvironment( player, move, bigWeaponRestrict, isCrouching );
	}
}
//////////////////////////////////////////////////////////////////////////
// NOTE: This function must be thread-safe. Before adding stuff contact MarcoC.
void CVehicleMovementTank::ProcessAI(const float deltaTime)
{
	FUNCTION_PROFILER( GetISystem(), PROFILE_GAME );

	float dt = max( deltaTime, 0.005f);

	m_movementAction.brake = false;
	m_movementAction.rotateYaw = 0.0f;
	m_movementAction.power = 0.0f;

	float inputSpeed = 0.0f;
	{
		if (m_aiRequest.HasDesiredSpeed())
			inputSpeed = m_aiRequest.GetDesiredSpeed();
		Limit(inputSpeed, -m_maxSpeed, m_maxSpeed);
	}

	Vec3 vMove(ZERO);
	{
		if (m_aiRequest.HasMoveTarget())
			vMove = ( m_aiRequest.GetMoveTarget() - m_PhysPos.pos ).GetNormalizedSafe();
	}

	//start calculation
	if ( fabsf( inputSpeed ) < 0.0001f || m_tireBlownTimer > 1.5f )
	{
		// only the case to use a hand break
		m_movementAction.brake = true;
	}
	else
	{

		Matrix33 entRotMatInvert( m_PhysPos.q );
		entRotMatInvert.Invert();
		float currentAngleSpeed = RAD2DEG(-m_PhysDyn.w.z);

		const static float maxSteer = RAD2DEG(gf_PI/4.f); // fix maxsteer, shouldn't change  
		Vec3 vVel = m_PhysDyn.v;
		Vec3 vVelR = entRotMatInvert * vVel;
		float currentSpeed =vVel.GetLength();
		vVelR.NormalizeSafe();
		if ( vVelR.Dot( FORWARD_DIRECTION ) < 0 )
			currentSpeed *= -1.0f;

		// calculate pedal
		static float accScale = 0.5f;
		m_movementAction.power = (inputSpeed - currentSpeed) * accScale;
		Limit( m_movementAction.power, -1.0f, 1.0f);

		// calculate angles
		Vec3 vMoveR = entRotMatInvert * vMove;
		Vec3 vFwd	= FORWARD_DIRECTION;

		vMoveR.z =0.0f;
		vMoveR.NormalizeSafe();

		if ( inputSpeed < 0.0 )	// when going back
		{
			vFwd *= -1.0f;
			vMoveR *= -1.0f;
			currentAngleSpeed *=-1.0f;
		}

		float cosAngle = vFwd.Dot(vMoveR);
		float angle = RAD2DEG( acos_tpl(cosAngle));
		if ( vMoveR.Dot( Vec3( 1.0f,0.0f,0.0f ) )< 0 )
			angle = -angle;

		//		int step =0;
		m_movementAction.rotateYaw = angle * 1.75f/ maxSteer; 

		// implementation 1. if there is enough angle speed, we don't need to steer more
		if ( fabsf(currentAngleSpeed) > fabsf(angle) && angle*currentAngleSpeed > 0.0f )
		{
			m_movementAction.rotateYaw = m_currSteer*0.995f; 
			//			step =1;
		}

		// implementation 2. if we can guess we reach the distination angle soon, start counter steer.
		float predictDelta = inputSpeed < 0.0f ? 0.1f : 0.07f;
		float dict = angle + predictDelta * ( angle - m_prevAngle) / dt ;
		if ( dict*currentAngleSpeed<0.0f )
		{
			if ( fabsf( angle ) < 2.0f )
			{
				m_movementAction.rotateYaw = angle* 1.75f/ maxSteer; 
				//				step =3;
			}
			else
			{
				m_movementAction.rotateYaw = currentAngleSpeed < 0.0f ? 1.0f : -1.0f; 
				//				step =2;
			}
		}

		// implementation 3. tank can rotate at a point
		if ( fabs( angle )> 20.0f ) 
		{
			m_movementAction.power *=0.1f;
			//			step =4;
		}

		//		char buf[1024];
		//		sprintf(buf, "steering	%4.2f	%4.2f	%4.2f	%d\n", deltaTime,currentAngleSpeed, angle - m_prevAngle, step);
		//		OutputDebugString( buf );
		m_prevAngle =  angle;

	}

}
//////////////////////////////////////////////////////////////////////////
// NOTE: This function must be thread-safe. Before adding stuff contact MarcoC.
void CVehicleMovementVTOL::ProcessAI(const float deltaTime)
{
	FUNCTION_PROFILER( GetISystem(), PROFILE_GAME );
	
	if (!m_isVTOLMovement)
	{
		CVehicleMovementHelicopter::ProcessAI(deltaTime);
		return;
	}

	m_velDamp = 0.15f;

	const float maxDirChange = 15.0f;

	// it's useless to progress further if the engine has yet to be turned on
	if (!m_isEnginePowered)
		return;

	m_movementAction.Clear();
	m_movementAction.isAI = true;
	ResetActions();

	// Our current state
	const Vec3 worldPos =  m_PhysPos.pos;
	const Matrix33 worldMat( m_PhysPos.q);
	Ang3 worldAngles = Ang3::GetAnglesXYZ(worldMat);

	const Vec3 currentVel = m_PhysDyn.v;
	const Vec3 currentVel2D(currentVel.x, currentVel.y, 0.0f);
	// +ve direction mean rotation anti-clocwise about the z axis - 0 means along y
	float currentDir = worldAngles.z;

	// to avoid singularity
	const Vec3 vWorldDir = worldMat * FORWARD_DIRECTION;
	const Vec3 vWorldDir2D =  Vec3( vWorldDir.x,  vWorldDir.y, 0.0f ).GetNormalizedSafe();

	// Our inputs
	const float desiredSpeed = m_aiRequest.HasDesiredSpeed() ? m_aiRequest.GetDesiredSpeed() : 0.0f;
	const Vec3 desiredMoveDir = m_aiRequest.HasMoveTarget() ? (m_aiRequest.GetMoveTarget() - worldPos).GetNormalizedSafe() : vWorldDir;
	const Vec3 desiredMoveDir2D = Vec3(desiredMoveDir.x, desiredMoveDir.y, 0.0f).GetNormalizedSafe(vWorldDir2D);
	const Vec3 desiredVel = desiredMoveDir * desiredSpeed; 
	const Vec3 desiredVel2D(desiredVel.x, desiredVel.y, 0.0f);
	const Vec3 desiredLookDir = m_aiRequest.HasLookTarget() ? (m_aiRequest.GetLookTarget() - worldPos).GetNormalizedSafe() : desiredMoveDir;
	const Vec3 desiredLookDir2D = Vec3(desiredLookDir.x, desiredLookDir.y, 0.0f).GetNormalizedSafe(vWorldDir2D);

	// Calculate the desired 2D velocity change
	Vec3 desiredVelChange2D = desiredVel2D - currentVel2D;
	float velChangeLength = desiredVelChange2D.GetLength2D();

	bool isLandingMode = false;
	if (m_pLandingGears && m_pLandingGears->AreLandingGearsOpen())
		isLandingMode = true;

	bool isHorizontal = (desiredSpeed >= 5.0f) && (desiredMoveDir.GetLength2D() > desiredMoveDir.z);
	float desiredPitch = 0.0f;
	float desiredRoll = 0.0f;

	float desiredDir = atan2f(-desiredLookDir2D.x, desiredLookDir2D.y);

	while (currentDir < desiredDir - gf_PI)
		currentDir += 2.0f * gf_PI;
	while (currentDir > desiredDir + gf_PI)
		currentDir -= 2.0f * gf_PI;

	float diffDir = (desiredDir - currentDir);
	m_actionYaw = diffDir * m_yawInputConst;
	m_actionYaw += m_yawInputDamping * (currentDir - m_lastDir) / deltaTime;
	m_lastDir = currentDir;

	if (isHorizontal && !isLandingMode)
	{
		float desiredFwdSpeed = desiredVelChange2D.GetLength();

		desiredFwdSpeed *= min(1.0f, diffDir / DEG2RAD(maxDirChange));

		if (!iszero(desiredFwdSpeed))
		{
			const Vec3 desiredWorldTiltAxis = Vec3(-desiredVelChange2D.y, desiredVelChange2D.x, 0.0f);
			const Vec3 desiredLocalTiltAxis = worldMat.GetTransposed() * desiredWorldTiltAxis;

			m_forwardAction = m_fwdPID.Update(currentVel.y, desiredLocalTiltAxis.GetLength(), -1.0f, 1.0f);

		float desiredTiltAngle = m_tiltPerVelDifference * desiredVelChange2D.GetLength();
		Limit(desiredTiltAngle, -m_maxTiltAngle, m_maxTiltAngle);

		if (desiredTiltAngle > 0.0001f)
		{
			const Vec3 desiredWorldTiltAxis2 = Vec3(-desiredVelChange2D.y, desiredVelChange2D.x, 0.0f).GetNormalizedSafe();
			const Vec3 desiredLocalTiltAxis2 = worldMat.GetTransposed() * desiredWorldTiltAxis2;

			Vec3 vVelLocal = worldMat.GetTransposed() * desiredVel;
			vVelLocal.NormalizeSafe();

			float dotup = vVelLocal.Dot(Vec3( 0.0f,0.0f,1.0f ) );
			float currentSpeed = currentVel.GetLength();

			desiredPitch = dotup *currentSpeed / 100.0f;
			desiredRoll = desiredTiltAngle * desiredLocalTiltAxis2.y *currentSpeed/30.0f;
		}

		}
	}
	else
	{
		float desiredTiltAngle = m_tiltPerVelDifference * desiredVelChange2D.GetLength();
		Limit(desiredTiltAngle, -m_maxTiltAngle, m_maxTiltAngle);

		if (desiredTiltAngle > 0.0001f)
		{
			const Vec3 desiredWorldTiltAxis = Vec3(-desiredVelChange2D.y, desiredVelChange2D.x, 0.0f).GetNormalizedSafe();
			const Vec3 desiredLocalTiltAxis = worldMat.GetTransposed() * desiredWorldTiltAxis;

			desiredPitch = desiredTiltAngle * desiredLocalTiltAxis.x;
			desiredRoll = desiredTiltAngle * desiredLocalTiltAxis.y;
		}
	}

	float currentHeight = m_PhysPos.pos.z;
	if ( m_aiRequest.HasMoveTarget() )
	{
		m_hoveringPower = m_powerPID.Update(currentVel.z, desiredVel.z, -1.0f, 4.0f);
		
		//m_hoveringPower = (m_desiredHeight - currentHeight) * m_powerInputConst;
		//m_hoveringPower += m_powerInputDamping * (currentHeight - m_lastHeight) / deltaTime;

		if (isHorizontal)
		{
			if (desiredMoveDir.z > 0.6f || desiredMoveDir.z < -0.85f)
			{
				desiredPitch = max(-0.5f, min(0.5f, desiredMoveDir.z)) * DEG2RAD(35.0f);
				m_forwardAction += abs(desiredMoveDir.z);
			}

			m_liftAction = min(2.0f, max(m_liftAction, m_hoveringPower * 2.0f));
		}
		else
		{
			m_liftAction = 0.0f;
		}
	}
	else
	{
		// to keep hovering at the same place
		m_hoveringPower = m_powerPID.Update(currentVel.z, m_desiredHeight - currentHeight, -1.0f, 1.0f);
		m_liftAction = 0.0f;

		if (m_pVehicle->GetAltitude() > 10.0f)	//TODO: this line is not MTSafe
			m_liftAction = m_forwardAction;
	}

	m_actionPitch += m_pitchActionPerTilt * (desiredPitch - worldAngles.x);
	m_actionRoll += m_pitchActionPerTilt * (desiredRoll - worldAngles.y);

	Limit(m_actionPitch, -1.0f, 1.0f);
	Limit(m_actionRoll, -1.0f, 1.0f);
	Limit(m_actionYaw, -1.0f, 1.0f);

	if (m_horizontal > 0.0001f)
		m_desiredHeight = m_PhysPos.pos.z;
	
	Limit(m_forwardAction, -1.0f, 1.0f);
}
示例#13
0
void CNetLerper::Update(float dt, const Vec3& entityPos, SPrediction& predictionOut, const Vec3& velGround, bool bInAirOrJumping)
{
	if(!m_enabled)
	{
		predictionOut.predictedPos = entityPos;
		predictionOut.lerpVel.zero();
		predictionOut.shouldSnap = false;
		return;
	}

	CRY_ASSERT(m_settings);
	dt = max(dt, 0.001f);
	
	IEntity* pGroundEntity = gEnv->pEntitySystem->GetEntity(m_standingOn);
	m_desired.worldPos = m_desired.pos;
	if (pGroundEntity)
	{
		if (IPhysicalEntity* pGroundPhys = pGroundEntity->GetPhysics())
		{
			pe_status_pos psp;
			pGroundPhys->GetStatus(&psp);
			m_desired.worldPos = psp.q * m_desired.pos + psp.pos;
		}
	}

	// Prediction is done a "long" time ahead
	const float predictTime = min(m_clock + m_settings->lookAhead, m_settings->maxLookAhead);
	const Vec3 predictedPos = m_desired.worldPos + (m_desired.vel * predictTime);
	const Vec3 predOffset = predictedPos - entityPos;
	const float predDist = predOffset.GetLength();

	// Errors:
	m_lerpedError = entityPos - predictedPos;
	// Error between desired pos (nb: not predicted pos)
	const Vec3 errorToDesiredPos = entityPos - m_desired.worldPos;
	const int snapError = GetLerpError(errorToDesiredPos, m_lerpedError);

	m_clock += dt;

	const float lerpDist = predDist + (dt*velGround).GetLength();

	if (lerpDist<m_settings->minLerpDistance && m_desired.vel.GetLengthSquared() < sqr(m_settings->minLerpSpeed) && !bInAirOrJumping)  // Stop lerping
	{
		// This block should be entered as few times as possible while on a moving platform.
		predictionOut.predictedPos = predictedPos;
		predictionOut.lerpVel.zero();
		predictionOut.shouldSnap = false;
		m_lerpedPos = m_desired.worldPos;
		m_lerpedError.zero();

		if (m_snapType== eSnap_None)
		{
			predictionOut.shouldSnap = true;
			m_snapType = eSnap_Minor;
			LogSnapError();
		}
	}
	else if (snapError & k_desiredError)  // k_lerpError is ignored because it works improperly during collisions with living entities
	{
		predictionOut.predictedPos = m_desired.worldPos;
		predictionOut.lerpVel.zero();
		predictionOut.shouldSnap = true;
		m_lerpedPos = m_desired.worldPos;
		m_lerpedError.zero();
		if(errorToDesiredPos.GetLengthSquared() > sqr(m_settings->snapDistMarkedMajor))
		{
			m_snapType = eSnap_Major;
		}
		else
		{
			m_snapType = eSnap_Normal;
		}
		LogSnapError();
	}
	else 
	{
		// Calculate simple lerp velocity
		Vec3 lerpVel = predOffset * (float)__fres(m_settings->lookAhead);
			
		// Clamp it
		const float maxPredictionDistance = m_settings->maxInterSpeed * m_settings->lookAhead;
		if (predDist > maxPredictionDistance)
			lerpVel *= maxPredictionDistance * (float)__fres(predDist);

		// Output
		predictionOut.predictedPos = predictedPos;
		predictionOut.lerpVel = lerpVel;
		predictionOut.shouldSnap = false;
		m_snapType = eSnap_None;
	}

	// Keep this in local space
	m_lerpedPos += dt * (predictionOut.lerpVel + velGround);
	m_lerpedPos += (m_desired.worldPos - m_lerpedPos) * 0.05f;	// Keep on top of any drift
}
示例#14
0
void CFireModePlugin_AutoAim::AdjustFiringDirection( const Vec3& attackerPos, Vec3& firingDirToAdjust, const bool bCurrentlyZoomed, const EntityId ownerId ) const
{
	CPlayer* pAttackingPlayer = static_cast<CPlayer*>(g_pGame->GetIGameFramework()->GetIActorSystem()->GetActor(ownerId));
	if (pAttackingPlayer && pAttackingPlayer->IsPlayer())
	{
		const ConeParams& aimConeSettings = GetAimConeSettings(bCurrentlyZoomed);

		// Don't do any projectile adjusting if the player already has a target for themselves, and is on target (e.g. manually scoping to get a headshot)	
		if( m_targetSelectionParams.m_bDisableAutoAimIfPlayerAlreadyHasTarget && pAttackingPlayer->GetCurrentTargetEntityId() ||
			!aimConeSettings.m_enabled)
		{

#if ALLOW_PROJECTILEHELPER_DEBUGGING
			m_lastShotAutoAimedStatus.append("FALSE - [Reason]: Player already on target");
#endif //#if #endif //#if ALLOW_PROJECTILEHELPER_DEBUGGING

			return;
		}

		float incomingDirLength = firingDirToAdjust.GetLength();
		CRY_ASSERT(incomingDirLength>0.f);
		Vec3 firingDirToAdjustNorm(firingDirToAdjust*__fres(incomingDirLength));

	#if ALLOW_PROJECTILEHELPER_DEBUGGING
		// DEBUG RENDER
		if (g_pGameCVars->pl_debug_projectileAimHelper)
		{
			// Draw Target acquisition cone
			float length = aimConeSettings.m_maxDistance;
			float radius = length * tan(aimConeSettings.m_outerConeRads * 0.5f);

			SAuxGeomRenderFlags originalFlags = gEnv->pRenderer->GetIRenderAuxGeom()->GetRenderFlags();
			SAuxGeomRenderFlags newFlags = originalFlags;
			newFlags.SetCullMode(e_CullModeNone);
			newFlags.SetFillMode(e_FillModeWireframe);
			newFlags.SetAlphaBlendMode(e_AlphaBlended);

			gEnv->pRenderer->GetIRenderAuxGeom()->SetRenderFlags(newFlags);
			gEnv->pRenderer->GetIRenderAuxGeom()->DrawCone(attackerPos + (firingDirToAdjustNorm*aimConeSettings.m_maxDistance),-firingDirToAdjustNorm, radius , length , ColorB(132,190,255,120), true );

			// Draw projectile adjust cone
			radius = length * tan(aimConeSettings.m_innerConeRads * 0.5f);
			gEnv->pRenderer->GetIRenderAuxGeom()->DrawCone(attackerPos + (firingDirToAdjustNorm*aimConeSettings.m_maxDistance),-firingDirToAdjustNorm, radius , length ,ColorB(0,0,127,120), true );
		
			// Restore render flags
			gEnv->pRenderer->GetIRenderAuxGeom()->SetRenderFlags(originalFlags);
		}
	#endif //#if ALLOW_PROJECTILEHELPER_DEBUGGING

		IEntity* pTargetPlayer = CalculateBestProjectileAutoAimTarget(attackerPos, firingDirToAdjustNorm, bCurrentlyZoomed, ownerId);
		if(pTargetPlayer)
		{
			const SAutoaimTarget* pAutoAimInfo = g_pGame->GetAutoAimManager().GetTargetInfo(pTargetPlayer->GetId());
			if(pAutoAimInfo)
			{
				Vec3 desiredFiringDir = ( pAutoAimInfo->primaryAimPosition - attackerPos ).GetNormalized();

				// Make sure final firing dir still constrained to valid cone
				float vecDot = firingDirToAdjustNorm.Dot(desiredFiringDir);
				float maxConeAngle = cos(0.5f * aimConeSettings.m_innerConeRads);
				if(vecDot >= maxConeAngle)
				{
					// within cone
					firingDirToAdjustNorm = desiredFiringDir;

#if ALLOW_PROJECTILEHELPER_DEBUGGING
					m_lastShotAutoAimedStatus.append("TRUE + desired dir fully WITHIN allowed adjust cone");
#endif //#if ALLOW_PROJECTILEHELPER_DEBUGGING

				}
				else
				{
					// constrain (generally working with small angles, nLerp should be fine + cheap)
					const float invConeDot = 1.0f - maxConeAngle;
					const float invVecDot  = 1.0f - vecDot;
					float zeroToOne  = invConeDot / invVecDot;
					Vec3 finalVec	  = (zeroToOne * desiredFiringDir) + ((1.0f - zeroToOne) * firingDirToAdjustNorm);
					finalVec.Normalize();
					firingDirToAdjustNorm = finalVec;

#if ALLOW_PROJECTILEHELPER_DEBUGGING
					m_lastShotAutoAimedStatus.Format("TRUE + desired dir CONSTRAINED to allowed cone [desired]: %.3f deg [constrained To]: %.3f deg", RAD2DEG(acos(vecDot)), 0.5f * RAD2DEG(aimConeSettings.m_innerConeRads));
#endif //#if ALLOW_PROJECTILEHELPER_DEBUGGING
				}
				
			}
		}
#if ALLOW_PROJECTILEHELPER_DEBUGGING
		else
		{
			m_lastShotAutoAimedStatus.Format("FALSE - CalculateBestProjectileAutoAimTarget NULL [Last reason]: %s", m_lastTargetRejectionReason.c_str());
		}

		// Draw adjusted vec
		if (g_pGameCVars->pl_debug_projectileAimHelper)
		{
			float length = aimConeSettings.m_maxDistance;
			gEnv->pRenderer->GetIRenderAuxGeom()->DrawLine(attackerPos,ColorB(255,0,255,0),attackerPos + firingDirToAdjustNorm * length,ColorB(255,0,255,0));
		}
#endif //#if ALLOW_PROJECTILEHELPER_DEBUGGING

		firingDirToAdjust = firingDirToAdjustNorm*incomingDirLength;

	}
}
int CFlowConvoyNode::OnPhysicsPostStep(const EventPhys * pEvent)
{
	FUNCTION_PROFILER(GetISystem(), PROFILE_GAME);

  if(m_bFirstUpdate)
    return 0; //after QuickLoad OnPhysicsPostStep called before ProcessEvent

	const EventPhysPostStep *pPhysPostStepEvent = (const EventPhysPostStep *)pEvent;

	IPhysicalEntity *pEventPhysEnt = pPhysPostStepEvent->pEntity;

	Vec3 posBack, posFront, posCenter;

	for (size_t i = 0; i < m_coaches.size(); ++i)
	{
		IPhysicalEntity *pPhysEnt = m_coaches[i].m_pEntity->GetPhysics();

		if (pEventPhysEnt == pPhysEnt)
		{
			if (m_ShiftTime > 0.0f)
			{
				m_speed = m_speed * (1.0f - breakValue * pPhysPostStepEvent->dt / m_MaxShiftTime);
				m_ShiftTime -= pPhysPostStepEvent->dt;
			}
			else
			{
				m_speed = m_speed + min(1.0f, (pPhysPostStepEvent->dt / 5.0f)) * (m_desiredSpeed - m_speed);
			}
		

			float speed = (m_splitCoachIndex > 0 && (int)i >= m_splitCoachIndex) ? m_splitSpeed : m_speed;
			float distance = (m_coaches[i].m_distanceOnPath += pPhysPostStepEvent->dt * speed);
			
			if(m_splitCoachIndex>0)
			{//train splitted
				if(i==m_splitCoachIndex-1) // update m_distanceOnPath for serialization
					m_distanceOnPath=distance-m_coaches[i].m_coachOffset;
				else if(i==m_coaches.size()-1) // update m_splitDistanceOnPath for serialization
					m_splitDistanceOnPath=distance-m_coaches[i].m_coachOffset;
			}
			else
			{//train in one piece
				if(i==m_coaches.size()-1)// update m_distanceOnPath for serialization
					m_distanceOnPath=distance-m_coaches[i].m_coachOffset;
			}

			posBack  = m_path.GetPointAlongPath(distance - m_coaches[i].m_wheelDistance, m_coaches[i].m_backWheelIterator[0]);
			posFront = m_path.GetPointAlongPath(distance + m_coaches[i].m_wheelDistance, m_coaches[i].m_frontWheelIterator[0]);
			posCenter = (posBack+posFront)*0.5f;


			Vec3 posDiff = posFront - posBack;
			float magnitude = posDiff.GetLength();

			if (magnitude > FLT_EPSILON)
			{
				posDiff *= 1.0f / magnitude;

				pe_params_pos ppos;
				ppos.pos = posCenter;
				ppos.q = Quat::CreateRotationVDir(posDiff);
				if (m_bXAxisFwd)
					ppos.q *= Quat::CreateRotationZ(gf_PI*-0.5f);
				pPhysEnt->SetParams(&ppos, 0 /* bThreadSafe=0 */); // as we are calling from the physics thread

				Vec3 futurePositionBack, futurePositionFront;
				futurePositionBack  = m_path.GetPointAlongPath(distance + PATH_DERIVATION_TIME * speed - m_coaches[i].m_wheelDistance, m_coaches[i].m_backWheelIterator[1]);
				futurePositionFront = m_path.GetPointAlongPath(distance + PATH_DERIVATION_TIME * speed + m_coaches[i].m_wheelDistance, m_coaches[i].m_frontWheelIterator[1]);

				Vec3 futurePosDiff = futurePositionFront - futurePositionBack;
				magnitude = futurePosDiff.GetLength();

				if (magnitude > FLT_EPSILON)
				{
					futurePosDiff *= 1.0f / magnitude;

					pe_action_set_velocity setVel;
					setVel.v = ((futurePositionBack+ futurePositionFront)*0.5f - posCenter) * (1.0f/PATH_DERIVATION_TIME);

					//Vec3 dir=(posFront-posBack).GetNormalized();
					//Vec3 future_dir=(futurePositionFront-futurePositionBack).GetNormalized();
					Vec3 w=posDiff.Cross(futurePosDiff);
					float angle=cry_asinf(w.GetLength());
					setVel.w=(angle/PATH_DERIVATION_TIME)*w.GetNormalized();
					pPhysEnt->Action(&setVel, 0 /* bThreadSafe=0 */); // as we are calling from the physics thread
					break;
				}
			}
		}
	}

	// Done processing once we reach end of path
	if (m_atEndOfPath)
		m_processNode = false;

	return 0;
}
示例#16
0
void CPlayerRotation::TargetAimAssistance(CWeapon* pWeapon, float& followH, float& followV, float& scale, float& _fZoomAmount, const Vec3 playerView[4])
{
	FUNCTION_PROFILER(GetISystem(), PROFILE_GAME);

	CRY_ASSERT(m_player.IsClient());

	followH = 0.0f;
	followV = 0.0f;
	scale = 1.0f;
	float bestScale = 1.0f;

	const Vec3 playerFwd = playerView[1];
	const Vec3 playerRgt = playerView[0];
	const Vec3 playerUp = playerView[2];
	const Vec3 playerPos = playerView[3];

	Vec3 follow_target_pos(ZERO);
	float follow_vote_leader = 0.0f;
	float snap_vote_leader = 0.0f;
	Vec3 follow_target_dir(ZERO);
	Vec3 snap_target_dir(ZERO);
	EntityId follow_target_id = 0;
	EntityId snap_target_id = 0;

	CGameRules * pGameRules = g_pGame->GetGameRules();
	float distance_follow_threshold_near	= max(0.0f, g_pGameCVars->aim_assistMinDistance);
	float distance_follow_threshold_far		= max(20.0f, g_pGameCVars->aim_assistMaxDistance);
	int playerTeam = pGameRules->GetTeam(m_player.GetEntity()->GetId());
	float cloakedPlayerMultiplier = g_pGameCVars->pl_aim_cloaked_multiplier;
	const bool multipleTeams = pGameRules->GetTeamCount() > 0;
	const float fFollowFalloffDist = g_pGameCVars->aim_assistFalloffDistance + FLT_EPSILON*g_pGameCVars->aim_assistFalloffDistance;
	const bool playerIsScoped = m_player.GetActorStats()->isScoped;

	float minTurnScale, fAimAssistStrength, fMaxDistMult;

	if(pWeapon)
	{
		const float fZoomAmount = pWeapon->GetZoomTransition();
		_fZoomAmount = fZoomAmount;
		
		const float fStrength						= g_pGameCVars->aim_assistStrength;
		const float fStrengthIronSight              = playerIsScoped ? g_pGameCVars->aim_assistStrength_SniperScope : g_pGameCVars->aim_assistStrength_IronSight;
		const float fDiff								= fStrengthIronSight - fStrength;
		fAimAssistStrength							= fStrength + (fZoomAmount * fDiff);
		
		const float fMinTurn						= g_pGameCVars->aim_assistMinTurnScale;
		const float fMinTurnIronSight               = playerIsScoped ? g_pGameCVars->aim_assistMinTurnScale_SniperScope : g_pGameCVars->aim_assistMinTurnScale_IronSight;
		const float fMinTurnDiff				= fMinTurnIronSight - fMinTurn;
		minTurnScale										= fMinTurn + (fZoomAmount * fMinTurnDiff);

		const float fMaxAssistDist			= g_pGameCVars->aim_assistMaxDistance;
		const float fMaxAssistDist_Iron             = playerIsScoped ? g_pGameCVars->aim_assistMaxDistance_SniperScope : g_pGameCVars->aim_assistMaxDistance_IronSight;
		const float fMaxAssistDistDiff	= (fMaxAssistDist_Iron - fMaxAssistDist) * fZoomAmount;
		fMaxDistMult                                = (fMaxAssistDist + fMaxAssistDistDiff) * __fres(fMaxAssistDist);
	}
	else
	{
		_fZoomAmount = 0.0f;
		fMaxDistMult = 1.0f;
		fAimAssistStrength = g_pGameCVars->aim_assistStrength;
		minTurnScale = g_pGameCVars->aim_assistMinTurnScale;
	}

	const float falloffStartDistance = g_pGameCVars->aim_assistSlowFalloffStartDistance;
	const float falloffPerMeter = 1.0f / (g_pGameCVars->aim_assistSlowDisableDistance - falloffStartDistance);

	const TAutoaimTargets& aaTargets = g_pGame->GetAutoAimManager().GetAutoAimTargets();
	const int targetCount = aaTargets.size();
	float fBestTargetDistance = FLT_MAX;

#if DBG_AUTO_AIM
	SAuxGeomRenderFlags oldFlags = gEnv->pRenderer->GetIRenderAuxGeom()->GetRenderFlags();
	SAuxGeomRenderFlags newFlags = e_Def3DPublicRenderflags;
	newFlags.SetAlphaBlendMode(e_AlphaBlended);
	newFlags.SetDepthTestFlag(e_DepthTestOff);
	newFlags.SetCullMode(e_CullModeNone); 
	gEnv->pRenderer->GetIRenderAuxGeom()->SetRenderFlags(newFlags);
#endif

	for (int i = 0; i < targetCount; ++i)
	{
		const SAutoaimTarget& target = aaTargets[i];

		CRY_ASSERT(target.entityId != m_player.GetEntityId());

		//Skip friendly ai
		if(gEnv->bMultiplayer)
		{
			if(multipleTeams &&  (pGameRules->GetTeam(target.entityId) == playerTeam))
			{
				continue;
			}

		}
		else 
		{		
			if (target.HasFlagSet(eAATF_AIHostile) == false)
				continue;

			distance_follow_threshold_far = fMaxDistMult * (target.HasFlagSet(eAATF_AIRadarTagged) ? g_pGameCVars->aim_assistMaxDistanceTagged : g_pGameCVars->aim_assistMaxDistance);
		}
		
		Vec3 targetPos = target.primaryAimPosition;
		Vec3 targetDistVec = (targetPos - playerPos);
		float distance = targetDistVec.GetLength();
		
		if (distance <= 0.1f)
			continue;

		Vec3 dirToTarget = targetDistVec / distance;

		// fast reject everything behind player, too far away or too near from line of view
		// sort rest by angle to crosshair and distance from player
		float alignment = playerFwd * dirToTarget;
		if (alignment <= 0.0f)
			continue;

		if ((distance < distance_follow_threshold_near) || (distance > distance_follow_threshold_far))
			continue;

		const int kAutoaimVisibilityLatency = 2;
		CPlayerVisTable::SVisibilityParams visParams(target.entityId);
		visParams.queryParams = eVQP_IgnoreGlass;
		if (!g_pGame->GetPlayerVisTable()->CanLocalPlayerSee(visParams, kAutoaimVisibilityLatency))
		{
			// Since both player and target entities are ignored, and the ray still intersected something, there's something in the way.
			// Need to profile this and see if it's faster to do the below checks before doing the linetest. It's fairly expensive but
			// linetests generally are as well... - Richard
			continue;
		}

#if DBG_AUTO_AIM
		const ColorB green(0,255,0,255);
		const ColorB darkgreen(0,155,0,225);
		gEnv->pRenderer->GetIRenderAuxGeom()->DrawLine( playerPos, darkgreen, targetPos, green);
#endif

		const float angleDot = dirToTarget.dot(-playerRgt);
		const float angle = (RAD2DEG(acos_tpl(angleDot)) - 90.f);
		const float absAngle = fabsf(angle);

		const float angleDotV = playerUp.dot(dirToTarget);
		const float angleToTargetV = (RAD2DEG(acos_tpl(angleDotV)) - 90.f);
		const float absAngleV = fabsf(angleToTargetV);

		const float slowModifiedDistance = distance * g_pGameCVars->aim_assistSlowDistanceModifier;
		const float radius_slow_threshold_inner = 0.5f;
		const float radius_slow_threshold_outer = g_pGameCVars->aim_assistSlowThresholdOuter;
		const float angle_slow_threshold_inner = RAD2DEG(atan_tpl(radius_slow_threshold_inner / slowModifiedDistance));
		const float angle_slow_threshold_outer = RAD2DEG(atan_tpl(radius_slow_threshold_outer / slowModifiedDistance));
		float angle_slow_fractionH = clamp_tpl((absAngle - angle_slow_threshold_inner) / (angle_slow_threshold_outer - angle_slow_threshold_inner), 0.0f, 1.0f);
		float angle_slow_fractionV = clamp_tpl((absAngleV - angle_slow_threshold_inner) / (angle_slow_threshold_outer - angle_slow_threshold_inner), 0.0f, 1.0f);

		float angle_slow_fraction = max(angle_slow_fractionH, angle_slow_fractionV);

		const float distance_follow_fraction = clamp_tpl((distance - fFollowFalloffDist) / (distance_follow_threshold_far - fFollowFalloffDist), 0.0f, 1.0f);
		const float radius_follow_threshold_inner = target.innerRadius;
		const float radius_follow_threshold_outer = target.outerRadius;
		const float radius_snap = target.HasFlagSet(eAATF_AIRadarTagged) ?	target.snapRadiusTagged * g_pGameCVars->aim_assistSnapRadiusTaggedScale : 
																			target.snapRadius * g_pGameCVars->aim_assistSnapRadiusScale;
		const float angle_follow_threshold_inner = RAD2DEG(atan_tpl(radius_follow_threshold_inner / distance));
		const float angle_follow_threshold_outer = RAD2DEG(atan_tpl(radius_follow_threshold_outer / distance));
		const float angle_follow_fraction = clamp_tpl((absAngle - angle_follow_threshold_inner) / (angle_follow_threshold_outer - angle_follow_threshold_inner), 0.0f, 1.0f);
		const float angle_follow_fractionV = clamp_tpl((absAngleV - angle_follow_threshold_inner) / (angle_follow_threshold_outer - angle_follow_threshold_inner), 0.0f, 1.0f);
		const float worst_follow_fraction = (float)__fsel(angle_follow_fraction - angle_follow_fractionV, angle_follow_fraction, angle_follow_fractionV);
		float follow_fraction = ((1.0f - worst_follow_fraction) * (1.0f - distance_follow_fraction));
		float follow_vote = follow_fraction;

		//clamp the lower bound of the distance_slow_modifier so it can't be lower than the angle slow fraction
		//  which prevents close but off-centre targets slowing us too much
		const float distance_slow_modifier = clamp_tpl( 1.0f - ((distance - falloffStartDistance) * falloffPerMeter), angle_slow_fraction, 1.0f);


		const float fCombinedModifier = angle_slow_fraction * distance_slow_modifier;
		fBestTargetDistance = (float)__fsel(fCombinedModifier - bestScale, fBestTargetDistance, distance);
		bestScale = min(fCombinedModifier, bestScale);		

		if (follow_vote > follow_vote_leader)
		{
			follow_vote_leader = follow_vote;

			//m_follow_target_id only gets set after the loop -> this won't get hit when a target is selected
			// as a follow target for the first time. This doesn't need to be in the loop.
			if ( m_follow_target_id == target.entityId)
			{
				const Vec3 follow_target_dir_local = m_follow_target_dir;
				Vec3 target_rgt = playerRgt;
				Vec3 target_up = target_rgt.cross(follow_target_dir_local);
				target_rgt = follow_target_dir_local.cross(target_up);
				target_rgt.Normalize();
				target_up.Normalize();
				
				float alignH = dirToTarget * -target_rgt;
				float alignV = dirToTarget.z - follow_target_dir_local.z;
				float angleH = min(fabsf(alignH * fAimAssistStrength), fabsf(angleDot));
				float angleV = min(fabsf(alignV * fAimAssistStrength), fabsf(angleDotV));

				followH = follow_fraction * (float)__fsel(angleDot, angleH, -angleH);
				followV = follow_fraction * (float)__fsel(angleDotV, angleV, -angleV);	
								
				follow_vote_leader += 0.05f; // anti oscillation between different targets
				follow_target_pos = targetPos;
			}

			follow_target_id = target.entityId;
			snap_target_id = target.entityId;
			follow_target_dir = dirToTarget;
			snap_target_dir = PickBestSnapDirection(playerPos, playerFwd, target);

		}
		else if (!follow_target_id && (radius_snap > 0.0f))
		{
			Lineseg lineSegment;
			lineSegment.start = playerPos;
			lineSegment.end = playerPos + (playerFwd * (distance + radius_snap));
			Sphere sphere;
			sphere.center = targetPos;
			sphere.radius = radius_snap;
			Vec3 intersectionPoint;

			if (Intersect::Lineseg_SphereFirst(lineSegment, sphere, intersectionPoint))
			{
				float t = 0.0f;
				const float snap_fraction = 1.0f - (Distance::Point_Lineseg(targetPos, lineSegment, t) * (float)__fres(radius_snap));

				if (snap_fraction > snap_vote_leader)
				{
					snap_vote_leader = snap_fraction;
					snap_target_id = target.entityId;
					snap_target_dir = PickBestSnapDirection(playerPos, playerFwd, target);
				}
			}
		}
	}

#if DBG_AUTO_AIM
	if ((!follow_target_pos.IsZeroFast()) && (g_pGameCVars->pl_targeting_debug != 0))
	{
		float radius_inner = 0.30f;
		float radius_outer = 0.33f;
		ColorB colorInner(255,255,0,0x40);
		ColorB colorOuter(255,255,0,0x40);
		DrawDisc(follow_target_pos, follow_target_dir, radius_inner, radius_outer, colorInner, colorOuter);
	}

	gEnv->pRenderer->GetIRenderAuxGeom()->SetRenderFlags(oldFlags);
#endif

	m_follow_target_id  = follow_target_id;
	m_follow_target_dir = follow_target_dir;

	//IMPORTANT: Apply the minimum-distance scaling of the slowdown _after_ calculating the slowdown for the best target
	//						as we want to help the player aim at the nearest target, and modifying the slowdown multiplier prior to this
	//						could result in a different target being selected

	const float fSlowDownProximityFadeInBand = (g_pGameCVars->aim_assistSlowStopFadeinDistance - g_pGameCVars->aim_assistSlowStartFadeinDistance) + FLT_EPSILON;
	float fSlowDownProximityScale = (fBestTargetDistance - g_pGameCVars->aim_assistSlowStartFadeinDistance) / fSlowDownProximityFadeInBand; 
	Limit(fSlowDownProximityScale, 0.0f, 1.0f);
	float fInvBestScale = (1.0f - bestScale) * fSlowDownProximityScale;
	bestScale = 1.0f - fInvBestScale;

	scale = minTurnScale + ((1.0f - minTurnScale) * bestScale);

	UpdateCurrentSnapTarget(snap_target_id, snap_target_dir);
}
示例#17
0
static void GetTalosInput(CPlayerRotation * pPlayerRotation, const CPlayer& rPlayer, float& x, float& z, const Vec3 playerView[4], float fFrameTime)
{
	//Do I need to reproject the view to actually get the positioning correct? Shouldn't be.
	const Vec3 playerFwd = playerView[1];
	const Vec3 playerRgt = playerView[0];
	const Vec3 playerUp = playerView[2];
	const Vec3 playerViewPos = playerView[3];


	Vec3 playerPos = playerViewPos;

	IPhysicalEntity * pPhysicalEntity = rPlayer.GetEntity()->GetPhysics();
	if(pPhysicalEntity)
	{
		pe_status_dynamics dyn_status;
		pPhysicalEntity->GetStatus(&dyn_status);		
		playerPos = playerViewPos + (dyn_status.v * fFrameTime * 2.0f);
	}

	Vec3 follow_target_dir(ZERO);

	EntityId follow_target_id = 0;
	static EntityId s_follow_target_id = 0;

	CGameRules * pGameRules = g_pGame->GetGameRules();
	int playerTeam = pGameRules->GetTeam(rPlayer.GetEntity()->GetId());
	float cloakedPlayerMultiplier = g_pGameCVars->pl_aim_cloaked_multiplier;
	const bool multipleTeams = pGameRules->GetTeamCount() > 0;

	const TAutoaimTargets& aaTargets = g_pGame->GetAutoAimManager().GetAutoAimTargets();
	const int targetCount = aaTargets.size();
	float fBestTargetDistance = FLT_MAX;

	for (int i = 0; i < targetCount; ++i)
	{
		const SAutoaimTarget& target = aaTargets[i];

		if(multipleTeams &&  (pGameRules->GetTeam(target.entityId) == playerTeam))
		{
			continue;
		}

		Vec3 targetPos = target.secondaryAimPosition;
		
		IEntity * pEntity = gEnv->pEntitySystem->GetEntity(target.entityId);
		if(pEntity)
		{
			IPhysicalEntity * pPhysicalEntity2 = pEntity->GetPhysics();
			if(pPhysicalEntity2)
			{
				pe_status_dynamics dyn_status;
				pPhysicalEntity2->GetStatus(&dyn_status);		
				targetPos = targetPos + (dyn_status.v * fFrameTime);
			}
		}

		Vec3 targetDistVec = (targetPos - playerPos);
		float distance = targetDistVec.GetLength();

		if (distance <= 0.01f)
			continue;

		Vec3 dirToTarget = targetDistVec / distance;

		// fast reject everything behind player, too far away or too near from line of view
		// sort rest by angle to crosshair and distance from player

		const int kAutoaimVisibilityLatency = 1;
		if (!g_pGame->GetPlayerVisTable()->CanLocalPlayerSee(target.entityId, kAutoaimVisibilityLatency))
		{
			// Since both player and target entities are ignored, and the ray still intersected something, there's something in the way.
			// Need to profile this and see if it's faster to do the below checks before doing the linetest. It's fairly expensive but
			// linetests generally are as well... - Richard
			continue;
		}

		const float angleDot = dirToTarget.dot(-playerRgt);
		const float angle = (RAD2DEG(acos_tpl(angleDot)) - 90.f);
		const float absAngle = fabsf(angle);

		const float angleDotV = playerUp.dot(dirToTarget);
		const float angleToTargetV = (RAD2DEG(acos_tpl(angleDotV)) - 90.f);
		const float absAngleV = fabsf(angleToTargetV);

		if ( s_follow_target_id == target.entityId )
		{
			follow_target_id = target.entityId;
			follow_target_dir = dirToTarget;
			break;
		}
		else if(distance < fBestTargetDistance)
		{
			fBestTargetDistance = distance;
			follow_target_id = target.entityId;
			follow_target_dir = dirToTarget;
		}
	}

	if(follow_target_id != 0)
	{
		//Player up is the normal of the plane that we are rotating around - (Correct? Or do we want to project both the player direction and the target direction onto the X/Y plane?)
		Vec3 vProjectedTargetHorz = playerUp.cross(follow_target_dir.cross(playerUp));
		Vec3 vProjectedTargetVert = playerRgt.cross(follow_target_dir.cross(playerRgt));

		float horzDot = vProjectedTargetHorz.GetNormalized().dot(playerFwd);
		float vertDot = vProjectedTargetVert.GetNormalized().dot(playerFwd);

		const float directionDotHorz = follow_target_dir.dot(playerRgt);
		const float directionDotVert = follow_target_dir.dot(playerUp);
		
		const float angle						= acos_tpl(horzDot);
		const float angleToTargetV	= acos_tpl(vertDot);		

		const float fHorzFinalAngle = (float)__fsel(directionDotHorz, -angle, angle);
		const float fVertFinalAngle = (float)__fsel(directionDotVert, angleToTargetV, -angleToTargetV);

		//CryWatch("Angle to target: %.6f", RAD2DEG(angle));
		//CryWatch("Final Angle to target: %.6f", RAD2DEG(fHorzFinalAngle));

		x = x + fVertFinalAngle;
		z = z + fHorzFinalAngle;
	}

	s_follow_target_id  = follow_target_id;

	return;
}
示例#18
0
//------------------------------------------------------------------------
void CTornado::Update(SEntityUpdateContext &ctx, int updateSlot)
{
	if (g_pGame->GetIGameFramework()->IsEditing())
		return;

	// wandering
	Matrix34 m = GetEntity()->GetWorldTM();
	Vec3 dir(m.GetColumn(1));
	Vec3 pos(GetEntity()->GetWorldPos());

	if(!gEnv->bServer)
		pos = m_currentPos;

	Vec3 wanderPos(dir * 1.414214f);
	float wanderStrength(1.0f);
	float wanderRate(0.6f);
	Vec3 wanderOffset;
	wanderOffset.SetRandomDirection();
	wanderOffset.z = 0.0f;
	wanderOffset.NormalizeSafe(Vec3(1,0,0));
	m_wanderDir += wanderOffset * wanderRate + (m_wanderDir - wanderPos) * wanderStrength;
	m_wanderDir = (m_wanderDir - wanderPos).GetNormalized() + wanderPos;

	Vec3 wanderSteer = (dir + m_wanderDir * gEnv->pTimer->GetFrameTime());
	wanderSteer.z = 0;
	wanderSteer.NormalizeSafe(Vec3(1,0,0));

	Vec3 targetSteer(0,0,0);
	// go to target
	if (m_pTargetEntity)
	{
		Vec3 target = m_pTargetEntity->GetWorldPos() - pos;
		if (target.GetLength() < 10.0f)
		{
			// emit target reached event
			SEntityEvent event( ENTITY_EVENT_SCRIPT_EVENT );
			event.nParam[0] = (INT_PTR)"TargetReached";
			event.nParam[1] = IEntityClass::EVT_BOOL;
			bool bValue = true;
			event.nParam[2] = (INT_PTR)&bValue;
			GetEntity()->SendEvent( event );
			if (m_pTargetCallback)
				m_pTargetCallback->Done();

			m_pTargetEntity = 0;
			m_pTargetCallback = 0;
		}

		targetSteer = (target - dir);
		targetSteer.z = 0;
		targetSteer.NormalizeSafe(Vec3(1,0,0));
	}

	Vec3 steerDir = (0.4f * wanderSteer + 0.6f * targetSteer).GetNormalized();
	Matrix34 tm = Matrix34(Matrix33::CreateRotationVDir(steerDir));
	pos = pos + steerDir * gEnv->pTimer->GetFrameTime() * m_wanderSpeed;
	pos.z = gEnv->p3DEngine->GetTerrainElevation(pos.x, pos.y);
	float waterLevel = gEnv->p3DEngine->GetWaterLevel(&pos);

	bool prevIsOnWater = m_isOnWater;
	m_isOnWater = (pos.z < waterLevel);
	if (m_isOnWater)
	{
		pos.z = waterLevel;
	}

	// raycast does not work for oceans
	if (prevIsOnWater != m_isOnWater && m_isOnWater)
	{
			m_pGroundEffect->SetParticleEffect("weather.tornado.water");
	}
	else if (!m_isOnWater)
	{		
		IMaterialEffects *mfx = gEnv->pGame->GetIGameFramework()->GetIMaterialEffects();
		Vec3 down = Vec3(0,0,-1.0f);
		int matID = mfx->GetDefaultSurfaceIndex();

		static const int objTypes = ent_all;    
		static const unsigned int flags = rwi_stop_at_pierceable|rwi_colltype_any;
		ray_hit hit;
		int col = gEnv->pPhysicalWorld->RayWorldIntersection(pos, (down * 5.0f), objTypes, flags, &hit, 1, GetEntity()->GetPhysics());
		if (col)
		{
			matID = hit.surface_idx;
		}

		if (m_curMatID != matID)
		{
			TMFXEffectId effectId = mfx->GetEffectId("tornado", matID);
			
			SMFXResourceListPtr pList = mfx->GetResources(effectId);
			if (pList && pList->m_particleList)
			{
				m_pGroundEffect->SetParticleEffect(pList->m_particleList->m_particleParams.name);
			}
			m_curMatID = matID;
		}
	}

	if(gEnv->bServer)
	{
		tm.SetTranslation(pos);
		m_currentPos = pos;
		CHANGED_NETWORK_STATE(this, POSITION_ASPECT);
		GetEntity()->SetWorldTM(tm);
	}
	else
	{
		tm.SetTranslation(m_currentPos);
		GetEntity()->SetWorldTM(tm);
	}

	UpdateParticleEmitters();
	UpdateTornadoSpline();

	UpdateFlow();
}
示例#19
0
void CNetLerper::DebugDraw(const SPrediction& prediction, const Vec3& entityPos, bool hadNewData)
{
#if !defined(_RELEASE)
	if (m_debug == NULL)
		m_debug = new Debug;
	
	Vec3 desiredVelocity = m_desired.vel;
	Vec3 lerpVel = prediction.lerpVel;
	Vec3 desiredPosition = m_desired.worldPos;
	Vec3 predictedPosition = prediction.predictedPos;

	if(g_pGameCVars->pl_debugInterpolation > 1)
	{
		CryWatch("Cur: (%.2f, %.2f, %.2f) Des: (%.2f, %.2f, %.2f) Pred: (%.2f, %.2f, %.2f) ", entityPos.x, entityPos.y, entityPos.z, desiredPosition.x, desiredPosition.y, desiredPosition.z, predictedPosition.x, predictedPosition.y, predictedPosition.z);
		CryWatch("LerpErrorXY: (%.2f)", m_lerpedError.GetLength2D());
		CryWatch("InputSpeed: (%.2f, %.2f, %.2f) lerpVel: (%.2f, %.2f, %.2f) lerpSpeed: %.2f", desiredVelocity.x, desiredVelocity.y, desiredVelocity.z, lerpVel.x, lerpVel.y, lerpVel.z, lerpVel.GetLength());
	}	
	if (hadNewData)
	{
		m_debug->AddDesired(m_desired.worldPos, m_desired.vel);
	}
	m_debug->AddCurrent(prediction.shouldSnap ? prediction.predictedPos : entityPos, prediction.lerpVel, m_lerpedError, prediction.shouldSnap);
	m_debug->Draw();
#endif
}
示例#20
0
void CChickenBoid::Think( float dt,SBoidContext &bc )
{
	Vec3 flockHeading(0,0,0);

	m_accel(0,0,0);
//	float height = m_pos.z - bc.terrainZ;

	if (m_bThrown)
	{
		m_accel.Set(0,0,-10.0f);
		//float z = bc.engine->GetTerrainElevation(m_pos.x,m_pos.y) + bc.fBoidRadius*0.5f;
		m_pos.z = bc.engine->GetTerrainElevation(m_pos.x,m_pos.y) + bc.fBoidRadius*0.5f;
		//pe_status_pos ppos;
		//m_pPhysics->GetStatus(&ppos);
		//if (m_pos.z < z)
		{
			m_physicsControlled = false;
			m_bThrown = false;
			m_heading.z = 0;
			if (m_heading.IsZero())
				m_heading = Vec3(1,0,0);
			m_heading.Normalize();
			m_accel.Set(0,0,0);
			m_speed = bc.MinSpeed;
			m_heading.z = 0;
		}
		return;
	}

	// Free will.
	// Continue accelerating in same dir untill target speed reached.
	// Try to maintain average speed of (maxspeed+minspeed)/2
	float targetSpeed = bc.MinSpeed;
	m_accel -= m_heading*(m_speed-targetSpeed)*0.4f;

	// Gaussian weight.
	m_accel.z = 0;

	m_bScared = false;

	if (bc.factorAlignment != 0)
	{
		//CalcCohesion();
		Vec3 alignmentAccel;
		Vec3 cohesionAccel;
		Vec3 separationAccel;
		CalcFlockBehavior(bc,alignmentAccel,cohesionAccel,separationAccel);

		//! Adjust for allignment,
		//m_accel += alignmentAccel.Normalized()*ALIGNMENT_FACTOR;
		m_accel += alignmentAccel*bc.factorAlignment;
		m_accel += cohesionAccel*bc.factorCohesion;
		m_accel += separationAccel;
	}

	/*
	// Avoid land.
	if (height < bc.MinHeight && !m_landing)
	{
		float v = (1.0f - height/bc.MinHeight);
		m_accel += Vec3(0,0,v*v)*bc.factorAvoidLand;
	}
	else if (height > bc.MaxHeight) // Avoid max height.
	{
		float v = (height - bc.MaxHeight)*0.1f;
		m_accel += Vec3(0,0,-v);
	}
	else
	{
		// Always try to accelerate in direction oposite to current in Z axis.
		m_accel.z = -(m_heading.z*m_heading.z*m_heading.z * 100.0f);
	}
	*/

	// Attract to origin point.
	if (bc.followPlayer)
	{
		m_accel += (bc.playerPos - m_pos) * bc.factorAttractToOrigin;
	}
	else
	{
		//m_accel += (m_birdOriginPos - m_pos) * bc.factorAttractToOrigin;
		if ((cry_rand()&31) == 1)
		{
			m_birdOriginPos = Vec3(	bc.flockPos.x+frand()*bc.fSpawnRadius,bc.flockPos.y+frand()*bc.fSpawnRadius,bc.flockPos.z+frand()*bc.fSpawnRadius );
			if (m_birdOriginPos.z - bc.terrainZ < bc.MinHeight)
			{
				m_birdOriginPos.z = bc.terrainZ + bc.MinHeight;
			}
		}

		/*
		if (m_pos.x < bc.flockPos.x-bc.fSpawnRadius || m_pos.x > bc.flockPos.x+bc.fSpawnRadius ||
		m_pos.y < bc.flockPos.y-bc.fSpawnRadius || m_pos.y > bc.flockPos.y+bc.fSpawnRadius ||
		m_pos.z < bc.flockPos.z-bc.fSpawnRadius || m_pos.z > bc.flockPos.z+bc.fSpawnRadius)
		*/
		{
			m_accel += (m_birdOriginPos - m_pos) * bc.factorAttractToOrigin;
		}
	}


	// Avoid collision with Terrain and Static objects.
	float fCollisionAvoidanceWeight = 10.0f;

	// Do walk sounds.
	if ((cry_rand()&0xFF) == 0)
		PlaySound(CHICKEN_SOUND_CLUCK);

	//////////////////////////////////////////////////////////////////////////
	// Player must scare chickens off.
	//////////////////////////////////////////////////////////////////////////
	float fScareDist = 5.0f;
	float sqrPlayerDist = m_pos.GetSquaredDistance(bc.playerPos);
	if (sqrPlayerDist < fScareDist*fScareDist)
	{
		Vec3 retreatDir = (m_pos - bc.playerPos) + Vec3(frand()*2.0f,frand()*2.0f,0);
		retreatDir.NormalizeFast();
		float scareFactor = (1.0f - sqrPlayerDist/(fScareDist*fScareDist));
		m_accel.x += retreatDir.x*scareFactor*bc.factorAvoidLand;
		m_accel.y += retreatDir.y*scareFactor*bc.factorAvoidLand;

		m_bScared = true;
		if (m_landing) m_flightTime = m_maxIdleTime+1.0f; // Stop idle.
		// Do walk sounds.
		if ((cry_rand()&0xFF) == 0)
			PlaySound(CHICKEN_SOUND_SCARED);
	}

	//////////////////////////////////////////////////////////////////////////
	// Scare points also scare chicken off.
	//////////////////////////////////////////////////////////////////////////
	if (bc.scareRatio > 0)
	{
		float sqrScareDist = m_pos.GetSquaredDistance(bc.scarePoint);
		if (sqrScareDist < bc.scareRadius*bc.scareRadius)
		{
			float fScareMultiplier = 10.0f;
			Vec3 retreatDir = m_pos - bc.scarePoint;
			retreatDir.NormalizeFast();
			float scareFactor = (1.0f - sqrScareDist/(bc.scareRadius*bc.scareRadius));
			m_accel.x += retreatDir.x*scareFactor*fScareMultiplier;
			m_accel.y += retreatDir.y*scareFactor*fScareMultiplier;

			if (m_landing) m_flightTime = m_maxIdleTime+1.0f; // Stop idle.

			m_bScared = true;

			// Do walk sounds.
			if ((cry_rand()&0xF) == 0)
				PlaySound(CHICKEN_SOUND_CLUCK);
		}
	}
	//////////////////////////////////////////////////////////////////////////


	if (bc.avoidObstacles)
	{
		// Avoid obstacles & terrain.
		IPhysicalWorld *physWorld = bc.physics;

		Vec3 vDir0 = m_heading*bc.fBoidRadius*0.5f;
		Vec3 vPos = m_pos + Vec3(0,0,bc.fBoidRadius*0.5f) + vDir0;
		Vec3 vDir = m_heading*(bc.fBoidRadius*2) + Vec3(0,0,bc.fBoidRadius*0.5f);
		// Add some random variation in probe ray.
		vDir.x += frand()*0.5f;
		vDir.y += frand()*0.5f;

		int objTypes = ent_all|ent_no_ondemand_activation;
		int flags = rwi_stop_at_pierceable|rwi_ignore_terrain_holes;
		ray_hit hit;
		int col = physWorld->RayWorldIntersection( vPos,vDir,objTypes,flags,&hit,1 );
		if (col != 0 && hit.dist > 0)
		{
			// Turn from collided surface.
			Vec3 normal = hit.n;
			float rayLen = vDir.GetLength();
			float w = (1.0f - hit.dist/rayLen);
			Vec3 R = m_heading - (2.0f*m_heading.Dot(normal))*normal;
			R.NormalizeFast();
			R += normal;
			//m_accel += R*(w*w)*bc.factorAvoidLand * fCollisionAvoidanceWeight;
			Vec3 accel = R*w*bc.factorAvoidLand * fCollisionAvoidanceWeight;
			m_avoidanceAccel = m_avoidanceAccel*bc.fSmoothFactor + accel*(1.0f-bc.fSmoothFactor);
		}
	}

	m_accel += m_avoidanceAccel;
	m_avoidanceAccel = m_avoidanceAccel*bc.fSmoothFactor;

	if (!m_landing)
	{
		m_flightTime += dt;
		if (m_flightTime > m_maxNonIdleTime && (m_pos.z > bc.waterLevel && bc.bAvoidWater))
		{
			// Play idle.
			PlayAnimationId( CHICKEN_IDLE_ANIM + (cry_rand()%CHICKEN_IDLE_ANIM_NUM),true );
			m_maxIdleTime = 2.0f + cry_frand()*MAX_REST_TIME;
			m_landing = true;
			m_flightTime = 0;
			
			m_accel.Set(0,0,0);
			m_speed = 0;
		}
	}
	else
	{
		m_accel = m_heading;
		m_speed = 0.1f;

		m_flightTime += dt;
		if (m_flightTime > m_maxIdleTime)
		{
			m_maxNonIdleTime = cry_frand()*MAX_WALK_TIME;
			PlayAnimationId( CHICKEN_WALK_ANIM,true );
			m_landing = false;
			m_flightTime = 0;
		}
	}

	// Limits birds to above water and land.
	m_pos.z = bc.engine->GetTerrainElevation(m_pos.x,m_pos.y) + bc.fBoidRadius*0.5f;
	m_accel.z = 0;

	//////////////////////////////////////////////////////////////////////////
	// Avoid water ocean..
	if (m_pos.z < bc.waterLevel && bc.bAvoidWater)
	{
		if (m_landing)
			m_flightTime = m_maxIdleTime;
		Vec3 nextpos = m_pos + m_heading;
		float farz = bc.engine->GetTerrainElevation(nextpos.x,nextpos.y) + bc.fBoidRadius*0.5f;
		if (farz > m_pos.z)
			m_accel += m_heading*bc.factorAvoidLand;
		else
			m_accel += -m_heading*bc.factorAvoidLand;
		m_accel.z = 0;
	}
	//////////////////////////////////////////////////////////////////////////
}
示例#21
0
//------------------------------------------------------------------------
void CFireModePlugin_Reject::OnShoot()
{
	const SEffectParams& rejectEffect = m_pParams->rejectEffect;
	CWeapon* pWeapon = m_pOwnerFiremode->GetWeapon();

	const int slot = pWeapon->GetStats().fp ? 0 : 1;
	const bool doRejectEffect = (g_pGameCVars->i_rejecteffects != 0) && (!rejectEffect.effect[slot].empty());

	if (doRejectEffect)
	{
		//First check if we can skip/cull the effect (not for the local player)
		if (!pWeapon->IsOwnerClient())
		{
			const CCamera& camera = gEnv->p3DEngine->GetRenderingCamera();
			const Vec3 cameraPos = camera.GetPosition();
			const Vec3 effectPosition = pWeapon->GetWorldPos();

			const float fDist2 = (cameraPos-effectPosition).len2();

			// Too far, skip
			if (fDist2 > g_pGameCVars->g_rejectEffectCullDistance)			
			{
				return; 
			}

			// Not in the view ?
			if(g_pGameCVars->g_rejectEffectVisibilityCull)
			{
				Sphere emitterSphere(effectPosition, 2.0f);
				if(camera.IsSphereVisible_F(emitterSphere) == false)
				{
					return;
				}
			}
		}

		IParticleEffect* pParticleEffect = gEnv->pParticleManager->FindEffect(rejectEffect.effect[slot].c_str());

		if (m_shellFXSpeed == 0.0f)
		{
			
			if (pParticleEffect)
			{
				const ParticleParams& particleParams = pParticleEffect->GetParticleParams();
				m_shellFXSpeed = particleParams.fSpeed.GetMaxValue();
			}
		}
		const Vec3 shellDirection = pWeapon->GetSlotHelperRotation(slot, rejectEffect.helper[slot].c_str(), true).GetColumn1();
		const Vec3 shellVelocity = m_shellHelperVelocity + (shellDirection * m_shellFXSpeed);

		EntityEffects::SEffectSpawnParams spawnParams(ZERO, shellVelocity.GetNormalized(), rejectEffect.scale[slot], shellVelocity.GetLength(), false);
		EntityEffects::SpawnParticleWithEntity(pWeapon->GetEntity(), slot, pParticleEffect, rejectEffect.helper[slot].c_str(), spawnParams);
	}
}
示例#22
0
void CBoidObject::CalcMovement(float dt,SBoidContext &bc,bool banking)
{
	// Calc movement with current velocity.
	Vec3 prevAccel(0,0,0);

	if(banking)
	{
		if(m_currentAccel.x != 0 && m_currentAccel.y != 0 && m_currentAccel.z != 0)
			prevAccel = m_currentAccel.GetNormalized();
		else
			banking = false;
	}

	m_currentAccel = m_currentAccel*bc.fSmoothFactor + m_accel*(1.0f - bc.fSmoothFactor);

	Vec3 velocity = m_heading*m_speed;
	m_pos = m_pos + velocity*dt;
	velocity = velocity + m_currentAccel*dt;
	m_speed = velocity.GetLength();

//	ClampSpeed(bc,dt);

	if(fabs(m_speed) > 0.0001f)
	{
		Vec3 newHeading = velocity;// * (1.0f/m_speed); // Normalized velocity vector is our heading.
		newHeading.NormalizeFast();

		if(bc.fMaxTurnRatio)
		{
			float fHeadingSmothFactor = bc.fMaxTurnRatio * bc.fSmoothFactor;

			if(fHeadingSmothFactor > 1.0f)
				fHeadingSmothFactor = 1.0f;

			m_heading = newHeading*fHeadingSmothFactor + m_heading*(1.0f - fHeadingSmothFactor);
		}
		else
		{
			m_heading = newHeading;
		}
	}

	/*
		if (m_speed > bc.MaxSpeed)
			m_speed = bc.MaxSpeed;
		if (m_speed < bc.MinSpeed)
			m_speed = bc.MinSpeed;
	*/
	ClampSpeed(bc,dt);

	if(banking)
	{
		Vec3 sideDir = m_heading.Cross(Vec3(0,0,1));

		if(sideDir.IsZero())
			sideDir = m_heading.Cross(Vec3(0,1,0));

//		Vec3 v = m_currentAccel.GetLength();
		m_bankingTrg = prevAccel.Dot(sideDir.GetNormalized());
	}
	else
		m_bankingTrg = 0;

	// Slowly go into the target banking.
	float bd = m_bankingTrg - m_banking;
	m_banking = m_banking + bd*dt*10.0f;



	/*
	if (m_pPhysics)
	{
		//pe_params_pos ppos;
		//ppos.pos = Vec3(m_pos);
		//m_pPhysics->SetParams(&ppos);

		//pe_action_set_velocity asv;
		//asv.v = m_heading*m_speed;
		//m_pPhysics->Action(&asv);
	}
	*/
}
示例#23
0
	void Update(float elapsed)
	{
		float maxTime = GetPortFloat(&m_actInfo, EIP_Duration);
		float percent = maxTime > FLT_EPSILON ? elapsed / maxTime : 1.0f;
		if(percent >= 1.0f)
		{
			m_actInfo.pGraph->SetRegularlyUpdated(m_actInfo.myID, false);
			m_triggered = false;
			return;
		}

		Vec3 N = GetPortVec3(&m_actInfo, EIP_Normal);

		float rangeMin = GetPortFloat(&m_actInfo, EIP_RangeMin);
		float rangeMax = GetPortFloat(&m_actInfo, EIP_RangeMax);
		const float range = rangeMax - rangeMin;
		Vec3 boxDim(rangeMax, rangeMax, rangeMax);
		Vec3 ptmin = m_effectCenter - boxDim;
		Vec3 ptmax = m_effectCenter + boxDim;

		float speed = GetPortFloat(&m_actInfo, EIP_Speed);
		float waveFront = elapsed * speed;

		float decay = GetPortFloat(&m_actInfo, EIP_Decay);
		if(decay > FLT_EPSILON) decay = 1.0f / decay;

		float force = GetPortFloat(&m_actInfo, EIP_Force);
		force = pow_tpl(force * (1-percent), decay);

		float amplitude = GetPortFloat(&m_actInfo, EIP_Amplitude);
		amplitude = pow_tpl(amplitude * (1-percent), decay);

		if (gEnv->bMultiplayer) // Turned off for performance and network issues
		{
			return;
		}

		IPhysicalEntity** pEntityList = NULL;
		static const int iObjTypes = ent_rigid | ent_sleeping_rigid | ent_living;// | ent_allocate_list;
		int numEntities = gEnv->pPhysicalWorld->GetEntitiesInBox(ptmin, ptmax, pEntityList, iObjTypes);
		AABB bounds;
		for(int i=0; i<numEntities; ++i)
		{
			IPhysicalEntity* pPhysicalEntity = pEntityList[i];
			IEntity* pEntity = static_cast<IEntity*>(pPhysicalEntity->GetForeignData(PHYS_FOREIGN_ID_ENTITY));

			// Has the entity already been affected?
			if(pEntity)
			{
				bool affected = stl::find(m_entitiesAffected, pEntity->GetId());
				if(!affected)
				{
					IEntityPhysicalProxy* pPhysicalProxy = static_cast<IEntityPhysicalProxy*>(pEntity->GetProxy(ENTITY_PROXY_PHYSICS));
					if(pPhysicalProxy)
					{
						pPhysicalProxy->GetWorldBounds(bounds);
						Vec3 p = bounds.GetCenter();
						Vec3 v = p - m_effectCenter;
						float distFromCenter = v.GetLength() + FLT_EPSILON;
						if(distFromCenter < rangeMax)
						{
							if(waveFront > distFromCenter) // has the wavefront passed the entity?
							{
								//pPhysicalEntity->GetStatus(&dyn);

								// normalize v, cheaper than another sqrt
								v /= distFromCenter;

								Vec3 dir = N + v * force;
								static bool usePos = false;
								float impulse = 1.0f - (max(0.0f, distFromCenter - rangeMin) / range);
								impulse = impulse * amplitude;// / dyn.mass;
								if(impulse > FLT_EPSILON)
								{
									pPhysicalProxy->AddImpulse(-1, p, dir * impulse, usePos, 1.0f);
									m_entitiesAffected.push_back(pEntity->GetId());
								}
							}
						}
					}
				}
			}
		}
	}
//------------------------------------------------------------------------
bool CVehicleMovementHelicopter::RequestMovement(CMovementRequest& movementRequest)
{
	FUNCTION_PROFILER( gEnv->pSystem, PROFILE_GAME );
 
	m_movementAction.isAI = true;
  //StartEngine(0);

  if (m_HoverAnim && !(m_HoverAnim->GetAnimTime() < 1.0f - FLT_EPSILON))
  {
    m_HoverAnim->StartAnimation();
  }


	CryAutoCriticalSection lk(m_lock);


	if (movementRequest.HasLookTarget())
		m_aiRequest.SetLookTarget(movementRequest.GetLookTarget());
	else
		m_aiRequest.ClearLookTarget();

  if (movementRequest.HasBodyTarget())
    m_aiRequest.SetBodyTarget(movementRequest.GetBodyTarget());
  else
    m_aiRequest.ClearBodyTarget();

  if (movementRequest.HasDesiredBodyDirectionAtTarget())
    m_aiRequest.SetDesiredBodyDirectionAtTarget(movementRequest.GetDesiredBodyDirectionAtTarget());
  else
    m_aiRequest.ClearDesiredBodyDirectionAtTarget();

	if (movementRequest.HasMoveTarget())
	{
		Vec3 end( movementRequest.GetMoveTarget() );
		if(m_bExtendMoveTarget)
		{
			Vec3 entityPos = m_pEntity->GetWorldPos();
			Vec3 start(entityPos);
			Vec3 pos = ( end - start ) * 100.0f;
			pos +=start;
			m_aiRequest.SetMoveTarget( pos );
		}
		else
		{
			m_aiRequest.SetMoveTarget( end );
		}


    if (!m_isEnginePowered)
    {
      StartDriving(0);
    }
	}
	else
		m_aiRequest.ClearMoveTarget();

	float fDesiredSpeed = 0.0f;

	if (movementRequest.HasDesiredSpeed())
		fDesiredSpeed = movementRequest.GetDesiredSpeed();
	else
		m_aiRequest.ClearDesiredSpeed();

	if (movementRequest.HasForcedNavigation())
	{
		const Vec3 forcedNavigation = movementRequest.GetForcedNavigation();
		const Vec3 entityPos = m_pEntity->GetWorldPos();
		m_aiRequest.SetForcedNavigation(forcedNavigation);
		m_aiRequest.SetMoveTarget(entityPos+forcedNavigation.GetNormalizedSafe()*100.0f);
		
		if (fabsf(fDesiredSpeed) <= FLT_EPSILON)
			fDesiredSpeed = forcedNavigation.GetLength();
	}
	else
		m_aiRequest.ClearForcedNavigation();

	m_aiRequest.SetDesiredSpeed(fDesiredSpeed * m_EnginePerformance);

	m_pVehicle->NeedsUpdate(IVehicle::eVUF_AwakePhysics, false);

	return true;
		
}
示例#25
0
void CBoidBird::Kill( const Vec3 &hitPoint,const Vec3 &force )
{
	if (m_dead)
		return;
	
	m_status = Bird::DEAD;

	m_flock->m_bAnyKilled = true;
	IEntity *pEntity = gEnv->pEntitySystem->GetEntity(m_entity);
	if (pEntity)
	{
		SpawnParams params;
		params.eAttachForm = GeomForm_Surface;
		params.eAttachType = GeomType_Render;
		gEnv->pEntitySystem->GetBreakableManager()->AttachSurfaceEffect( pEntity,0,SURFACE_BREAKAGE_TYPE("destroy"),params,ePEF_Independent );
	}

	if (CFlock::m_e_flocks_hunt == 0)
	{
		m_physicsControlled = false;
		m_dead = true;
		m_nodraw = true;

		if (pEntity)
		{
			pEntity->Hide(true);
		}

		if (!m_dead && m_pPhysics)
		{
			if (pEntity)
			{
				pEntity->UnphysicalizeSlot(0);
			}
			m_pPhysics = 0;
		}

		// No physics at all.
		return;
	}

	SBoidContext bc;
	m_flock->GetBoidSettings(bc);

	Vec3 impulse = force;
	if (impulse.GetLength() > 100.0f)
	{
		impulse.Normalize();
		impulse *= 100.0f;
	}

	//if (!m_physicsControlled)
	{
		if (!m_object)
			return;

		AABB aabb =	m_object->GetAABB( );
		Vec3 size = ((aabb.max - aabb.min)/2.2f)*m_scale;

		CreateArticulatedCharacter( bc, size, bc.fBoidMass );

		m_physicsControlled = true;

		// Small impulse.
		// Apply force on this body.
		pe_action_impulse theAction;
		Vec3 someforce;
		someforce = impulse;
		//someforce.Normalize();
		theAction.impulse = someforce;
		theAction.ipart = 0;
		theAction.iApplyTime = 0;
		if (m_pPhysics)
			m_pPhysics->Action(&theAction);
	}

	if (m_object && !m_dying && !m_dead)
	{
		m_object->GetISkeletonAnim()->StopAnimationsAllLayers();
	}

	m_dead = true;
}
void CVehiclePartSuspensionPart::Update(const float frameTime)
{
	inherited::Update(frameTime);

	const Matrix34& parentTm = m_pParentPart->GetLocalTM(false);
	const Matrix34& targetTm = m_targetPart->GetLocalTM(false);

	Vec3 pos = parentTm * m_pos0;
 	Vec3 targetPos = (m_ikFlags&k_flagIgnoreTargetRotation) ? (targetTm.GetColumn3() + m_targetOffset) : (targetTm * m_targetOffset);
 	Vec3 dir = targetPos - pos;
	float length = dir.GetLength();
	if (length > 1e-2f)
	{
		Matrix33 rot = Matrix33::CreateRotationV0V1(m_direction0, dir*(1.f/length));
		Matrix33 partRot = rot*Matrix33(m_initialRot);

		if (m_mode==k_modeRotate || m_mode==k_modeSnapToEF)
		{
			if (m_mode==k_modeSnapToEF)
			{
				pos = targetPos - rot * m_direction0;
			}
			Matrix34 tm(partRot, pos);
			SetLocalTM(tm);
		}
		else if (m_mode==k_modeStretch)
		{
			const float scale = length * m_invLength0;
			const Vec3 z = m_direction0;
			const Vec3 sz = m_direction0*(scale-1.f);
			Matrix33 scaleM;
			scaleM.m00 = 1.f+sz.x*z.x; scaleM.m01 =  sz.y*z.x    ; scaleM.m02 =  sz.z*z.x;
			scaleM.m10 = sz.x*z.y    ; scaleM.m11 =  1.f+sz.y*z.y; scaleM.m12 =  sz.z*z.y;
			scaleM.m20 = sz.x*z.z    ; scaleM.m21 =  sz.y*z.z    ; scaleM.m22 =  1.f+sz.z*z.z;
			Matrix34 tm(partRot * scaleM, pos);
			SetLocalTM(tm);
		}
	}

#if !defined(_RELEASE)
	if (VehicleCVars().v_debugSuspensionIK)
	{
		IRenderAuxGeom* pAuxGeom = gEnv->pRenderer->GetIRenderAuxGeom();
		SAuxGeomRenderFlags flags = pAuxGeom->GetRenderFlags();
		SAuxGeomRenderFlags oldFlags = pAuxGeom->GetRenderFlags();
		flags.SetDepthWriteFlag(e_DepthWriteOff);
		flags.SetDepthTestFlag(e_DepthTestOff);
		pAuxGeom->SetRenderFlags(flags);
	
		ColorB colRed(255,0,0,255);
		ColorB colBlue(0,0,255,255);
		ColorB colWhite(255,255,255,255);
		ColorB colGreen(0,255,0,255);

		pos = m_pVehicle->GetEntity()->GetWorldTM() * pos;
		targetPos = m_pVehicle->GetEntity()->GetWorldTM() * targetPos;
		pAuxGeom->DrawSphere(pos, 0.02f, colGreen);
		pAuxGeom->DrawSphere(targetPos, 0.02f, colBlue);
		pAuxGeom->DrawLine(pos, colWhite, targetPos, colWhite);
	}
#endif
}
//////////////////////////////////////////////////////////////////////////
// NOTE: This function must be thread-safe. Before adding stuff contact MarcoC.
void CVehicleMovementStdBoat::ProcessAI(const float deltaTime)
{
	FUNCTION_PROFILER( GetISystem(), PROFILE_GAME );

	float dt = max( deltaTime, 0.005f);
	SVehiclePhysicsStatus* physStatus = &m_physStatus[k_physicsThread];

	// It is copyed from CVehicleMoventTank::ProcessAI
	m_movementAction.brake = false;
	m_movementAction.rotateYaw = 0.0f;
	m_movementAction.power = 0.0f;

	float inputSpeed = 0.0f;
	{
		if (m_aiRequest.HasDesiredSpeed())
			inputSpeed = m_aiRequest.GetDesiredSpeed();
		Limit(inputSpeed, -(m_maxSpeed*m_factorMaxSpeed), m_maxSpeed*m_factorMaxSpeed);
	}

	Vec3 vMove(ZERO);
	{
		if (m_aiRequest.HasMoveTarget())
			vMove = ( m_aiRequest.GetMoveTarget() - m_pEntity->GetWorldPos() ).GetNormalizedSafe();
	}

	//start calculation
	if ( fabsf( inputSpeed ) < 0.0001f )
	{
		m_movementAction.brake = true;
		if ( physStatus->v.GetLength() > 1.0f )
		{
			m_movementAction.power =-1.0f;
		}

	}
	else
	{
		Matrix33 entRotMatInvert( physStatus->q );
		entRotMatInvert.Invert();
		float currentAngleSpeed = RAD2DEG(-physStatus->w.z);

		const static float maxSteer = RAD2DEG(gf_PI/4.f); // fix maxsteer, shouldn't change  
		Vec3 vVel = physStatus->v;
		Vec3 vVelR = entRotMatInvert * vVel;
		float currentSpeed =vVel.GetLength();
		vVelR.NormalizeSafe();
		if ( vVelR.Dot( FORWARD_DIRECTION ) < 0 )
			currentSpeed *= -1.0f;

		// calculate pedal
		static float accScale = 0.5f;
		m_movementAction.power = (inputSpeed - currentSpeed) * accScale;
		Limit( m_movementAction.power, -1.0f, 1.0f);

		// calculate angles
		Vec3 vMoveR = entRotMatInvert * vMove;
		Vec3 vFwd	= FORWARD_DIRECTION;

		vMoveR.z =0.0f;
		vMoveR.NormalizeSafe();

		if ( inputSpeed < 0.0f )	// when going back
		{
			vFwd *= -1.0f;
			vMoveR *= -1.0f;
			currentAngleSpeed *=-1.0f;
		}

		float cosAngle = vFwd.Dot(vMoveR);
		float angle = RAD2DEG(acos_tpl(cosAngle));
		if ( vMoveR.Dot( Vec3( 1.0f,0.0f,0.0f ) )< 0 )
			 angle = -angle;

		//int step =0;
		m_movementAction.rotateYaw = angle * 1.75f/ maxSteer; 

		// implementation 1. if there is enough angle speed, we don't need to steer more
		if ( fabsf(currentAngleSpeed) > fabsf(angle) && angle*currentAngleSpeed > 0.0f )
		{
			m_movementAction.rotateYaw = m_movementAction.rotateYaw*0.995f; //step =1;
		}

		// implementation 2. if we can guess we reach the distination angle soon, start counter steer.
		float predictDelta = inputSpeed < 0.0f ? 0.1f : 0.1f;
		float dict = angle + predictDelta * ( angle - m_prevAngle) / dt ;
		if ( dict*currentAngleSpeed<0.0f )
		{
			if ( fabsf( angle ) < 2.0f )
			{
				m_movementAction.rotateYaw = angle* 1.75f/ maxSteer;// ; step =3;
			}
			else
			{
				m_movementAction.rotateYaw = currentAngleSpeed < 0.0f ? 1.0f : -1.0f;// step =2;
			}
		}

		if ( fabsf( angle ) > 20.0f && currentSpeed > 3.0f ) 
		{
			m_movementAction.power = 0.1f ;
			//step =4;
		}

		m_prevAngle =  angle;
		//CryLog("steering	%4.2f	%4.2f %4.2f	%4.2f	%4.2f	%4.2f	%d", deltaTime,inputSpeed - currentSpeed,angle,currentAngleSpeed, m_movementAction.rotateYaw,currentAngleSpeed-m_prevAngle,step);

	}

}