Main Page   Namespace List   Class Hierarchy   Alphabetical List   Compound List   File List   Namespace Members   Compound Members   File Members  

MilitaryUnit.cpp

Go to the documentation of this file.
00001 /*
00002 CS Senior Project 2003
00003 Team : Leftfield
00004 Project : ModernWarfare
00005 Members :
00006 - Russ Christensen              <rchriste@cs.utah.edu>
00007 - Todd Smith                    <tcsmith@cs.utah.edu>
00008 - Usit Duongsaa                 <duongsaa@cs.utah.edu>
00009 Copyright 2003 Russ Christensen, Usit Duongsaa, and Todd Smith. All rights reserved.
00010 
00011 Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
00012 
00013 Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 
00014 Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 
00015 THIS SOFTWARE IS PROVIDED BY RUSS CHRISTENSEN, USIT DUONGSAA, AND TODD SMITH ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL RUSS, USIT, TODD OR OTHER CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
00016 */
00017 
00022 #include "HelperFunctions.h"    // Helper::
00023 #include "MilitaryUnit.h"
00024 #include "Player.h"
00025 #include "Sound.h"
00026 #include "BattleEntry.h"
00027 #include "BattleUnitData.h"
00028 #include "GameState.h"
00029 
00030 namespace {
00032         const FLOAT overheadMovementRate = 0.15f;
00033 }
00034 
00035 MilitaryUnit::MilitaryUnit(Vec3D initalPosition, Player* owner, UnitType unitType, const int armySize, Vec3D unitSize) : 
00036 m_currPos(initalPosition), 
00037 m_teamColor(owner->color()), 
00038 m_unitSize(unitSize), 
00039 m_direction(Vec3D(0,90.0f,0)),
00040 m_goalPos(initalPosition),
00041 m_unitType(unitType),
00042 m_armySize(armySize),
00043 m_currState(BUSY),
00044 m_collisionSize(unitSize*2),
00045 m_pOwner(owner),
00046 m_overheadShortcutKey(-1)
00047 {
00048 }
00049 
00050 MilitaryUnit::~MilitaryUnit(void)
00051 {
00052 }
00053 
00054 void MilitaryUnit::goal(Vec3D dest)
00055 {
00056         this->m_goalPos = dest;
00057         m_currState = BUSY;
00058 }
00059 
00060 Vec3D MilitaryUnit::goalPosition() const
00061 {
00062         return this->m_goalPos;
00063 }
00064 
00065 bool MilitaryUnit::contains(Vec3D that) const
00066 {
00067         // because a unit also has height (instead of just x,y) we'll do screen-space checking
00068         Vec2D pt(math_translateWorldToScreen(that));
00069         Vec2D unitPt(math_translateWorldToScreen(m_currPos));
00070         return math_dist2D(pt,unitPt)<0.03f;
00071 }
00072 
00073 bool MilitaryUnit::around(Vec3D that)
00074 {
00075         return math_dist2D(Vec2D(this->m_currPos.x, this->m_currPos.y), Vec2D(that.x, that.y)) < BATTLE_RADIUS;
00076 }
00077 
00078 bool MilitaryUnit::collision(const MilitaryUnit* const that) const
00079 {
00080         return (
00081                 (m_currPos.z + m_collisionSize.z > that->position().z) &&
00082                 (m_currPos.z - m_collisionSize.z < that->position().z) &&
00083                 (m_currPos.x + m_collisionSize.x > that->position().x) &&
00084                 (m_currPos.x - m_collisionSize.x < that->position().x) &&
00085                 (m_currPos.y + m_collisionSize.y > that->position().y) &&
00086                 (m_currPos.y - m_collisionSize.y < that->position().y) );
00087 }
00088 
00089 bool MilitaryUnit::fightingCollision(const MilitaryUnit* const that) const
00090 {
00091         const FLOAT distanceForAFight(25.0f);
00092         return distanceForAFight > math_distPlanar3D(this->m_currPos, that->m_currPos);
00093 }
00094 
00095 bool MilitaryUnit::nearEachOther(const MilitaryUnit* const that) const
00096 {
00097         const FLOAT distance(50.0f);
00098         return distance > math_distPlanar3D(this->m_currPos, that->m_currPos);
00099 }
00100 
00101 void MilitaryUnit::move()
00102 {
00103         if (this->m_currState == WANTS_TO_STOP && !OverheadCollisonWithIdleUnit(this) && !OverheadCollisionWithCity(this))
00104         {
00105                 m_currState = IDLE;
00106         }       
00107         if (this->m_currState != IDLE) {
00108 
00109                 Vec3D savePos( m_currPos );
00110                 Vec3D targetVec = m_goalPos - m_currPos;
00111                 FLOAT targetDir = clipAngle( 90-D3DXToDegree( atan2f( targetVec.x, targetVec.y ) ) );
00112                 FLOAT currentDir = m_direction.x;
00113                 FLOAT delta;                            // signed (+CW,-CCW) smallest-magnitude difference in angle
00114                 if(targetDir>currentDir)
00115                 {
00116                         delta = targetDir - currentDir;
00117                         if(delta>180.0f) delta = delta - 360.0f;
00118                 }
00119                 else
00120                 {
00121                         delta = targetDir - currentDir;
00122                         if(delta<-180.0f) delta = 360.0f - delta;
00123                 }               
00124 
00125                 const FLOAT turnRate = 0.4f;
00126                 FLOAT turnAngle = delta;
00127                 if (delta > turnRate ) turnAngle = turnRate;
00128                 else if (delta < -turnRate ) turnAngle = -turnRate;
00129                 else turnAngle = delta;
00130                 m_direction.x = clipAngle( currentDir + turnAngle );                            // turn
00131 
00132                 // move if we're heading roughly the right way
00133                 FLOAT speed = 0.0f;
00134                 if (absf(delta)<10.0f ) speed = 0.1f;
00135                 else if( absf(delta)<90.0f ) speed = 0.06f;
00136                 if (D3DXVec3Length(&targetVec) < 3.0f )                                 // if we're close to target, help stop accurately
00137                 {
00138                         m_currPos += (m_goalPos-m_currPos) * 0.06f;
00139                         speed = 0.0f;
00140                 }
00141                 if (speed>0.0f)                                                                                 // otherwise, move normally
00142                 {
00143                         FLOAT rad = D3DXToRadian( m_direction.x );
00144                         m_currPos += speed * Vec3D( cosf(rad), sinf(rad), 0.0f );
00145                 }               
00146 
00147                 /*
00148                 FLOAT x_delta = this->m_goalPos.x - this->m_currPos.x;
00149                 FLOAT y_delta = this->m_goalPos.y - this->m_currPos.y;
00150                 FLOAT abs_x_delta = Helper::abs(x_delta);
00151                 FLOAT abs_y_delta = Helper::abs(y_delta);
00152                 if (abs_x_delta + abs_y_delta > 0.0f) { 
00153                 FLOAT x_percent = abs_x_delta / (abs_x_delta + abs_y_delta);
00154                 if (x_delta < 0.0f) x_percent *= -1;
00155                 FLOAT y_percent = abs_y_delta / (abs_x_delta + abs_y_delta);
00156                 if (y_delta < 0.0f) y_percent *= -1;
00157                 FLOAT x_amount = x_percent * overheadMovementRate;
00158                 FLOAT y_amount = y_percent * overheadMovementRate;
00159                 if (Helper::abs(x_amount) > abs_x_delta) this->m_currPos.x = this->m_goalPos.x;
00160                 else this->m_currPos.x += x_amount;
00161                 if (Helper::abs(y_amount) > abs_y_delta) this->m_currPos.y = this->m_goalPos.y;
00162                 else this->m_currPos.y += y_amount;
00163                 */
00164                 // make sure unit is within map bounds
00165                 if (!GameState::worldMap().bounds.contains(Vec2D(this->m_currPos.x, this->m_currPos.y)) )
00166                         m_currPos = savePos;
00167 
00168                 // is the unit at the goal position?
00169                 FLOAT thresh = 0.1f;
00170                 if (this->m_currPos.x <= m_goalPos.x + thresh  &&  this->m_currPos.x >= m_goalPos.x - thresh &&
00171                         this->m_currPos.y <= m_goalPos.y + thresh  &&  this->m_currPos.y >= m_goalPos.y - thresh )
00172                 {
00173                         if (OverheadCollisonWithIdleUnit(this) || OverheadCollisionWithCity(this)) 
00174                         {
00175                                 this->m_currState = WANTS_TO_STOP;
00176                                 FLOAT newGoal = sys_randFloat() * 40.0F;
00177                                 this->m_goalPos = Vec3D(m_currPos.x + newGoal, m_currPos.y + newGoal, 0);
00178                         } else 
00179                         {
00180                                 m_currState = IDLE;
00181                         }
00182                 }
00183         } else if (OverheadCollisonWithIdleUnit(this) || OverheadCollisionWithCity(this)) 
00184         {
00185                 this->m_currState = WANTS_TO_STOP;
00186                 FLOAT newGoal = sys_randFloat() * 40.0F;
00187                 this->m_goalPos = Vec3D(m_currPos.x + newGoal, m_currPos.y + newGoal, 0);
00188         } else 
00189         {
00190                 this->m_currState = IDLE;
00191         }
00192 
00193         // stay on terrain
00194         m_currPos.z = terrain_getHeight( artWork->worldMap, m_currPos.x, m_currPos.y ) + 0.33f;  // 0.33f to offset unit size
00195 }
00196 
00197 void MilitaryUnit::drawBox(void) const
00198 {
00199         Vec3D pos = m_currPos;
00200         pos.z += 0.3f;
00201         FLOAT angle = (FLOAT)( (Globals::currGameTick*5) % 360 );
00202         mesh_render( artWork->circle, pos, Vec3D(5.0f,5.0f,0.001f), Vec3D(angle,0,0), artWork->colorGreen );
00203 }
00204 
00205 Player* MilitaryUnit::owner(void) const
00206 {
00207         return this->m_pOwner;
00208 }
00209 
00210 Vec3D MilitaryUnit::color() const
00211 {
00212         return m_teamColor;
00213 }
00214 
00215 Vec3D MilitaryUnit::position(void) const
00216 {
00217         return this->m_currPos;
00218 }
00219 
00220 void MilitaryUnit::drawColor() const
00221 {
00222         // team color box
00223         Vec3D p1(m_currPos), p2(m_currPos), p3(m_currPos), p4(m_currPos);
00224         const int delta = 4;    
00225         p1.x -= delta;
00226         p2.y += delta;
00227         p3.x += delta;
00228         p4.y -= delta;
00229         Vec2D s1( math_translateWorldToScreen(p1) );
00230         Vec2D s2( math_translateWorldToScreen(p2) );
00231         Vec2D s3( math_translateWorldToScreen(p3) );
00232         Vec2D s4( math_translateWorldToScreen(p4) );
00233         overlay_line( s1,s2, m_teamColor );
00234         overlay_line( s2,s3, m_teamColor );
00235         overlay_line( s3,s4, m_teamColor );
00236         overlay_line( s4,s1, m_teamColor );
00237 }
00238 
00239 void MilitaryUnit::setShortcutKey(int key)
00240 {
00241         m_overheadShortcutKey = key;
00242 }
00243 
00244 int MilitaryUnit::shortcutKey() const
00245 {
00246         return m_overheadShortcutKey;
00247 }
00248 
00250 
00251 LightTank::LightTank(const Vec3D & initialPosition, Player* owner, const int armySize) 
00252 : MilitaryUnit(initialPosition, owner, UnitTypes::LIGHT_TANK, armySize, BattleUnitData::getObj().lightTankSize()),
00253 m_turretSize(BattleUnitData::getObj().lightTankTurretSize())
00254 {
00255 }
00256 
00257 LightTank::~LightTank(void)
00258 {
00259 }
00260 
00261 void LightTank::draw(void) const
00262 {
00263         mesh_render( artWork->lightTank_mesh, this->m_currPos, this->m_unitSize, this->m_direction, artWork->lightTank_texture, 0,
00264                 this->color());
00265         mesh_render( artWork->lightTankTurret_mesh, this->m_currPos, this->m_turretSize, this->m_direction, artWork->lightTank_texture, 0,
00266                 this->color());
00267 }
00268 
00270 HeavyTank::HeavyTank(const Vec3D & initialPosition, Player* owner, const int armySize) 
00271 : MilitaryUnit(initialPosition, owner, UnitTypes::HEAVY_TANK, armySize, BattleUnitData::getObj().heavyTankSize()),
00272 m_turretSize(BattleUnitData::getObj().heavyTankTurretSize())
00273 {
00274 }
00275 
00276 HeavyTank::~HeavyTank(void)
00277 {
00278 }
00279 
00280 void HeavyTank::draw() const
00281 {
00282         mesh_render( artWork->heavyTank_mesh, this->m_currPos, this->m_unitSize, this->m_direction, artWork->heavyTank_texture, 0,
00283                 this->color());
00284         mesh_render( artWork->heavyTankTurret_mesh, this->m_currPos, this->m_turretSize, this->m_direction, artWork->heavyTank_texture, 0,
00285                 this->color());
00286 }
00287 
00289 RocketLauncher::RocketLauncher(const Vec3D & initialPosition, Player* owner, const int armySize) 
00290 : MilitaryUnit(initialPosition, owner, UnitTypes::LAUNCHER, armySize, BattleUnitData::getObj().launcherSize())
00291 {
00292 }
00293 
00294 RocketLauncher::~RocketLauncher(void)
00295 {
00296 }
00297 
00298 void RocketLauncher::draw() const
00299 {
00300         mesh_render( artWork->launcher_mesh, this->m_currPos, this->m_unitSize, this->m_direction, artWork->launcher_texture, 0,
00301                 this->color());
00302 }
00303 
00305 Artillery::Artillery(const Vec3D & initialPosition, Player* owner, const int armySize) 
00306 : MilitaryUnit(initialPosition, owner, UnitTypes::ARTILLERY, armySize, BattleUnitData::getObj().artillerySize()),
00307 m_turretSize(BattleUnitData::getObj().artilleryTurretSize())
00308 {
00309 }
00310 
00311 Artillery::~Artillery(void)
00312 {
00313 }
00314 
00315 void Artillery::draw() const
00316 {
00317         mesh_render( artWork->artillery_mesh, this->m_currPos, this->m_unitSize, this->m_direction, artWork->artillery_texture, 0,
00318                 this->color());
00319         mesh_render( artWork->artilleryTurret_mesh, this->m_currPos, this->m_turretSize, this->m_direction, artWork->artillery_texture, 0,
00320                 this->color());
00321 }
00322 
00324 Jet::Jet(const Vec3D & initialPosition, Player* owner, const int armySize, const int cityID )
00325 : MilitaryUnit(initialPosition, owner, UnitTypes::JET, armySize, BattleUnitData::getObj().jetSize()),
00326  m_cityCenter(GameState::getCity(cityID)->position()),  m_ang(0.0f), m_liftOffAng(0.0f), 
00327  m_cityID(cityID), m_jetState(CIRCLE)
00328 {
00329   m_currState = IDLE;
00330   // every 4 jets that guard city increases the radius at which they draw
00331   m_distFromCity = ((GameState::getCity(m_cityID)->jetGaurdSize() / 4)+1)*15.0f;
00332   m_currPos.x = m_cityCenter.x + (m_distFromCity * (cosf(m_ang*(D3DX_PI/180))));
00333   m_currPos.y = m_cityCenter.y + (m_distFromCity * (sinf(m_ang*(D3DX_PI/180))));
00334   m_currPos.z = 20.0f;
00335   // add one to the city i'm gaurding's list of jets
00336   GameState::getCity(m_cityID)->addJetGaurd();
00337   //sys_console() << "Adding jet gaurd" << GameState::getCity(m_cityID)->jetGaurdSize() << endl;
00338 
00339 }
00340 
00341 //const float Jet::s_drawDist = 15.0f;
00342 const float Jet::s_dTheta = 0.5f;
00343 const float Jet::s_speed = 0.2f;
00344 
00345 Jet::~Jet(void)
00346 {
00347   // delete one from the city i'm guarding
00348   GameState::getCity(m_cityID)->deleteJetGuard();
00349   //sys_console() << "Deleting jet gaurd" << GameState::getCity(m_cityID)->jetGaurdSize() << endl;
00350 }
00351 
00352 
00353 int Jet::getCityID()
00354 {
00355         return m_cityID;
00356 }
00357 
00358 void Jet::draw() const
00359 {
00360         mesh_render( artWork->jet_mesh, this->m_currPos, this->m_unitSize, this->m_direction, artWork->jet_texture, 0,
00361                 this->color());
00362 }
00363 
00364 void Jet::goal(Vec3D dest)
00365 {
00366   vector<City*>& cities = GameState::cities();
00367   for(CityIter iter=cities.begin(); iter != cities.end(); ++iter)
00368   {
00369     // if destination is a city
00370     if( (*iter)->color() == this->color() && math_distPlanar3D((*iter)->position(),dest) < 40.0f )
00371     {
00372       //   move there
00373       // remove myself from the current cities gaurd
00374       GameState::getCity(m_cityID)->deleteJetGuard();
00375       m_currState = BUSY;
00376       m_jetState = LIFTOFF;
00377       m_cityID = (*iter)->uniqueID();
00378       m_cityCenter = (*iter)->position();
00379       (*iter)->addJetGaurd();
00380       // radius the plane should fly at when it reaches city
00381       m_distFromCity = (((*iter)->jetGaurdSize() / 4)+1)*15.0f;
00382       m_ang = 0.0f;
00383       m_liftOffAng = math_getDir(m_currPos, (*iter)->position());
00384       m_goalPos.x = m_cityCenter.x + (m_distFromCity * (cosf(m_ang*(D3DX_PI/180))));
00385       m_goalPos.y = m_cityCenter.y + (m_distFromCity * (sinf(m_ang*(D3DX_PI/180))));
00386       m_velocity = m_goalPos - m_currPos;
00387       m_velocity *= (1/(sqrtf( m_velocity.x*m_velocity.x + m_velocity.y*m_velocity.y )))*s_speed  ;
00388       
00389       break;
00390     }
00391     // else
00392     //   do nothing
00393   }
00394 }
00395 
00396 const float Jet::s_dZ(0.1f);
00397 
00398 void Jet::move()
00399 {
00400   if(m_currState == IDLE)
00401   {
00402     // jet should circle the cities center
00403     // dont want to draw jets on top of each other, move if they collide
00404     m_ang += (OverheadCollisonWithIdleUnit(this) ? (sys_randInt()*s_dTheta) : s_dTheta);
00405     m_direction.x = math_clipAngle(m_ang + 90.0f);
00406     m_currPos.x = m_cityCenter.x + (m_distFromCity * (cosf(m_ang*(D3DX_PI/180))));
00407     m_currPos.y = m_cityCenter.y + (m_distFromCity * (sinf(m_ang*(D3DX_PI/180))));
00408   }
00409   else if (m_currState == BUSY)
00410   {
00411     // if we have just been order to move increase z and rotate to face new city
00412     if(m_jetState == LIFTOFF) 
00413     {
00414       if(Helper::abs(m_direction.x - m_liftOffAng) < 1.0f)
00415       {
00416         m_jetState = MOVING;
00417         return;
00418       }
00419       else
00420       {
00421         m_direction.x = math_clipAngle(m_direction.x+1.0f);
00422         m_currPos.z += s_dZ;
00423       }
00424     }
00425     else if(m_jetState == MOVING)
00426     {
00427       if( Helper::abs(m_currPos.x - m_goalPos.x) < 0.1f && Helper::abs(m_currPos.y - m_goalPos.y) < 0.1f )
00428       {
00429         m_jetState = ARRIVE;
00430       }
00431       else
00432       {
00433         // jet is moving to a new city
00434         m_currPos.x += m_velocity.x;
00435         m_currPos.y += m_velocity.y;
00436       }
00437     }
00438     else if(m_jetState == ARRIVE)
00439     {
00440       // jet should face 90.0 and descend
00441 
00442       bool atHeight = !((m_currPos.z - s_dZ) > 20.0f);
00443       if( !atHeight )
00444         m_currPos.z -= s_dZ;
00445 
00446       //if( math_clipAngle(m_direction.x + 1.0f) != 90.0f)
00447       bool atAng = !(Helper::abs(m_direction.x - 90.0f) > 1.0f); 
00448       if( !atAng )
00449         m_direction.x = math_clipAngle(m_direction.x + 1.0f);
00450 
00451       if( atHeight && atAng )
00452       {
00453         m_jetState = CIRCLE;
00454         m_currState = IDLE;
00455       }
00456     }
00457 
00458   }
00459 }

Generated on Wed Apr 23 05:50:16 2003 for Modern Warfare by doxygen1.3-rc2