More refactoring: duplicated code handling track sectors and

distance along track is now moved into a separate class TrackSector
and used in linear_world and rubber ball.


git-svn-id: svn+ssh://svn.code.sf.net/p/supertuxkart/code/main/trunk@9422 178a84e3-b1eb-0310-8ba1-8eac791a3b58
This commit is contained in:
hikerstk 2011-08-04 23:33:41 +00:00
parent 428ed5a07b
commit 6e5086f9b8
10 changed files with 259 additions and 137 deletions

View File

@ -566,6 +566,8 @@ add_executable(supertuxkart
src/tracks/track_object.hpp
src/tracks/track_object_manager.cpp
src/tracks/track_object_manager.hpp
src/tracks/track_sector.cpp
src/tracks/track_sector.hpp
src/tutorial/tutorial.cpp
src/tutorial/tutorial_data.cpp
src/tutorial/tutorial_data.hpp

View File

@ -434,6 +434,8 @@ supertuxkart_SOURCES = \
tracks/track_object.hpp \
tracks/track_object_manager.cpp \
tracks/track_object_manager.hpp \
tracks/track_sector.cpp \
tracks/track_sector.hpp \
tutorial/tutorial.cpp \
tutorial/tutorial.hpp \
tutorial/tutorial_data.cpp \

View File

@ -874,6 +874,10 @@
RelativePath="..\..\tracks\track_object_manager.cpp"
>
</File>
<File
RelativePath="..\..\tracks\track_sector.cpp"
>
</File>
</Filter>
<Filter
Name="replay"
@ -1912,6 +1916,10 @@
RelativePath="..\..\tracks\track_object_manager.hpp"
>
</File>
<File
RelativePath="..\..\tracks\track_sector.hpp"
>
</File>
</Filter>
<Filter
Name="replay"

View File

@ -28,8 +28,9 @@ float RubberBall::m_st_interval;
float RubberBall::m_st_squash_duration;
float RubberBall::m_st_squash_slowdown;
RubberBall::RubberBall(Kart *kart) : Flyable(kart, PowerupManager::POWERUP_RUBBERBALL,
0.0f /* mass */)
RubberBall::RubberBall(Kart *kart)
: Flyable(kart, PowerupManager::POWERUP_RUBBERBALL, 0.0f /* mass */),
TrackSector()
{
float forw_offset = 0.5f*kart->getKartLength() + m_extend.getZ()*0.5f+5.0f;
@ -66,9 +67,11 @@ RubberBall::RubberBall(Kart *kart) : Flyable(kart, PowerupManager::POWERUP_RUBBE
m_aiming_points[0] = QuadGraph::get()->getQuadOfNode(pred).getCenter();
m_aiming_points[1] = QuadGraph::get()->getQuadOfNode(m_current_graph_node)
.getCenter();
m_aiming_points[2] = QuadGraph::get()->getQuadOfNode(m_aimed_graph_node).getCenter();
m_aiming_points[2] = QuadGraph::get()->getQuadOfNode(m_aimed_graph_node)
.getCenter();
int succ_succ = getSuccessorToHitTarget(m_aimed_graph_node);
m_aiming_points[3] = QuadGraph::get()->getQuadOfNode(succ_succ).getCenter();
m_aiming_points[3] = QuadGraph::get()->getQuadOfNode(succ_succ)
.getCenter();
m_t = 0;
m_t_increase = 1.0f/(m_aiming_points[2]-m_aiming_points[1]).length();
@ -172,6 +175,8 @@ void RubberBall::update(float dt)
int indx = getSuccessorToHitTarget(m_current_graph_node);
// Determine new distance along track
TrackSector::update(next_xyz);
Vec3 ball_distance_vec;
QuadGraph::get()->findRoadSector(next_xyz, &m_current_graph_node);
if(m_current_graph_node == QuadGraph::UNKNOWN_SECTOR)

View File

@ -21,6 +21,7 @@
#define HEADER_RUBBER_BALL_HPP
#include "items/flyable.hpp"
#include "tracks/track_sector.hpp"
class Kart;
class QuadGraph;
@ -28,7 +29,7 @@ class QuadGraph;
/**
* \ingroup items
*/
class RubberBall: public Flyable
class RubberBall: public Flyable, public TrackSector
{
private:
/** A class variable to store the default interval size. */

View File

@ -25,6 +25,7 @@
#include "audio/sfx_manager.hpp"
#include "network/network_manager.hpp"
#include "race/history.hpp"
#include "tracks/track_sector.hpp"
#include "tracks/track.hpp"
#include "utils/constants.hpp"
#include "utils/string_utils.hpp"
@ -61,31 +62,7 @@ void LinearWorld::init()
for(unsigned int n=0; n<kart_amount; n++)
{
KartInfo info;
info.m_track_sector = QuadGraph::UNKNOWN_SECTOR;
info.m_last_valid_sector = 0;
info.m_lap_start_time = 0;
QuadGraph::get()->findRoadSector(m_karts[n]->getXYZ(),
&info.m_track_sector);
//If m_track_sector == UNKNOWN_SECTOR, then the kart is not on top of
//the road, so we have to use another function to find the sector.
info.m_on_road = info.m_track_sector != QuadGraph::UNKNOWN_SECTOR;
if (!info.m_on_road)
{
info.m_track_sector =
QuadGraph::get()->findOutOfRoadSector(m_karts[n]->getXYZ(),
QuadGraph::UNKNOWN_SECTOR );
}
QuadGraph::get()->spatialToTrack(&info.m_curr_track_coords,
m_karts[n]->getXYZ(),
info.m_track_sector );
info.m_race_lap = -1;
info.m_lap_start_time = 0;
info.m_time_at_last_lap = 99999.9f;
info.m_estimated_finish = -1.0f;
info.getSector()->update(m_karts[n]->getXYZ());
m_kart_info.push_back(info);
} // next kart
@ -114,29 +91,8 @@ void LinearWorld::restartRace()
const unsigned int kart_amount = m_karts.size();
for(unsigned int i=0; i<kart_amount; i++)
{
KartInfo& info = m_kart_info[i];
info.m_track_sector = QuadGraph::UNKNOWN_SECTOR;
info.m_last_valid_sector = 0;
info.m_lap_start_time = 0;
QuadGraph::get()->findRoadSector(m_karts[i]->getXYZ(),
&info.m_track_sector);
//If m_track_sector == UNKNOWN_SECTOR, then the kart is not on top of
//the road, so we have to use another function to find the sector.
info.m_on_road = info.m_track_sector != QuadGraph::UNKNOWN_SECTOR;
if (!info.m_on_road)
{
info.m_track_sector =
QuadGraph::get()->findOutOfRoadSector(m_karts[i]->getXYZ(),
QuadGraph::UNKNOWN_SECTOR);
}
QuadGraph::get()->spatialToTrack(&info.m_curr_track_coords,
m_karts[i]->getXYZ(),
info.m_track_sector );
info.m_race_lap = -1;
info.m_lap_start_time = -0;
info.m_time_at_last_lap = 99999.9f;
m_kart_info[i].reset();
m_kart_info[i].getSector()->update(m_karts[i]->getXYZ());
} // next kart
// First all kart infos must be updated before the kart position can be
@ -193,30 +149,7 @@ void LinearWorld::update(float dt)
// Nothing to do for karts that are currently being rescued or eliminated
if(kart->playingEmergencyAnimation()) continue;
// ---------- deal with sector data ---------
// update sector variables
int prev_sector = kart_info.m_track_sector;
QuadGraph::get()->findRoadSector(kart->getXYZ(),
&kart_info.m_track_sector);
kart_info.m_on_road = kart_info.m_track_sector != QuadGraph::UNKNOWN_SECTOR;
if(kart_info.m_on_road)
{
kart_info.m_last_valid_sector = kart_info.m_track_sector;
}
else
{
// Kart off road. Find the closest sector instead.
kart_info.m_track_sector =
QuadGraph::get()->findOutOfRoadSector(kart->getXYZ(), prev_sector );
}
// Update track coords (=progression)
QuadGraph::get()->spatialToTrack(&kart_info.m_curr_track_coords,
kart->getXYZ(),
kart_info.m_track_sector );
kart_info.getSector()->update(kart->getXYZ());
} // for n
// Update all positions. This must be done after _all_ karts have
@ -390,7 +323,7 @@ void LinearWorld::newLap(unsigned int kart_index)
//-----------------------------------------------------------------------------
int LinearWorld::getSectorForKart(const int kart_id) const
{
return m_kart_info[kart_id].m_track_sector;
return m_kart_info[kart_id].getSector()->getCurrentGraphNode();
} // getSectorForKart
//-----------------------------------------------------------------------------
@ -400,7 +333,7 @@ int LinearWorld::getSectorForKart(const int kart_id) const
*/
float LinearWorld::getDistanceDownTrackForKart(const int kart_id) const
{
return m_kart_info[kart_id].m_curr_track_coords.getZ();
return m_kart_info[kart_id].getSector()->getDistanceFromStart();
} // getDistanceDownTrackForKart
//-----------------------------------------------------------------------------
@ -410,7 +343,7 @@ float LinearWorld::getDistanceDownTrackForKart(const int kart_id) const
*/
float LinearWorld::getDistanceToCenterForKart(const int kart_id) const
{
return m_kart_info[kart_id].m_curr_track_coords.getX();
return m_kart_info[kart_id].getSector()->getDistanceToCenter();
} // getDistanceToCenterForKart
//-----------------------------------------------------------------------------
@ -566,31 +499,13 @@ void LinearWorld::moveKartAfterRescue(Kart* kart)
{
KartInfo& info = m_kart_info[kart->getWorldKartId()];
// If the kart is off road, rescue it to the last valid track position
// instead of the current one (since the sector might be determined by
// being closest to it, which allows shortcuts like drive towards another
// part of the lap, press rescue, and be rescued to this other part of
// the track (example: math class, drive towards the left after start,
// when hitting the books, press rescue --> you are rescued to the
// end of the track).
if(!info.m_on_road)
{
info.m_track_sector = info.m_last_valid_sector;
}
// Using the predecessor has the additional afvantage (besides punishing
// the player a bit more) that it makes it less likely to fall in a
// rescue loop since the kart moves back on each attempt.
info.m_track_sector = QuadGraph::get()->getNode(info.m_track_sector)
.getPredecessor();
info.m_last_valid_sector= QuadGraph::get()->getNode(info.m_track_sector)
.getPredecessor();
kart->setXYZ( QuadGraph::get()->getQuadOfNode(info.m_track_sector)
.getCenter());
info.getSector()->rescue();
int sector = info.getSector()->getCurrentGraphNode();
kart->setXYZ( QuadGraph::get()
->getQuadOfNode(sector).getCenter());
btQuaternion heading(btVector3(0.0f, 1.0f, 0.0f),
m_track->getAngle(info.m_track_sector) );
m_track->getAngle(sector) );
kart->setRotation(heading);
// A certain epsilon is added here to the Z coordinate, in case
@ -602,7 +517,7 @@ void LinearWorld::moveKartAfterRescue(Kart* kart)
btTransform pos;
pos.setOrigin(kart->getXYZ()+btVector3(0, kart->getKartHeight() + epsilon, 0));
pos.setRotation(btQuaternion(btVector3(0.0f, 1.0f, 0.0f),
m_track->getAngle(info.m_track_sector)));
m_track->getAngle(sector)));
kart->getBody()->setCenterOfMassTransform(pos);
@ -815,19 +730,20 @@ void LinearWorld::updateRacePosition()
void LinearWorld::checkForWrongDirection(unsigned int i)
{
if(!m_karts[i]->getController()->isPlayerController()) return;
if(!m_kart_info[i].m_on_road ||
if(!m_kart_info[i].getSector()->isOnRoad()||
m_karts[i]->playingEmergencyAnimation()) return;
const Kart *kart=m_karts[i];
// If the kart can go in more than one directions from the current track
// don't do any reverse message handling, since it is likely that there
// will be one direction in which it isn't going backwards anyway.
if(QuadGraph::get()->getNumberOfSuccessors(m_kart_info[i].m_track_sector)>1)
int sector = m_kart_info[i].getSector()->getCurrentGraphNode();
if(QuadGraph::get()->getNumberOfSuccessors(sector)>1)
return;
// check if the player is going in the wrong direction
float angle_diff = kart->getHeading() -
m_track->getAngle(m_kart_info[i].m_track_sector);
m_track->getAngle(sector);
if(angle_diff > M_PI) angle_diff -= 2*M_PI;
else if (angle_diff < -M_PI) angle_diff += 2*M_PI;
// Display a warning message if the kart is going back way (unless

View File

@ -21,6 +21,7 @@
#include <vector>
#include "modes/world_with_rank.hpp"
#include "tracks/track_sector.hpp"
#include "utils/aligned_array.hpp"
class SFXBase;
@ -33,6 +34,7 @@ class SFXBase;
*/
class LinearWorld : public WorldWithRank
{
private:
/** Sfx for the final lap. */
SFXBase *m_last_lap_sfx;
@ -41,27 +43,48 @@ class LinearWorld : public WorldWithRank
bool m_last_lap_sfx_playing;
private:
// ------------------------------------------------------------------------
/** Some additional info that needs to be kept for each kart
* in this kind of race.
*/
struct KartInfo
class KartInfo
{
int m_race_lap; /**<Number of finished(!) laps. */
float m_time_at_last_lap; /**<Time at finishing last lap. */
float m_lap_start_time; /**<Time at start of a new lap. */
float m_estimated_finish; /**<During last lap only:
* estimated finishing time! */
int m_track_sector; /**<Index in driveline, special values
* e.g. UNKNOWN_SECTOR can be negative!*/
public:
/** Number of finished(!) laps. */
int m_race_lap;
int m_last_valid_sector; /* used when rescusing, e.g. for invalid shortcuts */
/** Time at finishing last lap. */
float m_time_at_last_lap;
Vec3 m_curr_track_coords;
/** True if the kart is on top of the road path drawn by the drivelines */
bool m_on_road;
/** Time at start of a new lap. */
float m_lap_start_time;
/** During last lap only: estimated finishing time! */
float m_estimated_finish;
/** Stores the current graph node and track coordinates etc. */
TrackSector m_current_sector;
/** Initialises all fields. */
KartInfo() { reset(); }
// --------------------------------------------------------------------
/** Re-initialises all data. */
void reset()
{
m_race_lap = -1;
m_lap_start_time = 0;
m_time_at_last_lap = 99999.9f;
m_estimated_finish = -1.0f;
m_current_sector.reset();
}
// --------------------------------------------------------------------
/** Returns a pointer to the current node object. */
TrackSector *getSector() {return &m_current_sector; }
// --------------------------------------------------------------------
/** Returns a pointer to the current node object. */
const TrackSector *getSector() const {return &m_current_sector; }
};
// ------------------------------------------------------------------------
protected:
RaceGUIBase::KartIconDisplayInfo* m_kart_display_info;
@ -101,17 +124,19 @@ public:
getKartsDisplayInfo();
virtual void moveKartAfterRescue(Kart* kart);
virtual void restartRace();
virtual bool raceHasLaps(){ return true; }
virtual void newLap(unsigned int kart_index);
// ------------------------------------------------------------------------
/** Returns if this race mode has laps. */
virtual bool raceHasLaps(){ return true; }
// ------------------------------------------------------------------------
/** Returns if this race mode has bonus items. */
virtual bool haveBonusBoxes(){ return true; }
// ------------------------------------------------------------------------
/** Returns true if the kart is on a valid driveline quad.
* \param kart_index Index of the kart.
*/
* \param kart_index Index of the kart. */
bool isOnRoad(unsigned int kart_index) const
{ return m_kart_info[kart_index].m_on_road; }
{ return m_kart_info[kart_index].getSector()->isOnRoad(); }
}; // LinearWorld
#endif

View File

@ -516,12 +516,9 @@ void QuadGraph::spatialToTrack(Vec3 *dst, const Vec3& xyz,
//-----------------------------------------------------------------------------
/** findRoadSector returns in which sector on the road the position
* xyz is. If xyz is not on top of the road, it returns
* UNKNOWN_SECTOR.
* xyz is. If xyz is not on top of the road, it sets UNKNOWN_SECTOR as sector.
*
* The 'sector' could be defined as the number of the closest track
* segment to XYZ.
* \param XYZ Position for which the segment should be determined.
* \param xyz Position for which the segment should be determined.
* \param sector Contains the previous sector (as a shortcut, since usually
* the sector is the same as the last one), and on return the result
* \param all_sectors If this is not NULL, it is a list of all sectors to
@ -565,7 +562,7 @@ void QuadGraph::findRoadSector(const Vec3& xyz, int *sector,
indx = indx<(int)m_all_nodes.size()-1 ? indx +1 : 0;
const Quad &q = getQuadOfNode(indx);
float dist = xyz.getY() - q.getMinHeight();
// While negative distances are unlikely, we allow some small netative
// While negative distances are unlikely, we allow some small negative
// numbers in case that the kart is partly in the track.
if(q.pointInQuad(xyz) && dist < min_dist && dist>-1.0f)
{

View File

@ -0,0 +1,91 @@
// $Id$
//
// SuperTuxKart - a fun racing game with go-kart
// Copyright (C) 2011 Joerg Henrichs
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
// as published by the Free Software Foundation; either version 3
// of the License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#include "tracks/track_sector.hpp"
#include "tracks/quad_graph.hpp"
// ----------------------------------------------------------------------------
/** Initialises the object, and sets the current graph node to be undefined.
*/
TrackSector::TrackSector()
{
reset();
} // TrackSector
// ----------------------------------------------------------------------------
void TrackSector::reset()
{
m_current_graph_node = QuadGraph::UNKNOWN_SECTOR;
m_last_valid_graph_node = QuadGraph::UNKNOWN_SECTOR;
m_on_road = false;
} // reset
// ----------------------------------------------------------------------------
/** Updates the current graph node index, and the track coordinates for
* the specified point.
* \param xyz The new coordinates to search the graph node for.
*/
void TrackSector::update(const Vec3 &xyz)
{
int prev_sector = m_current_graph_node;
QuadGraph::get()->findRoadSector(xyz, &m_current_graph_node);
m_on_road = m_current_graph_node != QuadGraph::UNKNOWN_SECTOR;
// If m_track_sector == UNKNOWN_SECTOR, then the kart is not on top of
// the road, so we have to use search for the closest graph node.
if(m_current_graph_node == QuadGraph::UNKNOWN_SECTOR)
{
m_current_graph_node =
QuadGraph::get()->findOutOfRoadSector(xyz,
prev_sector);
}
else
m_last_valid_graph_node = m_current_graph_node;
// Now determine the 'track' coords, i.e. ow far from the start of the
// track, and how far to the left or right of the center driveline.
QuadGraph::get()->spatialToTrack(&m_current_track_coords, xyz,
m_current_graph_node);
} // update
// ----------------------------------------------------------------------------
void TrackSector::rescue()
{
// If the kart is off road, rescue it to the last valid track position
// instead of the current one (since the sector might be determined by
// being closest to it, which allows shortcuts like drive towards another
// part of the lap, press rescue, and be rescued to this other part of
// the track (example: math class, drive towards the left after start,
// when hitting the books, press rescue --> you are rescued to the
// end of the track).
if(!isOnRoad())
{
m_current_graph_node = m_last_valid_graph_node;
}
// Using the predecessor has the additional advantage (besides punishing
// the player a bit more) that it makes it less likely to fall in a
// rescue loop since the kart moves back on each attempt.
m_current_graph_node = QuadGraph::get()->getNode(m_current_graph_node)
.getPredecessor();
m_last_valid_graph_node = QuadGraph::get()->getNode(m_current_graph_node)
.getPredecessor();
} // rescue

View File

@ -0,0 +1,75 @@
// $Id$
//
// SuperTuxKart - a fun racing game with go-kart
// Copyright (C) 2011 Joerg Henrichs
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
// as published by the Free Software Foundation; either version 3
// of the License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#ifndef HEADER_TRACK_SECTOR_HPP
#define HEADER_TRACK_SECTOR_HPP
#include "utils/vec3.hpp"
/** This object keeps track of which sector an object is on. A sector is
* actually just the graph node (it's called sector to better distinguish
* the graph node from say xml node and scene node).
* An object that has a track sector can determine how far away it is from
* the start line, how far away it is from the center driveline. If the
* object is not actually on part of the quad graph, it will determine the
* closest sector it is to, and set a flag (!isOnRoad).
* This object will also keep track on the last valid sector an object was
* on, which is used to reset a kart in case of a rescue.
*/
class TrackSector
{
private:
/** The graph node the object is on. */
int m_current_graph_node;
/** The index of the last valid graph node. */
int m_last_valid_graph_node;
/** The coordinates of this object on the track, i.e. how far from
* the start of the track, and how far to the left or right
* of the center driveline. */
Vec3 m_current_track_coords;
/** True if the object is on the road (driveline), or not. */
bool m_on_road;
public:
TrackSector();
void reset();
void rescue();
void update(const Vec3 &xyz);
// ------------------------------------------------------------------------
/** Returns how far the the object is from the start line. */
float getDistanceFromStart() const { return m_current_track_coords.getZ();}
// ------------------------------------------------------------------------
/** Returns the distance to the centre driveline. */
float getDistanceToCenter() const { return m_current_track_coords.getX(); }
// ------------------------------------------------------------------------
/** Returns the current graph node. */
int getCurrentGraphNode() const {return m_current_graph_node;}
// ------------------------------------------------------------------------
/** Returns if this object is on the road (driveline). */
bool isOnRoad() const { return m_on_road; }
}; // TrackSector
#endif