Chris Taylor / Mbed 2 deprecated RETRO-CityRally

Dependencies:   mbed

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers Enemy.h Source File

Enemy.h

00001 #include <climits>
00002 #include "RallyCar.h"
00003 #include "Player.h"
00004 
00005 #ifndef __ENEMY_H__
00006 #define __ENEMY_H__
00007 
00008 class Enemy : public RallyCar
00009 {
00010 private:
00011     enum Action { Start, Chase, Scatter };
00012     
00013 public:
00014 
00015     Enemy(Point startPosition, Point homePosition, Point targetOffset, Player &player) :
00016         _startPosition(startPosition),
00017         _homePosition(homePosition),
00018         _targetOffset(targetOffset),
00019         _player(player)
00020     {        
00021         reset();
00022     }            
00023     
00024     virtual void reset()
00025     {
00026         setPosition(_startPosition);
00027         
00028         setDirection(Up);
00029         setDesiredDirection(Up);
00030         setState(Driving);
00031         
00032         _action = Start;        
00033         
00034         setSpriteId(0);
00035         
00036         _actionCounter = 0;
00037         
00038         _startCount = 120;
00039         _scatterCount = 210;
00040         _chaseCount = 600;
00041     }
00042  
00043     virtual void update()
00044     {        
00045         ++_actionCounter;
00046         
00047         Point &position = getPosition();
00048         
00049         bool allowLeftRightTurn = position.Y % 8 == 0;
00050         bool allowUpDownTurn = position.X % 8 == 0;        
00051         
00052         if (getState() == Driving)
00053         {
00054             switch(_action)
00055             {
00056                 case Start:
00057                     if (_actionCounter == _startCount) 
00058                     {
00059                         _action = Scatter;
00060                         _actionCounter = 0;
00061                     }
00062                     break;        
00063                     
00064                 case Scatter:
00065                     if (_actionCounter == _scatterCount) 
00066                     {
00067                         _action = Chase;
00068                         _actionCounter = 0;
00069                     }
00070                     else
00071                     {
00072                         Direction direction = hunt(_homePosition);
00073                         setDesiredDirection(direction);
00074                     }
00075                     break;
00076                     
00077                 case Chase:
00078                     if (_actionCounter == _chaseCount) 
00079                     {
00080                         _action = Scatter;
00081                         _actionCounter = 0;
00082                     }
00083                     else
00084                     {      
00085                         Point target = _player.getPosition();
00086                         
00087                         if (distanceToTarget(target) > 4096)
00088                         {
00089                             switch(_player.getDirection())
00090                             {
00091                                 case Left: target.X -= _targetOffset.X; break;
00092                                 case Right: target.X += _targetOffset.X; break;
00093                                 case Up: target.Y -= _targetOffset.Y; break;
00094                                 case Down: target.Y += _targetOffset.Y; break;
00095                             }
00096                         }              
00097                         
00098                         Direction direction = hunt(target);  
00099                         if (getDesiredDirection() != direction)
00100                         {
00101                             setDesiredDirection(direction);
00102                             // Slow enemy down when they change direction
00103                             return;
00104                         }
00105                     }
00106                     break;
00107                 
00108             }
00109             
00110             if (_action != Start)
00111             {
00112                 if (getDirection() != getDesiredDirection())
00113                 {            
00114                     if ((getDesiredDirection() == Left && allowLeftRightTurn && canGoLeft())
00115                     || (getDesiredDirection() == Right && allowLeftRightTurn && canGoRight())
00116                     || (getDesiredDirection() == Up && allowUpDownTurn && canGoUp())
00117                     || (getDesiredDirection() == Down && allowUpDownTurn && canGoDown()))
00118                     {
00119                          setDirection(getDesiredDirection());                              
00120                     }                
00121                 }
00122             
00123                 switch(getDirection())
00124                 {
00125                     case Left : setSpriteId(3); moveLeft(); break;
00126                     case Right : setSpriteId(1); moveRight(); break;
00127                     case Up : setSpriteId(0); moveUp();break;
00128                     case Down : setSpriteId(2); moveDown(); break;
00129                 }            
00130             }
00131         }
00132         else 
00133         {
00134             if (getState() == StartSpinning)
00135             {
00136                 _actionCounter = (int)getDirection();
00137                 setState(Spinning);
00138             }
00139             
00140             if (getState() == Spinning)
00141             {
00142                 setSpriteId(_actionCounter % 4);                
00143             }
00144         }
00145         
00146         RallyCar::update();
00147     }
00148     
00149 private:
00150     Direction hunt(Point &target)
00151     {
00152         Direction bestDirection = None;
00153         uint32_t minDistance = LONG_MAX;
00154         
00155         uint32_t leftDistance = distanceToTarget(target, Left);
00156         uint32_t rightDistance = distanceToTarget(target, Right);
00157         uint32_t upDistance = distanceToTarget(target, Up);
00158         uint32_t downDistance = distanceToTarget(target, Down);
00159          
00160         if (getDirection() != Right && canGoLeft() &&  leftDistance < minDistance)
00161         {
00162             minDistance = leftDistance;
00163             bestDirection = Left;
00164         } 
00165         
00166         if (getDirection() != Left && canGoRight() &&  rightDistance < minDistance)
00167         {
00168             minDistance = rightDistance;
00169             bestDirection = Right;
00170         }
00171                
00172         if (getDirection() != Up && canGoDown() &&  downDistance < minDistance)
00173         {
00174             minDistance = downDistance;
00175             bestDirection = Down;
00176         } 
00177         
00178         if (getDirection() != Down && canGoUp() &&  upDistance < minDistance)
00179         {
00180             minDistance = upDistance;
00181             bestDirection = Up;
00182         }
00183         
00184         return bestDirection;
00185     }
00186     
00187     uint32_t distanceToTarget(Point &target)
00188     {
00189         int16_t dx = target.X - getPosition().X;
00190         int16_t dy = target.Y - getPosition().Y;
00191         return (dx * dx) + (dy * dy);
00192     }
00193     
00194     uint32_t distanceToTarget(Point &target, Direction direction)
00195     {
00196         int16_t x = getPosition().X;
00197         int16_t y = getPosition().Y;
00198         
00199         switch(direction)
00200         {
00201             case Left   : x -= 16; break;
00202             case Right  : x += 16; break;
00203             case Up     : y -= 16; break;
00204             case Down   : y += 16; break;
00205         }
00206         
00207         int16_t dx = target.X - x;
00208         int16_t dy = target.Y - y;
00209         return (dx * dx) + (dy * dy);
00210     }
00211     
00212 private:    
00213     Point       _startPosition;
00214     Point       _homePosition;
00215     Point       _targetOffset;
00216     Player     &_player;
00217     
00218     Action      _action;
00219     uint16_t    _actionCounter;    
00220     uint16_t    _startCount;
00221     uint16_t    _scatterCount;
00222     uint16_t    _chaseCount;       
00223 };
00224 #endif //__ENEMY_H__