Back to index

supertuxkart  0.5+dfsg1
flyable.cpp
Go to the documentation of this file.
00001 //  $Id: flyable.cpp 1284 2007-11-08 12:31:54Z hikerstk $
00002 //
00003 //  SuperTuxKart - a fun racing game with go-kart
00004 //  Copyright (C) 2007 Joerg Henrichs
00005 //
00006 //  This program is free software; you can redistribute it and/or
00007 //  modify it under the terms of the GNU General Public License
00008 //  as published by the Free Software Foundation; either version 2
00009 //  of the License, or (at your option) any later version.
00010 //
00011 //  This program is distributed in the hope that it will be useful,
00012 //  but WITHOUT ANY WARRANTY; without even the implied warranty of
00013 //  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00014 //  GNU General Public License for more details.
00015 //
00016 //  You should have received a copy of the GNU General Public License
00017 //  along with this program; if not, write to the Free Software
00018 //  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
00019 
00020 #include <math.h>
00021 
00022 #include "flyable.hpp"
00023 #include "world.hpp"
00024 #include "kart.hpp"
00025 #include "projectile_manager.hpp"
00026 #include "callback_manager.hpp"
00027 #include "sound_manager.hpp"
00028 #include "scene.hpp"
00029 #include "ssg_help.hpp"
00030 
00031 // static variables:
00032 float      Flyable::m_st_speed[COLLECT_MAX];
00033 ssgEntity* Flyable::m_st_model[COLLECT_MAX];
00034 float      Flyable::m_st_min_height[COLLECT_MAX];
00035 float      Flyable::m_st_max_height[COLLECT_MAX];
00036 float      Flyable::m_st_force_updown[COLLECT_MAX];
00037 btVector3  Flyable::m_st_extend[COLLECT_MAX];
00038 // ----------------------------------------------------------------------------
00039 
00040 Flyable::Flyable(Kart *kart, CollectableType type) : Moveable(false)
00041 {
00042     // get the appropriate data from the static fields
00043     m_speed             = m_st_speed[type];
00044     m_extend            = m_st_extend[type];
00045     m_max_height        = m_st_max_height[type];
00046     m_min_height        = m_st_min_height[type];
00047     m_average_height    = (m_min_height+m_max_height)/2.0f;
00048     m_force_updown      = m_st_force_updown[type];
00049 
00050     m_owner             = kart;
00051     m_has_hit_something = false;
00052     m_last_radar_beep   = -1;
00053     m_exploded          = false;
00054     m_shape             = NULL;
00055     m_mass              = 1.0f;
00056 
00057     // Add the graphical model
00058     ssgTransform *m     = getModelTransform();
00059     m->addKid(m_st_model[type]);
00060     scene->add(m);
00061 }   // Flyable
00062 // ----------------------------------------------------------------------------
00063 void Flyable::createPhysics(float y_offset, const btVector3 velocity,
00064                             btCollisionShape *shape)
00065 {
00066     // The actual transform is determined as follows:
00067     // 1) Compute the heading of the kart
00068     // 2) Compute the pitch of the terrain. This avoids the problem of the
00069     //    rocket hitting the floor (e.g. if the kart is braking and therefore
00070     //    pointing downwards).
00071     btTransform trans = m_owner->getTrans();
00072 
00073     // get heading=trans.getBasis*(0,1,0) ... so save the multiplication:
00074     btVector3 direction(trans.getBasis()[0][1],
00075                         trans.getBasis()[1][1],
00076                         trans.getBasis()[2][1]);
00077     float heading=atan2(-direction.getX(), direction.getY());
00078 
00079     TerrainInfo::update(trans.getOrigin());
00080     float pitch = getTerrainPitch(heading);
00081 
00082     btMatrix3x3 m;
00083     m.setEulerZYX(pitch, 0.0f, heading);
00084     trans.setBasis(m);
00085 
00086     // Apply rotation and offset
00087     btTransform offset_transform;
00088     offset_transform.setIdentity();
00089     btVector3 offset=btVector3(0,y_offset,m_average_height);
00090     offset_transform.setOrigin(offset);
00091         
00092     trans  *= offset_transform;
00093 
00094     m_shape = shape;
00095     createBody(m_mass, trans, m_shape);
00096     m_user_pointer.set(this);
00097     world->getPhysics()->addBody(getBody());
00098 
00099     // Simplified rockets: no gravity
00100     m_body->setGravity(btVector3(0.0f, 0.0f, 0.0f));
00101 
00102     // Rotate velocity to point in the right direction
00103     btVector3 v=trans.getBasis()*velocity;
00104 
00105     if(m_mass!=0.0f)  // Don't set velocity for kinematic or static objects
00106     {
00107         m_body->setLinearVelocity(v);
00108         m_body->setAngularFactor(0.0f);   // prevent rotations
00109     }
00110     m_body->setCollisionFlags(btCollisionObject::CF_NO_CONTACT_RESPONSE);
00111 
00112 }   // createPhysics
00113 
00114 // -----------------------------------------------------------------------------
00115 void Flyable::init(const lisp::Lisp* lisp, ssgEntity *model, 
00116                    CollectableType type)
00117 {
00118     m_st_speed[type]        = 25.0f;
00119     m_st_max_height[type]   = 1.0f;
00120     m_st_min_height[type]   = 3.0f;
00121     m_st_force_updown[type] = 15.0f;
00122     lisp->get("speed",           m_st_speed[type]       );
00123     lisp->get("min-height",      m_st_min_height[type]  );
00124     lisp->get("max-height",      m_st_max_height[type]  );
00125     lisp->get("force-updown",    m_st_force_updown[type]);
00126 
00127     // Store the size of the model
00128     float x_min, x_max, y_min, y_max, z_min, z_max;
00129     MinMax(model, &x_min, &x_max, &y_min, &y_max, &z_min, &z_max);
00130     m_st_extend[type] = btVector3(x_max-x_min,y_max-y_min, z_max-z_min);
00131     m_st_model[type]  = model;
00132 }   // init
00133 
00134 //-----------------------------------------------------------------------------
00135 Flyable::~Flyable()
00136 {
00137     if(m_shape) delete m_shape;
00138     world->getPhysics()->removeBody(getBody());
00139 }   // ~Flyable
00140 
00141 //-----------------------------------------------------------------------------
00142 void Flyable::getClosestKart(const Kart **minKart, float *minDist, btVector3 *minDelta) const
00143 {
00144     btTransform tProjectile=getTrans();
00145     *minDist = 99999.9f;
00146     for(unsigned int i=0 ; i<race_manager->getNumKarts(); i++ )
00147     {
00148         Kart *kart = world -> getKart(i);
00149         if(kart->isEliminated() || kart == m_owner) continue;
00150         btTransform t=kart->getTrans();
00151        
00152         btVector3 delta = t.getOrigin()-tProjectile.getOrigin();
00153         float distance2 = delta.length2();
00154 
00155         if(distance2 < *minDist)
00156         {
00157             *minDist  = sqrt(distance2);
00158             *minKart  = kart;
00159             *minDelta = delta;
00160         }
00161     }  // for i<getNumKarts
00162 }   // getClosestKart
00163 
00164 //-----------------------------------------------------------------------------
00165 void Flyable::update (float dt)
00166 {
00167     if(m_exploded) return;
00168        
00169     btTransform trans=getBody()->getWorldTransform();
00170     TerrainInfo::update(trans.getOrigin());
00171     if(getHoT()==Track::NOHIT) 
00172     {
00173         explode(NULL);    // flyable out of track boundary
00174         return;
00175     }
00176 
00177     float hat = trans.getOrigin().getZ()-getHoT();
00178 
00179     // Use the Height Above Terrain to set the Z velocity.
00180     // HAT is clamped by min/max height. This might be somewhat
00181     // unphysical, but feels right in the game.
00182     hat = std::max(std::min(hat, m_max_height) , m_min_height);
00183     float delta = m_average_height - hat;
00184     btVector3 v=getVelocity();
00185     v.setZ(m_force_updown*delta);
00186     setVelocity(v);
00187 
00188     Moveable::update(dt);
00189 }   // update
00190 // -----------------------------------------------------------------------------
00191 void Flyable::placeModel()
00192 {
00193        btTransform t=getTrans();
00194     float m[4][4];
00195     t.getOpenGLMatrix((float*)&m);
00196     sgSetCoord(&m_curr_pos, m);
00197     Moveable::placeModel();
00198 }  // placeModel
00199 
00200 // -----------------------------------------------------------------------------
00201 void Flyable::explode(Kart *kart_hit, MovingPhysics* moving_physics)
00202 {
00203        if(m_exploded) return;
00204 
00205     m_has_hit_something=true;
00206     // Notify the projectile manager that this rocket has hit something.
00207     // The manager will create the appropriate explosion object.
00208     projectile_manager->explode();
00209 
00210     // Now remove this projectile from the graph:
00211     ssgTransform *m = getModelTransform();
00212     m->removeAllKids();
00213     scene->remove(m);
00214 
00215     // The explosion is a bit higher in the air
00216     btVector3 pos_explosion=getPos();
00217     pos_explosion.setZ(pos_explosion.getZ()+1.2f);
00218     world->getPhysics()->removeBody(getBody());
00219        m_exploded=true;
00220 
00221     for ( unsigned int i = 0 ; i < race_manager->getNumKarts() ; i++ )
00222     {
00223         Kart *kart = world->getKart(i);
00224         // Handle the actual explosion. The kart that fired a flyable will 
00225         // only be affected if it's a direct hit. This allows karts to use
00226         // rockets on short distance.
00227         if(m_owner!=kart || m_owner==kart_hit) 
00228         {
00229             // Set a flag it if was a direct hit.
00230             kart->handleExplosion(getPos(), kart==kart_hit);
00231         }
00232     }
00233     callback_manager->handleExplosion(pos_explosion, moving_physics);
00234 }   // explode
00235 
00236 /* EOF */