First playable advanced soccer ai
This commit is contained in:
parent
748051871c
commit
d2f26fe70d
@ -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
|
||||
|
@ -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);
|
||||
|
@ -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)
|
||||
{
|
||||
|
@ -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; }
|
||||
|
@ -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
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
@ -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; }
|
||||
|
@ -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(),
|
||||
|
@ -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;
|
||||
// ------------------------------------------------------------------------
|
||||
|
@ -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; }
|
||||
|
Loading…
Reference in New Issue
Block a user