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 "Constants.h"
taylorza 0:d85c449aca6d 2 #include "RallyCar.h"
taylorza 0:d85c449aca6d 3 #include "Flag.h"
taylorza 0:d85c449aca6d 4 #include "Smoke.h"
taylorza 1:1b8125937f28 5 #include "Beeper.h"
taylorza 0:d85c449aca6d 6
taylorza 0:d85c449aca6d 7 #ifndef __PLAYER_H__
taylorza 0:d85c449aca6d 8 #define __PLAYER_H__
taylorza 0:d85c449aca6d 9
taylorza 0:d85c449aca6d 10 class Player : public RallyCar
taylorza 0:d85c449aca6d 11 {
taylorza 0:d85c449aca6d 12 public:
taylorza 0:d85c449aca6d 13 Player(Point startPosition) :
taylorza 0:d85c449aca6d 14 _startPosition(startPosition),
taylorza 0:d85c449aca6d 15 _smokeIndex(255),
taylorza 1:1b8125937f28 16 _lives(MAX_LIVES),
taylorza 0:d85c449aca6d 17 _score(0)
taylorza 0:d85c449aca6d 18 {
taylorza 0:d85c449aca6d 19 reset();
taylorza 0:d85c449aca6d 20 }
taylorza 0:d85c449aca6d 21
taylorza 0:d85c449aca6d 22 virtual void reset()
taylorza 0:d85c449aca6d 23 {
taylorza 0:d85c449aca6d 24 setPosition(_startPosition);
taylorza 0:d85c449aca6d 25 setDirection(Up);
taylorza 0:d85c449aca6d 26 setDesiredDirection(Up);
taylorza 1:1b8125937f28 27 setState(RallyCar::Idle);
taylorza 0:d85c449aca6d 28 setSpriteId(4);
taylorza 0:d85c449aca6d 29 _fuel = 100;
taylorza 0:d85c449aca6d 30 _updateCounter = 0;
taylorza 1:1b8125937f28 31
taylorza 1:1b8125937f28 32 if (_flagCount == MAX_FLAGS)
taylorza 1:1b8125937f28 33 {
taylorza 1:1b8125937f28 34 _flagCount = 0;
taylorza 1:1b8125937f28 35 }
taylorza 1:1b8125937f28 36
taylorza 1:1b8125937f28 37 _stateCounter = 60;
taylorza 0:d85c449aca6d 38 }
taylorza 0:d85c449aca6d 39
taylorza 0:d85c449aca6d 40 void setCars(RallyCar **cars) { _cars = cars; }
taylorza 0:d85c449aca6d 41 void setFlags(Flag *flags) { _flags = flags; }
taylorza 0:d85c449aca6d 42
taylorza 0:d85c449aca6d 43 static uint16_t lfsr_rand()
taylorza 0:d85c449aca6d 44 {
taylorza 0:d85c449aca6d 45 static uint16_t lfsr = 0xACE1u;
taylorza 0:d85c449aca6d 46 lfsr = (lfsr >> 1) ^ (-(lfsr & 1u) & 0xB400u);
taylorza 0:d85c449aca6d 47 return lfsr;
taylorza 0:d85c449aca6d 48 }
taylorza 0:d85c449aca6d 49
taylorza 0:d85c449aca6d 50 virtual void update()
taylorza 0:d85c449aca6d 51 {
taylorza 0:d85c449aca6d 52 if (_smokeIndex == 255)
taylorza 0:d85c449aca6d 53 {
taylorza 0:d85c449aca6d 54 for(int i = 0; i < MAX_SMOKE; ++i)
taylorza 0:d85c449aca6d 55 {
taylorza 0:d85c449aca6d 56 _smoke[i].setCars(_cars);
taylorza 0:d85c449aca6d 57 getParent()->addGameObject(&_smoke[i]);
taylorza 0:d85c449aca6d 58 }
taylorza 0:d85c449aca6d 59 _smokeIndex = 0;
taylorza 0:d85c449aca6d 60 }
taylorza 0:d85c449aca6d 61
taylorza 1:1b8125937f28 62 if (getState() == RallyCar::Idle)
taylorza 1:1b8125937f28 63 {
taylorza 1:1b8125937f28 64 if (--_stateCounter == 0)
taylorza 1:1b8125937f28 65 {
taylorza 1:1b8125937f28 66 setState(RallyCar::Driving);
taylorza 1:1b8125937f28 67 }
taylorza 1:1b8125937f28 68 }
taylorza 1:1b8125937f28 69 else if (getState() == RallyCar::Driving)
taylorza 0:d85c449aca6d 70 {
taylorza 0:d85c449aca6d 71 ++_updateCounter;
taylorza 0:d85c449aca6d 72 if (_updateCounter % FUEL_COUNTER == 0) --_fuel;
taylorza 0:d85c449aca6d 73 if (_fuel == 0) setState(RallyCar::StartCrash);
taylorza 0:d85c449aca6d 74
taylorza 0:d85c449aca6d 75 Point &position = getPosition();
taylorza 0:d85c449aca6d 76
taylorza 0:d85c449aca6d 77 bool allowLeftRightTurn = position.Y % 8 == 0;
taylorza 0:d85c449aca6d 78 bool allowUpDownTurn = position.X % 8 == 0;
taylorza 0:d85c449aca6d 79
taylorza 0:d85c449aca6d 80 if (GameInput::isLeftPressed()) { setDesiredDirection(Left); }
taylorza 0:d85c449aca6d 81 if (GameInput::isRightPressed()) { setDesiredDirection(Right); }
taylorza 0:d85c449aca6d 82 if (GameInput::isUpPressed()) { setDesiredDirection(Up); }
taylorza 0:d85c449aca6d 83 if (GameInput::isDownPressed()) { setDesiredDirection(Down); }
taylorza 0:d85c449aca6d 84 if (GameInput::isCirclePressed() && !_dropSmoke) {_dropSmoke = true; }
taylorza 0:d85c449aca6d 85
taylorza 0:d85c449aca6d 86 bool forceTurn = false;
taylorza 0:d85c449aca6d 87 do
taylorza 0:d85c449aca6d 88 {
taylorza 0:d85c449aca6d 89 if (getDirection() != getDesiredDirection())
taylorza 0:d85c449aca6d 90 {
taylorza 0:d85c449aca6d 91 if ((getDesiredDirection() == Left && allowLeftRightTurn && canGoLeft())
taylorza 0:d85c449aca6d 92 || (getDesiredDirection() == Right && allowLeftRightTurn && canGoRight())
taylorza 0:d85c449aca6d 93 || (getDesiredDirection() == Up && allowUpDownTurn && canGoUp())
taylorza 0:d85c449aca6d 94 || (getDesiredDirection() == Down && allowUpDownTurn && canGoDown()))
taylorza 0:d85c449aca6d 95 {
taylorza 0:d85c449aca6d 96 setDirection(getDesiredDirection());
taylorza 0:d85c449aca6d 97 }
taylorza 0:d85c449aca6d 98 }
taylorza 0:d85c449aca6d 99
taylorza 0:d85c449aca6d 100 switch(getDirection())
taylorza 0:d85c449aca6d 101 {
taylorza 0:d85c449aca6d 102 case Left : setSpriteId(7); forceTurn = !moveLeft(); if (_dropSmoke) smoke(Right); break;
taylorza 0:d85c449aca6d 103 case Right : setSpriteId(5); forceTurn = !moveRight(); if (_dropSmoke) smoke(Left); break;
taylorza 0:d85c449aca6d 104 case Up : setSpriteId(4); forceTurn = !moveUp(); if (_dropSmoke) smoke(Down); break;
taylorza 0:d85c449aca6d 105 case Down : setSpriteId(6); forceTurn = !moveDown(); if (_dropSmoke) smoke(Up); break;
taylorza 0:d85c449aca6d 106 }
taylorza 0:d85c449aca6d 107
taylorza 0:d85c449aca6d 108 if (forceTurn)
taylorza 0:d85c449aca6d 109 {
taylorza 0:d85c449aca6d 110 switch (getDirection())
taylorza 0:d85c449aca6d 111 {
taylorza 0:d85c449aca6d 112 case Left:
taylorza 0:d85c449aca6d 113 case Right:
taylorza 0:d85c449aca6d 114 if (lfsr_rand() & 1)
taylorza 0:d85c449aca6d 115 setDesiredDirection(Up);
taylorza 0:d85c449aca6d 116 else
taylorza 0:d85c449aca6d 117 setDesiredDirection(Down);
taylorza 0:d85c449aca6d 118 break;
taylorza 0:d85c449aca6d 119
taylorza 0:d85c449aca6d 120 case Up:
taylorza 0:d85c449aca6d 121 case Down:
taylorza 0:d85c449aca6d 122 if (lfsr_rand() & 1)
taylorza 0:d85c449aca6d 123 setDesiredDirection(Left);
taylorza 0:d85c449aca6d 124 else
taylorza 0:d85c449aca6d 125 setDesiredDirection(Right);
taylorza 0:d85c449aca6d 126 break;
taylorza 0:d85c449aca6d 127 }
taylorza 0:d85c449aca6d 128 }
taylorza 0:d85c449aca6d 129 } while (forceTurn);
taylorza 0:d85c449aca6d 130
taylorza 0:d85c449aca6d 131 for(int i = 0; i < MAX_CARS; ++i)
taylorza 0:d85c449aca6d 132 {
taylorza 0:d85c449aca6d 133 RallyCar *car = _cars[i];
taylorza 0:d85c449aca6d 134 if (car != this)
taylorza 0:d85c449aca6d 135 {
taylorza 0:d85c449aca6d 136 if (detectCollision(car))
taylorza 0:d85c449aca6d 137 {
taylorza 0:d85c449aca6d 138 setState(RallyCar::StartCrash);
taylorza 0:d85c449aca6d 139 }
taylorza 0:d85c449aca6d 140 }
taylorza 0:d85c449aca6d 141 }
taylorza 0:d85c449aca6d 142
taylorza 0:d85c449aca6d 143 for (int i = 0; i < MAX_FLAGS; ++i)
taylorza 0:d85c449aca6d 144 {
taylorza 0:d85c449aca6d 145 Flag *flag = &_flags[i];
taylorza 0:d85c449aca6d 146 if (flag->getActive() == true && detectCollision(flag))
taylorza 0:d85c449aca6d 147 {
taylorza 0:d85c449aca6d 148 flag->setActive(false);
taylorza 0:d85c449aca6d 149 getParent()->removeGameObject(flag);
taylorza 0:d85c449aca6d 150 _score += 100;
taylorza 1:1b8125937f28 151 ++_flagCount;
taylorza 1:1b8125937f28 152 Beeper::beep(500, 3);
taylorza 1:1b8125937f28 153 Beeper::beep(2000, 4);
taylorza 1:1b8125937f28 154 Beeper::beep(1000, 2);
taylorza 0:d85c449aca6d 155 }
taylorza 0:d85c449aca6d 156 }
taylorza 0:d85c449aca6d 157 }
taylorza 0:d85c449aca6d 158 else if (getState() == RallyCar::StartCrash)
taylorza 0:d85c449aca6d 159 {
taylorza 1:1b8125937f28 160 _stateCounter = 30;
taylorza 0:d85c449aca6d 161 setState(RallyCar::Crashed);
taylorza 0:d85c449aca6d 162 }
taylorza 0:d85c449aca6d 163 else if (getState() == RallyCar::Crashed)
taylorza 0:d85c449aca6d 164 {
taylorza 1:1b8125937f28 165 setSpriteId(10);
taylorza 1:1b8125937f28 166 if (--_stateCounter == 0)
taylorza 0:d85c449aca6d 167 {
taylorza 0:d85c449aca6d 168 --_lives;
taylorza 0:d85c449aca6d 169 for (int i = 0; i < MAX_CARS; ++i)
taylorza 0:d85c449aca6d 170 {
taylorza 0:d85c449aca6d 171 _cars[i]->reset();
taylorza 0:d85c449aca6d 172 }
taylorza 0:d85c449aca6d 173 }
taylorza 1:1b8125937f28 174 Beeper::noise(2000, 2);
taylorza 0:d85c449aca6d 175 }
taylorza 0:d85c449aca6d 176
taylorza 0:d85c449aca6d 177 RallyCar::update();
taylorza 0:d85c449aca6d 178 }
taylorza 0:d85c449aca6d 179
taylorza 0:d85c449aca6d 180 inline uint8_t getLives() { return _lives; }
taylorza 0:d85c449aca6d 181 inline uint32_t getScore() { return _score; }
taylorza 0:d85c449aca6d 182 inline uint8_t getFuel() { return _fuel; }
taylorza 1:1b8125937f28 183 inline uint8_t getFlagCount() { return _flagCount; }
taylorza 1:1b8125937f28 184
taylorza 1:1b8125937f28 185 inline void decreaseFuel() { if (_fuel > 0) --_fuel; }
taylorza 1:1b8125937f28 186 inline void increaseScore(int score) { _score += score; }
taylorza 0:d85c449aca6d 187 private:
taylorza 0:d85c449aca6d 188 void smoke(Direction direction)
taylorza 0:d85c449aca6d 189 {
taylorza 0:d85c449aca6d 190 Point &position = getPosition();
taylorza 0:d85c449aca6d 191 TileViewer* parent = getParent();
taylorza 0:d85c449aca6d 192
taylorza 0:d85c449aca6d 193 if (_fuel < 10)
taylorza 0:d85c449aca6d 194 {
taylorza 0:d85c449aca6d 195 _dropSmoke = false;
taylorza 0:d85c449aca6d 196 return;
taylorza 0:d85c449aca6d 197 }
taylorza 0:d85c449aca6d 198
taylorza 0:d85c449aca6d 199 bool onLeftRightBoundary = position.X % 16 == 0 && position.X > 16 && position.X < (parent->getMapTilesX() * 16);
taylorza 0:d85c449aca6d 200 bool onUpDownBoundary = position.Y % 16 == 0 && position.Y > 16 && position.Y < (parent->getMapTilesY() * 16);
taylorza 0:d85c449aca6d 201 int x = 0;
taylorza 0:d85c449aca6d 202 int y = 0;
taylorza 0:d85c449aca6d 203 bool drop = false;
taylorza 0:d85c449aca6d 204 if (direction == Left && onLeftRightBoundary)
taylorza 0:d85c449aca6d 205 {
taylorza 0:d85c449aca6d 206 x = position.X - 16;
taylorza 0:d85c449aca6d 207 y = position.Y;
taylorza 0:d85c449aca6d 208 drop = true;
taylorza 0:d85c449aca6d 209 }
taylorza 0:d85c449aca6d 210 else if (direction == Right && onLeftRightBoundary)
taylorza 0:d85c449aca6d 211 {
taylorza 0:d85c449aca6d 212 x = position.X + 16;
taylorza 0:d85c449aca6d 213 y = position.Y;
taylorza 0:d85c449aca6d 214 drop = true;
taylorza 0:d85c449aca6d 215 }
taylorza 0:d85c449aca6d 216 else if (direction == Up && onUpDownBoundary)
taylorza 0:d85c449aca6d 217 {
taylorza 0:d85c449aca6d 218 x = position.X;
taylorza 0:d85c449aca6d 219 y = position.Y - 16;
taylorza 0:d85c449aca6d 220 drop = true;
taylorza 0:d85c449aca6d 221 }
taylorza 0:d85c449aca6d 222 else if (direction == Down && onUpDownBoundary)
taylorza 0:d85c449aca6d 223 {
taylorza 0:d85c449aca6d 224 x = position.X;
taylorza 0:d85c449aca6d 225 y = position.Y + 16;
taylorza 0:d85c449aca6d 226 drop = true;
taylorza 0:d85c449aca6d 227 }
taylorza 0:d85c449aca6d 228
taylorza 0:d85c449aca6d 229 if (drop)
taylorza 0:d85c449aca6d 230 {
taylorza 0:d85c449aca6d 231 _dropSmoke = false;
taylorza 0:d85c449aca6d 232 Smoke &smoke = _smoke[_smokeIndex];
taylorza 0:d85c449aca6d 233 smoke.setPosition(Point(x, y));
taylorza 0:d85c449aca6d 234 smoke.setActive(true);
taylorza 0:d85c449aca6d 235 _smokeIndex = (_smokeIndex + 1) % MAX_SMOKE;
taylorza 0:d85c449aca6d 236 _fuel -= 2;
taylorza 1:1b8125937f28 237
taylorza 1:1b8125937f28 238 Beeper::beep(500, 2);
taylorza 1:1b8125937f28 239 Beeper::beep(1000, 3);
taylorza 1:1b8125937f28 240 Beeper::beep(600, 2);
taylorza 0:d85c449aca6d 241 }
taylorza 0:d85c449aca6d 242 }
taylorza 0:d85c449aca6d 243
taylorza 0:d85c449aca6d 244 private:
taylorza 0:d85c449aca6d 245 Point _startPosition;
taylorza 0:d85c449aca6d 246 bool _dropSmoke;
taylorza 0:d85c449aca6d 247 uint8_t _smokeIndex;
taylorza 0:d85c449aca6d 248 RallyCar **_cars;
taylorza 0:d85c449aca6d 249 Flag *_flags;
taylorza 0:d85c449aca6d 250 Smoke _smoke[MAX_SMOKE];
taylorza 1:1b8125937f28 251 uint16_t _stateCounter;
taylorza 0:d85c449aca6d 252
taylorza 0:d85c449aca6d 253 uint8_t _lives;
taylorza 0:d85c449aca6d 254 uint32_t _score;
taylorza 0:d85c449aca6d 255 uint8_t _fuel;
taylorza 0:d85c449aca6d 256 uint16_t _updateCounter;
taylorza 1:1b8125937f28 257 uint8_t _flagCount;
taylorza 0:d85c449aca6d 258 };
taylorza 0:d85c449aca6d 259 #endif //__PLAYER_H__