00001 #include "Unit.h"
00002
00003 #include "Game.h"
00004 #include "Timer.h"
00005 #include "Projectile.h"
00006
00007 #include "OgreMath.h"
00008 #include "OgreStringConverter.h"
00009 #include "OgreException.h"
00010 #include "OgreAnimationState.h"
00011 #include "OgreAnimation.h"
00012 #include "OgreMaterialManager.h"
00013 #include "OgreMaterial.h"
00014 #include "OgreSubEntity.h"
00015 #include "OgreMovableObject.h"
00016
00017 using Ogre::MovableObject;
00018 using Ogre::AnimationState;
00019 using Ogre::AnimationStateSet;
00020 using Ogre::AnimationStateIterator;
00021 using Ogre::MaterialManager;
00022 using Ogre::Material;
00023 using Ogre::SubEntity;
00024 using Ogre::MaterialPtr;
00025 using Ogre::ColourValue;
00026 using Ogre::Exception;
00027 using Ogre::StringConverter;
00028 using Ogre::Degree;
00029 using Ogre::Math;
00030 using Ogre::Radian;
00031
00032
00033 namespace ASR
00034 {
00035 int Unit::mNumUnits = 0;
00036 const float Unit::mSearchUpdateTime = 1.0f;
00037 String Unit::TYPE_NAME = "Unit";
00038
00039
00040 Unit::Unit( SceneNode* parentNode, String meshName )
00041 : mMeshName ( meshName )
00042 {
00043 mNumUnits++;
00044
00045 SceneManager* sceneMgr = Game::getSingletonPtr ()->getSceneManager ();
00046
00047 mUnitName = "unit_" + StringConverter::toString ( mNumUnits );
00048 mEntity = sceneMgr->createEntity ( mUnitName, mMeshName);
00049 mEntity->setUserObject( this );
00050 mEntity->setCastShadows ( true );
00051
00052 mUnitNode = parentNode->createChildSceneNode( mUnitName + "_node" );
00053 mUnitNode->attachObject( mEntity );
00054 mUnitNode->setFixedYawAxis ( true );
00055
00056 mNavDirty = false;
00057
00058 mAnimationState = getEntity()->getAnimationState ( "Idle" );
00059
00060 mStatus = US_DEAD;
00061
00062 assignTarget ( NULL );
00063 setStatus ( US_IDLE );
00064
00065 mSearch = NULL;
00066 mSearchElapsedTime = 0.0f;
00067
00068
00069 mFireRate = 1.0f;
00070 mRange = 80.0f;
00071 mSightRadius = 200.0f;
00072 mMaxHitPoints = 100;
00073 mCurHitPoints = mMaxHitPoints;
00074
00075
00076
00077 String shieldName = mUnitName + "_shield";
00078 mShield = sceneMgr->createEntity( shieldName, "lizardmanShield1.mesh" );
00079 SceneNode *shield_Node = sceneMgr->getRootSceneNode()->createChildSceneNode( shieldName + "_Node" );
00080 shield_Node->yaw(Radian(Degree(90)));
00081 shield_Node->pitch(Radian(Degree(-90)));
00082
00083 String shoulderName = mUnitName + "_shoulder";
00084 mShoulder = sceneMgr->createEntity( shoulderName, "lizardmanShoulder1.mesh" );
00085 SceneNode *shoulder_Node = sceneMgr->getRootSceneNode()->createChildSceneNode( shoulderName + "_Node" );
00086 shoulder_Node->roll(Radian(Degree(10)));
00087
00088 String swordName = mUnitName + "_sword";
00089 mWeapon = sceneMgr->createEntity( swordName, "lizardmanWeapon1.mesh" );
00090 SceneNode *sword_Node = sceneMgr->getRootSceneNode()->createChildSceneNode( swordName + "_Node" );
00091 sword_Node->pitch(Radian(Degree(90)));
00092 sword_Node->roll(Radian(Degree(95)));
00093
00094 mEntity->attachObjectToBone ("LeftShoulder", mShoulder, shoulder_Node->getOrientation(), Vector3(4.7, 0.5, 0.5));
00095 mEntity->attachObjectToBone ("LeftForearm", mShield, shield_Node->getOrientation(), Vector3(3.5, 3.0, 0.2));
00096 mEntity->attachObjectToBone ("RightHand", mWeapon, sword_Node->getOrientation(), Vector3(2.0, 0.0, 0.9));
00097 }
00098
00099
00100
00101 Unit::~Unit(void)
00102 {
00103 _destroyAttacks ();
00104 _destroySearch ();
00105 }
00106
00107
00108
00109 float Unit::getSightRadius () const
00110 {
00111 return mSightRadius;
00112 }
00113
00114
00115
00116 void Unit::clearWaypoints()
00117 {
00118 mNavDirty = true;
00119 mWaypoints.clear ();
00120 }
00121
00122
00123
00124 void Unit::addWaypoint( const Vector3& waypoint )
00125 {
00126 setStatus ( US_MOVING );
00127 assignTarget ( NULL );
00128
00129 mNavDirty = true;
00130 mWaypoints.push_back ( waypoint );
00131
00132 if ( mWaypoints.size() == 1 )
00133 _alignToWaypoint ();
00134 }
00135
00136
00137
00138 void Unit::removeDestination()
00139 {
00140 assert ( !mWaypoints.empty() );
00141 mWaypoints.pop_front ();
00142
00143
00144 if ( hasDestination () )
00145 {
00146 _alignToWaypoint ();
00147 }
00148 else
00149 {
00150 stopMovement ();
00151 }
00152 }
00153
00154
00155
00156 Vector3 Unit::getDestination()
00157 {
00158 assert ( !mWaypoints.empty() );
00159 return mWaypoints.front ();
00160 }
00161
00162
00163
00164 bool Unit::hasDestination()
00165 {
00166 return !mWaypoints.empty ();
00167 }
00168
00169
00170
00171 Entity* Unit::getEntity ()
00172 {
00173 return mEntity;
00174 }
00175
00176
00177
00178 const String& Unit::getTypeName () const
00179 {
00180 return Unit::TYPE_NAME;
00181 }
00182
00183
00184
00185 void Unit::scale ( Real x, Real y, Real z )
00186 {
00187 mUnitNode->scale ( x, y, z );
00188 }
00189
00190
00191
00192 void Unit::translate ( const Vector3& vec, Node::TransformSpace space )
00193 {
00194 mUnitNode->translate ( vec, space );
00195 }
00196
00197
00198
00199 Vector3 Unit::getPosition () const
00200 {
00201 return mUnitNode->getWorldPosition ();
00202 }
00203
00204
00205
00206 void Unit::setPosition ( const Vector3& pos )
00207 {
00208 mUnitNode->setPosition ( pos );
00209 }
00210
00211
00212
00213 void Unit::setDirection ( const Vector3& dir )
00214 {
00215 mUnitNode->setDirection ( dir );
00216 }
00217
00218
00219
00220 void Unit::setDirection ( float x, float y, float z )
00221 {
00222 mUnitNode->setDirection( x, y, z );
00223 }
00224
00225
00226
00227 void Unit::_alignToWaypoint ()
00228 {
00229
00230 Vector3 dest = getDestination();
00231 dest.y = getPosition ().y;
00232
00233 Vector3 direction = dest - getPosition ();
00234
00235
00236 if ( direction.isZeroLength () )
00237 {
00238 return;
00239 }
00240
00241 getEntity()->getParentSceneNode ()->lookAt ( dest, SceneNode::TS_WORLD, Vector3::UNIT_Z );
00242 }
00243
00244
00245
00246 Unit::WaypointIterator Unit::getWaypointIterator ()
00247 {
00248 return WaypointIterator ( mWaypoints.begin(), mWaypoints.end() );
00249 }
00250
00251
00252
00253 void Unit::assignTarget ( Unit* target )
00254 {
00255
00256 if ( target != NULL && target->isDead() )
00257 throw Exception ( Exception::ERR_INTERNAL_ERROR, "Targetting a dead unit", "Unit::assignTarget" );
00258
00259
00260 if ( mStatus == US_MOVING )
00261 return;
00262
00263 clearWaypoints ();
00264
00265 mTarget = target;
00266 mAttackTime = 0.0f;
00267
00268 if ( target == NULL )
00269 {
00270 setStatus ( US_IDLE );
00271 }
00272 else
00273 {
00274
00275 Vector3 distanceToTarget = target->getPosition() - getPosition();
00276
00277
00278
00279 if ( distanceToTarget.length () > getRange() )
00280 {
00281 _chaseTarget ();
00282 }
00283 else
00284 {
00285 setStatus ( US_ATTACKING );
00286 _alignToTarget ();
00287 }
00288 }
00289 }
00290
00291
00292
00293 bool Unit::isEngaged () const
00294 {
00295 return (mStatus == US_ATTACKING || mStatus == US_CHASING);
00296 }
00297
00298
00299
00300 Unit* Unit::getTarget () const
00301 {
00302 return mTarget;
00303 }
00304
00305
00306
00307 void Unit::doAttack ()
00308 {
00309 _updateProjectiles ();
00310
00311 if ( isDead () )
00312 {
00313 clearWaypoints ();
00314 setStatus ( US_DYING );
00315
00316
00317 hide ();
00318 return;
00319 }
00320
00321 if ( mTarget == NULL || !isEngaged() )
00322 return;
00323
00324 float targetDist = _getDistanceToTarget ();
00325
00326
00327 if ( targetDist > getSightRadius() )
00328 {
00329 assignTarget ( NULL );
00330 _destroyAttacks ();
00331 return;
00332 }
00333
00334
00335 if ( mStatus == US_CHASING )
00336 {
00337 if ( targetDist <= getRange() )
00338 {
00339
00340 clearWaypoints ();
00341 setStatus ( US_ATTACKING );
00342 }
00343 else
00344 {
00345 mSearchElapsedTime += Timer::getSingleton ().getTimeSinceLastFrame ();
00346 if ( mSearchElapsedTime >= mSearchUpdateTime )
00347 {
00348 mSearchElapsedTime -= mSearchUpdateTime;
00349
00350
00351
00352
00353 setDestination ( mTarget->getPosition() );
00354 setStatus ( US_CHASING );
00355 }
00356 }
00357 }
00358 else if ( mStatus == US_ATTACKING )
00359 {
00360
00361 if ( targetDist > (getRange () + 10.0f) )
00362 {
00363 _chaseTarget ();
00364 return;
00365 }
00366
00367
00368
00369 _alignToTarget ();
00370
00371 mAttackTime += Timer::getSingleton ().getTimeSinceLastFrame();
00372
00373 if ( mAttackTime > _getTimeBetweenAttacks() )
00374 {
00375 _spawnAttack ();
00376
00377
00378
00379
00380 if ( mTarget->isDead() )
00381 {
00382 assignTarget ( NULL );
00383 }
00384 }
00385 }
00386 }
00387
00388
00389
00390 float Unit::_getTimeBetweenAttacks ()
00391 {
00392 return mFireRate;
00393 }
00394
00395
00396
00397 void Unit::_spawnAttack ()
00398 {
00399
00400 float projectileSpeed = 150.0f;
00401
00402 Projectile* newBullet = new Projectile ( this, mTarget );
00403 newBullet->setDamage ( _calcDamage(mTarget) );
00404 newBullet->setSpeed ( projectileSpeed );
00405
00406 mProjectiles.push_back ( newBullet );
00407
00408 mAttackTime = 0.0f;
00409 }
00410
00411
00412
00413 void Unit::_updateProjectiles ()
00414 {
00415 vector<Projectile*>::iterator iter = mProjectiles.begin();
00416 vector<Projectile*> toRemove;
00417
00418 while ( iter != mProjectiles.end() )
00419 {
00420 if ( (*iter)->update () )
00421 toRemove.push_back ( (*iter) );
00422
00423 iter++;
00424 }
00425
00426 iter = toRemove.begin();
00427 while ( iter != toRemove.end() )
00428 {
00429 vector<Projectile*>::iterator projIter = find ( mProjectiles.begin(), mProjectiles.end(), (*iter) );
00430 mProjectiles.erase ( projIter );
00431
00432 delete (*iter);
00433 iter++;
00434 }
00435 }
00436
00437
00438
00439 float Unit::_getDistanceToTarget ()
00440 {
00441 OgreAssert ( mTarget != NULL, "No target to get distance to" );
00442 Vector3 targPos = mTarget->getPosition();
00443 targPos.y = 0.0f;
00444
00445 Vector3 ourPos = getPosition();
00446 ourPos.y = 0.0f;
00447
00448 return ( targPos - ourPos ).length();
00449 }
00450
00451
00452
00453 void Unit::_destroyAttacks ()
00454 {
00455 BulletList::iterator iter = mProjectiles.begin();
00456 while ( iter != mProjectiles.end() )
00457 {
00458 delete (*iter);
00459 iter++;
00460 }
00461
00462 mProjectiles.clear ();
00463 }
00464
00465
00466
00467 void Unit::stopMovement ()
00468 {
00469 setStatus ( US_IDLE );
00470 mWaypoints.clear ();
00471
00472 assignTarget ( NULL );
00473 }
00474
00475
00476
00477 void Unit::setStatus ( UnitStatus status )
00478 {
00479 if ( mStatus == status )
00480 return;
00481
00482 mStatus = status;
00483
00484 mAnimationState->setEnabled ( false );
00485
00486 switch ( mStatus )
00487 {
00488 case US_MOVING:
00489 case US_CHASING:
00490 mAnimationState = getEntity()->getAnimationState( "Run" );
00491 break;
00492
00493 case US_IDLE:
00494 case US_ATTACKING:
00495 case US_DEAD:
00496 case US_DYING:
00497 default:
00498 mAnimationState = getEntity()->getAnimationState( "Idle" );
00499 break;
00500 }
00501
00502 mAnimationState->setEnabled( true );
00503 mAnimationState->setTimePosition ( 0.0 );
00504 }
00505
00506
00507
00508 void Unit::updateAnimation (float deltaTime )
00509 {
00510 mAnimationState->addTime ( deltaTime );
00511 }
00512
00513
00514
00515 void Unit::_alignToTarget ()
00516 {
00517 Vector3 direction = mTarget->getPosition () - getPosition();
00518 if ( direction.isZeroLength () )
00519 return;
00520
00521 direction.normalise ();
00522
00523 Vector3 target = mTarget->getPosition ();
00524 target.y = getPosition().y;
00525
00526 mUnitNode->lookAt ( target, SceneNode::TS_WORLD, Vector3::UNIT_Z );
00527 }
00528
00529
00530
00531 void Unit::assignDamage ( int damage )
00532 {
00533 mCurHitPoints -= damage;
00534 }
00535
00536
00537
00538 bool Unit::isDead () const
00539 {
00540 return mCurHitPoints <= 0;
00541 }
00542
00543
00544
00545 float Unit::_calcDamage ( const Unit* target ) const
00546 {
00547
00548 return 5;
00549 }
00550
00551
00552
00553 String Unit::getUnitName() const
00554 {
00555 return mUnitName;
00556 }
00557
00558
00559
00560 bool Unit::setDestination ( const Vector3& destination )
00561 {
00562 AStarSearch<Level::LevelNode>* search = NULL;
00563 Level* lev = Level::getSingletonPtr ();
00564
00565 _destroySearch ();
00566
00567
00568 Level::LevelNode* startNode = lev->getNode ( getPosition () );
00569 Level::LevelNode* endNode = lev->getNode ( destination );
00570
00571
00572 mSearch = Level::getSingleton().getPathManager()->createSearch ( getEntity ()->getName(), startNode, endNode );
00573 while ( mSearch->isRunnable() )
00574 {
00575 mSearch->advanceSearch();
00576 }
00577
00578 if ( mSearch->isSolved() )
00579 {
00580 _assignWaypoints ();
00581 return true;
00582 }
00583
00584 return false;
00585 }
00586
00587
00588
00589 void Unit::_assignWaypoints ()
00590 {
00591 OgreAssert ( mSearch, "There is no search defined" );
00592 if ( !mSearch->isSolved() )
00593 throw Ogre::Exception ( Exception::ERR_INTERNAL_ERROR, "Copying from an unsolved search", "Unit::_assignWaypoints" );
00594
00595 clearWaypoints();
00596
00597 const WaypointList<Level::LevelNode>* waypoints = mSearch->getSolutionPath();
00598
00599
00600
00601 if ( waypoints->getNumWaypoints () > 1 )
00602 {
00603
00604 for ( unsigned int i = 1; i < waypoints->getNumWaypoints() - 1; i++ )
00605 {
00606 addWaypoint( waypoints->getWaypoint(i)->getWorldPosition() );
00607 }
00608
00609 }
00610
00611
00612
00613
00614 else if ( waypoints->getNumWaypoints () == 1 )
00615 {
00616 addWaypoint ( waypoints->getWaypoint (0)->getWorldPosition () );
00617 }
00618 }
00619
00620
00621
00622 void Unit::_destroySearch ()
00623 {
00624 if ( mSearch )
00625 {
00626 Level::getSingleton().getPathManager()->destroySearch( getEntity ()->getName() );
00627 mSearch = NULL;
00628 }
00629 }
00630
00631
00632
00633 float Unit::getRange() const
00634 {
00635 return mRange;
00636 }
00637
00638
00639
00640 void Unit::_chaseTarget ()
00641 {
00642 OgreAssert ( mTarget, "Unit has no target to chase" );
00643
00644 mSearchElapsedTime = 0.0f;
00645 setDestination ( mTarget->getPosition() );
00646 setStatus ( US_CHASING );
00647 }
00648
00649
00650
00651 void Unit::hide ()
00652 {
00653 getEntity ()->getParentSceneNode ()->setVisible ( false );
00654 Entity::ChildObjectListIterator iter = getEntity ()->getAttachedObjectIterator ();
00655 while ( iter.hasMoreElements () )
00656 {
00657 MovableObject* obj = iter.getNext ();
00658 obj->setVisible ( false );
00659 }
00660 }
00661
00662
00663
00664 void Unit::show ()
00665 {
00666 getEntity ()->getParentSceneNode ()->setVisible ( true );
00667 Entity::ChildObjectListIterator iter = getEntity ()->getAttachedObjectIterator ();
00668 while ( iter.hasMoreElements () )
00669 {
00670 MovableObject* obj = iter.getNext ();
00671 obj->setVisible ( true );
00672 }
00673 }
00674 }