00001 #include "TeamUnits.h"
00002 #include "Game.h"
00003
00004 #include "Team.h"
00005 #include "Level.h"
00006 #include "Unit.h"
00007
00008 #include <cassert>
00009
00010 #include "OgreSceneManager.h"
00011 #include "OgreStringConverter.h"
00012 #include "OgreEntity.h"
00013 #include "OgreRay.h"
00014 #include "OgreNode.h"
00015 #include "OgreMath.h"
00016 #include "OgreException.h"
00017 #include "OgreQuaternion.h"
00018 #include "OgreLogManager.h"
00019 #include "OgreStringConverter.h"
00020
00021
00022 using Ogre::SceneManager;
00023 using Ogre::Exception;
00024 using Ogre::LogManager;
00025 using Ogre::StringConverter;
00026 using Ogre::Quaternion;
00027 using Ogre::Degree;
00028
00029 using Ogre::RaySceneQueryResult;
00030 using Ogre::Ray;
00031 using Ogre::StringConverter;
00032 using Ogre::Node;
00033 using Ogre::Math;
00034
00035
00036 namespace ASR
00037 {
00038 const int UNIT_SPEED = 60;
00039
00040 int TeamUnits::mNumTeams = 0;
00041
00042
00043 TeamUnits::TeamUnits ( Team* parentTeam, unsigned int initialUnits )
00044 : mTeam ( parentTeam )
00045 {
00046
00047
00048 SceneManager* sceneMgr = Game::getSingletonPtr ()->getSceneManager ();
00049 mTeamNode = sceneMgr->getRootSceneNode()->createChildSceneNode( parentTeam->getName () );
00050
00051 mRaySceneQuery = sceneMgr->createRayQuery( Ray() );
00052
00053 mUnits.reserve ( initialUnits );
00054 }
00055
00056
00057
00058 TeamUnits::~TeamUnits ()
00059 {
00060 UnitList::iterator iter = mUnits.begin ();
00061 while ( iter != mUnits.end() )
00062 {
00063 delete (*iter);
00064 iter++;
00065 }
00066
00067 SceneManager* sceneMgr = Game::getSingletonPtr ()->getSceneManager ();
00068 sceneMgr->destroyQuery ( mRaySceneQuery );
00069 }
00070
00071
00072
00073 Unit* TeamUnits::createUnit ( String meshName )
00074 {
00075 Unit* newUnit = new Unit ( mTeamNode, meshName );
00076
00077 mUnits.push_back ( newUnit );
00078
00079 return newUnit;
00080 }
00081
00082
00083
00084 Unit* TeamUnits::getUnit ( size_t index )
00085 {
00086 if ( index >= mUnits.size() )
00087 throw Exception ( Exception::ERR_ITEM_NOT_FOUND, "Unit index to high", "TeamUnits::GetUnit" );
00088
00089 return mUnits[index];
00090 }
00091
00092
00093
00094 size_t TeamUnits::getNumUnits ()
00095 {
00096 return mUnits.size();
00097 }
00098
00099
00100
00101 void TeamUnits::moveUnits ( float deltaTime )
00102 {
00103
00104 UnitList::iterator unitIter;
00105 Vector3 nodePos;
00106
00107 for ( unitIter = mUnits.begin(); unitIter != mUnits.end(); unitIter++ )
00108 {
00109
00110 if ( (*unitIter)->hasDestination () )
00111 {
00112 Vector3 destPos = (*unitIter)->getDestination();
00113 Vector3 srcPos = (*unitIter)->getPosition ();
00114 destPos.y = srcPos.y;
00115
00116
00117 Vector3 diff = destPos - srcPos;
00118
00119 if ( diff.isZeroLength() )
00120 {
00121
00122 (*unitIter)->setPosition ( destPos );
00123 (*unitIter)->removeDestination ();
00124 }
00125 else
00126 {
00127
00128 Vector3 translation = diff.normalisedCopy();
00129 translation = translation * (deltaTime * UNIT_SPEED);
00130
00131
00132
00133
00134
00135 if ( translation.length() > diff.length() )
00136 {
00137 (*unitIter)->setPosition( destPos );
00138 (*unitIter)->removeDestination();
00139 }
00140 else
00141 {
00142 (*unitIter)->translate ( Vector3(translation.x, 0.0, translation.z), Node::TS_WORLD );
00143 }
00144 }
00145
00146
00147
00148
00149
00150
00151 }
00152 else
00153 {
00154
00155
00156
00157
00158
00159 }
00160
00161 nodePos = (*unitIter)->getPosition ();
00162
00163
00164 Ray unitRay ( Vector3( nodePos.x, 5000.0f, nodePos.z ), Vector3::NEGATIVE_UNIT_Y );
00165 mRaySceneQuery->setRay ( unitRay );
00166
00167
00168 RaySceneQueryResult& result = mRaySceneQuery->execute ();
00169 RaySceneQueryResult::iterator iter = result.begin();
00170
00171
00172 if ( iter != result.end() && iter->worldFragment )
00173 {
00174 Real terrainHeight = iter->worldFragment->singleIntersection.y;
00175 (*unitIter)->setPosition ( Vector3((*unitIter)->getPosition().x, terrainHeight, (*unitIter)->getPosition().z ));
00176 }
00177 }
00178 }
00179
00180
00181
00182 void TeamUnits::animateUnits ( float deltaTime )
00183 {
00184
00185 UnitList::iterator iter;
00186 for ( iter = mUnits.begin(); iter != mUnits.end(); iter++ )
00187 {
00188 (*iter)->updateAnimation ( deltaTime );
00189 }
00190 }
00191
00192
00193
00194 void TeamUnits::findTargets ()
00195 {
00196
00197
00198
00199
00200 Level::TeamList enemyTeams = Level::getSingleton ().getEnemyTeams ( mTeam );
00201
00202
00203
00204
00205
00206
00207
00208 UnitIterator iter = getUnitIterator ();
00209 while ( iter.hasMoreElements () )
00210 {
00211 Unit* curUnit = iter.getNext ();
00212 if ( curUnit->isEngaged() || curUnit->isDead () )
00213 continue;
00214
00215 UnitList allEnemies;
00216 Level::TeamIterator curEnemyTeam ( enemyTeams.begin(), enemyTeams.end() );
00217
00218 while ( curEnemyTeam.hasMoreElements () )
00219 {
00220 Team* enemy = curEnemyTeam.getNext ();
00221 UnitList unitList = enemy->getAdjacentUnits ( curUnit->getPosition(), curUnit->getSightRadius () );
00222 allEnemies.insert ( allEnemies.end(), unitList.begin(), unitList.end() );
00223 }
00224
00225
00226 float distance = Math::POS_INFINITY;
00227 Unit* bestTarget = NULL;
00228
00229 UnitIterator secondIter ( allEnemies.begin(), allEnemies.end() );
00230 while ( secondIter.hasMoreElements () )
00231 {
00232 Unit* enemyUnit = secondIter.getNext ();
00233
00234 if ( enemyUnit->isDead() )
00235 continue;
00236
00237 Vector3 targetLine = enemyUnit->getPosition () - curUnit->getPosition ();
00238 if ( targetLine.length() < distance )
00239 {
00240 bestTarget = enemyUnit;
00241 distance = targetLine.length();
00242 }
00243 }
00244
00245 if ( distance <= curUnit->getSightRadius () )
00246 curUnit->assignTarget ( bestTarget );
00247 }
00248 }
00249
00250
00251
00252 TeamUnits::UnitIterator TeamUnits::getUnitIterator ()
00253 {
00254 return UnitIterator ( mUnits.begin(), mUnits.end() );
00255 }
00256
00257
00258
00259 void TeamUnits::setSpatialGridSize ( int numBucketsWide, int numBucketsHigh )
00260 {
00261
00262
00263
00264 mUnitGrid.clear ();
00265
00266 for ( int i = 0; i < numBucketsWide; i++ )
00267 {
00268 SpatialColumn col;
00269 col.resize ( numBucketsHigh );
00270 mUnitGrid.push_back ( col );
00271 }
00272 }
00273
00274
00275
00276 void TeamUnits::updateSpatialGrid ()
00277 {
00278
00279
00280
00281
00282
00283 _clearSpatialGrid ();
00284
00285 int worldWidth = Level::getSingleton ().getWorldWidth ();
00286 int worldHeight = Level::getSingleton ().getWorldHeight ();
00287
00288 unsigned int cellWidth = worldWidth / mUnitGrid.size ();
00289 unsigned int cellHeight = worldHeight / mUnitGrid[0].size();
00290
00291 UnitIterator iter = getUnitIterator ();
00292 while ( iter.hasMoreElements () )
00293 {
00294 Unit* curUnit = iter.getNext ();
00295
00296 unsigned int cellX = curUnit->getPosition ().x / cellWidth;
00297 unsigned int cellZ = curUnit->getPosition ().z / cellHeight;
00298
00299 mUnitGrid[cellX][cellZ].push_back ( curUnit );
00300 }
00301 }
00302
00303
00304
00305 void TeamUnits::_clearSpatialGrid ()
00306 {
00307 for ( size_t i = 0; i < mUnitGrid.size(); i++ )
00308 {
00309 for ( size_t j = 0; j < mUnitGrid[i].size(); j++ )
00310 {
00311 mUnitGrid[i][j].clear ();
00312 }
00313 }
00314 }
00315
00316
00317
00318 TeamUnits::UnitList TeamUnits::getAdjacentUnits ( const Vector3& worldPos, float radius )
00319 {
00320
00321
00322
00323
00324
00325
00326
00327 UnitList units;
00328
00329 int worldWidth = Level::getSingleton ().getWorldWidth ();
00330 int worldHeight = Level::getSingleton ().getWorldHeight ();
00331
00332 unsigned int cellWidth = worldWidth / mUnitGrid.size ();
00333 unsigned int cellHeight = worldHeight / mUnitGrid[0].size();
00334
00335 unsigned int cellX = worldPos.x / cellWidth;
00336 unsigned int cellZ = worldPos.z / cellHeight;
00337
00338 if ( cellX >= mUnitGrid.size () || cellZ >= mUnitGrid[cellX].size() )
00339 throw Exception ( Exception::ERR_INVALIDPARAMS, "World position is outside of grid", "TeamUnits::getAdjacentUnits" );
00340
00341 if ( cellX < 0 || cellZ < 0 )
00342 throw Exception ( Exception::ERR_INVALIDPARAMS, "World position is outside of grid", "TeamUnits::getAdjacentUnits" );
00343
00344
00345 units = mUnitGrid[cellX][cellZ];
00346
00347 OgreAssert ( Level::getSingleton().getNumNodesWide(), "Must have at least one node width" );
00348 OgreAssert ( Level::getSingleton().getNumNodesHigh(), "Must have at least one node height" );
00349
00350 unsigned int cellsWide = Level::getSingleton ().getNumNodesWide () - 1;
00351 unsigned int cellsHigh = Level::getSingleton ().getNumNodesHigh () - 1;
00352
00353
00354
00355 if ( cellX > 0 && cellZ > 0 )
00356 units.insert ( units.end(), mUnitGrid[cellX - 1][cellZ - 1].begin(), mUnitGrid[cellX - 1][cellZ - 1].end () );
00357
00358 if ( cellX > 0 && cellZ < cellsWide )
00359 units.insert ( units.end(), mUnitGrid[cellX - 1][cellZ + 1].begin(), mUnitGrid[cellX - 1][cellZ + 1].end () );
00360
00361 if ( cellX > 0 )
00362 units.insert ( units.end(), mUnitGrid[cellX - 1][cellZ].begin(), mUnitGrid[cellX - 1][cellZ].end () );
00363
00364 if ( cellX < cellsWide && cellZ > 0 )
00365 units.insert ( units.end(), mUnitGrid[cellX + 1][cellZ - 1].begin(), mUnitGrid[cellX + 1][cellZ - 1].end () );
00366
00367 if ( cellX < cellsWide && cellZ < cellsWide )
00368 units.insert ( units.end(), mUnitGrid[cellX + 1][cellZ + 1].begin(), mUnitGrid[cellX + 1][cellZ + 1].end () );
00369
00370 if ( cellX < cellsWide )
00371 units.insert ( units.end(), mUnitGrid[cellX + 1][cellZ].begin(), mUnitGrid[cellX + 1][cellZ].end () );
00372
00373 if ( cellZ > 0 )
00374 units.insert ( units.end(), mUnitGrid[cellX][cellZ - 1].begin(), mUnitGrid[cellX][cellZ - 1].end () );
00375
00376 if ( cellZ < cellsHigh )
00377 units.insert ( units.end(), mUnitGrid[cellX][cellZ + 1].begin(), mUnitGrid[cellX][cellZ + 1].end () );
00378
00379 return units;
00380 }
00381
00382
00383
00384 void TeamUnits::performAttacks ()
00385 {
00386 UnitIterator iter = getUnitIterator ();
00387 while ( iter.hasMoreElements () )
00388 {
00389 Unit* curUnit = iter.getNext ();
00390
00391 curUnit->doAttack ();
00392 }
00393 }
00394 }