Race around the city collecting the flags while avoiding those that stand in the way of your mission. Make no mistake you will need to be quick to outwit your opponents, they are smart and will try to box you in. I wrote this game to prove that writing a game with scrolling scenery is possible even with the limited 6kB of RAM available. I had to compromise sound effects for features, I wanted multiple opponents, I wanted to be able to drop smoke bombs to trap the opponents but all this required memory so the sound effects had to take a back seat.

Dependencies:   mbed

Committer:
taylorza
Date:
Sun Feb 01 00:43:25 2015 +0000
Revision:
1:1b8125937f28
Parent:
0:d85c449aca6d
Minor updates

Who changed what in which revision?

UserRevisionLine numberNew contents of line
taylorza 0:d85c449aca6d 1 #include <climits>
taylorza 0:d85c449aca6d 2 #include "RallyCar.h"
taylorza 0:d85c449aca6d 3 #include "Player.h"
taylorza 0:d85c449aca6d 4
taylorza 0:d85c449aca6d 5 #ifndef __ENEMY_H__
taylorza 0:d85c449aca6d 6 #define __ENEMY_H__
taylorza 0:d85c449aca6d 7
taylorza 0:d85c449aca6d 8 class Enemy : public RallyCar
taylorza 0:d85c449aca6d 9 {
taylorza 0:d85c449aca6d 10 private:
taylorza 0:d85c449aca6d 11 enum Action { Start, Chase, Scatter };
taylorza 0:d85c449aca6d 12
taylorza 0:d85c449aca6d 13 public:
taylorza 0:d85c449aca6d 14
taylorza 0:d85c449aca6d 15 Enemy(Point startPosition, Point homePosition, Point targetOffset, Player &player) :
taylorza 0:d85c449aca6d 16 _startPosition(startPosition),
taylorza 0:d85c449aca6d 17 _homePosition(homePosition),
taylorza 0:d85c449aca6d 18 _targetOffset(targetOffset),
taylorza 0:d85c449aca6d 19 _player(player)
taylorza 0:d85c449aca6d 20 {
taylorza 0:d85c449aca6d 21 reset();
taylorza 0:d85c449aca6d 22 }
taylorza 0:d85c449aca6d 23
taylorza 0:d85c449aca6d 24 virtual void reset()
taylorza 0:d85c449aca6d 25 {
taylorza 0:d85c449aca6d 26 setPosition(_startPosition);
taylorza 0:d85c449aca6d 27
taylorza 0:d85c449aca6d 28 setDirection(Up);
taylorza 0:d85c449aca6d 29 setDesiredDirection(Up);
taylorza 0:d85c449aca6d 30 setState(Driving);
taylorza 0:d85c449aca6d 31
taylorza 0:d85c449aca6d 32 _action = Start;
taylorza 0:d85c449aca6d 33
taylorza 0:d85c449aca6d 34 setSpriteId(0);
taylorza 0:d85c449aca6d 35
taylorza 0:d85c449aca6d 36 _actionCounter = 0;
taylorza 0:d85c449aca6d 37
taylorza 1:1b8125937f28 38 _startCount = 120;
taylorza 0:d85c449aca6d 39 _scatterCount = 210;
taylorza 0:d85c449aca6d 40 _chaseCount = 600;
taylorza 0:d85c449aca6d 41 }
taylorza 0:d85c449aca6d 42
taylorza 0:d85c449aca6d 43 virtual void update()
taylorza 0:d85c449aca6d 44 {
taylorza 0:d85c449aca6d 45 ++_actionCounter;
taylorza 1:1b8125937f28 46
taylorza 0:d85c449aca6d 47 Point &position = getPosition();
taylorza 0:d85c449aca6d 48
taylorza 0:d85c449aca6d 49 bool allowLeftRightTurn = position.Y % 8 == 0;
taylorza 0:d85c449aca6d 50 bool allowUpDownTurn = position.X % 8 == 0;
taylorza 0:d85c449aca6d 51
taylorza 0:d85c449aca6d 52 if (getState() == Driving)
taylorza 0:d85c449aca6d 53 {
taylorza 0:d85c449aca6d 54 switch(_action)
taylorza 0:d85c449aca6d 55 {
taylorza 0:d85c449aca6d 56 case Start:
taylorza 0:d85c449aca6d 57 if (_actionCounter == _startCount)
taylorza 0:d85c449aca6d 58 {
taylorza 0:d85c449aca6d 59 _action = Scatter;
taylorza 0:d85c449aca6d 60 _actionCounter = 0;
taylorza 0:d85c449aca6d 61 }
taylorza 0:d85c449aca6d 62 break;
taylorza 0:d85c449aca6d 63
taylorza 0:d85c449aca6d 64 case Scatter:
taylorza 0:d85c449aca6d 65 if (_actionCounter == _scatterCount)
taylorza 0:d85c449aca6d 66 {
taylorza 0:d85c449aca6d 67 _action = Chase;
taylorza 0:d85c449aca6d 68 _actionCounter = 0;
taylorza 0:d85c449aca6d 69 }
taylorza 0:d85c449aca6d 70 else
taylorza 0:d85c449aca6d 71 {
taylorza 0:d85c449aca6d 72 Direction direction = hunt(_homePosition);
taylorza 0:d85c449aca6d 73 setDesiredDirection(direction);
taylorza 0:d85c449aca6d 74 }
taylorza 0:d85c449aca6d 75 break;
taylorza 0:d85c449aca6d 76
taylorza 0:d85c449aca6d 77 case Chase:
taylorza 0:d85c449aca6d 78 if (_actionCounter == _chaseCount)
taylorza 0:d85c449aca6d 79 {
taylorza 0:d85c449aca6d 80 _action = Scatter;
taylorza 0:d85c449aca6d 81 _actionCounter = 0;
taylorza 0:d85c449aca6d 82 }
taylorza 0:d85c449aca6d 83 else
taylorza 0:d85c449aca6d 84 {
taylorza 0:d85c449aca6d 85 Point target = _player.getPosition();
taylorza 0:d85c449aca6d 86
taylorza 0:d85c449aca6d 87 if (distanceToTarget(target) > 4096)
taylorza 0:d85c449aca6d 88 {
taylorza 0:d85c449aca6d 89 switch(_player.getDirection())
taylorza 0:d85c449aca6d 90 {
taylorza 0:d85c449aca6d 91 case Left: target.X -= _targetOffset.X; break;
taylorza 0:d85c449aca6d 92 case Right: target.X += _targetOffset.X; break;
taylorza 0:d85c449aca6d 93 case Up: target.Y -= _targetOffset.Y; break;
taylorza 0:d85c449aca6d 94 case Down: target.Y += _targetOffset.Y; break;
taylorza 0:d85c449aca6d 95 }
taylorza 0:d85c449aca6d 96 }
taylorza 0:d85c449aca6d 97
taylorza 0:d85c449aca6d 98 Direction direction = hunt(target);
taylorza 1:1b8125937f28 99 if (getDesiredDirection() != direction)
taylorza 1:1b8125937f28 100 {
taylorza 1:1b8125937f28 101 setDesiredDirection(direction);
taylorza 1:1b8125937f28 102 // Slow enemy down when they change direction
taylorza 1:1b8125937f28 103 return;
taylorza 1:1b8125937f28 104 }
taylorza 0:d85c449aca6d 105 }
taylorza 0:d85c449aca6d 106 break;
taylorza 0:d85c449aca6d 107
taylorza 0:d85c449aca6d 108 }
taylorza 0:d85c449aca6d 109
taylorza 0:d85c449aca6d 110 if (_action != Start)
taylorza 0:d85c449aca6d 111 {
taylorza 0:d85c449aca6d 112 if (getDirection() != getDesiredDirection())
taylorza 0:d85c449aca6d 113 {
taylorza 0:d85c449aca6d 114 if ((getDesiredDirection() == Left && allowLeftRightTurn && canGoLeft())
taylorza 0:d85c449aca6d 115 || (getDesiredDirection() == Right && allowLeftRightTurn && canGoRight())
taylorza 0:d85c449aca6d 116 || (getDesiredDirection() == Up && allowUpDownTurn && canGoUp())
taylorza 0:d85c449aca6d 117 || (getDesiredDirection() == Down && allowUpDownTurn && canGoDown()))
taylorza 0:d85c449aca6d 118 {
taylorza 1:1b8125937f28 119 setDirection(getDesiredDirection());
taylorza 0:d85c449aca6d 120 }
taylorza 0:d85c449aca6d 121 }
taylorza 0:d85c449aca6d 122
taylorza 0:d85c449aca6d 123 switch(getDirection())
taylorza 0:d85c449aca6d 124 {
taylorza 0:d85c449aca6d 125 case Left : setSpriteId(3); moveLeft(); break;
taylorza 0:d85c449aca6d 126 case Right : setSpriteId(1); moveRight(); break;
taylorza 0:d85c449aca6d 127 case Up : setSpriteId(0); moveUp();break;
taylorza 0:d85c449aca6d 128 case Down : setSpriteId(2); moveDown(); break;
taylorza 0:d85c449aca6d 129 }
taylorza 0:d85c449aca6d 130 }
taylorza 0:d85c449aca6d 131 }
taylorza 0:d85c449aca6d 132 else
taylorza 0:d85c449aca6d 133 {
taylorza 0:d85c449aca6d 134 if (getState() == StartSpinning)
taylorza 0:d85c449aca6d 135 {
taylorza 0:d85c449aca6d 136 _actionCounter = (int)getDirection();
taylorza 0:d85c449aca6d 137 setState(Spinning);
taylorza 0:d85c449aca6d 138 }
taylorza 0:d85c449aca6d 139
taylorza 0:d85c449aca6d 140 if (getState() == Spinning)
taylorza 0:d85c449aca6d 141 {
taylorza 0:d85c449aca6d 142 setSpriteId(_actionCounter % 4);
taylorza 0:d85c449aca6d 143 }
taylorza 0:d85c449aca6d 144 }
taylorza 0:d85c449aca6d 145
taylorza 0:d85c449aca6d 146 RallyCar::update();
taylorza 0:d85c449aca6d 147 }
taylorza 0:d85c449aca6d 148
taylorza 0:d85c449aca6d 149 private:
taylorza 0:d85c449aca6d 150 Direction hunt(Point &target)
taylorza 0:d85c449aca6d 151 {
taylorza 0:d85c449aca6d 152 Direction bestDirection = None;
taylorza 0:d85c449aca6d 153 uint32_t minDistance = LONG_MAX;
taylorza 0:d85c449aca6d 154
taylorza 0:d85c449aca6d 155 uint32_t leftDistance = distanceToTarget(target, Left);
taylorza 0:d85c449aca6d 156 uint32_t rightDistance = distanceToTarget(target, Right);
taylorza 0:d85c449aca6d 157 uint32_t upDistance = distanceToTarget(target, Up);
taylorza 0:d85c449aca6d 158 uint32_t downDistance = distanceToTarget(target, Down);
taylorza 0:d85c449aca6d 159
taylorza 0:d85c449aca6d 160 if (getDirection() != Right && canGoLeft() && leftDistance < minDistance)
taylorza 0:d85c449aca6d 161 {
taylorza 0:d85c449aca6d 162 minDistance = leftDistance;
taylorza 0:d85c449aca6d 163 bestDirection = Left;
taylorza 0:d85c449aca6d 164 }
taylorza 0:d85c449aca6d 165
taylorza 0:d85c449aca6d 166 if (getDirection() != Left && canGoRight() && rightDistance < minDistance)
taylorza 0:d85c449aca6d 167 {
taylorza 0:d85c449aca6d 168 minDistance = rightDistance;
taylorza 0:d85c449aca6d 169 bestDirection = Right;
taylorza 0:d85c449aca6d 170 }
taylorza 0:d85c449aca6d 171
taylorza 0:d85c449aca6d 172 if (getDirection() != Up && canGoDown() && downDistance < minDistance)
taylorza 0:d85c449aca6d 173 {
taylorza 0:d85c449aca6d 174 minDistance = downDistance;
taylorza 0:d85c449aca6d 175 bestDirection = Down;
taylorza 0:d85c449aca6d 176 }
taylorza 0:d85c449aca6d 177
taylorza 0:d85c449aca6d 178 if (getDirection() != Down && canGoUp() && upDistance < minDistance)
taylorza 0:d85c449aca6d 179 {
taylorza 0:d85c449aca6d 180 minDistance = upDistance;
taylorza 0:d85c449aca6d 181 bestDirection = Up;
taylorza 0:d85c449aca6d 182 }
taylorza 0:d85c449aca6d 183
taylorza 0:d85c449aca6d 184 return bestDirection;
taylorza 0:d85c449aca6d 185 }
taylorza 0:d85c449aca6d 186
taylorza 0:d85c449aca6d 187 uint32_t distanceToTarget(Point &target)
taylorza 0:d85c449aca6d 188 {
taylorza 0:d85c449aca6d 189 int16_t dx = target.X - getPosition().X;
taylorza 0:d85c449aca6d 190 int16_t dy = target.Y - getPosition().Y;
taylorza 0:d85c449aca6d 191 return (dx * dx) + (dy * dy);
taylorza 0:d85c449aca6d 192 }
taylorza 0:d85c449aca6d 193
taylorza 0:d85c449aca6d 194 uint32_t distanceToTarget(Point &target, Direction direction)
taylorza 0:d85c449aca6d 195 {
taylorza 0:d85c449aca6d 196 int16_t x = getPosition().X;
taylorza 0:d85c449aca6d 197 int16_t y = getPosition().Y;
taylorza 0:d85c449aca6d 198
taylorza 0:d85c449aca6d 199 switch(direction)
taylorza 0:d85c449aca6d 200 {
taylorza 0:d85c449aca6d 201 case Left : x -= 16; break;
taylorza 0:d85c449aca6d 202 case Right : x += 16; break;
taylorza 0:d85c449aca6d 203 case Up : y -= 16; break;
taylorza 0:d85c449aca6d 204 case Down : y += 16; break;
taylorza 0:d85c449aca6d 205 }
taylorza 0:d85c449aca6d 206
taylorza 0:d85c449aca6d 207 int16_t dx = target.X - x;
taylorza 0:d85c449aca6d 208 int16_t dy = target.Y - y;
taylorza 0:d85c449aca6d 209 return (dx * dx) + (dy * dy);
taylorza 0:d85c449aca6d 210 }
taylorza 0:d85c449aca6d 211
taylorza 0:d85c449aca6d 212 private:
taylorza 0:d85c449aca6d 213 Point _startPosition;
taylorza 0:d85c449aca6d 214 Point _homePosition;
taylorza 0:d85c449aca6d 215 Point _targetOffset;
taylorza 0:d85c449aca6d 216 Player &_player;
taylorza 0:d85c449aca6d 217
taylorza 0:d85c449aca6d 218 Action _action;
taylorza 0:d85c449aca6d 219 uint16_t _actionCounter;
taylorza 0:d85c449aca6d 220 uint16_t _startCount;
taylorza 0:d85c449aca6d 221 uint16_t _scatterCount;
taylorza 0:d85c449aca6d 222 uint16_t _chaseCount;
taylorza 0:d85c449aca6d 223 };
taylorza 0:d85c449aca6d 224 #endif //__ENEMY_H__