Make AI really bends it like Beckham

Notice: AI will only try to skid to save the ball from being scored
when expert and supertux mode.
This commit is contained in:
Benau 2016-01-22 22:01:22 +08:00
parent ea05f4b6ba
commit df9dc5ff34
7 changed files with 68 additions and 73 deletions

View File

@ -184,7 +184,7 @@ float AIBaseController::normalizeAngle(float angle)
void AIBaseController::setSteering(float angle, float dt)
{
float steer_fraction = angle / m_kart->getMaxSteerAngle();
if(!doSkid(steer_fraction))
if(!canSkid(steer_fraction))
m_controls->m_skid = KartControl::SC_NONE;
else
m_controls->m_skid = steer_fraction > 0 ? KartControl::SC_RIGHT
@ -214,15 +214,6 @@ void AIBaseController::setSteering(float angle, float dt)
}
} // setSteering
// ----------------------------------------------------------------------------
/** Determines if the kart should skid. The base implementation enables
* skidding if a sharp turn is needed (which is for the old skidding
* implementation).
* \param steer_fraction The steering fraction as computed by the
* AIBaseController.
* \return True if the kart should skid.
*/
// ------------------------------------------------------------------------
/** Certain AI levels will not receive a slipstream bonus in order to
* be not as hard.
@ -232,23 +223,6 @@ bool AIBaseController::disableSlipstreamBonus() const
return m_ai_properties->disableSlipstreamUsage();
} // disableSlipstreamBonus
bool AIBaseController::doSkid(float steer_fraction)
{
// Disable skidding when a plunger is in the face
if(m_kart->getBlockedByPlungerTime()>0) return false;
// FIXME: Disable skidding for now if the new skidding
// code is activated, since the AI can not handle this
// properly.
if(m_kart->getKartProperties()->getSkidVisualTime() > 0)
return false;
// Otherwise return if we need a sharp turn (which is
// for the old skidding implementation).
return fabsf(steer_fraction)>=m_ai_properties->m_skidding_threshold;
} // doSkid
//-----------------------------------------------------------------------------
/** This is called when the kart crashed with the terrain. This subroutine
* tries to detect if the AI is stuck by determining if a certain number

View File

@ -51,7 +51,7 @@ protected:
float m_kart_width;
/** Keep a pointer to the track to reduce calls */
Track *m_track;
Track *m_track;
/** A pointer to the AI properties for this kart. */
const AIProperties *m_ai_properties;
@ -61,17 +61,17 @@ protected:
/** Position info structure of targets. */
struct posData {bool behind; bool on_side; float angle; float distance;};
void setControllerName(const std::string &name);
float steerToPoint(const Vec3 &point);
float normalizeAngle(float angle);
virtual void update (float delta) ;
virtual void setSteering (float angle, float dt);
void setControllerName(const std::string &name);
float steerToPoint(const Vec3 &point);
float normalizeAngle(float angle);
virtual bool doSkid(float steer_fraction);
virtual bool canSkid(float steer_fraction) { return false; }
// ------------------------------------------------------------------------
/** This can be called to detect if the kart is stuck (i.e. repeatedly
* hitting part of the track). */
bool isStuck() const { return m_stuck; }
void checkPosition(const Vec3&, posData*, Vec3* lc = NULL) const;
bool isStuck() const { return m_stuck; }
void checkPosition(const Vec3&, posData*, Vec3* lc = NULL) const;
public:
AIBaseController(AbstractKart *kart,

View File

@ -45,19 +45,8 @@ BattleAI::BattleAI(AbstractKart *kart,
m_debug_sphere = irr_driver->addSphere(1.0f, col_debug);
m_debug_sphere->setVisible(true);
#endif
if (race_manager->getMinorMode() == RaceManager::MINOR_MODE_3_STRIKES)
{
m_world = dynamic_cast<ThreeStrikesBattle*>(World::getWorld());
m_track = m_world->getTrack();
}
else
{
// Those variables are not defined in a battle mode (m_world is
// a linear world, since it assumes the existance of drivelines)
m_world = NULL;
m_track = NULL;
}
m_world = dynamic_cast<ThreeStrikesBattle*>(World::getWorld());
m_track = m_world->getTrack();
// Don't call our own setControllerName, since this will add a
// billboard showing 'AIBaseController' to the kart.

View File

@ -2210,7 +2210,7 @@ void SkiddingAI::handleCurve()
* AIBaseLapController.
* \return True if the kart should skid.
*/
bool SkiddingAI::doSkid(float steer_fraction)
bool SkiddingAI::canSkid(float steer_fraction)
{
if(fabsf(steer_fraction)>1.5f)
{
@ -2319,7 +2319,7 @@ bool SkiddingAI::doSkid(float steer_fraction)
m_kart->getIdent().c_str());
#endif
return false;
} // doSkid
} // canSkid
//-----------------------------------------------------------------------------
/** Converts the steering angle to a lr steering in the range of -1 to 1.
@ -2341,7 +2341,7 @@ void SkiddingAI::setSteering(float angle, float dt)
// Use a simple finite state machine to make sure to randomly decide
// whether to skid or not only once per skid section. See docs for
// m_skid_probability_state for more details.
if(!doSkid(steer_fraction))
if(!canSkid(steer_fraction))
{
m_skid_probability_state = SKID_PROBAB_NOT_YET;
m_controls->m_skid = KartControl::SC_NONE;

View File

@ -94,7 +94,7 @@ the AI does the following steps:
behaviour.
The function handleSteering() then calls setSteering() to set the
actually steering amount. The latter function also decides if skidding
should be done or not (by calling doSkid()).
should be done or not (by calling canSkid()).
- decide if to try to collect or avoid items (handeItems).
It considers all items on quads between the current quad of the kart
and the quad the AI is aiming at (see handleSteering). If it finds
@ -270,7 +270,7 @@ private:
const Vec3 &end,
Vec3 *center,
float *radius);
virtual bool doSkid(float steer_fraction);
virtual bool canSkid(float steer_fraction);
virtual void setSteering(float angle, float dt);
void handleCurve();

View File

@ -45,19 +45,8 @@ SoccerAI::SoccerAI(AbstractKart *kart,
m_debug_sphere = irr_driver->addSphere(1.0f, col_debug);
m_debug_sphere->setVisible(true);
#endif
if (race_manager->getMinorMode() == RaceManager::MINOR_MODE_SOCCER)
{
m_world = dynamic_cast<SoccerWorld*>(World::getWorld());
m_track = m_world->getTrack();
}
else
{
// Those variables are not defined in a battle mode (m_world is
// a linear world, since it assumes the existance of drivelines)
m_world = NULL;
m_track = NULL;
}
m_world = dynamic_cast<SoccerWorld*>(World::getWorld());
m_track = m_world->getTrack();
// Don't call our own setControllerName, since this will add a
// billboard showing 'AIBaseController' to the kart.
@ -82,6 +71,7 @@ void SoccerAI::reset()
ArenaAI::reset();
AIBaseController::reset();
m_saving_ball = false;
if (race_manager->getNumPlayers() == 1)
{
// Same handle in SoccerWorld::createKart
@ -106,6 +96,7 @@ void SoccerAI::reset()
//-----------------------------------------------------------------------------
void SoccerAI::update(float dt)
{
m_saving_ball = false;
if (World::getWorld()->getPhase() == World::GOAL_PHASE)
{
m_controls->m_accel = 0.0f;
@ -196,12 +187,40 @@ Vec3 SoccerAI::correctBallPosition(const Vec3& orig_pos)
if (goal_pos.behind)
{
// If facing the wrong goal, apply more offset to the ball
// to prevent shooting into its own team goal
ball_lc = (goal_pos.on_side ? ball_lc - Vec3 (2, 0, 0) + Vec3 (0, 0, 2):
ball_lc + Vec3 (2, 0, 2));
if (goal_pos.angle > 0.3f && ball_pos.distance < 3.0f &&
!ball_pos.behind)
{
// Only steer with ball if same sides for ball and goal
if (ball_pos.on_side && goal_pos.on_side)
{
ball_lc = ball_lc + Vec3 (1, 0, 1);
return m_kart->getTrans()(ball_lc);
}
else if (!ball_pos.on_side && !goal_pos.on_side)
{
ball_lc = ball_lc - Vec3 (1, 0, 0) + Vec3 (0, 0, 1);
return m_kart->getTrans()(ball_lc);
}
else
m_controls->m_brake = true;
}
else
{
// This case is facing straight ahead opposite goal
// (which is straight behind itself), apply more
// offset for skidding, to save the ball from behind
// scored.
// Notice: this assume map maker make soccer field
// with two goals facing each other straight
ball_lc = (goal_pos.on_side ? ball_lc - Vec3 (2, 0, 0) +
Vec3 (0, 0, 2) : ball_lc + Vec3 (2, 0, 2));
return m_kart->getTrans()(ball_lc);
if (ball_pos.distance < 3.0f &&
(m_cur_difficulty == RaceManager::DIFFICULTY_HARD ||
m_cur_difficulty == RaceManager::DIFFICULTY_BEST))
m_saving_ball = true;
return m_kart->getTrans()(ball_lc);
}
}
if (ball_pos.distance < 3.0f &&
@ -211,9 +230,19 @@ Vec3 SoccerAI::correctBallPosition(const Vec3& orig_pos)
return orig_pos;
else
{
ball_lc = (goal_pos.on_side ? ball_lc + Vec3 (1, 0, 1) :
ball_lc - Vec3 (1, 0, 0) + Vec3 (0, 0, 1));
return m_kart->getTrans()(ball_lc);
// Same with above
if (ball_pos.on_side && goal_pos.on_side)
{
ball_lc = ball_lc + Vec3 (1, 0, 1);
return m_kart->getTrans()(ball_lc);
}
else if (!ball_pos.on_side && !goal_pos.on_side)
{
ball_lc = ball_lc - Vec3 (1, 0, 0) + Vec3 (0, 0, 1);
return m_kart->getTrans()(ball_lc);
}
else
m_controls->m_brake = true;
}
}
return orig_pos;

View File

@ -35,12 +35,15 @@ private:
SoccerWorld *m_world;
SoccerTeam m_cur_team;
bool m_saving_ball;
Vec3 correctBallPosition(const Vec3&);
virtual void findClosestKart(bool use_difficulty);
virtual void findTarget();
virtual int getCurrentNode() const;
virtual bool isWaiting() const;
virtual bool canSkid(float steer_fraction) { return m_saving_ball; }
public:
SoccerAI(AbstractKart *kart,
StateManager::ActivePlayer *player = NULL);