1) Bubble gums now take roll and pitch from the terrain they are at

(i.e. they will always lie flat on the terrain).
2) Cleaned up some code, added doxygen comments.


git-svn-id: svn+ssh://svn.code.sf.net/p/supertuxkart/code/trunk/supertuxkart@2443 178a84e3-b1eb-0310-8ba1-8eac791a3b58
This commit is contained in:
hikerstk 2008-11-11 08:33:06 +00:00
parent 0fae019d40
commit f915db5b78
12 changed files with 111 additions and 35 deletions

View File

@ -26,13 +26,20 @@
#include "constants.hpp"
#include "LinearMath/btTransform.h"
/** A class that stores a translation and rotation. It is used to convert
* between bullet data structures and the data structure for the graphics.
*/
class Coord
{
private:
/** Translation. */
Vec3 m_xyz;
/** Rotation as Eulerian HPR value. */
Vec3 m_hpr;
/** The correspondig plib data structure. */
sgCoord m_coord;
/** Sets the sgCoord data structures (and converts radians to degrees). */
void setSgCoord()
{
sgSetCoord(&m_coord, m_xyz.toFloat(), m_hpr.toFloat());
@ -44,6 +51,10 @@ private:
}
public:
/** Constructor.
* \param xyz Translation.
* \param hpr Rotation.
*/
Coord(const Vec3& xyz, const Vec3& hpr)
{
m_xyz = xyz;
@ -51,6 +62,10 @@ public:
setSgCoord();
} // Coord
// ------------------------------------------------------------------------
/** Constructor based on a bullet transformation (which is a translation
* and rotation as well).
* \param t The bullet transform.
*/
Coord(const btTransform& t)
{
m_xyz = t.getOrigin();
@ -58,10 +73,22 @@ public:
setSgCoord();
} // Coord
// ------------------------------------------------------------------------
/** Default constructor. Sets xyz and hpr to 0. */
Coord()
{
m_xyz = Vec3(0.0f);
m_hpr = Vec3(0.0f);
}
// ------------------------------------------------------------------------
/** Returns the corresponding plib data structure. */
const sgCoord& toSgCoord() const { return m_coord; }
/** Returns the translation. */
const Vec3& getXYZ() const { return m_xyz; }
/** Returns heading, pitch, rolll. */
const Vec3& getHPR() const { return m_hpr; }
/** Sets hpr. \param a Heading, pitch and roll. */
void setHPR(const Vec3& a) { m_hpr = a; setSgCoord(); }
/** Sets xyz. \param a Coordinates. */
void setXYZ(const Vec3& a) { m_xyz = a; setSgCoord(); }
}; // Coord

View File

@ -19,8 +19,9 @@
#include "items/bubblegumitem.hpp"
BubbleGumItem::BubbleGumItem(ItemType type, const Vec3& xyz, ssgEntity* model,
unsigned int item_id) : Item(type, xyz, model, item_id)
BubbleGumItem::BubbleGumItem(ItemType type, const Vec3& xyz, const Vec3 &normal,
ssgEntity* model, unsigned int item_id)
: Item(type, xyz, normal, model, item_id)
{
m_rotate = false;
} // BubbleGumItem

View File

@ -26,7 +26,8 @@
class BubbleGumItem : public Item
{
public:
BubbleGumItem (ItemType type, const Vec3& xyz, ssgEntity* model,
BubbleGumItem (ItemType type, const Vec3& xyz,
const Vec3 &normal, ssgEntity* model,
unsigned int item_id);
~BubbleGumItem ();
}

View File

@ -24,10 +24,12 @@
#include "coord.hpp"
#include "karts/kart.hpp"
Item::Item(ItemType type, const Vec3& xyz, ssgEntity* model,
unsigned int item_id)
: m_coord(xyz, Vec3(0, 0, 0))
Item::Item(ItemType type, const Vec3& xyz, const Vec3& normal,
ssgEntity* model, unsigned int item_id)
{
// Sets heading to 0, and sets pitch and roll depending on the normal. */
Vec3 hpr = Vec3(0, normal);
m_coord = Coord(xyz, hpr);
m_item_id = item_id;
m_type = type;
m_collected = false;

View File

@ -60,8 +60,8 @@ protected:
float m_immunity_timer; // can be used so it's not hit by its own item
public:
Item (ItemType type, const Vec3& xyz, ssgEntity* model,
unsigned int item_id);
Item (ItemType type, const Vec3& xyz, const Vec3& normal,
ssgEntity* model, unsigned int item_id);
~Item ();
unsigned int getItemId() const {return m_item_id; }
void update (float delta);

View File

@ -207,13 +207,16 @@ void ItemManager::setDefaultItemStyle()
} // setDefaultItemStyle
//-----------------------------------------------------------------------------
Item* ItemManager::newItem(ItemType type, const Vec3& xyz, Kart* parent)
Item* ItemManager::newItem(ItemType type, const Vec3& xyz, const Vec3 &normal,
Kart* parent)
{
Item* h;
if(type == ITEM_BUBBLEGUM)
h = new BubbleGumItem(type, xyz, m_item_model[type], m_all_items.size());
h = new BubbleGumItem(type, xyz, normal, m_item_model[type],
m_all_items.size());
else
h = new Item(type, xyz, m_item_model[type], m_all_items.size());
h = new Item(type, xyz, normal, m_item_model[type],
m_all_items.size());
if(parent != NULL) h->setParent(parent);

View File

@ -56,7 +56,8 @@ public:
~ItemManager();
void loadDefaultItems();
void loadItemStyle (const std::string filename);
Item* newItem (ItemType type, const Vec3& xyz, Kart* parent=NULL);
Item* newItem (ItemType type, const Vec3& xyz,
const Vec3 &normal, Kart* parent=NULL);
void update (float delta);
void hitItem (Kart* kart);
void cleanup ();

View File

@ -101,15 +101,15 @@ void Powerup::use()
m_sound_shot->play();
btVector3 pos = m_owner->getXYZ();
float z_coord = Track::NOHIT;
Vec3 unused; const Material* unused2;
RaceManager::getTrack()->getTerrainInfo(pos, &z_coord, &unused, &unused2);
Vec3 normal;
const Material* unused2;
RaceManager::getTrack()->getTerrainInfo(pos, &z_coord, &normal, &unused2);
normal.normalize();
assert(z_coord != Track::NOHIT);
pos.setZ(z_coord-0.05f);
item_manager->newItem(ITEM_BUBBLEGUM, pos, m_owner);
item_manager->newItem(ITEM_BUBBLEGUM, pos, normal, m_owner);
}
break;

View File

@ -1192,7 +1192,7 @@ void Track::loadTrackModel()
if ( htype=='G' || htype=='g' ) { type = ITEM_BANANA ;}
if ( htype=='R' || htype=='r' ) { type = ITEM_BONUS_BOX ;}
if ( htype=='S' || htype=='s' ) { type = ITEM_SILVER_COIN ;}
item_command(&loc.xyz, type, false) ;
itemCommand(&loc.xyz, type, false) ;
}
else if ( sscanf ( s, "%cHERRING,%f,%f", &htype,
&(loc.xyz[0]), &(loc.xyz[1]) ) == 3 )
@ -1202,52 +1202,52 @@ void Track::loadTrackModel()
if ( htype=='G' || htype=='g' ) { type = ITEM_BANANA ;}
if ( htype=='R' || htype=='r' ) { type = ITEM_BONUS_BOX ;}
if ( htype=='S' || htype=='s' ) { type = ITEM_SILVER_COIN ;}
item_command (&loc.xyz, type, true) ;
itemCommand (&loc.xyz, type, true) ;
}
/* and now the new names */
else if ( sscanf ( s, "BBOX,%f,%f,%f",
&(loc.xyz[0]), &(loc.xyz[1]), &(loc.xyz[2]) ) == 3 )
{
item_command(&loc.xyz, ITEM_BONUS_BOX, false);
itemCommand(&loc.xyz, ITEM_BONUS_BOX, false);
}
else if ( sscanf ( s, "BBOX,%f,%f",
&(loc.xyz[0]), &(loc.xyz[1]) ) == 2 )
{
item_command(&loc.xyz, ITEM_BONUS_BOX, true);
itemCommand(&loc.xyz, ITEM_BONUS_BOX, true);
}
else if ( sscanf ( s, "BANA,%f,%f,%f",
&(loc.xyz[0]), &(loc.xyz[1]), &(loc.xyz[2]) ) == 3 )
{
item_command(&loc.xyz, ITEM_BANANA, false);
itemCommand(&loc.xyz, ITEM_BANANA, false);
}
else if ( sscanf ( s, "BANA,%f,%f",
&(loc.xyz[0]), &(loc.xyz[1]) ) == 2 )
{
item_command(&loc.xyz, ITEM_BANANA, true);
itemCommand(&loc.xyz, ITEM_BANANA, true);
}
else if ( sscanf ( s, "COIN,%f,%f,%f",
&(loc.xyz[0]), &(loc.xyz[1]), &(loc.xyz[2]) ) == 3 )
{
item_command(&loc.xyz, ITEM_SILVER_COIN, false);
itemCommand(&loc.xyz, ITEM_SILVER_COIN, false);
}
else if ( sscanf ( s, "COIN,%f,%f",
&(loc.xyz[0]), &(loc.xyz[1]) ) == 2 )
{
item_command(&loc.xyz, ITEM_SILVER_COIN, true);
itemCommand(&loc.xyz, ITEM_SILVER_COIN, true);
}
else if ( sscanf ( s, "GOLD,%f,%f,%f",
&(loc.xyz[0]), &(loc.xyz[1]), &(loc.xyz[2]) ) == 3 )
{
item_command(&loc.xyz, ITEM_GOLD_COIN, false);
itemCommand(&loc.xyz, ITEM_GOLD_COIN, false);
}
else if ( sscanf ( s, "GOLD,%f,%f",
&(loc.xyz[0]), &(loc.xyz[1]) ) == 2 )
{
item_command(&loc.xyz, ITEM_GOLD_COIN, true);
itemCommand(&loc.xyz, ITEM_GOLD_COIN, true);
}
else if ( sscanf ( s, "START,%f,%f,%f",
@ -1394,7 +1394,7 @@ void Track::loadTrackModel()
} // loadTrack
//-----------------------------------------------------------------------------
void Track::item_command (sgVec3 *xyz, int type, int bNeedHeight )
void Track::itemCommand (sgVec3 *xyz, int type, int bNeedHeight )
{
// if only 2d coordinates are given, let the item fall from very high
@ -1407,8 +1407,13 @@ void Track::item_command (sgVec3 *xyz, int type, int bNeedHeight )
if(type==ITEM_BONUS_BOX && !RaceManager::getWorld()->enableBonusBoxes())
return;
Vec3 loc((*xyz));
item_manager->newItem((ItemType)type, loc);
} // item_command
// Don't tilt the items, since otherwise the rotation will look odd,
// i.e. the items will not rotate around the normal, but 'wobble'
// around.
Vec3 normal(0, 0, 0.0f);
item_manager->newItem((ItemType)type, loc, normal);
} // itemCommand
// ----------------------------------------------------------------------------
void Track::getTerrainInfo(const Vec3 &pos, float *hot, Vec3 *normal,

View File

@ -195,7 +195,7 @@ public:
private:
void loadTrack (std::string filename);
void item_command (sgVec3 *xyz, int item_type, int bNeedHeight);
void itemCommand (sgVec3 *xyz, int item_type, int bNeedHeight);
void loadDriveline ();
void readDrivelineFromFile (std::vector<Vec3>& line,
const std::string& file_ext);

View File

@ -83,3 +83,22 @@ void Vec3::degreeToRad()
} // degreeToRad
// ----------------------------------------------------------------------------
/** Sets the pitch and the roll of this vector to follow the normal given. The
* heading is taken from this vector.
* \param normal The normal vector to which pitch and roll should be aligned.
*/
void Vec3::setPitchRoll(const Vec3 &normal)
{
const float X =-sin(m_x);
const float Y = cos(m_x);
// Compute the angle between the normal of the plane and the line to
// (x,y,0). (x,y,0) is normalised, so are the coordinates of the plane,
// simplifying the computation of the scalar product.
float pitch = ( normal.getX()*X + normal.getY()*Y ); // use ( x,y,0)
float roll = (-normal.getX()*Y + normal.getY()*X ); // use (-y,x,0)
// The actual angle computed above is between the normal and the (x,y,0)
// line, so to compute the actual angles 90 degrees must be subtracted.
m_y = acosf(pitch) - NINETY_DEGREE_RAD;
m_z = acosf(roll) - NINETY_DEGREE_RAD;
} // setPitchRoll

View File

@ -23,10 +23,13 @@
#include "LinearMath/btVector3.h"
#include "LinearMath/btMatrix3x3.h"
/** A wrapper around bullets btVector3 to include conventient conversion
* functions (e.g. between btVector3 and the graphics specific 3d vector). */
class Vec3 : public btVector3
{
private:
inline float clampToUnity(float f) {return f<-1?f:(f>1?1:f);}
void setPitchRoll(const Vec3 &normal);
public:
inline Vec3(sgVec3 a) : btVector3(a[0], a[1], a[2]) {}
inline Vec3(const btVector3& a) : btVector3(a) {}
@ -34,6 +37,14 @@ public:
inline Vec3(float x, float y, float z)
: btVector3(x,y,z) {}
inline Vec3(float x) : btVector3(x,x,x) {}
/** Sets the heading, and computes pitch and roll dependent
* on the normal it is displayed on.
* \param heading The heading to set.
* \param normal The normal from which pitch and roll
should be computed. */
inline Vec3(float heading, const Vec3& normal)
{m_x=heading;
setPitchRoll(normal);}
void setHPR(const btMatrix3x3& m);
inline const float operator[](int n) const {return *(&m_x+n); }
@ -48,12 +59,18 @@ public:
Vec3& operator=(const btVector3& a) {*(btVector3*)this=a; return *this;}
Vec3& operator=(const btMatrix3x3& m) {setHPR(m); return *this;}
Vec3 operator-(const Vec3& v1) const {return (Vec3)(*(btVector3*)this-(btVector3)v1);}
// Helper functions to treat this vec3 as a 2d vector:
/** Helper functions to treat this vec3 as a 2d vector. This returns the
* square of the length of the first 2 dimensions. */
float length2_2d() {return m_x*m_x + m_y*m_y;}
/** Returns the length of the vector. */
float length_2d() {return sqrt(m_x*m_x + m_y*m_y);}
/** Sets this = max(this, a) componentwise.
* \param Vector to compare with. */
void max(const Vec3& a) {if(a.getX()>m_x) m_x=a.getX();
if(a.getY()>m_y) m_y=a.getY();
if(a.getZ()>m_z) m_z=a.getZ();}
/** Sets this = min(this, a) componentwise.
* \param a Vector to compare with. */
void min(const Vec3& a) {if(a.getX()<m_x) m_x=a.getX();
if(a.getY()<m_y) m_y=a.getY();
if(a.getZ()<m_z) m_z=a.getZ();}