Add more defense
This commit is contained in:
parent
ae18983655
commit
a18c53f4e7
@ -230,16 +230,16 @@ Vec3 SoccerAI::determineBallAimingPosition()
|
|||||||
|
|
||||||
if (m_overtake_ball)
|
if (m_overtake_ball)
|
||||||
{
|
{
|
||||||
Vec3 overtake_wc;
|
Vec3 overtake_lc;
|
||||||
const bool can_overtake = determineOvertakePosition(ball_lc, ball_pos,
|
const bool can_overtake = determineOvertakePosition(ball_lc, aim_lc,
|
||||||
&overtake_wc);
|
ball_pos, &overtake_lc);
|
||||||
if (!can_overtake)
|
if (!can_overtake)
|
||||||
{
|
{
|
||||||
m_overtake_ball = false;
|
m_overtake_ball = false;
|
||||||
return ball_aim_pos;
|
return ball_aim_pos;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
return overtake_wc;
|
return m_kart->getTrans()(Vec3(overtake_lc));
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@ -248,11 +248,10 @@ Vec3 SoccerAI::determineBallAimingPosition()
|
|||||||
// is behind the ball , if so m_overtake_ball is true
|
// is behind the ball , if so m_overtake_ball is true
|
||||||
if (aim_lc.z() > 0 && aim_lc.z() > ball_lc.z())
|
if (aim_lc.z() > 0 && aim_lc.z() > ball_lc.z())
|
||||||
{
|
{
|
||||||
const bool can_overtake = determineOvertakePosition(ball_lc,
|
if (isOvertakable(ball_lc, ball_pos))
|
||||||
ball_pos, NULL);
|
|
||||||
if (can_overtake)
|
|
||||||
{
|
{
|
||||||
m_overtake_ball = true;
|
m_overtake_ball = true;
|
||||||
|
return ball_aim_pos;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@ -284,28 +283,13 @@ Vec3 SoccerAI::determineBallAimingPosition()
|
|||||||
} // determineBallAimingPosition
|
} // determineBallAimingPosition
|
||||||
|
|
||||||
//-----------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------
|
||||||
bool SoccerAI::determineOvertakePosition(const Vec3& ball_lc,
|
bool SoccerAI::isOvertakable(const Vec3& ball_lc, const posData& ball_pos)
|
||||||
const posData& ball_pos,
|
|
||||||
Vec3* overtake_wc)
|
|
||||||
{
|
{
|
||||||
// This done by drawing a circle using the center of ball local coordinates
|
|
||||||
// and the distance / 2 from kart to ball center as radius (which allows more
|
|
||||||
// offset for overtaking), then find tangent line from kart (0, 0, 0) to the
|
|
||||||
// circle. The intercept point will be used as overtake position
|
|
||||||
|
|
||||||
// No overtake if ball is behind
|
// No overtake if ball is behind
|
||||||
if (ball_lc.z() < 0.0f) return false;
|
if (ball_lc.z() < 0.0f) return false;
|
||||||
|
|
||||||
// Circle equation: (x-a)2 + (y-b)2 = r2
|
// Circle equation: (x-a)2 + (y-b)2 = r2
|
||||||
const float r2 = (ball_pos.distance / 2) * (ball_pos.distance / 2);
|
const float r2 = (ball_pos.distance / 2) * (ball_pos.distance / 2);
|
||||||
|
|
||||||
// No overtake if sqrtf(r2) / 2 < ball radius,
|
|
||||||
// which will likely push to ball forward
|
|
||||||
if ((sqrtf(r2) / 2) < (m_world->getBallDiameter() / 2))
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
const float a = ball_lc.x();
|
const float a = ball_lc.x();
|
||||||
const float b = ball_lc.z();
|
const float b = ball_lc.z();
|
||||||
|
|
||||||
@ -316,6 +300,23 @@ bool SoccerAI::determineOvertakePosition(const Vec3& ball_lc,
|
|||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
return true;
|
||||||
|
|
||||||
|
} // isOvertakable
|
||||||
|
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
bool SoccerAI::determineOvertakePosition(const Vec3& ball_lc,
|
||||||
|
const Vec3& aim_lc,
|
||||||
|
const posData& ball_pos,
|
||||||
|
Vec3* overtake_lc)
|
||||||
|
{
|
||||||
|
// This done by drawing a circle using the center of ball local coordinates
|
||||||
|
// and the distance / 2 from kart to ball center as radius (which allows more
|
||||||
|
// offset for overtaking), then find tangent line from kart (0, 0, 0) to the
|
||||||
|
// circle. The intercept point will be used as overtake position
|
||||||
|
|
||||||
|
// Check if overtakable at current location
|
||||||
|
if (!isOvertakable(ball_lc, ball_pos)) return false;
|
||||||
|
|
||||||
// Otherwise calculate the tangent
|
// Otherwise calculate the tangent
|
||||||
// As all are local coordinates, so center is 0,0 which is y = mx for the
|
// As all are local coordinates, so center is 0,0 which is y = mx for the
|
||||||
@ -329,6 +330,13 @@ bool SoccerAI::determineOvertakePosition(const Vec3& ball_lc,
|
|||||||
// (E2 - 4F)m2 + (2DE)m + (D2 - 4F) = 0
|
// (E2 - 4F)m2 + (2DE)m + (D2 - 4F) = 0
|
||||||
// Now solve the above quadratic equation using
|
// Now solve the above quadratic equation using
|
||||||
// x = -b (+/-) sqrt(b2 - 4ac) / 2a
|
// x = -b (+/-) sqrt(b2 - 4ac) / 2a
|
||||||
|
|
||||||
|
// Circle equation: (x-a)2 + (y-b)2 = r2
|
||||||
|
const float r = ball_pos.distance / 2;
|
||||||
|
const float r2 = r * r;
|
||||||
|
const float a = ball_lc.x();
|
||||||
|
const float b = ball_lc.z();
|
||||||
|
|
||||||
const float d = -2 * a;
|
const float d = -2 * a;
|
||||||
const float e = -2 * b;
|
const float e = -2 * b;
|
||||||
const float f = (d * d / 4) + (e * e / 4) - r2;
|
const float f = (d * d / 4) + (e * e / 4) - r2;
|
||||||
@ -336,13 +344,43 @@ bool SoccerAI::determineOvertakePosition(const Vec3& ball_lc,
|
|||||||
(4 * ((e * e) - (4 * f)) * ((d * d) - (4 * f)));
|
(4 * ((e * e) - (4 * f)) * ((d * d) - (4 * f)));
|
||||||
|
|
||||||
assert(discriminant > 0.0f);
|
assert(discriminant > 0.0f);
|
||||||
const float slope_1 = (-(2 * d * e) + sqrtf(discriminant)) /
|
float t_slope_1 = (-(2 * d * e) + sqrtf(discriminant)) /
|
||||||
(2 * ((e * e) - (4 * f)));
|
(2 * ((e * e) - (4 * f)));
|
||||||
const float slope_2 = (-(2 * d * e) - sqrtf(discriminant)) /
|
float t_slope_2 = (-(2 * d * e) - sqrtf(discriminant)) /
|
||||||
(2 * ((e * e) - (4 * f)));
|
(2 * ((e * e) - (4 * f)));
|
||||||
|
|
||||||
assert(!std::isnan(slope_1));
|
assert(!std::isnan(t_slope_1));
|
||||||
assert(!std::isnan(slope_2));
|
assert(!std::isnan(t_slope_2));
|
||||||
|
|
||||||
|
// Make the slopes in correct order, allow easier rotate later
|
||||||
|
float slope_1 = 0.0f;
|
||||||
|
float slope_2 = 0.0f;
|
||||||
|
if ((t_slope_1 > 0 && t_slope_2 > 0) || (t_slope_1 < 0 && t_slope_2 < 0))
|
||||||
|
{
|
||||||
|
if (t_slope_1 > t_slope_2)
|
||||||
|
{
|
||||||
|
slope_1 = t_slope_1;
|
||||||
|
slope_2 = t_slope_2;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
slope_1 = t_slope_2;
|
||||||
|
slope_2 = t_slope_1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (t_slope_1 > t_slope_2)
|
||||||
|
{
|
||||||
|
slope_1 = t_slope_2;
|
||||||
|
slope_2 = t_slope_1;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
slope_1 = t_slope_1;
|
||||||
|
slope_2 = t_slope_2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Calculate two intercept points, as we already put y=mx into circle
|
// Calculate two intercept points, as we already put y=mx into circle
|
||||||
// equation and know that only one root for each slope, so x can be
|
// equation and know that only one root for each slope, so x can be
|
||||||
@ -350,35 +388,78 @@ bool SoccerAI::determineOvertakePosition(const Vec3& ball_lc,
|
|||||||
// From (1+m2)x2 + (D+Em)x +F = 0:
|
// From (1+m2)x2 + (D+Em)x +F = 0:
|
||||||
const float x1 = -(d + (e * slope_1)) / (2 * (1 + (slope_1 * slope_1)));
|
const float x1 = -(d + (e * slope_1)) / (2 * (1 + (slope_1 * slope_1)));
|
||||||
const float x2 = -(d + (e * slope_2)) / (2 * (1 + (slope_2 * slope_2)));
|
const float x2 = -(d + (e * slope_2)) / (2 * (1 + (slope_2 * slope_2)));
|
||||||
|
const float y1 = slope_1 * x1;
|
||||||
|
const float y2 = slope_2 * x2;
|
||||||
|
|
||||||
// Use the closest point to aim
|
const Vec3 point1(x1, 0, y1);
|
||||||
float x = std::min(fabsf(x1), fabsf(x2));
|
const Vec3 point2(x2, 0, y2);
|
||||||
float y = 0.0f;
|
|
||||||
if (-x == x1)
|
const float d1 = (point1 - aim_lc).length_2d();
|
||||||
|
const float d2 = (point2 - aim_lc).length_2d();
|
||||||
|
|
||||||
|
// Use the tangent closest to the ball aiming position to aim
|
||||||
|
const bool use_tangent_one = d1 < d2;
|
||||||
|
|
||||||
|
// Adjust x and y if r < ball diameter,
|
||||||
|
// which will likely push to ball forward
|
||||||
|
// Notice: we cannot increase the radius before, as the kart location
|
||||||
|
// will likely lie inside the enlarged circle
|
||||||
|
if (r < m_world->getBallDiameter())
|
||||||
{
|
{
|
||||||
// x was negative
|
// Constuctor a equation using y = (rotateSlope(old_m)) x which is
|
||||||
x = -x;
|
// a less steep or steeper line, and find out the new adjusted position
|
||||||
y = slope_1 * x;
|
// using the distance to the original point * 2 at new line
|
||||||
}
|
|
||||||
else if (x == x1)
|
// Determine if the circle is drawn around the side of kart
|
||||||
{
|
// ie point1 or point2 z() < 0, if so reverse the below logic
|
||||||
y = slope_1 * x;
|
const float m = ((point1.z() < 0 || point2.z() < 0) ?
|
||||||
}
|
(use_tangent_one ? rotateSlope(slope_1, false/*rotate_up*/) :
|
||||||
else if (-x == x2)
|
rotateSlope(slope_2, true/*rotate_up*/)) :
|
||||||
{
|
(use_tangent_one ? rotateSlope(slope_1, true/*rotate_up*/) :
|
||||||
x = -x;
|
rotateSlope(slope_2, false/*rotate_up*/)));
|
||||||
y = slope_2 * x;
|
|
||||||
|
// Calculate new distance from kart to new adjusted position
|
||||||
|
const float dist = (use_tangent_one ? point1 : point2).length_2d() * 2;
|
||||||
|
const float dist2 = dist * dist;
|
||||||
|
|
||||||
|
// x2 + y2 = dist2
|
||||||
|
// so y = m * sqrtf (dist2 - y2)
|
||||||
|
// y = sqrtf(m2 * dist2 / (1 + m2))
|
||||||
|
const float y = sqrtf((m * m * dist2) / (1 + (m * m)));
|
||||||
|
const float x = y / m;
|
||||||
|
*overtake_lc = Vec3(x, 0, y);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
y = slope_2 * x;
|
// Use the calculated position depends on distance to aim position
|
||||||
|
if (use_tangent_one)
|
||||||
|
*overtake_lc = point1;
|
||||||
|
else
|
||||||
|
*overtake_lc = point2;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (overtake_wc)
|
|
||||||
*overtake_wc = m_kart->getTrans()(Vec3(x, 0, y));
|
|
||||||
return true;
|
return true;
|
||||||
} // determineOvertakePosition
|
} // determineOvertakePosition
|
||||||
|
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
float SoccerAI::rotateSlope(float old_slope, bool rotate_up)
|
||||||
|
{
|
||||||
|
const float theta = atan(old_slope) + (old_slope < 0 ? M_PI : 0);
|
||||||
|
float new_theta = theta + (rotate_up ? M_PI / 6 : -M_PI /6);
|
||||||
|
if (new_theta > ((M_PI / 2) - 0.02f) && new_theta < ((M_PI / 2) + 0.02f))
|
||||||
|
{
|
||||||
|
// Avoid almost tan 90
|
||||||
|
new_theta = (M_PI / 2) - 0.02f;
|
||||||
|
}
|
||||||
|
// Check if over-rotated
|
||||||
|
if (new_theta > M_PI)
|
||||||
|
new_theta = M_PI - 0.1f;
|
||||||
|
else if (new_theta < 0)
|
||||||
|
new_theta = 0.1f;
|
||||||
|
|
||||||
|
return tan(new_theta);
|
||||||
|
} // rotateSlope
|
||||||
|
|
||||||
//-----------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------
|
||||||
int SoccerAI::getCurrentNode() const
|
int SoccerAI::getCurrentNode() const
|
||||||
{
|
{
|
||||||
|
@ -55,8 +55,10 @@ private:
|
|||||||
bool m_steer_with_ball;
|
bool m_steer_with_ball;
|
||||||
|
|
||||||
Vec3 determineBallAimingPosition();
|
Vec3 determineBallAimingPosition();
|
||||||
bool determineOvertakePosition(const Vec3& ball_lc,
|
bool isOvertakable(const Vec3& ball_lc, const posData& ball_pos);
|
||||||
const posData& ball_pos, Vec3* overtake_wc);
|
bool determineOvertakePosition(const Vec3& ball_lc, const Vec3& aim_lc,
|
||||||
|
const posData& ball_pos, Vec3* overtake_lc);
|
||||||
|
float rotateSlope(float old_slope, bool rotate_up);
|
||||||
|
|
||||||
virtual void findClosestKart(bool use_difficulty);
|
virtual void findClosestKart(bool use_difficulty);
|
||||||
virtual void findTarget();
|
virtual void findTarget();
|
||||||
|
Loading…
x
Reference in New Issue
Block a user