This commit is contained in:
auria.mg 2016-05-11 19:35:08 -04:00
commit dc885fbf05
22 changed files with 349 additions and 268 deletions

View File

@ -4,7 +4,7 @@ out vec4 FragColor;
void main(void)
{
vec3 eyedir = vec3(gl_FragCoord.xy / screen, 1.);
vec3 eyedir = vec3(mod(gl_FragCoord.xy, screen) / screen, 1.);
eyedir = 2.0 * eyedir - 1.0;
vec4 tmp = (InverseProjectionMatrix * vec4(eyedir, 1.));
tmp /= tmp.w;

View File

@ -8,28 +8,28 @@
<summary>A racing game</summary>
<description>
<p>
SuperTuxKart is a fun 3D kart racing game.
You can play with up to 4 friends on one PC, racing against each other or
just try to beat the computer.
Supertuxkart is a free 3D kart racing game, with a focus on having fun over
realism. You can play with up to 4 friends on one PC, racing against each
other, or try to beat the computer in single-player mode.
</p>
<p>
See the great lighthouse or drive through the sand and visit the pyramids.
Race underground or in space, watching the stars passing by.
Have some rest under the palms on the beach (watching the other karts
overtaking you :) ).
But don't eat the bananas! Watch for bowling balls, plungers, bubble gum
and cakes thrown by opponents.
Race underground or in space, watching the stars pass by. Or rest under the
palm trees on the beach, watching the other karts overtake you. But don't eat
the bananas! Watch for bowling balls, plungers, bubble gum and cakes thrown by
your opponents.
</p>
<p>
You can do a single race against other karts, compete in one of several
Grand Prix, try to beat the high score in time trials on your own, play
battle mode against your friends, and more!
You can do a single race against other karts, compete in one of several Grand
Prix, try to beat the high score in time trials on your own, play battle mode
against the computer or your friends, and more!
</p>
</description>
<url type="homepage">http://supertuxkart.sourceforge.net/</url>
<screenshots>
<screenshot type="default">http://supertuxkart.sourceforge.net/persistent/images/4/4d/SuperTuxKart_0.8_screenshot.jpg</screenshot>
<screenshot>http://supertuxkart.sourceforge.net/persistent/images/1/1f/SuperTuxKart_0.8_screenshot4.jpg</screenshot>
<screenshot type="default">http://supertuxkart.sourceforge.net/persistent/images/4/4e/Supertuxkart-0.9-screenshot-2.jpg</screenshot>
<screenshot>http://supertuxkart.sourceforge.net/persistent/images/a/a9/Supertuxkart-0.9-screenshot-1.jpg</screenshot>
<screenshot>http://supertuxkart.sourceforge.net/persistent/images/6/63/Supertuxkart-0.9-screenshot-3.jpg</screenshot>
</screenshots>
<updatecontact>supertuxkart-devel@lists.sourceforge.net</updatecontact>
</application>

View File

@ -289,17 +289,18 @@ void AIBaseController::checkPosition(const Vec3 &point,
{
// 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 - m_kart->getXYZ();
Vec3 local_coordinates = quatRotate(q, p);
// Save local coordinates for later use if needed
if (lc) *lc = local_coordinates;
// on_side: tell whether it's left or right hand side
if (pos_data == NULL) return;
// lhs: tell whether it's left or right hand side
if (local_coordinates.getX() < 0)
pos_data->on_side = true;
pos_data->lhs = true;
else
pos_data->on_side = false;
pos_data->lhs = false;
// behind: tell whether it's behind or not
if (local_coordinates.getZ() < 0)

View File

@ -65,7 +65,7 @@ protected:
static int m_test_ai;
/** Position info structure of targets. */
struct posData {bool behind; bool on_side; float angle; float distance;};
struct posData {bool behind; bool lhs; float angle; float distance;};
void setControllerName(const std::string &name);
float steerToPoint(const Vec3 &point);

View File

@ -33,6 +33,7 @@ ArenaAI::ArenaAI(AbstractKart *kart)
: AIBaseController(kart)
{
m_debug_sphere = NULL;
m_debug_sphere_next = NULL;
} // ArenaAI
//-----------------------------------------------------------------------------
@ -242,7 +243,7 @@ void ArenaAI::handleArenaSteering(const float dt)
#endif
if (m_cur_kart_pos_data.behind)
{
m_adjusting_side = m_cur_kart_pos_data.on_side;
m_adjusting_side = m_cur_kart_pos_data.lhs;
m_is_uturn = true;
}
else
@ -262,11 +263,22 @@ void ArenaAI::handleArenaSteering(const float dt)
checkPosition(m_target_point, &m_cur_kart_pos_data);
#ifdef AI_DEBUG
m_debug_sphere->setPosition(m_target_point.toIrrVector());
if (m_path_corners.size() > 2)
{
m_debug_sphere->setVisible(true);
m_debug_sphere_next->setVisible(true);
m_debug_sphere->setPosition(m_path_corners[1].toIrrVector());
m_debug_sphere_next->setPosition(m_path_corners[2].toIrrVector());
}
else
{
m_debug_sphere->setVisible(false);
m_debug_sphere_next->setVisible(false);
}
#endif
if (m_cur_kart_pos_data.behind)
{
m_adjusting_side = m_cur_kart_pos_data.on_side;
m_adjusting_side = m_cur_kart_pos_data.lhs;
m_is_uturn = true;
}
else
@ -306,7 +318,7 @@ void ArenaAI::handleArenaBanana()
{
// Check whether it's straight ahead towards a banana
// If so, adjust target point
banana_lc = (banana_pos.on_side ? banana_lc + Vec3 (2, 0, 0) :
banana_lc = (banana_pos.lhs ? banana_lc + Vec3 (2, 0, 0) :
banana_lc - Vec3 (2, 0, 0));
m_target_point = m_kart->getTrans()(banana_lc);
m_target_node = BattleGraph::get()
@ -478,28 +490,25 @@ void ArenaAI::stringPull(const Vec3& start_pos, const Vec3& end_pos)
*/
void ArenaAI::handleArenaBraking()
{
m_controls->m_brake = false;
if (getCurrentNode() == BattleGraph::UNKNOWN_POLY ||
m_target_node == BattleGraph::UNKNOWN_POLY) return;
// A kart will not brake when the speed is already slower than this
// value. This prevents a kart from going too slow (or even backwards)
// in tight curves.
const float MIN_SPEED = 5.0f;
std::vector<Vec3> points;
if (forceBraking() && m_kart->getSpeed() > MIN_SPEED)
{
// Brake now
return;
}
points.push_back(m_kart->getXYZ());
points.push_back(m_path_corners[0]);
points.push_back((m_path_corners.size()>=2) ? m_path_corners[1] : m_path_corners[0]);
m_controls->m_brake = false;
float current_curve_radius = determineTurnRadius(points);
if (getCurrentNode() == BattleGraph::UNKNOWN_POLY ||
m_target_node == BattleGraph::UNKNOWN_POLY) return;
Vec3 d1 = m_kart->getXYZ() - m_target_point;
Vec3 d2 = m_kart->getXYZ() - m_path_corners[0];
if (d1.length2_2d() < d2.length2_2d())
current_curve_radius = d1.length_2d();
float current_curve_radius = determineTurnRadius(m_kart->getXYZ(),
m_path_corners[0], (m_path_corners.size() >= 2 ? m_path_corners[1] :
m_path_corners[0]));
float max_turn_speed = m_kart->getSpeedForTurnRadius(current_curve_radius);
@ -516,55 +525,44 @@ void ArenaAI::handleArenaBraking()
* location of AI, first corner and the second corner. Once the constants are
* computed, a formula is used to find the radius of curvature at the kart's
* current location.
* NOTE: This method does not apply enough braking, should think of something
* else.
*/
float ArenaAI::determineTurnRadius( std::vector<Vec3>& points )
float ArenaAI::determineTurnRadius(const Vec3& p1, const Vec3& p2,
const Vec3& p3)
{
// Declaring variables
float a, b;
irr::core::CMatrix4<float> A;
irr::core::CMatrix4<float> X;
irr::core::CMatrix4<float> B;
// The parabola function is as following: y=ax2+bx+c
// No need to calculate c as after differentiating c will be zero
const float eps = 0.01f;
const float denominator = (p1.x() - p2.x()) * (p1.x() - p3.x()) *
(p2.x() - p3.x());
//Populating matrices
for (unsigned int i = 0; i < 3; i++)
{
A(i, 0) = points[i].x()*points[i].x();
A(i, 1) = points[i].x();
A(i, 2) = 1.0f;
A(i, 3) = 0.0f;
}
A(3, 0) = A(3, 1) = A(3, 2) = 0.0f;
A(3, 3) = 1.0f;
// Avoid nan, this will happen if three values of coordinates x are too
// close together, ie a straight line, return a large radius
// so no braking is needed
if (fabsf(denominator) < eps) return 25.0f;
for (unsigned int i = 0; i < 3; i++)
{
B(i, 0) = points[i].z();
B(i, 1) = 0.0f;
B(i, 2) = 0.0f;
B(i, 3) = 0.0f;
}
B(3, 0) = B(3, 1) = B(3, 2) = B(3, 3) = 0.0f;
const float a = (p3.x() * (p2.z() - p1.z()) +
p2.x() * (p1.z() - p3.z()) +
p1.x() * (p3.z() - p2.z())) / denominator;
//Computing inverse : X = inv(A)*B
irr::core::CMatrix4<float> invA;
if (!A.getInverse(invA))
return -1;
// Should not happen, otherwise y=c which is a straight line
if (fabsf(a) < eps) return 25.0f;
X = invA*B;
a = X(0, 0);
b = X(0, 1);
//c = X(0, 2);
const float b = (p3.x() * p3.x() * (p1.z() - p2.z()) +
p2.x() * p2.x() * (p3.z() - p1.z()) +
p1.x() * p1.x() * (p2.z() - p3.z())) / denominator;
float x = points.front().x();
//float z = a*pow(x, 2) + b*x + c;
float dx_by_dz = 2*a*x + b;
float d2x_by_dz = 2*a;
// Differentiate the function, so y=ax2+bx+c will become y=2ax+b for dy_dx,
// y=2a for d2y_dx2
// Use the p1 (current location of AI) as x
const float dy_dx = 2 * a * p1.x() + b;
const float d2y_dx2 = 2 * a;
float radius = pow(abs(1 + pow(dx_by_dz, 2)), 1.5f)/ abs(d2x_by_dz);
// Calculate the radius of curvature at current location of AI
const float radius = pow(1 + pow(dy_dx, 2), 1.5f) / fabsf(d2y_dx2);
assert(!std::isnan(radius));
return radius;
// Avoid returning too large radius
return (radius > 25.0f ? 25.0f : radius);
} // determineTurnRadius
//-----------------------------------------------------------------------------
@ -663,7 +661,8 @@ void ArenaAI::handleArenaItems(const float dt)
if (m_time_since_last_shot < 1.0f) break;
if (m_closest_kart_pos_data.distance < 6.0f &&
(difficulty || perfect_aim))
(difficulty || perfect_aim) &&
!m_closest_kart->isInvulnerable())
{
m_controls->m_fire = true;
m_controls->m_look_back = fire_behind;

View File

@ -56,6 +56,7 @@ protected:
/** For debugging purpose: a sphere indicating where the AI
* is targeting at. */
irr::scene::ISceneNode *m_debug_sphere;
irr::scene::ISceneNode *m_debug_sphere_next;
/** The node(poly) at which the target point lies in. */
int m_target_node;
@ -104,7 +105,8 @@ private:
float m_time_since_uturn;
void checkIfStuck(const float dt);
float determineTurnRadius(std::vector<Vec3>& points);
float determineTurnRadius(const Vec3& p1, const Vec3& p2,
const Vec3& p3);
void findPortals(int start, int end);
void handleArenaAcceleration(const float dt);
void handleArenaBanana();
@ -118,6 +120,7 @@ private:
virtual bool isWaiting() const = 0;
virtual void findClosestKart(bool use_difficulty) = 0;
virtual void findTarget() = 0;
virtual bool forceBraking() { return false; }
public:
ArenaAI(AbstractKart *kart);
virtual ~ArenaAI() {};

View File

@ -41,8 +41,11 @@ BattleAI::BattleAI(AbstractKart *kart)
#ifdef AI_DEBUG
video::SColor col_debug(128, 128, 0, 0);
video::SColor col_debug_next(128, 0, 128, 128);
m_debug_sphere = irr_driver->addSphere(1.0f, col_debug);
m_debug_sphere->setVisible(true);
m_debug_sphere_next = irr_driver->addSphere(1.0f, col_debug_next);
m_debug_sphere_next->setVisible(true);
#endif
m_world = dynamic_cast<ThreeStrikesBattle*>(World::getWorld());
m_track = m_world->getTrack();
@ -59,6 +62,7 @@ BattleAI::~BattleAI()
{
#ifdef AI_DEBUG
irr_driver->removeNode(m_debug_sphere);
irr_driver->removeNode(m_debug_sphere_next);
#endif
} // ~BattleAI
@ -157,12 +161,12 @@ void BattleAI::findTarget()
}
} // findTarget
// ------------------------------------------------------------------------
//-----------------------------------------------------------------------------
int BattleAI::getCurrentNode() const
{
return m_world->getKartNode(m_kart->getWorldKartId());
} // getCurrentNode
// ------------------------------------------------------------------------
//-----------------------------------------------------------------------------
bool BattleAI::isWaiting() const
{
return m_world->isStartPhase();

View File

@ -41,11 +41,15 @@ SoccerAI::SoccerAI(AbstractKart *kart)
#ifdef AI_DEBUG
video::SColor col_debug(128, 128, 0, 0);
video::SColor col_debug_next(128, 0, 128, 128);
m_debug_sphere = irr_driver->addSphere(1.0f, col_debug);
m_debug_sphere->setVisible(true);
m_debug_sphere_next = irr_driver->addSphere(1.0f, col_debug_next);
m_debug_sphere_next->setVisible(true);
#endif
m_world = dynamic_cast<SoccerWorld*>(World::getWorld());
m_track = m_world->getTrack();
m_cur_team = m_world->getKartTeam(m_kart->getWorldKartId());
// Don't call our own setControllerName, since this will add a
// billboard showing 'AIBaseController' to the kart.
@ -59,6 +63,7 @@ SoccerAI::~SoccerAI()
{
#ifdef AI_DEBUG
irr_driver->removeNode(m_debug_sphere);
irr_driver->removeNode(m_debug_sphere_next);
#endif
} // ~SoccerAI
@ -71,31 +76,15 @@ void SoccerAI::reset()
AIBaseController::reset();
m_saving_ball = false;
if (race_manager->getNumPlayers() == 1)
{
// Same handle in SoccerWorld::createKart
if (race_manager->getKartInfo(0).getSoccerTeam() == SOCCER_TEAM_RED)
{
m_cur_team = (m_kart->getWorldKartId() % 2 == 0 ?
SOCCER_TEAM_BLUE : SOCCER_TEAM_RED);
}
else
{
m_cur_team = (m_kart->getWorldKartId() % 2 == 0 ?
SOCCER_TEAM_RED : SOCCER_TEAM_BLUE);
}
}
else
{
m_cur_team = (m_kart->getWorldKartId() % 2 == 0 ?
SOCCER_TEAM_BLUE : SOCCER_TEAM_RED);
}
m_force_brake = false;
} // reset
//-----------------------------------------------------------------------------
void SoccerAI::update(float dt)
{
m_saving_ball = false;
m_force_brake = false;
if (World::getWorld()->getPhase() == World::GOAL_PHASE)
{
m_controls->m_brake = false;
@ -147,8 +136,8 @@ void SoccerAI::findClosestKart(bool use_difficulty)
void SoccerAI::findTarget()
{
// Check whether any defense is needed
if ((m_world->getBallPosition() - NavMesh::get()->getNavPoly(m_world
->getGoalNode(m_cur_team)).getCenter()).length_2d() < 50.0f &&
if ((m_world->getBallPosition() - m_world->getGoalLocation(m_cur_team,
CheckGoal::POINT_CENTER)).length_2d() < 50.0f &&
m_world->getDefender(m_cur_team) == (signed)m_kart->getWorldKartId())
{
m_target_node = m_world->getBallNode();
@ -174,86 +163,110 @@ Vec3 SoccerAI::correctBallPosition(const Vec3& orig_pos)
{
// Notice: Build with AI_DEBUG and change camera target to an AI kart,
// to debug or see how AI steer with the ball
posData ball_pos = {0};
posData goal_pos = {0};
Vec3 ball_lc(0, 0, 0);
Vec3 ball_lc;
checkPosition(orig_pos, &ball_pos, &ball_lc);
// opposite team goal
checkPosition(NavMesh::get()->getNavPoly(m_world
->getGoalNode(m_cur_team == SOCCER_TEAM_BLUE ?
SOCCER_TEAM_RED : SOCCER_TEAM_BLUE)).getCenter(), &goal_pos);
// Too far / behind from the ball,
// use path finding from arena ai to get close
if (!(ball_pos.distance < 3.0f) || ball_pos.behind) return orig_pos;
if (goal_pos.behind)
// Save the opposite team
SoccerTeam opp_team = (m_cur_team == SOCCER_TEAM_BLUE ?
SOCCER_TEAM_RED : SOCCER_TEAM_BLUE);
// Prevent lost control when steering with ball
const bool need_braking = ball_pos.angle > 0.1f &&
m_kart->getSpeed() > 9.0f && ball_pos.distance <2.5f;
// Goal / own goal detection first, as different aiming method will be used
const bool likely_to_goal =
ball_pos.angle < 0.2f && isLikelyToGoal(opp_team);
if (likely_to_goal)
{
if (goal_pos.angle > 0.3f && ball_pos.distance < 3.0f &&
!ball_pos.behind)
if (need_braking)
{
// 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));
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);
m_controls->m_brake = true;
m_force_brake = true;
// Prevent keep pushing by aiming a nearer point
return m_kart->getTrans()(ball_lc - Vec3(0, 0, 1));
}
// Keep pushing the ball straight to the goal
return orig_pos;
}
if (ball_pos.distance < 3.0f &&
!ball_pos.behind && !goal_pos.behind)
const bool likely_to_own_goal =
ball_pos.angle < 0.2f && isLikelyToGoal(m_cur_team);
if (likely_to_own_goal)
{
if (goal_pos.angle < 0.5f)
return orig_pos;
else
{
// 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;
}
// It's getting likely to own goal, apply more
// offset for skidding, to save the ball from behind
// scored.
if (m_cur_difficulty == RaceManager::DIFFICULTY_HARD ||
m_cur_difficulty == RaceManager::DIFFICULTY_BEST)
m_saving_ball = true;
return m_kart->getTrans()(ball_pos.lhs ?
ball_lc - Vec3(2, 0, 0) + Vec3(0, 0, 2) :
ball_lc + Vec3(2, 0, 2));
}
return orig_pos;
// Now try to make the ball face towards the goal
// Aim at upper/lower left/right corner of ball depends on location
posData goal_pos = {0};
checkPosition(m_world->getGoalLocation(opp_team, CheckGoal::POINT_CENTER),
&goal_pos);
Vec3 corrected_pos;
if (ball_pos.lhs && goal_pos.lhs)
{
corrected_pos = ball_lc + Vec3(1, 0, 1);
}
else if (!ball_pos.lhs && !goal_pos.lhs)
{
corrected_pos = ball_lc - Vec3(1, 0, 0) + Vec3(0, 0, 1);
}
else if (!ball_pos.lhs && goal_pos.lhs)
{
corrected_pos = ball_lc + Vec3(1, 0, 0) - Vec3(0, 0, 1);
}
else
{
corrected_pos = ball_lc - Vec3(1, 0, 1);
}
if (need_braking)
{
m_controls->m_brake = true;
m_force_brake = true;
}
return m_kart->getTrans()(corrected_pos);
} // correctBallPosition
// ------------------------------------------------------------------------
//-----------------------------------------------------------------------------
bool SoccerAI::isLikelyToGoal(SoccerTeam team) const
{
// Use local coordinate for easy compare
Vec3 first_pos;
Vec3 last_pos;
checkPosition(m_world->getGoalLocation(team, CheckGoal::POINT_FIRST),
NULL, &first_pos);
checkPosition(m_world->getGoalLocation(team, CheckGoal::POINT_LAST),
NULL, &last_pos);
// If the kart lies between the first and last pos, and faces
// in front of them, than it's likely to goal
if ((first_pos.z() > 0.0f && last_pos.z() > 0.0f) &&
((first_pos.x() < 0.0f && last_pos.x() > 0.0f) ||
(last_pos.x() < 0.0f && first_pos.x() > 0.0f)))
return true;
return false;
} // isLikelyToGoal
//-----------------------------------------------------------------------------
int SoccerAI::getCurrentNode() const
{
return m_world->getKartNode(m_kart->getWorldKartId());
} // getCurrentNode
// ------------------------------------------------------------------------
//-----------------------------------------------------------------------------
bool SoccerAI::isWaiting() const
{
return m_world->isStartPhase();

View File

@ -36,14 +36,17 @@ private:
SoccerTeam m_cur_team;
bool m_saving_ball;
bool m_force_brake;
Vec3 correctBallPosition(const Vec3&);
bool isLikelyToGoal(SoccerTeam team) const;
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; }
virtual bool forceBraking() OVERRIDE { return m_force_brake; }
public:
SoccerAI(AbstractKart *kart);
~SoccerAI();

View File

@ -30,7 +30,6 @@
#include "karts/controller/soccer_ai.hpp"
#include "physics/physics.hpp"
#include "states_screens/race_gui_base.hpp"
#include "tracks/check_goal.hpp"
#include "tracks/check_manager.hpp"
#include "tracks/track.hpp"
#include "tracks/track_object_manager.hpp"
@ -54,6 +53,8 @@ SoccerWorld::SoccerWorld() : WorldWithRank()
}
m_use_highscores = false;
m_red_ai = 0;
m_blue_ai = 0;
} // SoccerWorld
//-----------------------------------------------------------------------------
@ -76,8 +77,11 @@ void SoccerWorld::init()
m_display_rank = false;
m_goal_timer = 0.0f;
m_ball_hitter = -1;
m_red_check_goal = NULL;
m_blue_check_goal = NULL;
m_goal_target = race_manager->getMaxGoal();
m_goal_sound = SFXManager::get()->createSoundSource("goal_scored");
initGoal();
} // init
@ -129,8 +133,7 @@ void SoccerWorld::reset()
}
initKartList();
resetAllNodes();
initGoalNodes();
resetAllPosition();
resetBall();
} // reset
@ -355,22 +358,10 @@ AbstractKart *SoccerWorld::createKart(const std::string &kart_ident, int index,
if (kart_type == RaceManager::KT_AI)
{
if (race_manager->getNumPlayers() == 1)
{
// Make AI even when single player choose a different team
if (race_manager->getKartInfo(0).getSoccerTeam() == SOCCER_TEAM_RED)
{
team = (index % 2 == 0 ? SOCCER_TEAM_BLUE : SOCCER_TEAM_RED);
}
else
{
team = (index % 2 == 0 ? SOCCER_TEAM_RED : SOCCER_TEAM_BLUE);
}
}
if (index < m_red_ai)
team = SOCCER_TEAM_RED;
else
{
team = (index % 2 == 0 ? SOCCER_TEAM_BLUE : SOCCER_TEAM_RED);
}
team = SOCCER_TEAM_BLUE;
m_kart_team_map[index] = team;
}
else
@ -484,9 +475,7 @@ void SoccerWorld::updateBallPosition(float dt)
} // updateBallPosition
//-----------------------------------------------------------------------------
/** Localize two goals on the navigation mesh.
*/
void SoccerWorld::initGoalNodes()
void SoccerWorld::initGoal()
{
if (!m_track->hasNavMesh()) return;
@ -500,20 +489,18 @@ void SoccerWorld::initGoalNodes()
{
if (goal->getTeam())
{
m_blue_goal_node = BattleGraph::get()->pointToNode(m_blue_goal_node,
goal->convertTo3DCenter(), true/*ignore_vertical*/);
m_blue_check_goal = goal;
}
else
{
m_red_goal_node = BattleGraph::get()->pointToNode(m_red_goal_node,
goal->convertTo3DCenter(), true/*ignore_vertical*/);
m_red_check_goal = goal;
}
}
}
} // initGoalNodes
} // initGoal
//-----------------------------------------------------------------------------
void SoccerWorld::resetAllNodes()
void SoccerWorld::resetAllPosition()
{
m_kart_on_node.clear();
m_kart_on_node.resize(m_karts.size());
@ -521,9 +508,7 @@ void SoccerWorld::resetAllNodes()
m_kart_on_node[n] = BattleGraph::UNKNOWN_POLY;
m_ball_on_node = BattleGraph::UNKNOWN_POLY;
m_ball_position = Vec3(0, 0, 0);
m_red_goal_node = BattleGraph::UNKNOWN_POLY;
m_blue_goal_node = BattleGraph::UNKNOWN_POLY;
} // resetAllNodes
} // resetAllPosition
//-----------------------------------------------------------------------------
SoccerTeam SoccerWorld::getKartTeam(unsigned int kart_id) const
{
@ -571,9 +556,8 @@ void SoccerWorld::updateDefenders()
getKartTeam(m_karts[i]->getWorldKartId()) != SOCCER_TEAM_RED)
continue;
Vec3 d = NavMesh::get()->getNavPoly(this
->getGoalNode(SOCCER_TEAM_RED)).getCenter()
- m_karts[i]->getXYZ();
Vec3 d = this->getGoalLocation(SOCCER_TEAM_RED,
CheckGoal::POINT_CENTER) - m_karts[i]->getXYZ();
if (d.length_2d() <= distance)
{
@ -593,9 +577,8 @@ void SoccerWorld::updateDefenders()
getKartTeam(m_karts[i]->getWorldKartId()) != SOCCER_TEAM_BLUE)
continue;
Vec3 d = NavMesh::get()->getNavPoly(this
->getGoalNode(SOCCER_TEAM_BLUE)).getCenter()
- m_karts[i]->getXYZ();
Vec3 d = this->getGoalLocation(SOCCER_TEAM_BLUE,
CheckGoal::POINT_CENTER) - m_karts[i]->getXYZ();
if (d.length_2d() <= distance)
{
@ -642,3 +625,52 @@ void SoccerWorld::resetBall()
m_ball->reset();
m_ball->getPhysicalObject()->reset();
} // resetBall
//-----------------------------------------------------------------------------
void SoccerWorld::setAITeam()
{
const int total_player = race_manager->getNumPlayers();
const int total_karts = race_manager->getNumberOfKarts();
// No AI
if ((total_karts - total_player) == 0) return;
int red_player = 0;
int blue_player = 0;
for (int i = 0; i < total_player; i++)
{
SoccerTeam team = race_manager->getKartInfo(i).getSoccerTeam();
assert(team != SOCCER_TEAM_NONE);
team == SOCCER_TEAM_BLUE ? blue_player++ : red_player++;
}
int available_ai = total_karts - red_player - blue_player;
while (available_ai > 0)
{
if ((m_red_ai + red_player) > (m_blue_ai + blue_player))
{
m_blue_ai++;
available_ai--;
}
else if ((m_blue_ai + blue_player) > (m_red_ai + red_player))
{
m_red_ai++;
available_ai--;
}
else if ((m_blue_ai + blue_player) == (m_red_ai + red_player))
{
blue_player > red_player ? m_red_ai++ : m_blue_ai++;
available_ai--;
}
}
Log::debug("SoccerWorld","blue AI: %d red AI: %d", m_blue_ai, m_red_ai);
} // setAITeam
//-----------------------------------------------------------------------------
const Vec3& SoccerWorld::getGoalLocation(SoccerTeam team,
CheckGoal::PointLocation point) const
{
return (team == SOCCER_TEAM_BLUE ? m_blue_check_goal->getPoint(point) :
m_red_check_goal->getPoint(point));
} // getGoalLocation

View File

@ -22,6 +22,7 @@
#include "modes/world_with_rank.hpp"
#include "states_screens/race_gui_base.hpp"
#include "karts/abstract_kart.hpp"
#include "tracks/check_goal.hpp"
#include <IMesh.h>
#include <string>
@ -85,22 +86,26 @@ private:
std::vector<int> m_kart_on_node;
int m_ball_on_node;
Vec3 m_ball_position;
int m_red_goal_node;
int m_blue_goal_node;
CheckGoal* m_red_check_goal;
CheckGoal* m_blue_check_goal;
int m_red_defender;
int m_blue_defender;
int m_red_ai;
int m_blue_ai;
/** Set the team for the karts */
void initKartList();
/** Function to init the locations of two goals on the polygon map */
void initGoalNodes();
/** Function to save check goal for the getting of coordinate */
void initGoal();
/** Function to update the locations of all karts on the polygon map */
void updateKartNodes();
/** Function to update the location the ball on the polygon map */
void updateBallPosition(float dt);
/** Clean up */
void resetAllNodes();
void resetAllPosition();
/** Reset the ball to original starting position. */
void resetBall();
/** Function to update the AI which is the closest to its goal to defend. */
@ -166,17 +171,18 @@ public:
const Vec3& getBallPosition() const
{ return m_ball_position; }
// ------------------------------------------------------------------------
const int getGoalNode(SoccerTeam team) const
{
return (team == SOCCER_TEAM_BLUE ? m_blue_goal_node : m_red_goal_node);
}
// ------------------------------------------------------------------------
bool isCorrectGoal(unsigned int kart_id, bool first_goal) const;
// ------------------------------------------------------------------------
const int getDefender(SoccerTeam team) const
{
return (team == SOCCER_TEAM_BLUE ? m_blue_defender : m_red_defender);
}
// ------------------------------------------------------------------------
void setAITeam();
// ------------------------------------------------------------------------
const Vec3& getGoalLocation(SoccerTeam team,
CheckGoal::PointLocation point) const;
// ------------------------------------------------------------------------
}; // SoccerWorld

View File

@ -42,6 +42,7 @@
#include "karts/kart_properties_manager.hpp"
#include "modes/overworld.hpp"
#include "modes/profile_world.hpp"
#include "modes/soccer_world.hpp"
#include "network/network_config.hpp"
#include "physics/btKart.hpp"
#include "physics/physics.hpp"
@ -191,6 +192,11 @@ void World::init()
m_karts.push_back(ReplayPlay::get()->getGhostKart(k));
}
// Assign team of AIs for soccer mode before createKart
SoccerWorld* sw = dynamic_cast<SoccerWorld*>(this);
if (sw)
sw->setAITeam();
for(unsigned int i=0; i<num_karts; i++)
{
if (race_manager->getKartType(i) == RaceManager::KT_GHOST) continue;

View File

@ -329,7 +329,7 @@ void GrandPrixData::reload()
throw std::runtime_error("Missing track id");
}
if (number_of_laps < 1)
if (number_of_laps < 1 && !UserConfigParams::m_artist_debug_mode)
{
Log::error("GrandPrixData",
"Track '%s' in the Grand Prix file '%s' should be raced "

View File

@ -148,8 +148,6 @@ EventPropagation FocusDispatcher::focused(const int player_id)
return GUIEngine::EVENT_LET;
} // focused
static FocusDispatcher *g_dispatcher = NULL;
#if 0
#pragma mark -
#pragma mark KartHoverListener
@ -229,6 +227,7 @@ bool sameKart(const PlayerKartWidget& player1, const PlayerKartWidget& player2)
KartSelectionScreen::KartSelectionScreen(const char* filename) : Screen(filename)
{
m_dispatcher = NULL;
m_removed_widget = NULL;
m_multiplayer_message = NULL;
m_from_overworld = false;
@ -246,8 +245,8 @@ KartSelectionScreen* KartSelectionScreen::getRunningInstance()
void KartSelectionScreen::loadedFromFile()
{
g_dispatcher = new FocusDispatcher(this);
m_first_widget = g_dispatcher;
m_dispatcher = new FocusDispatcher(this);
m_first_widget = m_dispatcher;
m_game_master_confirmed = false;
m_multiplayer_message = NULL;
// Dynamically add tabs
@ -305,6 +304,7 @@ void KartSelectionScreen::beforeAddingWidget()
void KartSelectionScreen::init()
{
m_instance_ptr = this;
Screen::init();
m_must_delete_on_back = false;
@ -318,17 +318,17 @@ void KartSelectionScreen::init()
// FIXME : The reserved id value is -1 when we switch from KSS to NKSS and vice-versa
g_dispatcher->setRootID(placeholder->m_reserved_id);
m_dispatcher->setRootID(placeholder->m_reserved_id);
g_root_id = placeholder->m_reserved_id;
if (!m_widgets.contains(g_dispatcher))
if (!m_widgets.contains(m_dispatcher))
{
m_widgets.push_back(g_dispatcher);
m_widgets.push_back(m_dispatcher);
// this is only needed if the dispatcher wasn't already in
// the list of widgets. If it already was, it was added along
// other widgets.
g_dispatcher->add();
m_dispatcher->add();
}
m_game_master_confirmed = false;
@ -426,7 +426,7 @@ void KartSelectionScreen::tearDown()
void KartSelectionScreen::unloaded()
{
// these pointer is no more valid (have been deleted along other widgets)
g_dispatcher = NULL;
m_dispatcher = NULL;
}
// ----------------------------------------------------------------------------
@ -439,7 +439,7 @@ bool KartSelectionScreen::joinPlayer(InputDevice* device)
Log::info("KartSelectionScreen", "joinPlayer() invoked");
if (!m_multiplayer && !first_player) return false;
assert (g_dispatcher != NULL);
assert (m_dispatcher != NULL);
DynamicRibbonWidget* w = getWidget<DynamicRibbonWidget>("karts");
if (w == NULL)

View File

@ -36,6 +36,7 @@ namespace Online
class OnlineProfile;
}
class FocusDispatcher;
class InputDevice;
class KartHoverListener;
@ -79,6 +80,8 @@ protected:
/** Message shown in multiplayer mode */
GUIEngine::BubbleWidget* m_multiplayer_message;
FocusDispatcher *m_dispatcher;
KartSelectionScreen(const char* filename);
/** Called when all players selected their kart */

View File

@ -37,6 +37,7 @@
#include "modes/cutscene_world.hpp"
#include "modes/overworld.hpp"
#include "modes/demo_world.hpp"
#include "network/network_config.hpp"
#include "online/request_manager.hpp"
#include "states_screens/addons_screen.hpp"
#include "states_screens/credits.hpp"
@ -385,7 +386,8 @@ void MainMenuScreen::eventCallback(Widget* widget, const std::string& name,
#endif
if (selection == "new")
{
KartSelectionScreen* s = OfflineKartSelectionScreen::getInstance(); //FIXME : that was for tests
NetworkConfig::get()->unsetNetworking();
KartSelectionScreen* s = OfflineKartSelectionScreen::getInstance();
s->setMultiplayer(false);
s->setFromOverworld(false);
s->push();
@ -393,6 +395,7 @@ void MainMenuScreen::eventCallback(Widget* widget, const std::string& name,
else if (selection == "multiplayer")
{
KartSelectionScreen* s = OfflineKartSelectionScreen::getInstance();
NetworkConfig::get()->unsetNetworking();
s->setMultiplayer(true);
s->setFromOverworld(false);
s->push();

View File

@ -44,7 +44,6 @@ DEFINE_SCREEN_SINGLETON( NetworkKartSelectionScreen );
NetworkKartSelectionScreen::NetworkKartSelectionScreen()
: KartSelectionScreen("karts_online.stkgui")
{
KartSelectionScreen::m_instance_ptr = this;
} // NetworkKartSelectionScreen
// ----------------------------------------------------------------------------

View File

@ -21,7 +21,6 @@ DEFINE_SCREEN_SINGLETON( OfflineKartSelectionScreen );
OfflineKartSelectionScreen::OfflineKartSelectionScreen() : KartSelectionScreen("karts.stkgui")
{
KartSelectionScreen::m_instance_ptr = this;
}
OfflineKartSelectionScreen::~OfflineKartSelectionScreen()

View File

@ -35,6 +35,8 @@
#include "io/file_manager.hpp"
#include "karts/abstract_kart.hpp"
#include "karts/controller/controller.hpp"
#include "karts/controller/end_controller.hpp"
#include "karts/controller/local_player_controller.hpp"
#include "karts/kart_properties.hpp"
#include "karts/kart_properties_manager.hpp"
#include "modes/cutscene_world.hpp"
@ -384,10 +386,6 @@ void RaceResultGUI::eventCallback(GUIEngine::Widget* widget,
{
race_manager->exitRace();
race_manager->setAIKartOverride("");
// FIXME: why is this call necessary here? tearDown should be
// automatically called when the screen is left. Note that the
// NetworkKartSelectionScreen::getInstance()->tearDown(); caused #1347
KartSelectionScreen::getRunningInstance()->tearDown();
Screen* newStack[] = { MainMenuScreen::getInstance(),
RaceSetupScreen::getInstance(),
NULL };
@ -401,11 +399,6 @@ void RaceResultGUI::eventCallback(GUIEngine::Widget* widget,
{
race_manager->exitRace();
race_manager->setAIKartOverride("");
// FIXME: why is this call necessary here? tearDown should be
// automatically called when the screen is left. Note that the
// NetworkKartSelectionScreen::getInstance()->tearDown(); caused #1347
//if (KartSelectionScreen::getRunningInstance() != NULL)
// KartSelectionScreen::getRunningInstance()->tearDown();
StateManager::get()->resetAndGoToScreen(MainMenuScreen::getInstance());
if (race_manager->raceWasStartedFromOverworld())
@ -492,15 +485,7 @@ void RaceResultGUI::backToLobby()
// Save a pointer to the current row_info entry
RowInfo *ri = &(m_all_row_infos[position - first_position]);
ri->m_is_player_kart = kart->getController()->isLocalPlayerController();
// Identify Human player, if so display real name other than kart name
const int rm_id = kart->getWorldKartId() -
(race_manager->getNumberOfKarts() - race_manager->getNumPlayers());
if (rm_id >= 0 && !race_manager->isWatchingReplay())
ri->m_kart_name = race_manager->getKartInfo(rm_id).getPlayerName();
else
ri->m_kart_name = translations->fribidize(kart->getName());
ri->m_kart_name = getKartDisplayName(kart);
video::ITexture *icon =
kart->getKartProperties()->getIconMaterial()->getTexture();
@ -865,16 +850,8 @@ void RaceResultGUI::backToLobby()
RowInfo *ri = &(m_all_row_infos[rank]);
ri->m_kart_icon =
kart->getKartProperties()->getIconMaterial()->getTexture();
const int rm_id = kart_id -
(race_manager->getNumberOfKarts() - race_manager->getNumPlayers());
if (rm_id >= 0 && !race_manager->isWatchingReplay())
ri->m_kart_name = race_manager->getKartInfo(rm_id).getPlayerName();
else
ri->m_kart_name = translations->fribidize(kart->getName());
ri->m_is_player_kart = kart->getController()->isLocalPlayerController();
ri->m_kart_name = getKartDisplayName(kart);
// In FTL karts do have a time, which is shown even when the kart
// is eliminated
@ -925,6 +902,29 @@ void RaceResultGUI::backToLobby()
} // i < num_karts
} // determineGPLayout
//-----------------------------------------------------------------------------
/** Returns a string to display next to a kart. For a player that's the name
* of the player, for an AI kart it's the name of the driver.
*/
core::stringw RaceResultGUI::getKartDisplayName(const AbstractKart *kart) const
{
const EndController *ec =
dynamic_cast<const EndController*>(kart->getController());
// If the race was given up, there is no end controller for the
// players, so this case needs to be handled separately
if(ec && ec->isLocalPlayerController())
return ec->getName();
else
{
// No end controller, check explicitely for a player controller
const PlayerController *pc =
dynamic_cast<const PlayerController*>(kart->getController());
// Check if the kart is a player controller to get the real name
if(pc) return pc->getName();
}
return translations->fribidize(kart->getName());
} // getKartDisplayName
//-----------------------------------------------------------------------------
/** Displays the race results for a single kart.
* \param n Index of the kart to be displayed.
@ -1102,6 +1102,7 @@ void RaceResultGUI::backToLobby()
if (own_goal)
{
result_text.append(" ");
//I18N: indicates a player that scored in their own goal in result screen
result_text.append(_("(Own Goal)"));
}

View File

@ -194,6 +194,7 @@ private:
void displayHighScores();
void displaySoccerResults();
void displayScreenShots();
irr::core::stringw getKartDisplayName(const AbstractKart *kart) const;
int getFontHeight () const;

View File

@ -37,12 +37,12 @@ CheckGoal::CheckGoal(const XMLNode &node, unsigned int index)
m_first_goal = false;
node.get("first_goal", &m_first_goal);
Vec3 p1, p2;
node.get("p1", &p1);
node.get("p2", &p2);
node.get("p1", &m_p1);
node.get("p2", &m_p3);
m_line.setLine( core::vector2df(p1.getX(), p1.getZ()),
core::vector2df(p2.getX(), p2.getZ()) );
m_line.setLine( core::vector2df(m_p1.getX(), m_p1.getZ()),
core::vector2df(m_p3.getX(), m_p3.getZ()) );
m_p2 = (m_p1 + m_p3) / 2;
} // CheckGoal
// ----------------------------------------------------------------------------
@ -113,11 +113,3 @@ void CheckGoal::reset(const Track &track)
}
} // reset
// ----------------------------------------------------------------------------
Vec3 CheckGoal::convertTo3DCenter() const
{
float x = m_line.getMiddle().X;
float y = m_line.getMiddle().Y;
return Vec3(x, 0, y);
}

View File

@ -24,7 +24,6 @@
#include <line2d.h>
using namespace irr;
class CheckManager;
class XMLNode;
class Track;
class Vec3;
@ -37,6 +36,14 @@ class Vec3;
*/
class CheckGoal : public CheckStructure
{
public:
/** Used by AIs to test whether the ball is likely to goal. */
enum PointLocation
{
POINT_FIRST,
POINT_CENTER,
POINT_LAST
};
private:
/** Previois ball position. */
Vec3 m_previous_ball_position;
@ -47,6 +54,11 @@ private:
/** The line that is tested for being crossed. */
core::line2df m_line;
/** Used by AIs to test whether the ball is likely to goal. */
Vec3 m_p1;
Vec3 m_p2;
Vec3 m_p3;
public:
CheckGoal(const XMLNode &node, unsigned int index);
virtual ~CheckGoal() {}
@ -59,7 +71,11 @@ public:
// ------------------------------------------------------------------------
bool getTeam() const { return m_first_goal; }
// ------------------------------------------------------------------------
Vec3 convertTo3DCenter() const;
}; // CheckLine
const Vec3& getPoint(PointLocation point) const
{
return (point == POINT_LAST ? m_p3 :
(point == POINT_CENTER ? m_p2 : m_p1));
}
}; // CheckGoal
#endif