Improved ghost format to support events (like start/end
skidding), and to make it easier to concatenate ghost data. Skidding events are already stored, but not used in replay atm. git-svn-id: svn+ssh://svn.code.sf.net/p/supertuxkart/code/main/trunk@10969 178a84e3-b1eb-0310-8ba1-8eac791a3b58
This commit is contained in:
parent
83fc0b2644
commit
9377234935
@ -25,7 +25,8 @@ GhostKart::GhostKart(const std::string& ident)
|
|||||||
: Kart(ident, /*world kart id*/99999,
|
: Kart(ident, /*world kart id*/99999,
|
||||||
/*position*/-1, btTransform())
|
/*position*/-1, btTransform())
|
||||||
{
|
{
|
||||||
m_current = 0;
|
m_current_transform = 0;
|
||||||
|
m_next_event = 0;
|
||||||
} // GhostKart
|
} // GhostKart
|
||||||
|
|
||||||
// ----------------------------------------------------------------------------
|
// ----------------------------------------------------------------------------
|
||||||
@ -33,7 +34,8 @@ void GhostKart::reset()
|
|||||||
{
|
{
|
||||||
m_node->setVisible(true);
|
m_node->setVisible(true);
|
||||||
Kart::reset();
|
Kart::reset();
|
||||||
m_current = 0;
|
m_current_transform = 0;
|
||||||
|
m_next_event = 0;
|
||||||
// This will set the correct start position
|
// This will set the correct start position
|
||||||
update(0);
|
update(0);
|
||||||
} // reset
|
} // reset
|
||||||
@ -55,30 +57,60 @@ void GhostKart::addTransform(float time, const btTransform &trans)
|
|||||||
} // addTransform
|
} // addTransform
|
||||||
|
|
||||||
// ----------------------------------------------------------------------------
|
// ----------------------------------------------------------------------------
|
||||||
|
/** Adds a replay event for this kart.
|
||||||
|
*/
|
||||||
|
void GhostKart::addReplayEvent(const ReplayBase::KartReplayEvent &kre)
|
||||||
|
{
|
||||||
|
m_replay_events.push_back(kre);
|
||||||
|
} // addReplayEvent
|
||||||
|
|
||||||
|
// ----------------------------------------------------------------------------
|
||||||
|
/** Updates the ghost data each time step. It uses interpolation to get a new
|
||||||
|
* position and rotation.
|
||||||
|
* \param dt Time step size.
|
||||||
|
*/
|
||||||
void GhostKart::update(float dt)
|
void GhostKart::update(float dt)
|
||||||
{
|
{
|
||||||
float t = World::getWorld()->getTime();
|
float t = World::getWorld()->getTime();
|
||||||
// Don't do anything at startup
|
// Don't do anything at startup
|
||||||
if(t==0) return;
|
if(t==0) return;
|
||||||
|
updateTransform(t, dt);
|
||||||
|
while(m_next_event < m_replay_events.size() &&
|
||||||
|
m_replay_events[m_next_event].m_time <= t)
|
||||||
|
{
|
||||||
|
printf("Handling event %d\n", m_next_event);
|
||||||
|
// Handle the next event now
|
||||||
|
m_next_event++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// ----------------------------------------------------------------------------
|
||||||
|
/** Updates the current transform of the ghost kart using interpolation
|
||||||
|
* \param t Current world time.
|
||||||
|
* \param dt Time step size.
|
||||||
|
*/
|
||||||
|
void GhostKart::updateTransform(float t, float dt)
|
||||||
|
{
|
||||||
|
|
||||||
// Find (if necessary) the next index to use
|
// Find (if necessary) the next index to use
|
||||||
while(m_current+1 < m_all_times.size() &&
|
while(m_current_transform+1 < m_all_times.size() &&
|
||||||
t>=m_all_times[m_current+1])
|
t>=m_all_times[m_current_transform+1])
|
||||||
{
|
{
|
||||||
m_current ++;
|
m_current_transform ++;
|
||||||
}
|
}
|
||||||
if(m_current+1>=m_all_times.size())
|
if(m_current_transform+1>=m_all_times.size())
|
||||||
{
|
{
|
||||||
m_node->setVisible(false);
|
m_node->setVisible(false);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
float f =(t - m_all_times[m_current])
|
float f =(t - m_all_times[m_current_transform])
|
||||||
/ (m_all_times[m_current+1] - m_all_times[m_current]);
|
/ ( m_all_times[m_current_transform+1]
|
||||||
setXYZ((1-f)*m_all_transform[m_current ].getOrigin()
|
- m_all_times[m_current_transform] );
|
||||||
+ f *m_all_transform[m_current+1].getOrigin() );
|
setXYZ((1-f)*m_all_transform[m_current_transform ].getOrigin()
|
||||||
const btQuaternion q = m_all_transform[m_current].getRotation()
|
+ f *m_all_transform[m_current_transform+1].getOrigin() );
|
||||||
.slerp(m_all_transform[m_current+1].getRotation(),
|
const btQuaternion q = m_all_transform[m_current_transform].getRotation()
|
||||||
|
.slerp(m_all_transform[m_current_transform+1]
|
||||||
|
.getRotation(),
|
||||||
f);
|
f);
|
||||||
setRotation(q);
|
setRotation(q);
|
||||||
Moveable::updateGraphics(dt, Vec3(0,0,0), btQuaternion(0, 0, 0, 1));
|
Moveable::updateGraphics(dt, Vec3(0,0,0), btQuaternion(0, 0, 0, 1));
|
||||||
|
@ -20,6 +20,7 @@
|
|||||||
#define HEADER_GHOST_KART_HPP
|
#define HEADER_GHOST_KART_HPP
|
||||||
|
|
||||||
#include "karts/kart.hpp"
|
#include "karts/kart.hpp"
|
||||||
|
#include "replay/replay_base.hpp"
|
||||||
|
|
||||||
#include "LinearMath/btTransform.h"
|
#include "LinearMath/btTransform.h"
|
||||||
|
|
||||||
@ -37,17 +38,25 @@ class GhostKart : public Kart
|
|||||||
private:
|
private:
|
||||||
/** The list of the times at which the transform were reached. */
|
/** The list of the times at which the transform were reached. */
|
||||||
std::vector<float> m_all_times;
|
std::vector<float> m_all_times;
|
||||||
|
|
||||||
/** The transforms to assume at the corresponding time in m_all_times. */
|
/** The transforms to assume at the corresponding time in m_all_times. */
|
||||||
std::vector<btTransform> m_all_transform;
|
std::vector<btTransform> m_all_transform;
|
||||||
|
|
||||||
|
std::vector<ReplayBase::KartReplayEvent> m_replay_events;
|
||||||
|
|
||||||
/** Pointer to the last index in m_all_times that is smaller than
|
/** Pointer to the last index in m_all_times that is smaller than
|
||||||
* the current world time. */
|
* the current world time. */
|
||||||
unsigned int m_current;
|
unsigned int m_current_transform;
|
||||||
|
|
||||||
|
/** Index of the next kart replay event. */
|
||||||
|
unsigned int m_next_event;
|
||||||
|
|
||||||
|
void updateTransform(float t, float dt);
|
||||||
public:
|
public:
|
||||||
GhostKart(const std::string& ident);
|
GhostKart(const std::string& ident);
|
||||||
virtual void update (float dt);
|
virtual void update (float dt);
|
||||||
virtual void addTransform(float time, const btTransform &trans);
|
virtual void addTransform(float time, const btTransform &trans);
|
||||||
|
virtual void addReplayEvent(const ReplayBase::KartReplayEvent &kre);
|
||||||
virtual void reset();
|
virtual void reset();
|
||||||
// ------------------------------------------------------------------------
|
// ------------------------------------------------------------------------
|
||||||
/** No physics body for ghost kart, so nothing to adjust. */
|
/** No physics body for ghost kart, so nothing to adjust. */
|
||||||
|
@ -30,6 +30,8 @@
|
|||||||
*/
|
*/
|
||||||
class ReplayBase : public NoCopy
|
class ReplayBase : public NoCopy
|
||||||
{
|
{
|
||||||
|
// Needs access to KartReplayEvent
|
||||||
|
friend class GhostKart;
|
||||||
private:
|
private:
|
||||||
/** The filename of the replay file. Only defined after calling
|
/** The filename of the replay file. Only defined after calling
|
||||||
* openReplayFile. */
|
* openReplayFile. */
|
||||||
@ -44,9 +46,20 @@ protected:
|
|||||||
/** The transform at a certain time. */
|
/** The transform at a certain time. */
|
||||||
btTransform m_transform;
|
btTransform m_transform;
|
||||||
}; // TransformEvent
|
}; // TransformEvent
|
||||||
|
|
||||||
// ------------------------------------------------------------------------
|
// ------------------------------------------------------------------------
|
||||||
ReplayBase();
|
/** Records all other events - atm start and end skidding. */
|
||||||
|
struct KartReplayEvent
|
||||||
|
{
|
||||||
|
/** The type of event. */
|
||||||
|
enum {KRE_NONE, KRE_SKID_TOGGLE} m_type;
|
||||||
|
|
||||||
|
/** Time at which this event happens. */
|
||||||
|
float m_time;
|
||||||
|
}; // KartReplayEvent
|
||||||
|
|
||||||
// ------------------------------------------------------------------------
|
// ------------------------------------------------------------------------
|
||||||
|
ReplayBase();
|
||||||
FILE *openReplayFile(bool writeable);
|
FILE *openReplayFile(bool writeable);
|
||||||
// ----------------------------------------------------------------------
|
// ----------------------------------------------------------------------
|
||||||
/** Returns the filename that was opened. */
|
/** Returns the filename that was opened. */
|
||||||
|
@ -154,76 +154,99 @@ void ReplayPlay::Load()
|
|||||||
}
|
}
|
||||||
race_manager->setNumLaps(num_laps);
|
race_manager->setNumLaps(num_laps);
|
||||||
|
|
||||||
fgets(s, 1023, fd);
|
// eof actually doesn't trigger here, since it requires first to try
|
||||||
unsigned int num_ghost_karts;
|
// reading behind eof, but still it's clearer this way.
|
||||||
if(sscanf(s, "numkarts: %d",&num_ghost_karts)!=1)
|
while(!feof(fd))
|
||||||
{
|
{
|
||||||
fprintf(stderr,"WARNING: No number of karts found in replay file.\n");
|
if(fgets(s, 1023, fd)==NULL) // eof reached
|
||||||
exit(-2);
|
break;
|
||||||
}
|
readKartData(fd, s);
|
||||||
|
} // for k<num_ghost_karts
|
||||||
for(unsigned int k=0; k<num_ghost_karts; k++)
|
|
||||||
{
|
|
||||||
fgets(s, 1023, fd);
|
|
||||||
unsigned int kart_id;
|
|
||||||
if(sscanf(s, "model %d: %s",&kart_id, s1)!=2)
|
|
||||||
{
|
|
||||||
fprintf(stderr,
|
|
||||||
"WARNING: No model information for kart %d found.\n",
|
|
||||||
k);
|
|
||||||
exit(-2);
|
|
||||||
}
|
|
||||||
if(kart_id != k)
|
|
||||||
{
|
|
||||||
fprintf(stderr,
|
|
||||||
"WARNING: Expected kart id %d, got %d - ignored.\n",
|
|
||||||
k, kart_id);
|
|
||||||
}
|
|
||||||
m_ghost_karts.push_back(new GhostKart(std::string(s1)));
|
|
||||||
m_ghost_karts[m_ghost_karts.size()-1].init(RaceManager::KT_GHOST,
|
|
||||||
/*is_first_kart*/false);
|
|
||||||
|
|
||||||
fgets(s, 1023, fd);
|
|
||||||
unsigned int size;
|
|
||||||
if(sscanf(s,"size: %d",&size)!=1)
|
|
||||||
{
|
|
||||||
fprintf(stderr,
|
|
||||||
"WARNING: Number of records not found in replay file "
|
|
||||||
"for kart %d.\n",
|
|
||||||
k);
|
|
||||||
exit(-2);
|
|
||||||
}
|
|
||||||
|
|
||||||
for(unsigned int i=0; i<size; i++)
|
|
||||||
{
|
|
||||||
fgets(s, 1023, fd);
|
|
||||||
float x, y, z, rx, ry, rz, rw, time;
|
|
||||||
|
|
||||||
// Check for EV_TRANSFORM event:
|
|
||||||
// -----------------------------
|
|
||||||
if(sscanf(s, "%f %f %f %f %f %f %f %f\n",
|
|
||||||
&time,
|
|
||||||
&x, &y, &z,
|
|
||||||
&rx, &ry, &rz, &rw
|
|
||||||
)==8)
|
|
||||||
{
|
|
||||||
btQuaternion q(rx, ry, rz, rw);
|
|
||||||
btVector3 xyz(x, y, z);
|
|
||||||
m_ghost_karts[k].addTransform(time, btTransform(q, xyz));
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// Invalid record found
|
|
||||||
// ---------------------
|
|
||||||
fprintf(stderr, "Can't read replay data line %d:\n", i);
|
|
||||||
fprintf(stderr, "%s", s);
|
|
||||||
fprintf(stderr, "Ignored.\n");
|
|
||||||
}
|
|
||||||
} // for k
|
|
||||||
|
|
||||||
} // for i<nKarts
|
|
||||||
|
|
||||||
fprintf(fd, "Replay file end.\n");
|
fprintf(fd, "Replay file end.\n");
|
||||||
fclose(fd);
|
fclose(fd);
|
||||||
} // Load
|
} // Load
|
||||||
|
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
/** Reads all data from a replay file for a specific kart.
|
||||||
|
* \param fd The file descriptor from which to read.
|
||||||
|
*/
|
||||||
|
void ReplayPlay::readKartData(FILE *fd, char *next_line)
|
||||||
|
{
|
||||||
|
char s[1024];
|
||||||
|
if(sscanf(next_line, "model: %s", s)!=1)
|
||||||
|
{
|
||||||
|
fprintf(stderr,
|
||||||
|
"WARNING: No model information for kart %d found.\n",
|
||||||
|
m_ghost_karts.size());
|
||||||
|
exit(-2);
|
||||||
|
}
|
||||||
|
m_ghost_karts.push_back(new GhostKart(std::string(s)));
|
||||||
|
m_ghost_karts[m_ghost_karts.size()-1].init(RaceManager::KT_GHOST,
|
||||||
|
/*is_first_kart*/false);
|
||||||
|
|
||||||
|
fgets(s, 1023, fd);
|
||||||
|
unsigned int size;
|
||||||
|
if(sscanf(s,"size: %d",&size)!=1)
|
||||||
|
{
|
||||||
|
fprintf(stderr,
|
||||||
|
"WARNING: Number of records not found in replay file "
|
||||||
|
"for kart %d.\n",
|
||||||
|
m_ghost_karts.size()-1);
|
||||||
|
exit(-2);
|
||||||
|
}
|
||||||
|
|
||||||
|
for(unsigned int i=0; i<size; i++)
|
||||||
|
{
|
||||||
|
fgets(s, 1023, fd);
|
||||||
|
float x, y, z, rx, ry, rz, rw, time;
|
||||||
|
|
||||||
|
// Check for EV_TRANSFORM event:
|
||||||
|
// -----------------------------
|
||||||
|
if(sscanf(s, "%f %f %f %f %f %f %f %f\n",
|
||||||
|
&time,
|
||||||
|
&x, &y, &z,
|
||||||
|
&rx, &ry, &rz, &rw
|
||||||
|
)==8)
|
||||||
|
{
|
||||||
|
btQuaternion q(rx, ry, rz, rw);
|
||||||
|
btVector3 xyz(x, y, z);
|
||||||
|
m_ghost_karts[m_ghost_karts.size()-1].addTransform(time,
|
||||||
|
btTransform(q, xyz));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Invalid record found
|
||||||
|
// ---------------------
|
||||||
|
fprintf(stderr, "Can't read replay data line %d:\n", i);
|
||||||
|
fprintf(stderr, "%s", s);
|
||||||
|
fprintf(stderr, "Ignored.\n");
|
||||||
|
}
|
||||||
|
} // for i
|
||||||
|
fgets(s, 1023, fd);
|
||||||
|
unsigned int num_events;
|
||||||
|
if(sscanf(s,"events: %d",&num_events)!=1)
|
||||||
|
{
|
||||||
|
fprintf(stderr,
|
||||||
|
"WARNING: Number of events not found in replay file "
|
||||||
|
"for kart %d.\n",
|
||||||
|
m_ghost_karts.size()-1);
|
||||||
|
}
|
||||||
|
for(unsigned int i=0; i<num_events; i++)
|
||||||
|
{
|
||||||
|
fgets(s, 1023, fd);
|
||||||
|
KartReplayEvent kre;
|
||||||
|
if(sscanf(s, "%f %d\n", &kre.m_time, &kre.m_type)==2)
|
||||||
|
m_ghost_karts[m_ghost_karts.size()-1].addReplayEvent(kre);
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Invalid record found
|
||||||
|
// ---------------------
|
||||||
|
fprintf(stderr, "Can't read replay event line %d:\n", i);
|
||||||
|
fprintf(stderr, "%s", s);
|
||||||
|
fprintf(stderr, "Ignored.\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
} // for i < events
|
||||||
|
|
||||||
|
} // readKartData
|
||||||
|
@ -43,6 +43,7 @@ private:
|
|||||||
|
|
||||||
ReplayPlay();
|
ReplayPlay();
|
||||||
~ReplayPlay();
|
~ReplayPlay();
|
||||||
|
void readKartData(FILE *fd, char *next_line);
|
||||||
public:
|
public:
|
||||||
void init();
|
void init();
|
||||||
void update(float dt);
|
void update(float dt);
|
||||||
|
@ -52,9 +52,13 @@ void ReplayRecorder::init()
|
|||||||
{
|
{
|
||||||
m_transform_events.clear();
|
m_transform_events.clear();
|
||||||
m_transform_events.resize(race_manager->getNumberOfKarts());
|
m_transform_events.resize(race_manager->getNumberOfKarts());
|
||||||
|
m_skid_control.resize(race_manager->getNumberOfKarts(), false);
|
||||||
|
m_kart_replay_event.resize(race_manager->getNumberOfKarts());
|
||||||
for(unsigned int i=0; i<race_manager->getNumberOfKarts(); i++)
|
for(unsigned int i=0; i<race_manager->getNumberOfKarts(); i++)
|
||||||
{
|
{
|
||||||
m_transform_events[i].resize(stk_config->m_max_history);
|
m_transform_events[i].resize(stk_config->m_max_history);
|
||||||
|
// Rather arbitraritly sized, it will be added with push_back
|
||||||
|
m_kart_replay_event[i].reserve(100);
|
||||||
}
|
}
|
||||||
m_count_transforms.clear();
|
m_count_transforms.clear();
|
||||||
m_count_transforms.resize(race_manager->getNumberOfKarts(), 0);
|
m_count_transforms.resize(race_manager->getNumberOfKarts(), 0);
|
||||||
@ -90,6 +94,17 @@ void ReplayRecorder::update(float dt)
|
|||||||
|
|
||||||
for(unsigned int i=0; i<num_karts; i++)
|
for(unsigned int i=0; i<num_karts; i++)
|
||||||
{
|
{
|
||||||
|
const Kart *kart = world->getKart(i);
|
||||||
|
|
||||||
|
// Check if skidding state has changed. If so, store this
|
||||||
|
if(kart->getControls().m_skid != m_skid_control[i])
|
||||||
|
{
|
||||||
|
KartReplayEvent kre;
|
||||||
|
kre.m_time = World::getWorld()->getTime();
|
||||||
|
kre.m_type = KartReplayEvent::KRE_SKID_TOGGLE;
|
||||||
|
m_kart_replay_event[i].push_back(kre);
|
||||||
|
m_skid_control[i] = ! m_skid_control[i];
|
||||||
|
}
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
m_count ++;
|
m_count ++;
|
||||||
#endif
|
#endif
|
||||||
@ -102,7 +117,6 @@ void ReplayRecorder::update(float dt)
|
|||||||
}
|
}
|
||||||
|
|
||||||
m_count_transforms[i]++;
|
m_count_transforms[i]++;
|
||||||
const Kart *kart = world->getKart(i);
|
|
||||||
if(m_count_transforms[i]>=m_transform_events[i].size())
|
if(m_count_transforms[i]>=m_transform_events[i].size())
|
||||||
{
|
{
|
||||||
// Only print this message once.
|
// Only print this message once.
|
||||||
@ -116,13 +130,17 @@ void ReplayRecorder::update(float dt)
|
|||||||
p->m_transform.setOrigin(kart->getXYZ());
|
p->m_transform.setOrigin(kart->getXYZ());
|
||||||
p->m_transform.setRotation(kart->getVisualRotation());
|
p->m_transform.setRotation(kart->getVisualRotation());
|
||||||
} // for i
|
} // for i
|
||||||
} // updateRecording
|
} // update
|
||||||
|
|
||||||
//-----------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------
|
||||||
/** Saves the replay data stored in the internal data structures.
|
/** Saves the replay data stored in the internal data structures.
|
||||||
*/
|
*/
|
||||||
void ReplayRecorder::Save()
|
void ReplayRecorder::Save()
|
||||||
{
|
{
|
||||||
|
#ifdef DEBUG
|
||||||
|
printf("%d frames %d transform events %d frequency compressed\n",
|
||||||
|
m_count, m_count_transforms, m_count_skipped_time);
|
||||||
|
#endif
|
||||||
FILE *fd = openReplayFile(/*writeable*/true);
|
FILE *fd = openReplayFile(/*writeable*/true);
|
||||||
if(!fd)
|
if(!fd)
|
||||||
{
|
{
|
||||||
@ -139,11 +157,10 @@ void ReplayRecorder::Save()
|
|||||||
fprintf(fd, "difficulty: %d\n", race_manager->getDifficulty());
|
fprintf(fd, "difficulty: %d\n", race_manager->getDifficulty());
|
||||||
fprintf(fd, "track: %s\n", world->getTrack()->getIdent().c_str());
|
fprintf(fd, "track: %s\n", world->getTrack()->getIdent().c_str());
|
||||||
fprintf(fd, "Laps: %d\n", race_manager->getNumLaps());
|
fprintf(fd, "Laps: %d\n", race_manager->getNumLaps());
|
||||||
fprintf(fd, "numkarts: %d\n", num_karts);
|
|
||||||
|
|
||||||
for(unsigned int k=0; k<num_karts; k++)
|
for(unsigned int k=0; k<num_karts; k++)
|
||||||
{
|
{
|
||||||
fprintf(fd, "model %d: %s\n",k, world->getKart(k)->getIdent().c_str());
|
fprintf(fd, "model: %s\n", world->getKart(k)->getIdent().c_str());
|
||||||
fprintf(fd, "size: %d\n", m_count_transforms[k]);
|
fprintf(fd, "size: %d\n", m_count_transforms[k]);
|
||||||
|
|
||||||
for(unsigned int i=0; i<m_count_transforms[k]; i++)
|
for(unsigned int i=0; i<m_count_transforms[k]; i++)
|
||||||
@ -159,9 +176,14 @@ void ReplayRecorder::Save()
|
|||||||
p->m_transform.getRotation().getZ(),
|
p->m_transform.getRotation().getZ(),
|
||||||
p->m_transform.getRotation().getW()
|
p->m_transform.getRotation().getW()
|
||||||
);
|
);
|
||||||
} // for k
|
} // for i
|
||||||
|
fprintf(fd, "events: %d\n", m_kart_replay_event[k].size());
|
||||||
|
for(unsigned int i=0; i<m_kart_replay_event[k].size(); i++)
|
||||||
|
{
|
||||||
|
const KartReplayEvent *p=&(m_kart_replay_event[k][i]);
|
||||||
|
fprintf(fd, "%f %d\n", p->m_time, p->m_type);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
fprintf(fd, "Replay file end.\n");
|
|
||||||
fclose(fd);
|
fclose(fd);
|
||||||
} // Save
|
} // Save
|
||||||
|
|
||||||
|
@ -39,6 +39,11 @@ private:
|
|||||||
/** Counts the number of transform events for each kart. */
|
/** Counts the number of transform events for each kart. */
|
||||||
std::vector<unsigned int> m_count_transforms;
|
std::vector<unsigned int> m_count_transforms;
|
||||||
|
|
||||||
|
/** Stores the last skid state. */
|
||||||
|
std::vector<bool> m_skid_control;
|
||||||
|
|
||||||
|
std::vector< std::vector<KartReplayEvent> > m_kart_replay_event;
|
||||||
|
|
||||||
/** Static pointer to the one instance of the replay object. */
|
/** Static pointer to the one instance of the replay object. */
|
||||||
static ReplayRecorder *m_replay_recorder;
|
static ReplayRecorder *m_replay_recorder;
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user