First playable advanced soccer ai

This commit is contained in:
Benau 2016-05-16 15:24:05 +08:00
parent 748051871c
commit d2f26fe70d
9 changed files with 125 additions and 48 deletions

View File

@ -283,13 +283,13 @@ void AIBaseController::crashed(const Material *m)
} // crashed(Material) } // crashed(Material)
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
void AIBaseController::checkPosition(const Vec3 &point, void AIBaseController::checkPosition(const Vec3 &point, posData *pos_data,
posData *pos_data, Vec3 *lc, bool use_front_xyz) const
Vec3 *lc) const
{ {
// Convert to local coordinates from the point of view of current kart // Convert to local coordinates from the point of view of current kart
btQuaternion q(btVector3(0, 1, 0), -m_kart->getHeading()); btQuaternion q(btVector3(0, 1, 0), -m_kart->getHeading());
Vec3 p = point - m_kart->getXYZ(); Vec3 p = point -
(use_front_xyz ? m_kart->getFrontXYZ() : m_kart->getXYZ());
Vec3 local_coordinates = quatRotate(q, p); Vec3 local_coordinates = quatRotate(q, p);
// Save local coordinates for later use if needed // Save local coordinates for later use if needed

View File

@ -77,7 +77,9 @@ protected:
/** This can be called to detect if the kart is stuck (i.e. repeatedly /** This can be called to detect if the kart is stuck (i.e. repeatedly
* hitting part of the track). */ * hitting part of the track). */
bool isStuck() const { return m_stuck; } bool isStuck() const { return m_stuck; }
void checkPosition(const Vec3&, posData*, Vec3* lc = NULL) const; void checkPosition(const Vec3&, posData*,
Vec3* lc = NULL,
bool use_front_xyz = false) const;
public: public:
AIBaseController(AbstractKart *kart); AIBaseController(AbstractKart *kart);

View File

@ -76,7 +76,10 @@ void ArenaAI::update(float dt)
// Don't do anything if there is currently a kart animations shown. // Don't do anything if there is currently a kart animations shown.
if (m_kart->getKartAnimation()) if (m_kart->getKartAnimation())
{
resetAfterStop();
return; return;
}
if (isWaiting()) if (isWaiting())
{ {
@ -101,6 +104,7 @@ void ArenaAI::update(float dt)
if (m_is_uturn) if (m_is_uturn)
{ {
resetAfterStop();
handleArenaUTurn(dt); handleArenaUTurn(dt);
} }
else else
@ -202,6 +206,7 @@ bool ArenaAI::handleArenaUnstuck(const float dt)
{ {
if (!m_is_stuck || m_is_uturn) return false; if (!m_is_stuck || m_is_uturn) return false;
resetAfterStop();
setSteering(0.0f, dt); setSteering(0.0f, dt);
if (fabsf(m_kart->getSpeed()) > if (fabsf(m_kart->getSpeed()) >
@ -263,7 +268,8 @@ void ArenaAI::handleArenaSteering(const float dt)
checkPosition(m_target_point, &m_cur_kart_pos_data); checkPosition(m_target_point, &m_cur_kart_pos_data);
#ifdef AI_DEBUG #ifdef AI_DEBUG
if (m_path_corners.size() > 2) m_debug_sphere->setPosition(m_path_corners[0].toIrrVector());
/*if (m_path_corners.size() > 2)
{ {
m_debug_sphere->setVisible(true); m_debug_sphere->setVisible(true);
m_debug_sphere_next->setVisible(true); m_debug_sphere_next->setVisible(true);
@ -274,7 +280,7 @@ void ArenaAI::handleArenaSteering(const float dt)
{ {
m_debug_sphere->setVisible(false); m_debug_sphere->setVisible(false);
m_debug_sphere_next->setVisible(false); m_debug_sphere_next->setVisible(false);
} }*/
#endif #endif
if (m_cur_kart_pos_data.behind) if (m_cur_kart_pos_data.behind)
{ {

View File

@ -118,6 +118,7 @@ private:
void stringPull(const Vec3&, const Vec3&); void stringPull(const Vec3&, const Vec3&);
virtual int getCurrentNode() const = 0; virtual int getCurrentNode() const = 0;
virtual bool isWaiting() const = 0; virtual bool isWaiting() const = 0;
virtual void resetAfterStop() {};
virtual void findClosestKart(bool use_difficulty) = 0; virtual void findClosestKart(bool use_difficulty) = 0;
virtual void findTarget() = 0; virtual void findTarget() = 0;
virtual bool forceBraking() { return false; } virtual bool forceBraking() { return false; }

View File

@ -56,9 +56,9 @@ SoccerAI::SoccerAI(AbstractKart *kart)
video::SColor red(128, 128, 0, 0); video::SColor red(128, 128, 0, 0);
video::SColor blue(128, 0, 0, 128); video::SColor blue(128, 0, 0, 128);
m_red_sphere = irr_driver->addSphere(1.0f, red); m_red_sphere = irr_driver->addSphere(1.0f, red);
m_red_sphere->setVisible(true); m_red_sphere->setVisible(false);
m_blue_sphere = irr_driver->addSphere(1.0f, blue); m_blue_sphere = irr_driver->addSphere(1.0f, blue);
m_blue_sphere->setVisible(true); m_blue_sphere->setVisible(false);
#endif #endif
m_world = dynamic_cast<SoccerWorld*>(World::getWorld()); m_world = dynamic_cast<SoccerWorld*>(World::getWorld());
@ -114,6 +114,7 @@ void SoccerAI::update(float dt)
if (World::getWorld()->getPhase() == World::GOAL_PHASE) if (World::getWorld()->getPhase() == World::GOAL_PHASE)
{ {
resetAfterStop();
m_controls->m_brake = false; m_controls->m_brake = false;
m_controls->m_accel = 0.0f; m_controls->m_accel = 0.0f;
AIBaseController::update(dt); AIBaseController::update(dt);
@ -170,7 +171,10 @@ void SoccerAI::findTarget()
return; return;
} }
// Otherwise do the same as in battle mode, attack other karts // Always reset this flag,
// in case the ball chaser lost the ball somehow
m_overtake_ball = false;
if (m_kart->getPowerup()->getType() == PowerupManager::POWERUP_NOTHING && if (m_kart->getPowerup()->getType() == PowerupManager::POWERUP_NOTHING &&
m_kart->getAttachment()->getType() != Attachment::ATTACH_SWATTER) m_kart->getAttachment()->getType() != Attachment::ATTACH_SWATTER)
{ {
@ -212,30 +216,80 @@ Vec3 SoccerAI::determineBallAimingPosition()
posData aim_pos = {0}; posData aim_pos = {0};
Vec3 ball_lc; Vec3 ball_lc;
Vec3 aim_lc; Vec3 aim_lc;
checkPosition(orig_pos, &ball_pos); checkPosition(orig_pos, &ball_pos, &ball_lc, true/*use_front_xyz*/);
checkPosition(orig_pos, &aim_pos, &aim_lc); checkPosition(ball_aim_pos, &aim_pos, &aim_lc, true/*use_front_xyz*/);
// Too far from the ball, // Too far from the ball,
// use path finding from arena ai to get close // use path finding from arena ai to get close
if (ball_pos.distance > 6.0f) return ball_aim_pos; // ie no extra braking is needed
if (aim_pos.distance > 6.0f) return ball_aim_pos;
const Vec3 dist_to_aim_point = m_kart->getFrontXYZ() - ball_aim_pos; if (m_overtake_ball)
// Prevent lost control when steering with ball
const bool need_braking = ball_pos.angle > 0.1f &&
m_kart->getSpeed() > 9.0f && ball_pos.distance < 3.0f;
if (need_braking)
{ {
m_controls->m_brake = true; // Check if the kart passed the ball already,
m_force_brake = true; // If so aim the front side of ball
if (ball_pos.behind)
{
const Vec3& front_pos =
m_world->getBallAimPosition(m_opp_team, true/*reverse*/);
Vec3 d = front_pos - m_kart->getFrontXYZ();
if (d.length_2d() < (m_world->getBallDiameter() / 2))
{
// Almost arrive, reset
m_overtake_ball = false;
}
return front_pos;
}
else
{
// Otherwise aim left/right depends on the side of ball
if (ball_pos.lhs)
{
return m_world->getBallTrans()
(Vec3(m_world->getBallDiameter(), 0, 0));
}
else
{
return m_world->getBallTrans()
(Vec3(-m_world->getBallDiameter(), 0, 0));
}
}
} }
if (dist_to_aim_point.length_2d() < 0.4f) else
{ {
//Log::info("","%f",dist_to_aim_point.length_2d()); // Check whether the aim point is non-reachable
return m_world->getBallTrans()(Vec3(0, 0, 1)); // ie the ball is in front of the kart, which the aim position
// is behind the ball, in an almost straight line
// If so m_overtake_ball is true
if (aim_lc.z() > 0 && aim_lc.z() > ball_lc.z() &&
ball_pos.angle < 0.6f && aim_pos.angle < 0.2f)
{
m_overtake_ball = true;
}
// Otherwise use the aim position calculated by soccer world
// Prevent lost control when steering with ball
const bool need_braking = ball_pos.angle > 0.15f &&
m_kart->getSpeed() > 9.0f &&
ball_pos.distance < m_world->getBallDiameter();
if (need_braking)
{
m_controls->m_brake = true;
m_force_brake = true;
}
if (aim_pos.behind && aim_pos.distance <
(m_world->getBallDiameter() / 2))
{
// Reached aim point, aim forward
return m_world->getBallAimPosition(m_opp_team, true/*reverse*/);
}
return ball_aim_pos;
} }
// Make compiler happy
return ball_aim_pos; return ball_aim_pos;
} // determineBallAimingPosition } // determineBallAimingPosition
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------

View File

@ -57,6 +57,7 @@ private:
virtual void findClosestKart(bool use_difficulty); virtual void findClosestKart(bool use_difficulty);
virtual void findTarget(); virtual void findTarget();
virtual void resetAfterStop() OVERRIDE { m_overtake_ball = false; }
virtual int getCurrentNode() const; virtual int getCurrentNode() const;
virtual bool isWaiting() const; virtual bool isWaiting() const;
virtual bool canSkid(float steer_fraction) { return false; } virtual bool canSkid(float steer_fraction) { return false; }

View File

@ -97,7 +97,7 @@ void SoccerWorld::init()
if (!m_ball) if (!m_ball)
Log::fatal("SoccerWorld","Ball is missing in soccer field, abort."); Log::fatal("SoccerWorld","Ball is missing in soccer field, abort.");
m_bgd.init(); m_bgd.init(m_ball->getPhysicalObject()->getRadius());
} // init } // init
@ -423,9 +423,8 @@ void SoccerWorld::updateBallPosition(float dt)
{ {
if (isRaceOver()) return; if (isRaceOver()) return;
if (!(m_ball->getPhysicalObject()->getBody() if (!(m_ball_body->getLinearVelocity().x() == 0.0f ||
->getLinearVelocity().x() == 0.0f || m_ball->getPhysicalObject() m_ball_body->getLinearVelocity().z() == 0.0f))
->getBody()->getLinearVelocity().z() == 0.0f))
{ {
// Only update heading if the ball is moving // Only update heading if the ball is moving
m_ball_heading = atan2f(m_ball_body->getLinearVelocity().getX(), m_ball_heading = atan2f(m_ball_body->getLinearVelocity().getX(),

View File

@ -78,6 +78,9 @@ private:
{ {
// These data are used by AI to determine ball aiming angle // These data are used by AI to determine ball aiming angle
private: private:
// Radius of the ball
float m_radius;
// Slope of the line from ball to the center point of goals // Slope of the line from ball to the center point of goals
float m_red_goal_slope; float m_red_goal_slope;
float m_blue_goal_slope; float m_blue_goal_slope;
@ -116,8 +119,16 @@ private:
return m_trans; return m_trans;
} // getTrans } // getTrans
void init() float getDiameter() const
{ {
return m_radius * 2;
} // getTrans
void init(float ball_radius)
{
m_radius = ball_radius;
assert(m_radius > 0.0f);
// Save two goals // Save two goals
unsigned int n = CheckManager::get()->getCheckStructureCount(); unsigned int n = CheckManager::get()->getCheckStructureCount();
for (unsigned int i = 0; i < n; i++) for (unsigned int i = 0; i < n; i++)
@ -191,7 +202,7 @@ private:
return false; return false;
} // isApproachingGoal } // isApproachingGoal
Vec3 getAimPosition(SoccerTeam team) const Vec3 getAimPosition(SoccerTeam team, bool reverse) const
{ {
// If it's likely to goal already, aim the ball straight behind // If it's likely to goal already, aim the ball straight behind
// should do the job // should do the job
@ -202,16 +213,17 @@ private:
// This is done by using Pythagorean Theorem and solving the // This is done by using Pythagorean Theorem and solving the
// equation from ball to goal center (y = (m_***_goal_slope) x) // equation from ball to goal center (y = (m_***_goal_slope) x)
// We aim 1 unit behind the ball (easier to solve), // We aim behind the ball from the center of the ball to its
// so 1 = sqrt (x2 + y2) and than x = sqrt (1 - y2) // diameter, so 2*m_radius = sqrt (x2 + y2),
// which is next x = sqrt (2*m_radius - y2)
// And than we have x = y / m(m_***_goal_slope) // And than we have x = y / m(m_***_goal_slope)
// After put that in the slope equation, we have // After put that in the slope equation, we have
// y = sqrt(m2 / (1+m2)) // y = sqrt(2*m_radius*m2 / (1+m2))
float x = 0.0f; float x = 0.0f;
float y = 0.0f; float y = 0.0f;
if (team == SOCCER_TEAM_BLUE) if (team == SOCCER_TEAM_BLUE)
{ {
y = sqrt((m_blue_goal_slope * m_blue_goal_slope) / y = sqrt((m_blue_goal_slope * m_blue_goal_slope * m_radius*2) /
(1 + (m_blue_goal_slope * m_blue_goal_slope))); (1 + (m_blue_goal_slope * m_blue_goal_slope)));
if (m_blue_goal_2.x() == 0.0f || if (m_blue_goal_2.x() == 0.0f ||
(m_blue_goal_2.x() > 0.0f && m_blue_goal_2.z() > 0.0f) || (m_blue_goal_2.x() > 0.0f && m_blue_goal_2.z() > 0.0f) ||
@ -224,7 +236,7 @@ private:
} }
else else
{ {
y = sqrt((m_red_goal_slope * m_red_goal_slope) / y = sqrt((m_red_goal_slope * m_red_goal_slope * m_radius*2) /
(1 + (m_red_goal_slope * m_red_goal_slope))); (1 + (m_red_goal_slope * m_red_goal_slope)));
if (m_red_goal_2.x() == 0.0f || if (m_red_goal_2.x() == 0.0f ||
(m_red_goal_2.x() > 0.0f && m_red_goal_2.z() > 0.0f) || (m_red_goal_2.x() > 0.0f && m_red_goal_2.z() > 0.0f) ||
@ -237,7 +249,8 @@ private:
assert (!std::isnan(x)); assert (!std::isnan(x));
assert (!std::isnan(y)); assert (!std::isnan(y));
// Return the world coordinates // Return the world coordinates
return m_trans(Vec3(x, 0, y)); return (reverse ? m_trans(Vec3(-x, 0, -y)) :
m_trans(Vec3(x, 0, y)));
} // getAimPosition } // getAimPosition
}; // BallGoalData }; // BallGoalData
@ -344,29 +357,28 @@ public:
} }
// ------------------------------------------------------------------------ // ------------------------------------------------------------------------
int getKartNode(unsigned int kart_id) const int getKartNode(unsigned int kart_id) const
{ return m_kart_on_node[kart_id]; } { return m_kart_on_node[kart_id]; }
// ------------------------------------------------------------------------ // ------------------------------------------------------------------------
int getBallNode() const int getBallNode() const
{ return m_ball_on_node; } { return m_ball_on_node; }
// ------------------------------------------------------------------------ // ------------------------------------------------------------------------
const Vec3& getBallPosition() const const Vec3& getBallPosition() const
{ return (Vec3&)m_ball_body->getCenterOfMassTransform().getOrigin(); } { return (Vec3&)m_ball_body->getCenterOfMassTransform().getOrigin(); }
// ------------------------------------------------------------------------ // ------------------------------------------------------------------------
float getBallHeading() const float getBallHeading() const
{ return m_ball_heading; } { return m_ball_heading; }
// ------------------------------------------------------------------------
float getBallDiameter() const
{ return m_bgd.getDiameter(); }
// ------------------------------------------------------------------------ // ------------------------------------------------------------------------
bool ballApproachingGoal(SoccerTeam team) const bool ballApproachingGoal(SoccerTeam team) const
{ { return m_bgd.isApproachingGoal(team); }
return m_bgd.isApproachingGoal(team);
}
// ------------------------------------------------------------------------ // ------------------------------------------------------------------------
Vec3 getBallAimPosition(SoccerTeam team) const Vec3 getBallAimPosition(SoccerTeam team, bool reverse = false) const
{ { return m_bgd.getAimPosition(team, reverse); }
return m_bgd.getAimPosition(team);
}
// ------------------------------------------------------------------------ // ------------------------------------------------------------------------
const btTransform& getBallTrans() const const btTransform& getBallTrans() const
{ return m_bgd.getTrans(); } { return m_bgd.getTrans(); }
// ------------------------------------------------------------------------ // ------------------------------------------------------------------------
bool isCorrectGoal(unsigned int kart_id, bool first_goal) const; bool isCorrectGoal(unsigned int kart_id, bool first_goal) const;
// ------------------------------------------------------------------------ // ------------------------------------------------------------------------

View File

@ -211,6 +211,8 @@ public:
/** Add body to dynamic world */ /** Add body to dynamic world */
void addBody(); void addBody();
// ------------------------------------------------------------------------ // ------------------------------------------------------------------------
float getRadius() const { return m_radius; }
// ------------------------------------------------------------------------
const std::string& getOnKartCollisionFunction() const { return m_on_kart_collision; } const std::string& getOnKartCollisionFunction() const { return m_on_kart_collision; }
// ------------------------------------------------------------------------ // ------------------------------------------------------------------------
const std::string& getOnItemCollisionFunction() const { return m_on_item_collision; } const std::string& getOnItemCollisionFunction() const { return m_on_item_collision; }