1) Fixed 'objects' import from blender script: objects are now
converted into the physics track model (previously they were only shown, but karts could drive through them). 2) Cleaned start position code: arena and normal tracks now use the same way and variables/functions to specify the start positions. git-svn-id: svn+ssh://svn.code.sf.net/p/supertuxkart/code/main/branches/irrlicht@4046 178a84e3-b1eb-0310-8ba1-8eac791a3b58
This commit is contained in:
parent
dacf594076
commit
049ab14678
@ -261,7 +261,7 @@ RaceGUI::KartIconDisplayInfo* ThreeStrikesBattle::getKartsDisplayInfo()
|
|||||||
void ThreeStrikesBattle::moveKartAfterRescue(Kart* kart, btRigidBody* body)
|
void ThreeStrikesBattle::moveKartAfterRescue(Kart* kart, btRigidBody* body)
|
||||||
{
|
{
|
||||||
// find closest point to drop kart on
|
// find closest point to drop kart on
|
||||||
const int start_spots_amount = RaceManager::getTrack()->m_start_positions.size();
|
const int start_spots_amount = RaceManager::getTrack()->getNumberOfStartPositions();
|
||||||
assert(start_spots_amount > 0);
|
assert(start_spots_amount > 0);
|
||||||
|
|
||||||
int smallest_distance_found = -1, closest_id_found = -1;
|
int smallest_distance_found = -1, closest_id_found = -1;
|
||||||
@ -273,8 +273,9 @@ void ThreeStrikesBattle::moveKartAfterRescue(Kart* kart, btRigidBody* body)
|
|||||||
{
|
{
|
||||||
// no need for the overhead to compute exact distance with sqrt(), so using the
|
// no need for the overhead to compute exact distance with sqrt(), so using the
|
||||||
// 'manhattan' heuristic which will do fine enough.
|
// 'manhattan' heuristic which will do fine enough.
|
||||||
const int dist_n = abs((int)(kart_x - RaceManager::getTrack()->m_start_positions[n][0])) +
|
const Vec3 &v=RaceManager::getTrack()->getStartPosition(n);
|
||||||
abs((int)(kart_y - RaceManager::getTrack()->m_start_positions[n][1]));
|
const int dist_n = abs((int)(kart_x - v.getX())) +
|
||||||
|
abs((int)(kart_y - v.getY()));
|
||||||
if(dist_n < smallest_distance_found || closest_id_found == -1)
|
if(dist_n < smallest_distance_found || closest_id_found == -1)
|
||||||
{
|
{
|
||||||
closest_id_found = n;
|
closest_id_found = n;
|
||||||
@ -283,11 +284,12 @@ void ThreeStrikesBattle::moveKartAfterRescue(Kart* kart, btRigidBody* body)
|
|||||||
}
|
}
|
||||||
|
|
||||||
assert(closest_id_found != -1);
|
assert(closest_id_found != -1);
|
||||||
|
const Vec3 &v=RaceManager::getTrack()->getStartPosition(closest_id_found);
|
||||||
kart->setXYZ( Vec3(RaceManager::getTrack()->m_start_positions[closest_id_found]) );
|
kart->setXYZ( Vec3(v) );
|
||||||
|
|
||||||
// FIXME - implement correct heading
|
// FIXME - implement correct heading
|
||||||
btQuaternion heading(btVector3(0.0f, 0.0f, 1.0f), 0 /* angle */ );
|
btQuaternion heading(btVector3(0.0f, 0.0f, 1.0f),
|
||||||
|
RaceManager::getTrack()->getStartHeading(closest_id_found));
|
||||||
kart->setRotation(heading);
|
kart->setRotation(heading);
|
||||||
|
|
||||||
//position kart from same height as in World::resetAllKarts
|
//position kart from same height as in World::resetAllKarts
|
||||||
|
@ -2,6 +2,7 @@
|
|||||||
//
|
//
|
||||||
// SuperTuxKart - a fun racing game with go-kart
|
// SuperTuxKart - a fun racing game with go-kart
|
||||||
// Copyright (C) 2004 Steve Baker <sjbaker1@airmail.net>
|
// Copyright (C) 2004 Steve Baker <sjbaker1@airmail.net>
|
||||||
|
// 2009 Joerg Henrichs, Steve Baker
|
||||||
//
|
//
|
||||||
// This program is free software; you can redistribute it and/or
|
// This program is free software; you can redistribute it and/or
|
||||||
// modify it under the terms of the GNU General Public License
|
// modify it under the terms of the GNU General Public License
|
||||||
@ -166,21 +167,9 @@ const Vec3& Track::trackToSpatial(const int sector) const
|
|||||||
btTransform Track::getStartTransform(unsigned int pos) const
|
btTransform Track::getStartTransform(unsigned int pos) const
|
||||||
{
|
{
|
||||||
|
|
||||||
Vec3 orig;
|
Vec3 orig = pos<m_start_positions.size()
|
||||||
|
? m_start_positions[pos]
|
||||||
if(isArena())
|
: Vec3( (pos%2==0)?1.5f:-1.5f, -1.5f*pos-1.5f, 1.0f);
|
||||||
{
|
|
||||||
assert(pos < m_start_positions.size());
|
|
||||||
orig.setX( m_start_positions[pos][0] );
|
|
||||||
orig.setY( m_start_positions[pos][1] );
|
|
||||||
orig.setZ( m_start_positions[pos][2] );
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
orig.setX( pos<m_start_x.size() ? m_start_x[pos] : ((pos%2==0)?1.5f:-1.5f) );
|
|
||||||
orig.setY( pos<m_start_y.size() ? m_start_y[pos] : -1.5f*pos-1.5f );
|
|
||||||
orig.setZ( pos<m_start_z.size() ? m_start_z[pos] : 1.0f );
|
|
||||||
}
|
|
||||||
btTransform start;
|
btTransform start;
|
||||||
start.setOrigin(orig);
|
start.setOrigin(orig);
|
||||||
start.setRotation(btQuaternion(btVector3(0, 0, 1),
|
start.setRotation(btQuaternion(btVector3(0, 0, 1),
|
||||||
@ -226,10 +215,6 @@ void Track::loadTrackInfo(const std::string &filename)
|
|||||||
root->get("item", &m_item_style);
|
root->get("item", &m_item_style);
|
||||||
root->get("screenshot", &m_screenshot);
|
root->get("screenshot", &m_screenshot);
|
||||||
root->get("sky-color", &m_sky_color);
|
root->get("sky-color", &m_sky_color);
|
||||||
root->get("start-x", &m_start_x);
|
|
||||||
root->get("start-y", &m_start_y);
|
|
||||||
root->get("start-z", &m_start_z);
|
|
||||||
root->get("start-heading", &m_start_heading);
|
|
||||||
root->get("use-fog", &m_use_fog);
|
root->get("use-fog", &m_use_fog);
|
||||||
root->get("fog-color", &m_fog_color);
|
root->get("fog-color", &m_fog_color);
|
||||||
root->get("fog-density", &m_fog_density);
|
root->get("fog-density", &m_fog_density);
|
||||||
@ -343,10 +328,13 @@ void Track::loadQuadGraph(unsigned int mode_id)
|
|||||||
} // loadQuadGraph
|
} // loadQuadGraph
|
||||||
|
|
||||||
// -----------------------------------------------------------------------------
|
// -----------------------------------------------------------------------------
|
||||||
//* Convert the ssg track tree into its physics equivalents.
|
/** Convert the track tree into its physics equivalents.
|
||||||
void Track::createPhysicsModel()
|
* \param main_track_count The number of meshes that are already converted
|
||||||
|
* when the main track was converted. Only the additional meshes
|
||||||
|
* added later still need to be converted.
|
||||||
|
*/
|
||||||
|
void Track::createPhysicsModel(unsigned int main_track_count)
|
||||||
{
|
{
|
||||||
|
|
||||||
// Remove the temporary track rigid body, and then convert all objects
|
// Remove the temporary track rigid body, and then convert all objects
|
||||||
// (i.e. the track and all additional objects) into a new rigid body
|
// (i.e. the track and all additional objects) into a new rigid body
|
||||||
// and convert this again. So this way we have an optimised track
|
// and convert this again. So this way we have an optimised track
|
||||||
@ -367,9 +355,9 @@ void Track::createPhysicsModel()
|
|||||||
}
|
}
|
||||||
|
|
||||||
m_track_mesh->removeBody();
|
m_track_mesh->removeBody();
|
||||||
for(unsigned int i=1; i<m_all_meshes.size(); i++)
|
for(unsigned int i=main_track_count; i<m_all_meshes.size(); i++)
|
||||||
{
|
{
|
||||||
convertTrackToBullet(m_all_meshes[i]);
|
convertTrackToBullet(m_all_meshes[i], m_all_nodes[i]);
|
||||||
}
|
}
|
||||||
m_track_mesh->createBody();
|
m_track_mesh->createBody();
|
||||||
m_non_collision_mesh->createBody(btCollisionObject::CF_NO_CONTACT_RESPONSE);
|
m_non_collision_mesh->createBody(btCollisionObject::CF_NO_CONTACT_RESPONSE);
|
||||||
@ -377,9 +365,18 @@ void Track::createPhysicsModel()
|
|||||||
} // createPhysicsModel
|
} // createPhysicsModel
|
||||||
|
|
||||||
// -----------------------------------------------------------------------------
|
// -----------------------------------------------------------------------------
|
||||||
//* Convert the graohics track into its physics equivalents.
|
/** Convert the graohics track into its physics equivalents.
|
||||||
void Track::convertTrackToBullet(const scene::IMesh *mesh)
|
* \param mesh The mesh to convert.
|
||||||
|
* \param node The scene node.
|
||||||
|
*/
|
||||||
|
void Track::convertTrackToBullet(const scene::IMesh *mesh,
|
||||||
|
const scene::ISceneNode *node)
|
||||||
{
|
{
|
||||||
|
const core::vector3df &pos = node->getPosition();
|
||||||
|
const core::vector3df &hpr = node->getRotation();
|
||||||
|
core::matrix4 mat;
|
||||||
|
mat.setRotationDegrees(hpr);
|
||||||
|
mat.setTranslation(pos);
|
||||||
for(unsigned int i=0; i<mesh->getMeshBufferCount(); i++) {
|
for(unsigned int i=0; i<mesh->getMeshBufferCount(); i++) {
|
||||||
scene::IMeshBuffer *mb = mesh->getMeshBuffer(i);
|
scene::IMeshBuffer *mb = mesh->getMeshBuffer(i);
|
||||||
// FIXME: take translation/rotation into account
|
// FIXME: take translation/rotation into account
|
||||||
@ -405,7 +402,9 @@ void Track::convertTrackToBullet(const scene::IMesh *mesh)
|
|||||||
for(unsigned int j=0; j<mb->getIndexCount(); j+=3) {
|
for(unsigned int j=0; j<mb->getIndexCount(); j+=3) {
|
||||||
for(unsigned int k=0; k<3; k++) {
|
for(unsigned int k=0; k<3; k++) {
|
||||||
int indx=mbIndices[j+k];
|
int indx=mbIndices[j+k];
|
||||||
vertices[k] = Vec3(mbVertices[indx].Pos);
|
core::vector3df v = mbVertices[indx].Pos;
|
||||||
|
mat.transformVect(v);
|
||||||
|
vertices[k] = Vec3(v);
|
||||||
} // for k
|
} // for k
|
||||||
if(tmesh) tmesh->addTriangle(vertices[0], vertices[1],
|
if(tmesh) tmesh->addTriangle(vertices[0], vertices[1],
|
||||||
vertices[2], material );
|
vertices[2], material );
|
||||||
@ -418,43 +417,74 @@ void Track::convertTrackToBullet(const scene::IMesh *mesh)
|
|||||||
* scene might use raycast on this track model to determine the actual
|
* scene might use raycast on this track model to determine the actual
|
||||||
* height of the terrain.
|
* height of the terrain.
|
||||||
*/
|
*/
|
||||||
bool Track::loadMainTrack(const XMLNode &xml_node)
|
bool Track::loadMainTrack(const XMLNode &root)
|
||||||
{
|
{
|
||||||
|
const XMLNode *track_node= root.getNode("track");
|
||||||
std::string model_name;
|
std::string model_name;
|
||||||
xml_node.get("model", &model_name);
|
track_node->get("model", &model_name);
|
||||||
std::string full_path = m_root+"/"+model_name;
|
std::string full_path = m_root+"/"+model_name;
|
||||||
scene::IMesh *mesh = irr_driver->getAnimatedMesh(full_path);
|
scene::IMesh *mesh = irr_driver->getAnimatedMesh(full_path);
|
||||||
if(!mesh)
|
if(!mesh)
|
||||||
{
|
{
|
||||||
fprintf(stderr, "Warning: Main track model '%s' in '%s' not found, aborting.\n",
|
fprintf(stderr, "Warning: Main track model '%s' in '%s' not found, aborting.\n",
|
||||||
xml_node.getName().c_str(), model_name.c_str());
|
track_node->getName().c_str(), model_name.c_str());
|
||||||
exit(-1);
|
exit(-1);
|
||||||
}
|
}
|
||||||
|
|
||||||
m_all_meshes.push_back(mesh);
|
m_all_meshes.push_back(mesh);
|
||||||
|
scene::ISceneNode *scene_node = irr_driver->addOctTree(mesh);
|
||||||
|
core::vector3df xyz(0,0,0);
|
||||||
|
track_node->getXYZ(&xyz);
|
||||||
|
core::vector3df hpr(0,0,0);
|
||||||
|
track_node->getHPR(&hpr);
|
||||||
|
scene_node->setPosition(xyz);
|
||||||
|
scene_node->setRotation(hpr);
|
||||||
|
handleAnimatedTextures(scene_node, *track_node);
|
||||||
|
m_all_nodes.push_back(scene_node);
|
||||||
|
|
||||||
MeshTools::minMax3D(mesh, &m_aabb_min, &m_aabb_max);
|
MeshTools::minMax3D(mesh, &m_aabb_min, &m_aabb_max);
|
||||||
RaceManager::getWorld()->getPhysics()->init(m_aabb_min, m_aabb_max);
|
RaceManager::getWorld()->getPhysics()->init(m_aabb_min, m_aabb_max);
|
||||||
|
|
||||||
|
for(unsigned int i=0; i<track_node->getNumNodes(); i++)
|
||||||
|
{
|
||||||
|
const XMLNode *n=track_node->getNode(i);
|
||||||
|
assert(n->getName()=="object");
|
||||||
|
model_name="";
|
||||||
|
n->get("model", &model_name);
|
||||||
|
full_path = m_root+"/"+model_name;
|
||||||
|
scene::IAnimatedMesh *a_mesh = irr_driver->getAnimatedMesh(full_path);
|
||||||
|
if(!a_mesh)
|
||||||
|
{
|
||||||
|
fprintf(stderr, "Warning: object model '%s' not found, ignored.\n",
|
||||||
|
full_path.c_str());
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
m_all_meshes.push_back(a_mesh);
|
||||||
|
scene::ISceneNode *scene_node = irr_driver->addAnimatedMesh(a_mesh);
|
||||||
|
core::vector3df xyz(0,0,0);
|
||||||
|
n->get("xyz", &xyz);
|
||||||
|
core::vector3df hpr(0,0,0);
|
||||||
|
n->get("hpr", &hpr);
|
||||||
|
scene_node->setPosition(xyz);
|
||||||
|
scene_node->setRotation(hpr);
|
||||||
|
handleAnimatedTextures(scene_node, *n);
|
||||||
|
m_all_nodes.push_back(scene_node);
|
||||||
|
} // for i
|
||||||
|
|
||||||
// This will (at this stage) only convert the main track model.
|
// This will (at this stage) only convert the main track model.
|
||||||
convertTrackToBullet(mesh);
|
for(unsigned int i=0; i<m_all_meshes.size(); i++)
|
||||||
|
//for(unsigned int i=0; i<1; i++)
|
||||||
|
{
|
||||||
|
convertTrackToBullet(m_all_meshes[i], m_all_nodes[i]);
|
||||||
|
}
|
||||||
if (m_track_mesh == NULL)
|
if (m_track_mesh == NULL)
|
||||||
{
|
{
|
||||||
fprintf(stderr, "ERROR: m_track_mesh == NULL, cannot loadMainTrack\n");
|
fprintf(stderr, "ERROR: m_track_mesh == NULL, cannot loadMainTrack\n");
|
||||||
return false;
|
exit(-1);
|
||||||
}
|
}
|
||||||
|
|
||||||
m_track_mesh->createBody();
|
m_track_mesh->createBody();
|
||||||
|
|
||||||
|
|
||||||
scene::ISceneNode *scene_node = irr_driver->addOctTree(mesh);
|
|
||||||
core::vector3df xyz(0,0,0);
|
|
||||||
xml_node.getXYZ(&xyz);
|
|
||||||
core::vector3df hpr(0,0,0);
|
|
||||||
xml_node.getHPR(&hpr);
|
|
||||||
scene_node->setPosition(xyz);
|
|
||||||
scene_node->setRotation(hpr);
|
|
||||||
handleAnimatedTextures(scene_node, xml_node);
|
|
||||||
m_all_nodes.push_back(scene_node);
|
|
||||||
scene_node->setMaterialFlag(video::EMF_LIGHTING, true);
|
scene_node->setMaterialFlag(video::EMF_LIGHTING, true);
|
||||||
scene_node->setMaterialFlag(video::EMF_GOURAUD_SHADING, true);
|
scene_node->setMaterialFlag(video::EMF_GOURAUD_SHADING, true);
|
||||||
|
|
||||||
@ -463,7 +493,8 @@ bool Track::loadMainTrack(const XMLNode &xml_node)
|
|||||||
|
|
||||||
// ----------------------------------------------------------------------------
|
// ----------------------------------------------------------------------------
|
||||||
/** Handles animated textures.
|
/** Handles animated textures.
|
||||||
* \param node The node containing the data for the animated notion.
|
* \param node The scene node for which animated textures are handled.
|
||||||
|
* \param xml The node containing the data for the animated notion.
|
||||||
*/
|
*/
|
||||||
void Track::handleAnimatedTextures(scene::ISceneNode *node, const XMLNode &xml)
|
void Track::handleAnimatedTextures(scene::ISceneNode *node, const XMLNode &xml)
|
||||||
{
|
{
|
||||||
@ -631,8 +662,9 @@ void Track::loadTrackModel(unsigned int mode_id)
|
|||||||
<<"', aborting.";
|
<<"', aborting.";
|
||||||
throw std::runtime_error(msg.str());
|
throw std::runtime_error(msg.str());
|
||||||
}
|
}
|
||||||
const XMLNode *node = root->getNode("track");
|
loadMainTrack(*root);
|
||||||
loadMainTrack(*node);
|
unsigned int main_track_count = m_all_meshes.size();
|
||||||
|
|
||||||
for(unsigned int i=0; i<root->getNumNodes(); i++)
|
for(unsigned int i=0; i<root->getNumNodes(); i++)
|
||||||
{
|
{
|
||||||
const XMLNode *node = root->getNode(i);
|
const XMLNode *node = root->getNode(i);
|
||||||
@ -686,9 +718,12 @@ void Track::loadTrackModel(unsigned int mode_id)
|
|||||||
}
|
}
|
||||||
else if (name=="start")
|
else if (name=="start")
|
||||||
{
|
{
|
||||||
core::vector3df xyz(0,0,0);
|
Vec3 xyz(0,0,0);
|
||||||
node->getXYZ(&xyz);
|
node->getXYZ(&xyz);
|
||||||
m_start_positions.push_back(Vec3(xyz.X, xyz.Y, xyz.Z));
|
m_start_positions.push_back(xyz);
|
||||||
|
float h=0;
|
||||||
|
node->get("h", &h);
|
||||||
|
m_start_heading.push_back(h);
|
||||||
}
|
}
|
||||||
else if(name=="animations")
|
else if(name=="animations")
|
||||||
{
|
{
|
||||||
@ -777,7 +812,7 @@ void Track::loadTrackModel(unsigned int mode_id)
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Note: the physics world for irrlicht is created in loadMainTrack
|
// Note: the physics world for irrlicht is created in loadMainTrack
|
||||||
createPhysicsModel();
|
createPhysicsModel(main_track_count);
|
||||||
if(UserConfigParams::m_track_debug)
|
if(UserConfigParams::m_track_debug)
|
||||||
m_quad_graph->createDebugMesh();
|
m_quad_graph->createDebugMesh();
|
||||||
} // loadTrackModel
|
} // loadTrackModel
|
||||||
|
@ -56,7 +56,10 @@ private:
|
|||||||
std::string m_ident;
|
std::string m_ident;
|
||||||
std::string m_screenshot;
|
std::string m_screenshot;
|
||||||
std::vector<MusicInformation*> m_music;
|
std::vector<MusicInformation*> m_music;
|
||||||
std::vector<float> m_start_x, m_start_y, m_start_z, m_start_heading;
|
/** Start heading of karts (if specified in the scene file). */
|
||||||
|
std::vector<float> m_start_heading;
|
||||||
|
/** Start positions of karts (if specified in the scene file). */
|
||||||
|
std::vector<Vec3> m_start_positions;
|
||||||
std::string m_item_style;
|
std::string m_item_style;
|
||||||
std::string m_description;
|
std::string m_description;
|
||||||
std::string m_designer;
|
std::string m_designer;
|
||||||
@ -150,23 +153,21 @@ private:
|
|||||||
/** Checkline manager. */
|
/** Checkline manager. */
|
||||||
CheckManager *m_check_manager;
|
CheckManager *m_check_manager;
|
||||||
|
|
||||||
void loadTrackInfo(const std::string &filename);
|
void loadTrackInfo(const std::string &filename);
|
||||||
void itemCommand(const Vec3 &xyz, Item::ItemType item_type,
|
void itemCommand(const Vec3 &xyz, Item::ItemType item_type,
|
||||||
int bNeedHeight);
|
int bNeedHeight);
|
||||||
void loadQuadGraph(unsigned int mode_id);
|
void loadQuadGraph(unsigned int mode_id);
|
||||||
void convertTrackToBullet(const scene::IMesh *mesh);
|
void convertTrackToBullet(const scene::IMesh *mesh,
|
||||||
bool loadMainTrack(const XMLNode &node);
|
const scene::ISceneNode*node);
|
||||||
void createWater(const XMLNode &node);
|
bool loadMainTrack(const XMLNode &node);
|
||||||
void getMusicInformation(std::vector<std::string>& filenames,
|
void createWater(const XMLNode &node);
|
||||||
std::vector<MusicInformation*>& m_music );
|
void getMusicInformation(std::vector<std::string>& filenames,
|
||||||
|
std::vector<MusicInformation*>& m_music );
|
||||||
void loadCurves(const XMLNode &node);
|
void loadCurves(const XMLNode &node);
|
||||||
void handleAnimatedTextures(scene::ISceneNode *node, const XMLNode &xml);
|
void handleAnimatedTextures(scene::ISceneNode *node, const XMLNode &xml);
|
||||||
void handleSky(const XMLNode &root, const std::string &filename);
|
void handleSky(const XMLNode &root, const std::string &filename);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
/** Start positions for arenas (unused in linear races) */
|
|
||||||
std::vector<Vec3> m_start_positions;
|
|
||||||
|
|
||||||
static const float NOHIT;
|
static const float NOHIT;
|
||||||
|
|
||||||
@ -215,7 +216,7 @@ public:
|
|||||||
void getTerrainInfo(const Vec3 &pos, float *hot, Vec3* normal,
|
void getTerrainInfo(const Vec3 &pos, float *hot, Vec3* normal,
|
||||||
const Material **material) const;
|
const Material **material) const;
|
||||||
float getTerrainHeight(const Vec3 &pos) const;
|
float getTerrainHeight(const Vec3 &pos) const;
|
||||||
void createPhysicsModel();
|
void createPhysicsModel(unsigned int main_track_count);
|
||||||
void update(float dt);
|
void update(float dt);
|
||||||
void reset();
|
void reset();
|
||||||
void handleExplosion(const Vec3 &pos, const PhysicalObject *mp) const;
|
void handleExplosion(const Vec3 &pos, const PhysicalObject *mp) const;
|
||||||
@ -255,6 +256,13 @@ public:
|
|||||||
/** Sets the current ambient color. */
|
/** Sets the current ambient color. */
|
||||||
void setAmbientColor(const video::SColor &color)
|
void setAmbientColor(const video::SColor &color)
|
||||||
{ m_ambient_color = color; }
|
{ m_ambient_color = color; }
|
||||||
|
/** Get the number of start positions defined in the scene file. */
|
||||||
|
unsigned int getNumberOfStartPositions() const
|
||||||
|
{ return m_start_positions.size(); }
|
||||||
|
/** Returns the i-th. start position. */
|
||||||
|
const Vec3 &getStartPosition(unsigned int i) {return m_start_positions[i];}
|
||||||
|
/** Returns the heading of the i-th. start position. */
|
||||||
|
const float getStartHeading(unsigned int i) {return m_start_heading[i]; }
|
||||||
}; // class Track
|
}; // class Track
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
Loading…
x
Reference in New Issue
Block a user