////////////////////////////////////////////////////////////////////////// // 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 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); } }