1) Cleaned up and simplified handling of race phase in world.

2) Added a 'final camera': this camera will move forward and turn
   when a race is finished to show the finishing line. This is
   currently only enabled for the race track.


git-svn-id: svn+ssh://svn.code.sf.net/p/supertuxkart/code/trunk/supertuxkart@1953 178a84e3-b1eb-0310-8ba1-8eac791a3b58
This commit is contained in:
hikerstk 2008-05-20 03:33:48 +00:00
parent 359f281a4a
commit a0473ad24b
16 changed files with 373 additions and 255 deletions

View File

@ -36,6 +36,7 @@ Camera::Camera(int camera_index, const Kart* kart)
btVector3 start_pos = m_kart->getPos();
sgSetVec3(m_current_pos.xyz, start_pos.getX(), start_pos.getY(), start_pos.getZ());
sgSetVec3(m_current_pos.xyz, 0, 0, 0);
sgSetVec3(m_current_pos.hpr, 0, 0, 0);
// FIXME: clipping should be configurable for slower machines
@ -96,6 +97,20 @@ void Camera::setScreenPosition(int camera_index)
//-----------------------------------------------------------------------------
void Camera::setMode(Mode mode)
{
if(mode==CM_FINAL)
{
const Track* track=world->getTrack();
// If the track doesn't have a final position, ignore this mode
if(!track->hasFinalCamera()) return;
btVector3 coord(m_current_pos.xyz[0],m_current_pos.xyz[1],
m_current_pos.xyz[2]);
m_velocity = (track->getCameraPosition()-coord)/1.0f;
btVector3 rotation(m_current_pos.hpr[0],m_current_pos.hpr[1],
m_current_pos.hpr[2]);
// Rotate faster
m_angular_velocity = (track->getCameraHPR()-rotation)/1.0f;
m_final_time=0.0f;
}
m_mode = mode;
m_last_pitch = 0.0f;
if(m_mode==CM_CLOSEUP)
@ -119,6 +134,8 @@ void Camera::update (float dt)
sgCoord kartcoord;
const Kart *kart;
if(m_mode==CM_FINAL) return finalCamera(dt);
// First define the position of the kart
if(m_mode==CM_LEADER_MODE)
{
@ -183,6 +200,29 @@ void Camera::update (float dt)
} // update
//-----------------------------------------------------------------------------
void Camera::finalCamera(float dt)
{
// Turn/move the camera for 1 second only
m_final_time += dt;
if( m_final_time<1.0f )
{
btVector3 coord(m_current_pos.xyz[0],m_current_pos.xyz[1],m_current_pos.xyz[2]);
coord += m_velocity*dt;
printf("y %f vely %f dt %f\n",coord.getY(), m_velocity.getY(), dt);
m_current_pos.xyz[0]=coord.getX();
m_current_pos.xyz[1]=coord.getY();
m_current_pos.xyz[2]=coord.getZ();
btVector3 rotation(m_current_pos.hpr[0],m_current_pos.hpr[1],m_current_pos.hpr[2]);
rotation += m_angular_velocity*dt;
m_current_pos.hpr[0]=rotation.getX();
m_current_pos.hpr[1]=rotation.getY();
m_current_pos.hpr[2]=rotation.getZ();
m_context->setCamera(&m_current_pos);
}
} // finalCamera
//-----------------------------------------------------------------------------
void Camera::apply ()
{
int width = user_config->m_width ;

View File

@ -36,6 +36,7 @@ public:
CM_DRIFTING, // FIXME: drifting behind when accelerating = not yet implemented
CM_LEADER_MODE, // for deleted player karts in follow the leader
CM_REVERSE, // Camera is pointing backwards
CM_FINAL, // Final camera to show the end of the race
CM_SIMPLE_REPLAY
};
protected:
@ -47,8 +48,12 @@ protected:
float m_current_speed; // current speed of camera
float m_last_pitch; // for tiling the camera when going downhill
float m_distance; // distance between camera and kart
btVector3 m_velocity; // camera velocity for final mode
btVector3 m_angular_velocity; // camera angular velocity for final mode
float m_final_time; // time when final camera mode started
private:
void finalCamera (float dt); // handle the final camera
public:
Camera (int camera_index, const Kart* kart);
void setMode (Mode mode_); /** Set the camera to the given mode */

View File

@ -162,7 +162,7 @@ void Collectable::hitRedHerring(int n)
{
Kart *kart = world->getKart(i);
if(kart->isEliminated() || kart == m_owner) continue;
if(kart->getPosition() == 1 && kart->raceIsFinished())
if(kart->getPosition() == 1 && kart->hasFinishedRace())
{
m_type = COLLECT_PARACHUTE;
m_number = 1;

View File

@ -795,7 +795,7 @@ void RaceGUI::drawLap(Kart* kart, int offset_x, int offset_y,
offset_x += (int)(120*ratio_x);
offset_y += (int)(70*maxRatio);
if ( kart->getLap() >= race_manager->getNumLaps())
if(kart->hasFinishedRace())
{
sprintf(str, _("Finished"));
font_race->PrintShadow(str, (int)(48*maxRatio), offset_x, offset_y);

View File

@ -74,6 +74,7 @@ Kart::Kart (const std::string& kart_name, int position_ ,
m_skidmark_right = NULL;
m_track_sector = Track::UNKNOWN_SECTOR;
sgCopyCoord(&m_reset_pos, &init_pos);
// Neglecting the roll resistance (which is small for high speeds compared
// to the air resistance), maximum speed is reached when the engine
// power equals the air resistance force, resulting in this formula:
@ -376,6 +377,12 @@ void Kart::doLapCounting ()
setTimeAtLap(world->getTime());
m_race_lap++ ;
}
// Race finished
// =============
if(m_race_lap>=race_manager->getNumLaps())
{
raceFinished(world->getTime());
}
// Only do timings if original time was set properly. Driving backwards
// over the start line will cause the lap start time to be set to -1.
if(m_lap_start_time>=0.0)
@ -431,6 +438,14 @@ void Kart::doLapCounting ()
}
} // doLapCounting
//-----------------------------------------------------------------------------
void Kart::raceFinished(float time)
{
m_finished_race = true;
m_finish_time = time;
race_manager->RaceFinished(this, time);
} // raceFinished
//-----------------------------------------------------------------------------
void Kart::collectedHerring(Herring* herring)
{
@ -655,7 +670,7 @@ void Kart::update(float dt)
m_curr_pos.xyz,
m_track_sector );
doLapCounting () ;
if(!m_finished_race) doLapCounting();
processSkidMarks();
} // update
@ -1066,13 +1081,6 @@ void Kart::placeModel ()
m_curr_pos.xyz[2] -= offset_z;
m_curr_pos.hpr[1] -= offset_pitch;
} // placeModel
//-----------------------------------------------------------------------------
void Kart::setFinishingState(float time)
{
m_finished_race = true;
m_finish_time = time;
} // setFinishingState
//-----------------------------------------------------------------------------
float Kart::estimateFinishTime ()
{

View File

@ -142,9 +142,8 @@ public:
int getLap () const { return m_race_lap; }
int getPosition () const { return m_race_position; }
int getInitialPosition () const { return m_initial_position; }
void setFinishingState(float time);
float getFinishTime () const { return m_finish_time; }
bool raceIsFinished () const { return m_finished_race; }
float getFinishTime () const { return m_finish_time; }
bool hasFinishedRace () const { return m_finished_race; }
void endRescue ();
float estimateFinishTime ();
void processSkidMarks ();
@ -207,6 +206,7 @@ public:
void forceRescue (bool is_rescue=false);
void handleExplosion (const btVector3& pos, bool direct_hit);
const std::string& getName () const {return m_kart_properties->getName();}
const std::string& getIdent () const {return m_kart_properties->getIdent();}
virtual int isPlayerKart () const {return 0; }
// addMessages gets called by world to add messages to the gui
virtual void addMessages () {};
@ -215,7 +215,8 @@ public:
virtual void handleZipper ();
virtual void crashed () {};
virtual void doLapCounting ();
virtual void update (float dt );
virtual void update (float dt);
virtual void raceFinished (float time);
};
class TrafficDriver : public Kart

View File

@ -23,6 +23,7 @@
#include <string>
#include <vector>
#include <plib/sg.h>
#include "btBulletDynamicsCommon.h"
namespace lisp
{
@ -139,6 +140,28 @@ namespace lisp
}
return true;
}
bool get(const char* name, btVector3& val) const
{
const Lisp* lisp = getLisp(name);
if(!lisp)
return false;
lisp = lisp->getCdr();
if(!lisp)
return false;
float f[3];
for(int i = 0; i < 3 && lisp; ++i)
{
const Lisp* m_car = lisp->getCar();
if(!m_car)
return false;
m_car->get(f[i]);
lisp = lisp->getCdr();
}
// Lists are stored in reverse order, so reverse to original order
val.setValue(f[2],f[1],f[0]);
return true;
}
template<class T>
bool getVector(const char* name, std::vector<T>& vec) const

View File

@ -53,7 +53,7 @@ protected:
btRigidBody* m_body;
btDefaultMotionState* m_motion_state;
btTransform m_transform;
btVector3 m_hpr;
public:
Moveable (bool bHasHistory=false);
@ -64,9 +64,11 @@ public:
const btVector3 &getVelocityLC() const {return m_velocityLC; }
virtual void setVelocity(const btVector3& v) {m_body->setLinearVelocity(v); }
sgCoord* getCoord () {return &m_curr_pos; }
const btVector3 getPos () const {return m_transform.getOrigin(); }
const btVector3& getPos () const {return m_transform.getOrigin(); }
const btVector3& getRotation() const {return m_hpr; }
const sgCoord* getCoord () const {return &m_curr_pos; }
const sgVec4* getNormalHOT () const {return m_normal_hot; }
const sgCoord* getResetPos () const {return &m_reset_pos; }
void setCoord (sgCoord* pos) {sgCopyCoord ( &m_curr_pos,pos); }
virtual void placeModel ();
virtual void handleZipper () {};

View File

@ -220,6 +220,20 @@ void PlayerKart::setPosition(int p)
Kart::setPosition(p);
} // setPosition
//-----------------------------------------------------------------------------
void PlayerKart::raceFinished(float time)
{
Kart::raceFinished(time);
m_camera->setMode(Camera::CM_FINAL); // set race over camera
RaceGUI* m=(RaceGUI*)menu_manager->getRaceMenu();
if(m)
{
m->addMessage(getPosition()==1 ? _("You won") : _("You finished") ,
this, 2.0f, 60);
m->addMessage( _("the race!"), this, 2.0f, 60);
}
} // raceFinished
//-----------------------------------------------------------------------------
void PlayerKart::handleZipper()
{
@ -257,7 +271,7 @@ void PlayerKart::addMessages()
// Display a warning message if the kart is going back way (unless
// the kart has already finished the race).
if ((angle_diff > 120.0f || angle_diff < -120.0f) &&
getVelocity().getY() > 0.0f && !raceIsFinished() )
getVelocity().getY() > 0.0f && !hasFinishedRace() )
{
m->addMessage(_("WRONG WAY!"), this, -1.0f, 60);
} // if angle is too big

View File

@ -55,6 +55,7 @@ public:
void handleZipper ();
void collectedHerring (Herring* herring);
virtual void setPosition (int p);
virtual void raceFinished (float time);
int isPlayerKart () const {return 1;}
Camera* getCamera () {return m_camera;}

View File

@ -219,10 +219,25 @@ void RaceManager::exit_race()
} // exit_Race
//-----------------------------------------------------------------------------
void RaceManager::addKartResult(int kart, int pos, float time)
// Kart kart has finished the race at the specified time (which can be different
// from world->getClock() in case of setting extrapolated arrival times).
void RaceManager::RaceFinished(const Kart *kart, float time)
{
unsigned i;
for(i=0; i<m_kart_status.size(); i++)
{
printf("i %d %s %s\n",i,kart->getName().c_str(),m_kart_status[i].m_ident.c_str());
if(kart->getIdent()==m_kart_status[i].m_ident) break;
} // for i
if(i>=m_kart_status.size())
{
fprintf(stderr, "Kart '%s' not found. Ignored.\n",kart->getName().c_str());
return;
}
// In follow the leader mode, kart 0 does not get any points,
// so the position of each kart is actually one better --> decrease pos
int pos = kart->getPosition();
if(m_race_mode==RM_FOLLOW_LEADER)
{
pos--;
@ -232,11 +247,13 @@ void RaceManager::addKartResult(int kart, int pos, float time)
if(pos<=0) pos=stk_config->m_max_karts;
}
m_kart_status[kart].m_score += m_score_for_position[pos-1];
m_kart_status[kart].m_last_score = m_score_for_position[pos-1];
m_kart_status[kart].m_overall_time += time;
m_kart_status[kart].m_last_time = time;
} // addKartResult
m_kart_status[i].m_score += m_score_for_position[pos-1];
m_kart_status[i].m_last_score = m_score_for_position[pos-1];
m_kart_status[i].m_overall_time += time;
m_kart_status[i].m_last_time = time;
m_num_finished_karts ++;
if(kart->isPlayerKart()) m_num_finished_players++;
} // raceFinished
//-----------------------------------------------------------------------------
void RaceManager::restartRace()

View File

@ -102,46 +102,47 @@ public:
RaceManager();
~RaceManager();
void setPlayerKart(unsigned int player, const std::string& kart);
void setNumPlayers(int num);
void reset();
void setGrandPrix(const CupData &cup) { m_cup = cup; }
void setDifficulty(Difficulty diff);
void setNumLaps(int num) { m_num_laps.clear();
m_num_laps.push_back(num); }
void setTrack(const std::string& track);
void setRaceMode(RaceModeType mode) { m_race_mode = mode; }
void setNumKarts(int num) { m_num_karts = num; }
void setCoinTarget(int num) { m_coin_target = num; }
void addKartResult(int kart, int pos, float time);
RaceModeType getRaceMode() const { return m_race_mode; }
unsigned int getNumKarts() const { return m_num_karts; }
unsigned int getNumPlayers() const { return (int)m_player_karts.size();}
int getNumLaps() const { return m_num_laps[m_track_number];}
Difficulty getDifficulty() const { return m_difficulty; }
const std::string& getTrackName() const { return m_tracks[m_track_number]; }
const CupData *getGrandPrix() const { return &m_cup; }
unsigned int getFinishedKarts() const { return m_num_finished_karts; }
unsigned int getFinishedPlayers() const { return m_num_finished_players; }
const std::string& getKartName(int kart) const
{ return m_kart_status[kart].m_ident;}
const std::string& getHerringStyle() const
{ return m_cup.getHerringStyle(); }
int getKartScore(int krt) const { return m_kart_status[krt].m_score;}
int getPositionScore(int p) const { return m_score_for_position[p-1]; }
double getOverallTime(int kart) const { return m_kart_status[kart].m_overall_time;}
int getCoinTarget() const { return m_coin_target; }
bool isEliminated(int kart) const { return m_kart_status[kart].m_is_eliminated;}
bool raceHasLaps() const { return m_race_mode!=RM_FOLLOW_LEADER;}
void eliminate(int kart) { m_kart_status[kart].m_is_eliminated=true;}
void addFinishedKarts(int num) { m_num_finished_karts += num; }
void PlayerFinishes() { m_num_finished_players++; }
int allPlayerFinished() const {return m_num_finished_players==m_player_karts.size();}
int raceIsActive() const { return m_active_race; }
bool isPlayer(int kart) const {return m_kart_status[kart].m_player_id>-1; }
void setPlayerKart(unsigned int player, const std::string& kart);
void setNumPlayers(int num);
void reset();
void RaceFinished(const Kart* kart, float time);
void setTrack(const std::string& track);
void setGrandPrix(const CupData &cup){ m_cup = cup; }
void setDifficulty(Difficulty diff);
void setNumLaps(int num) { m_num_laps.clear();
m_num_laps.push_back(num); }
void setRaceMode(RaceModeType mode) { m_race_mode = mode; }
void setNumKarts(int num) { m_num_karts = num; }
void setCoinTarget(int num) { m_coin_target = num; }
RaceModeType getRaceMode() const { return m_race_mode; }
unsigned int getNumKarts() const { return m_num_karts; }
unsigned int getNumPlayers() const { return (int)m_player_karts.size();}
int getNumLaps() const { return m_num_laps[m_track_number];}
Difficulty getDifficulty() const { return m_difficulty; }
const std::string&
getTrackName() const { return m_tracks[m_track_number]; }
const CupData
*getGrandPrix() const { return &m_cup; }
unsigned int getFinishedKarts() const { return m_num_finished_karts; }
unsigned int getFinishedPlayers() const { return m_num_finished_players; }
const std::string&
getKartName(int kart) const { return m_kart_status[kart].m_ident;}
const std::string&
getHerringStyle() const { return m_cup.getHerringStyle(); }
int getKartScore(int krt) const { return m_kart_status[krt].m_score;}
int getPositionScore(int p) const { return m_score_for_position[p-1]; }
double getOverallTime(int kart) const { return m_kart_status[kart].m_overall_time;}
int getCoinTarget() const { return m_coin_target; }
bool isEliminated(int kart) const { return m_kart_status[kart].m_is_eliminated;}
bool raceHasLaps() const { return m_race_mode!=RM_FOLLOW_LEADER;}
void eliminate(int kart) { m_kart_status[kart].m_is_eliminated=true;}
int allPlayerFinished() const {return
m_num_finished_players==m_player_karts.size(); }
int raceIsActive() const { return m_active_race; }
bool isPlayer(int kart) const {return m_kart_status[kart].m_player_id>-1; }
void setMirror() {/*FIXME*/}
void setReverse(){/*FIXME*/}
void setMirror() {/*FIXME*/}
void setReverse(){/*FIXME*/}
void startNew(); // start new race/GP/...
void next(); // start the next race or go back to the start screen

View File

@ -54,15 +54,16 @@ const int Track::UNKNOWN_SECTOR = -1;
// ----------------------------------------------------------------------------
Track::Track( std::string filename_, float w, float h, bool stretch )
{
m_filename = filename_;
m_herring_style = "";
m_track_2d_width = w;
m_track_2d_height = h;
m_do_stretch = stretch;
m_description = "";
m_designer = "";
m_screenshot = "";
m_top_view = "";
m_filename = filename_;
m_herring_style = "";
m_track_2d_width = w;
m_track_2d_height = h;
m_do_stretch = stretch;
m_description = "";
m_designer = "";
m_screenshot = "";
m_top_view = "";
m_has_final_camera = false;
loadTrack(m_filename);
loadDriveline();
@ -842,6 +843,10 @@ void Track::loadTrack(std::string filename_)
LISP->get ("gravity", m_gravity);
LISP->get ("AI-angle-adjust", m_AI_angle_adjustment);
LISP->get ("AI-curve-speed-adjust", m_AI_curve_speed_adjustment);
// if both camera position and rotation are defined,
// set the flag that the track has final camera position
m_has_final_camera = LISP->get("camera-final-position", m_camera_final_position);
m_has_final_camera &= LISP->get("camera-final-hpr", m_camera_final_hpr);
// Set the correct paths
m_screenshot = file_manager->getTrackFile(m_screenshot, getIdent());

View File

@ -59,6 +59,9 @@ private:
// braking. These factors are used to adjust this.
float m_AI_angle_adjustment;
float m_AI_curve_speed_adjustment;
bool m_has_final_camera;
btVector3 m_camera_final_position;
btVector3 m_camera_final_hpr;
public:
enum RoadSide{ RS_DONT_KNOW = -1, RS_LEFT = 0, RS_RIGHT = 1 };
@ -192,6 +195,9 @@ public:
const std::string& getScreenshotFile () const {return m_screenshot; }
const std::vector<SGfloat>& getWidth () const {return m_path_width; }
const std::string& getHerringStyle () const {return m_herring_style; }
bool hasFinalCamera () const {return m_has_final_camera; }
const btVector3& getCameraPosition () const {return m_camera_final_position;}
const btVector3& getCameraHPR () const {return m_camera_final_hpr; }
void getStartCoords (unsigned int pos, sgCoord* coords) const;
void getTerrainInfo(const btVector3 &pos, float *hot, btVector3* normal,
const Material **material) const;

View File

@ -258,36 +258,7 @@ void World::update(float dt)
unlock_manager->raceFinished();
return;
}
// Add times to highscore list. First compute the order of karts,
// so that the timing of the fastest kart is added first (otherwise
// someone might get into the highscore list, only to be kicked out
// again by a faster kart in the same race), which might be confusing
// if we ever decide to display a message (e.g. during a race)
unsigned int *index = new unsigned int[m_kart.size()];
for (unsigned int i=0; i<m_kart.size(); i++ )
{
index[m_kart[i]->getPosition()-1] = i;
}
for(unsigned int pos=0; pos<m_kart.size(); pos++)
{
// Only record times for player karts
if(!m_kart[index[pos]]->isPlayerKart()) continue;
PlayerKart *k = (PlayerKart*)m_kart[index[pos]];
Highscores::HighscoreType hst = (race_manager->getRaceMode()==
RaceManager::RM_TIME_TRIAL)
? Highscores::HST_TIMETRIAL_OVERALL_TIME
: Highscores::HST_RACE_OVERALL_TIME;
if(m_highscores->addData(hst, k->getName(),
k->getPlayer()->getName(),
k->getFinishTime())>0 )
{
highscore_manager->Save();
}
}
delete []index;
updateHighscores();
pause();
menu_manager->pushMenu(MENUID_RACERESULT);
}
@ -305,7 +276,7 @@ void World::update(float dt)
for ( Karts::size_type i = 0 ; i < m_kart.size(); ++i)
{
if(m_kart[i]->isEliminated()) continue; // ignore eliminated kart
if(!m_kart[i]->raceIsFinished()) updateRacePosition((int)i);
if(!m_kart[i]->hasFinishedRace()) updateRacePosition((int)i);
if(m_kart[i]->isPlayerKart()) m_kart[i]->addMessages(); // add 'wrong direction'
}
@ -322,9 +293,43 @@ void World::update(float dt)
}
#endif
}
// ----------------------------------------------------------------------------
void World::updateHighscores()
{
// Add times to highscore list. First compute the order of karts,
// so that the timing of the fastest kart is added first (otherwise
// someone might get into the highscore list, only to be kicked out
// again by a faster kart in the same race), which might be confusing
// if we ever decide to display a message (e.g. during a race)
unsigned int *index = new unsigned int[m_kart.size()];
for (unsigned int i=0; i<m_kart.size(); i++ )
{
index[m_kart[i]->getPosition()-1] = i;
}
for(unsigned int pos=0; pos<m_kart.size(); pos++)
{
// Only record times for player karts
if(!m_kart[index[pos]]->isPlayerKart()) continue;
PlayerKart *k = (PlayerKart*)m_kart[index[pos]];
Highscores::HighscoreType hst = (race_manager->getRaceMode()==
RaceManager::RM_TIME_TRIAL)
? Highscores::HST_TIMETRIAL_OVERALL_TIME
: Highscores::HST_RACE_OVERALL_TIME;
if(m_highscores->addData(hst, k->getName(),
k->getPlayer()->getName(),
k->getFinishTime())>0 )
{
highscore_manager->Save();
}
}
delete []index;
} // updateHighscores
// ----------------------------------------------------------------------------
#ifdef HAVE_GHOST_REPLAY
//-----------------------------------------------------------------------------
bool World::saveReplayHumanReadable( std::string const &filename ) const
{
std::string path;
@ -403,17 +408,23 @@ bool World::loadReplayHumanReadable( std::string const &filename )
void World::updateRaceStatus(float dt)
{
switch (m_phase) {
case SETUP_PHASE: m_clock=0.0f; m_phase=READY_PHASE;
// Note: setup phase must be a separate phase, since the race_manager
// checks the phase when updating the camera: in the very first time
// step dt is large (it includes loading time), so the camera might
// tilt way too much. A separate setup phase for the first frame
// simplifies this handling
case SETUP_PHASE: m_clock = 0.0f;
m_phase = READY_PHASE;
sound_manager->playSfx(SOUND_PRESTART);
dt = 0.0f; // solves the problem of adding track loading time
break; // loading time, don't play sound yet
case READY_PHASE: if(m_clock==0.0) // play sound at beginning of next frame
sound_manager->playSfx(SOUND_PRESTART);
if(m_clock>1.0)
return; // loading time, don't play sound yet
case READY_PHASE: if(m_clock>1.0)
{
m_phase=SET_PHASE;
sound_manager->playSfx(SOUND_PRESTART);
}
break;
m_clock += dt;
return;
case SET_PHASE : if(m_clock>2.0)
{
m_phase=GO_PHASE;
@ -434,167 +445,148 @@ void World::updateRaceStatus(float dt)
m_replay_recorder.pushFrame();
#endif
}
break;
m_clock += dt;
return;
case GO_PHASE : if(race_manager->getRaceMode()==RaceManager::RM_FOLLOW_LEADER)
{
// Switch to race if more than 1 second has past
if(m_clock<m_leader_intervals[0]-1.0f)
m_phase=RACE_PHASE;
m_clock -= dt;
}
else
{
if(m_clock>1.0) // how long to display the 'go' message
m_phase=RACE_PHASE;
m_clock += dt;
}
return;
case DELAY_FINISH_PHASE :
{
m_clock += dt;
// Nothing more to do if delay time is not over yet
if(m_clock < TIME_DELAY_TILL_FINISH) return;
m_phase = FINISH_PHASE;
estimateFinishTimes();
unlock_manager->raceFinished();
return;
}
break;
default : break;
} // switch
if(race_manager->getRaceMode()==RaceManager::RM_FOLLOW_LEADER)
{
// Count 'normal' till race phase has started, then count backwards
if(m_phase==RACE_PHASE || m_phase==GO_PHASE)
m_clock -=dt;
else
m_clock +=dt;
if(m_clock<0.0f)
{
if(m_leader_intervals.size()>1)
m_leader_intervals.erase(m_leader_intervals.begin());
m_clock=m_leader_intervals[0];
int kart_number;
// If the leader kart is not the first kart, remove the first
// kart, otherwise remove the last kart.
int position_to_remove = m_kart[0]->getPosition()==1
? getCurrentNumKarts() : 1;
for (kart_number=0; kart_number<(int)m_kart.size(); kart_number++)
{
if(m_kart[kart_number]->isEliminated()) continue;
if(m_kart[kart_number]->getPosition()==position_to_remove)
break;
}
if(kart_number==m_kart.size())
{
fprintf(stderr,"Problem with removing leader: position %d not found\n",
position_to_remove);
for(int i=0; i<(int)m_kart.size(); i++)
{
fprintf(stderr,"kart %d: eliminated %d position %d\n",
i,m_kart[i]->isEliminated(), m_kart[i]->getPosition());
} // for i
} // kart_number==m_kart.size()
else
{
removeKart(kart_number);
}
// The follow the leader race is over if there isonly one kart left,
// or if all players have gone
if(getCurrentNumKarts()==2 ||getCurrentNumPlayers()==0)
{
// Add the results for the remaining kart
for(int i=1; i<(int)race_manager->getNumKarts(); i++)
if(!m_kart[i]->isEliminated())
race_manager->addKartResult(i, m_kart[i]->getPosition(),
m_clock);
m_phase=FINISH_PHASE;
return;
}
} // m_clock<0
return;
} // if is follow leader mode
return updateLeaderMode(dt);
// Now handling of normal race
// ===========================
m_clock += dt;
// The status must now be race mode!
// =================================
m_clock += dt;
/*if all players have finished, or if only one kart is not finished when
not in time trial mode, the race is over. Players are the last in the
vector, so substracting the number of players finds the first player's
position.*/
int new_finished_karts = 0;
for ( Karts::size_type i = 0; i < m_kart.size(); ++i)
{
if(m_kart[i]->isEliminated()) continue;
// FIXME: this part should be done as part of Kart::update
if ((m_kart[i]->getLap () >= race_manager->getNumLaps()) && !m_kart[i]->raceIsFinished())
{
m_kart[i]->setFinishingState(m_clock);
race_manager->addKartResult((int)i, m_kart[i]->getPosition(), m_clock);
++new_finished_karts;
if(m_kart[i]->isPlayerKart())
{
race_manager->PlayerFinishes();
RaceGUI* m=(RaceGUI*)menu_manager->getRaceMenu();
if(m)
{
m->addMessage(m_kart[i]->getPosition()==1
? _("You won")
: _("You finished") ,
m_kart[i], 2.0f, 60);
m->addMessage( _("the race!"), m_kart[i], 2.0f, 60);
}
}
}
}
race_manager->addFinishedKarts(new_finished_karts);
// 1) All karts are finished --> end the race
// ==========================================
// 2) A player comes in last, go immediately to finish phase
// =========================================================
if(race_manager->getFinishedKarts() >= race_manager->getNumKarts() )
{
m_phase = FINISH_PHASE;
if(user_config->m_profile<0) // profiling number of laps -> print stats
{
float min_t=999999.9f, max_t=0.0, av_t=0.0;
for ( Karts::size_type i = 0; i < m_kart.size(); ++i)
{
max_t = std::max(max_t, m_kart[i]->getFinishTime());
min_t = std::min(min_t, m_kart[i]->getFinishTime());
av_t += m_kart[i]->getFinishTime();
printf("%s start %d end %d time %f\n",
m_kart[i]->getName().c_str(),(int)i,
m_kart[i]->getPosition(),
m_kart[i]->getFinishTime());
}
printf("min %f max %f av %f\n",min_t, max_t, av_t/m_kart.size());
std::exit(-2);
}
if(user_config->m_profile<0) printProfileResultAndExit();
unlock_manager->raceFinished();
} // if all karts are finished
// 2) All player karts are finished --> wait some
// time for AI karts to arrive before finishing
// ===============================================
else if(race_manager->allPlayerFinished() && m_phase == RACE_PHASE &&
!user_config->m_profile)
// 3) All player karts are finished, but computer still racing
// ===========================================================
else if(race_manager->allPlayerFinished())
{
// Set delay mode to have time for camera animation, and
// to give the AI some time to get non-estimated timings
m_phase = DELAY_FINISH_PHASE;
m_finish_delay_start_time = m_clock;
m_clock = 0.0f;
}
// 3) If the 'wait for AI' time is over, estimate arrival times & finish
// =====================================================================
else if(m_phase==DELAY_FINISH_PHASE &&
m_clock-m_finish_delay_start_time>TIME_DELAY_TILL_FINISH &&
!user_config->m_profile)
{
m_phase = FINISH_PHASE;
for ( Karts::size_type i = 0; i < m_kart.size(); ++i)
{
if(!m_kart[i]->raceIsFinished())
{
const float est_finish_time = m_kart[i]->estimateFinishTime();
m_kart[i]->setFinishingState(est_finish_time);
race_manager->addKartResult((int)i, m_kart[i]->getPosition(),
est_finish_time);
} // if !raceIsFinished
} // for i
}
if(m_phase==FINISH_PHASE) unlock_manager->raceFinished();
} // updateRaceStatus
//-----------------------------------------------------------------------------
void World::estimateFinishTimes()
{
for ( Karts::size_type i = 0; i < m_kart.size(); ++i)
{
if(!m_kart[i]->hasFinishedRace())
{
const float est_finish_time = m_kart[i]->estimateFinishTime();
m_kart[i]->raceFinished(est_finish_time);
} // if !hasFinishedRace
} // for i
} // estimateFinishTimes
//-----------------------------------------------------------------------------
void World::updateLeaderMode(float dt)
{
// Count 'normal' till race phase has started, then count backwards
if(m_phase==RACE_PHASE || m_phase==GO_PHASE)
m_clock -=dt;
else
m_clock +=dt;
if(m_clock<0.0f)
{
if(m_leader_intervals.size()>1)
m_leader_intervals.erase(m_leader_intervals.begin());
m_clock=m_leader_intervals[0];
int kart_number;
// If the leader kart is not the first kart, remove the first
// kart, otherwise remove the last kart.
int position_to_remove = m_kart[0]->getPosition()==1
? getCurrentNumKarts() : 1;
for (kart_number=0; kart_number<(int)m_kart.size(); kart_number++)
{
if(m_kart[kart_number]->isEliminated()) continue;
if(m_kart[kart_number]->getPosition()==position_to_remove)
break;
}
if(kart_number==m_kart.size())
{
fprintf(stderr,"Problem with removing leader: position %d not found\n",
position_to_remove);
for(int i=0; i<(int)m_kart.size(); i++)
{
fprintf(stderr,"kart %d: eliminated %d position %d\n",
i,m_kart[i]->isEliminated(), m_kart[i]->getPosition());
} // for i
} // kart_number==m_kart.size()
else
{
removeKart(kart_number);
}
// The follow the leader race is over if there is only one kart left,
// or if all players have gone
if(getCurrentNumKarts()==2 ||getCurrentNumPlayers()==0)
{
// Add the results for the remaining kart
for(int i=1; i<(int)race_manager->getNumKarts(); i++)
if(!m_kart[i]->isEliminated())
race_manager->RaceFinished(m_kart[i], m_clock);
m_phase=FINISH_PHASE;
return;
}
} // m_clock<0
return;
} // updateLeaderMode
//-----------------------------------------------------------------------------
void World::printProfileResultAndExit()
{
float min_t=999999.9f, max_t=0.0, av_t=0.0;
for ( Karts::size_type i = 0; i < m_kart.size(); ++i)
{
max_t = std::max(max_t, m_kart[i]->getFinishTime());
min_t = std::min(min_t, m_kart[i]->getFinishTime());
av_t += m_kart[i]->getFinishTime();
printf("%s start %d end %d time %f\n",
m_kart[i]->getName().c_str(),(int)i,
m_kart[i]->getPosition(),
m_kart[i]->getFinishTime());
}
printf("min %f max %f av %f\n",min_t, max_t, av_t/m_kart.size());
std::exit(-2);
} // printProfileResultAndExit
//-----------------------------------------------------------------------------
/** Called in follow-leader-mode to remove the last kart
*/
@ -635,7 +627,7 @@ void World::removeKart(int kart_number)
// ignored in all loops). Important:world->getCurrentNumKarts() returns
// the number of karts still racing. This value can not be used for loops
// over all karts, use race_manager->getNumKarts() instead!
race_manager->addKartResult(kart_number, kart->getPosition(), m_clock);
race_manager->RaceFinished(kart, m_clock);
race_manager->eliminate(kart_number);
kart->eliminate();
m_eliminated_karts++;
@ -657,7 +649,7 @@ void World::updateRacePosition ( int k )
// Count karts ahead of the current kart, i.e. kart that are already
// finished (the current kart k has not yet finished!!), have done more
// laps, or the same number of laps, but a greater distance.
if (m_kart[j]->raceIsFinished() ||
if (m_kart[j]->hasFinishedRace() ||
m_kart[j]->getLap() > m_kart[k]->getLap() ||
(m_kart[j]->getLap() == m_kart[k]->getLap() &&
m_kart[j]->getDistanceDownTrack() > m_kart[k]->getDistanceDownTrack()) )

View File

@ -111,7 +111,6 @@ public:
private:
Karts m_kart;
std::vector<PlayerKart*> m_player_karts;
float m_finish_delay_start_time;
Physics* m_physics;
float m_fastest_lap;
Kart* m_fastest_kart;
@ -123,14 +122,18 @@ private:
std::vector<float>
m_leader_intervals; // time till elimination in follow leader
bool m_faster_music_active; // true if faster music was activated
void updateRacePosition( int k );
void loadTrack();
void updateRaceStatus(float dt);
void resetAllKarts();
void removeKart(int kart_number);
Kart* loadRobot(const std::string& kart_name, int position,
sgCoord init_pos);
void updateRacePosition(int k);
void updateHighscores ();
void loadTrack ();
void updateRaceStatus (float dt);
void resetAllKarts ();
void removeKart (int kart_number);
Kart* loadRobot (const std::string& kart_name, int position,
sgCoord init_pos);
void updateLeaderMode (float dt);
void printProfileResultAndExit();
void estimateFinishTimes();
#ifdef HAVE_GHOST_REPLAY
private:
bool saveReplayHumanReadable( std::string const &filename ) const;