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)
//-----------------------------------------------------------------------------
void AIBaseController::checkPosition(const Vec3 &point,
posData *pos_data,
Vec3 *lc) const
void AIBaseController::checkPosition(const Vec3 &point, posData *pos_data,
Vec3 *lc, bool use_front_xyz) const
{
// Convert to local coordinates from the point of view of current kart
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);
// 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
* hitting part of the track). */
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:
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.
if (m_kart->getKartAnimation())
{
resetAfterStop();
return;
}
if (isWaiting())
{
@ -101,6 +104,7 @@ void ArenaAI::update(float dt)
if (m_is_uturn)
{
resetAfterStop();
handleArenaUTurn(dt);
}
else
@ -202,6 +206,7 @@ bool ArenaAI::handleArenaUnstuck(const float dt)
{
if (!m_is_stuck || m_is_uturn) return false;
resetAfterStop();
setSteering(0.0f, dt);
if (fabsf(m_kart->getSpeed()) >
@ -263,7 +268,8 @@ void ArenaAI::handleArenaSteering(const float dt)
checkPosition(m_target_point, &m_cur_kart_pos_data);
#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_next->setVisible(true);
@ -274,7 +280,7 @@ void ArenaAI::handleArenaSteering(const float dt)
{
m_debug_sphere->setVisible(false);
m_debug_sphere_next->setVisible(false);
}
}*/
#endif
if (m_cur_kart_pos_data.behind)
{

View File

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

View File

@ -56,9 +56,9 @@ SoccerAI::SoccerAI(AbstractKart *kart)
video::SColor red(128, 128, 0, 0);
video::SColor blue(128, 0, 0, 128);
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->setVisible(true);
m_blue_sphere->setVisible(false);
#endif
m_world = dynamic_cast<SoccerWorld*>(World::getWorld());
@ -114,6 +114,7 @@ void SoccerAI::update(float dt)
if (World::getWorld()->getPhase() == World::GOAL_PHASE)
{
resetAfterStop();
m_controls->m_brake = false;
m_controls->m_accel = 0.0f;
AIBaseController::update(dt);
@ -170,7 +171,10 @@ void SoccerAI::findTarget()
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 &&
m_kart->getAttachment()->getType() != Attachment::ATTACH_SWATTER)
{
@ -212,30 +216,80 @@ Vec3 SoccerAI::determineBallAimingPosition()
posData aim_pos = {0};
Vec3 ball_lc;
Vec3 aim_lc;
checkPosition(orig_pos, &ball_pos);
checkPosition(orig_pos, &aim_pos, &aim_lc);
checkPosition(orig_pos, &ball_pos, &ball_lc, true/*use_front_xyz*/);
checkPosition(ball_aim_pos, &aim_pos, &aim_lc, true/*use_front_xyz*/);
// Too far from the ball,
// 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;
// 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)
if (m_overtake_ball)
{
m_controls->m_brake = true;
m_force_brake = true;
// Check if the kart passed the ball already,
// 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());
return m_world->getBallTrans()(Vec3(0, 0, 1));
// Check whether the aim point is non-reachable
// 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;
} // determineBallAimingPosition
//-----------------------------------------------------------------------------

View File

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

View File

@ -97,7 +97,7 @@ void SoccerWorld::init()
if (!m_ball)
Log::fatal("SoccerWorld","Ball is missing in soccer field, abort.");
m_bgd.init();
m_bgd.init(m_ball->getPhysicalObject()->getRadius());
} // init
@ -423,9 +423,8 @@ void SoccerWorld::updateBallPosition(float dt)
{
if (isRaceOver()) return;
if (!(m_ball->getPhysicalObject()->getBody()
->getLinearVelocity().x() == 0.0f || m_ball->getPhysicalObject()
->getBody()->getLinearVelocity().z() == 0.0f))
if (!(m_ball_body->getLinearVelocity().x() == 0.0f ||
m_ball_body->getLinearVelocity().z() == 0.0f))
{
// Only update heading if the ball is moving
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
private:
// Radius of the ball
float m_radius;
// Slope of the line from ball to the center point of goals
float m_red_goal_slope;
float m_blue_goal_slope;
@ -116,8 +119,16 @@ private:
return m_trans;
} // 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
unsigned int n = CheckManager::get()->getCheckStructureCount();
for (unsigned int i = 0; i < n; i++)
@ -191,7 +202,7 @@ private:
return false;
} // 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
// should do the job
@ -202,16 +213,17 @@ private:
// This is done by using Pythagorean Theorem and solving the
// equation from ball to goal center (y = (m_***_goal_slope) x)
// We aim 1 unit behind the ball (easier to solve),
// so 1 = sqrt (x2 + y2) and than x = sqrt (1 - y2)
// We aim behind the ball from the center of the ball to its
// 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)
// 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 y = 0.0f;
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)));
if (m_blue_goal_2.x() == 0.0f ||
(m_blue_goal_2.x() > 0.0f && m_blue_goal_2.z() > 0.0f) ||
@ -224,7 +236,7 @@ private:
}
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)));
if (m_red_goal_2.x() == 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(y));
// 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
}; // BallGoalData
@ -344,29 +357,28 @@ public:
}
// ------------------------------------------------------------------------
int getKartNode(unsigned int kart_id) const
{ return m_kart_on_node[kart_id]; }
{ return m_kart_on_node[kart_id]; }
// ------------------------------------------------------------------------
int getBallNode() const
{ return m_ball_on_node; }
{ return m_ball_on_node; }
// ------------------------------------------------------------------------
const Vec3& getBallPosition() const
{ return (Vec3&)m_ball_body->getCenterOfMassTransform().getOrigin(); }
// ------------------------------------------------------------------------
float getBallHeading() const
{ return m_ball_heading; }
{ return m_ball_heading; }
// ------------------------------------------------------------------------
float getBallDiameter() const
{ return m_bgd.getDiameter(); }
// ------------------------------------------------------------------------
bool ballApproachingGoal(SoccerTeam team) const
{
return m_bgd.isApproachingGoal(team);
}
{ return m_bgd.isApproachingGoal(team); }
// ------------------------------------------------------------------------
Vec3 getBallAimPosition(SoccerTeam team) const
{
return m_bgd.getAimPosition(team);
}
Vec3 getBallAimPosition(SoccerTeam team, bool reverse = false) const
{ return m_bgd.getAimPosition(team, reverse); }
// ------------------------------------------------------------------------
const btTransform& getBallTrans() const
{ return m_bgd.getTrans(); }
{ return m_bgd.getTrans(); }
// ------------------------------------------------------------------------
bool isCorrectGoal(unsigned int kart_id, bool first_goal) const;
// ------------------------------------------------------------------------

View File

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