Helios Lyons 201239214

Dependencies:   mbed

Brief

My aim for this project was to create a FRDM K64F adapted version of the classic Space Invaders by Tomohiro Nishikado. The game itself has a number of clear features to implement;

  • Left to right movement for the player 'canon'
  • A fixed amount of player lives
  • Firing mechanics for both canon and invaders (hence collision systems)
  • Random firing from remaining invaders
  • Wave based combat

My own addition to these established ideas was Boss waves, featuring a single, larger sprite which fires at a faster interval than previous waves. The addition of a movement system using a basic for loop, as opposed to a velocity based system, will enhance the nostalgic feel of the game.

https://os.mbed.com/media/uploads/helioslyons/screenshot_2020-05-27_at_06.12.00.png

Gameplay

Movement is controlled with the joystick, moving the canon left or right. Fire by pressing A. Invaders spawn at set positions, but randomly fire at a set interval, which is higher for boss waves. Time is taken during each wave, and displayed at wave intervals, and if the play wins.

Controls are shown on the Gamepad below: (attribution: Craig A. Evans, ELEC2645 University of Leeds)

https://os.mbed.com/media/uploads/helioslyons/screenshot_2020-05-27_at_06.20.18.png

Committer:
helioslyons
Date:
Wed May 27 15:40:47 2020 +0000
Revision:
13:1472c1637bfc
Parent:
1:a3f43007030e
Final Submission. I have read and agreed with Statement of Academic Integrity.

Who changed what in which revision?

UserRevisionLine numberNew contents of line
helioslyons 1:a3f43007030e 1 #include "Gamepad.h"
helioslyons 1:a3f43007030e 2
helioslyons 1:a3f43007030e 3 #include "mbed.h"
helioslyons 1:a3f43007030e 4
helioslyons 1:a3f43007030e 5 //////////// constructor/destructor ////////////
helioslyons 1:a3f43007030e 6 Gamepad::Gamepad()
helioslyons 1:a3f43007030e 7 :
helioslyons 1:a3f43007030e 8 _led1(new PwmOut(PTA2)),
helioslyons 1:a3f43007030e 9 _led2(new PwmOut(PTC2)),
helioslyons 1:a3f43007030e 10 _led3(new PwmOut(PTC3)),
helioslyons 1:a3f43007030e 11 _led4(new PwmOut(PTA1)),
helioslyons 1:a3f43007030e 12 _led5(new PwmOut(PTC10)),
helioslyons 1:a3f43007030e 13 _led6(new PwmOut(PTC11)),
helioslyons 1:a3f43007030e 14
helioslyons 1:a3f43007030e 15 _button_A(new InterruptIn(PTC7)),
helioslyons 1:a3f43007030e 16 _button_B(new InterruptIn(PTC9)),
helioslyons 1:a3f43007030e 17 _button_X(new InterruptIn(PTC5)),
helioslyons 1:a3f43007030e 18 _button_Y(new InterruptIn(PTC0)),
helioslyons 1:a3f43007030e 19 _button_start(new InterruptIn(PTC8)),
helioslyons 1:a3f43007030e 20
helioslyons 1:a3f43007030e 21 _vert(new AnalogIn(PTB11)),
helioslyons 1:a3f43007030e 22 _horiz(new AnalogIn(PTB10)),
helioslyons 1:a3f43007030e 23
helioslyons 1:a3f43007030e 24 _pot1(new AnalogIn(PTB2)),
helioslyons 1:a3f43007030e 25 _pot2(new AnalogIn(PTB3)),
helioslyons 1:a3f43007030e 26
helioslyons 1:a3f43007030e 27 dac(new AnalogOut(DAC0_OUT)),
helioslyons 1:a3f43007030e 28 ticker(new Ticker),
helioslyons 1:a3f43007030e 29 timeout(new Timeout),
helioslyons 1:a3f43007030e 30 note_timeout(new Timeout),
helioslyons 1:a3f43007030e 31
helioslyons 1:a3f43007030e 32 _x0(0),
helioslyons 1:a3f43007030e 33 _y0(0)
helioslyons 1:a3f43007030e 34 {}
helioslyons 1:a3f43007030e 35
helioslyons 1:a3f43007030e 36
helioslyons 1:a3f43007030e 37 ///////////////// public methods /////////////////
helioslyons 1:a3f43007030e 38
helioslyons 1:a3f43007030e 39 void Gamepad::init()
helioslyons 1:a3f43007030e 40 {
helioslyons 1:a3f43007030e 41 leds_off();
helioslyons 1:a3f43007030e 42
helioslyons 1:a3f43007030e 43 // read centred values of joystick
helioslyons 1:a3f43007030e 44 _x0 = _horiz->read();
helioslyons 1:a3f43007030e 45 _y0 = _vert->read();
helioslyons 1:a3f43007030e 46
helioslyons 1:a3f43007030e 47 // Set all buttons to PullUp
helioslyons 1:a3f43007030e 48 _button_A->mode(PullUp);
helioslyons 1:a3f43007030e 49 _button_B->mode(PullUp);
helioslyons 1:a3f43007030e 50 _button_X->mode(PullUp);
helioslyons 1:a3f43007030e 51 _button_Y->mode(PullUp);
helioslyons 1:a3f43007030e 52 _button_start->mode(PullUp);
helioslyons 1:a3f43007030e 53
helioslyons 1:a3f43007030e 54 // Set up interrupts for the fall of buttons
helioslyons 1:a3f43007030e 55 _button_A->fall(callback(this,&Gamepad::A_fall_interrupt));
helioslyons 1:a3f43007030e 56 _button_B->fall(callback(this,&Gamepad::B_fall_interrupt));
helioslyons 1:a3f43007030e 57 _button_X->fall(callback(this,&Gamepad::X_fall_interrupt));
helioslyons 1:a3f43007030e 58 _button_Y->fall(callback(this,&Gamepad::Y_fall_interrupt));
helioslyons 1:a3f43007030e 59 _button_start->fall(callback(this,&Gamepad::start_fall_interrupt));
helioslyons 1:a3f43007030e 60
helioslyons 1:a3f43007030e 61 // initalise button flags
helioslyons 1:a3f43007030e 62 reset_buttons();
helioslyons 1:a3f43007030e 63
helioslyons 1:a3f43007030e 64 // number of samples
helioslyons 1:a3f43007030e 65 _n = 16;
helioslyons 1:a3f43007030e 66 _sample_array = new float[_n];
helioslyons 1:a3f43007030e 67
helioslyons 1:a3f43007030e 68 // create sample array for one period between 0.0 and 1.0
helioslyons 1:a3f43007030e 69 for (int i = 0; i < _n ; i++) {
helioslyons 1:a3f43007030e 70 _sample_array[i] = 0.5f + 0.5f*sin(i*2*PI/_n);
helioslyons 1:a3f43007030e 71 //printf("y[%i] = %f\n",i,_sample_array[i]);
helioslyons 1:a3f43007030e 72 }
helioslyons 1:a3f43007030e 73
helioslyons 1:a3f43007030e 74 }
helioslyons 1:a3f43007030e 75
helioslyons 1:a3f43007030e 76 void Gamepad::leds_off()
helioslyons 1:a3f43007030e 77 {
helioslyons 1:a3f43007030e 78 leds(0.0);
helioslyons 1:a3f43007030e 79 }
helioslyons 1:a3f43007030e 80
helioslyons 1:a3f43007030e 81 void Gamepad::leds_on()
helioslyons 1:a3f43007030e 82 {
helioslyons 1:a3f43007030e 83 leds(1.0);
helioslyons 1:a3f43007030e 84 }
helioslyons 1:a3f43007030e 85
helioslyons 1:a3f43007030e 86 void Gamepad::leds(float val) const
helioslyons 1:a3f43007030e 87 {
helioslyons 1:a3f43007030e 88 if (val < 0.0f) {
helioslyons 1:a3f43007030e 89 val = 0.0f;
helioslyons 1:a3f43007030e 90 }
helioslyons 1:a3f43007030e 91 if (val > 1.0f) {
helioslyons 1:a3f43007030e 92 val = 1.0f;
helioslyons 1:a3f43007030e 93 }
helioslyons 1:a3f43007030e 94
helioslyons 1:a3f43007030e 95 // leds are active-low, so subtract from 1.0
helioslyons 1:a3f43007030e 96 // 0.0 corresponds to fully-off, 1.0 to fully-on
helioslyons 1:a3f43007030e 97 val = 1.0f - val;
helioslyons 1:a3f43007030e 98
helioslyons 1:a3f43007030e 99 _led1->write(val);
helioslyons 1:a3f43007030e 100 _led2->write(val);
helioslyons 1:a3f43007030e 101 _led3->write(val);
helioslyons 1:a3f43007030e 102 _led4->write(val);
helioslyons 1:a3f43007030e 103 _led5->write(val);
helioslyons 1:a3f43007030e 104 _led6->write(val);
helioslyons 1:a3f43007030e 105 }
helioslyons 1:a3f43007030e 106
helioslyons 1:a3f43007030e 107 void Gamepad::led(int n,float val) const
helioslyons 1:a3f43007030e 108 {
helioslyons 1:a3f43007030e 109 // ensure they are within valid range
helioslyons 1:a3f43007030e 110 if (val < 0.0f) {
helioslyons 1:a3f43007030e 111 val = 0.0f;
helioslyons 1:a3f43007030e 112 }
helioslyons 1:a3f43007030e 113 if (val > 1.0f) {
helioslyons 1:a3f43007030e 114 val = 1.0f;
helioslyons 1:a3f43007030e 115 }
helioslyons 1:a3f43007030e 116
helioslyons 1:a3f43007030e 117 switch (n) {
helioslyons 1:a3f43007030e 118
helioslyons 1:a3f43007030e 119 // check for valid LED number and set value
helioslyons 1:a3f43007030e 120
helioslyons 1:a3f43007030e 121 case 1:
helioslyons 1:a3f43007030e 122 _led1->write(1.0f-val); // active-low so subtract from 1
helioslyons 1:a3f43007030e 123 break;
helioslyons 1:a3f43007030e 124 case 2:
helioslyons 1:a3f43007030e 125 _led2->write(1.0f-val); // active-low so subtract from 1
helioslyons 1:a3f43007030e 126 break;
helioslyons 1:a3f43007030e 127 case 3:
helioslyons 1:a3f43007030e 128 _led3->write(1.0f-val); // active-low so subtract from 1
helioslyons 1:a3f43007030e 129 break;
helioslyons 1:a3f43007030e 130 case 4:
helioslyons 1:a3f43007030e 131 _led4->write(1.0f-val); // active-low so subtract from 1
helioslyons 1:a3f43007030e 132 break;
helioslyons 1:a3f43007030e 133 case 5:
helioslyons 1:a3f43007030e 134 _led5->write(1.0f-val); // active-low so subtract from 1
helioslyons 1:a3f43007030e 135 break;
helioslyons 1:a3f43007030e 136 case 6:
helioslyons 1:a3f43007030e 137 _led6->write(1.0f-val); // active-low so subtract from 1
helioslyons 1:a3f43007030e 138 break;
helioslyons 1:a3f43007030e 139
helioslyons 1:a3f43007030e 140 }
helioslyons 1:a3f43007030e 141 }
helioslyons 1:a3f43007030e 142
helioslyons 1:a3f43007030e 143 float Gamepad::read_pot1() const
helioslyons 1:a3f43007030e 144 {
helioslyons 1:a3f43007030e 145 return _pot1->read();
helioslyons 1:a3f43007030e 146 }
helioslyons 1:a3f43007030e 147
helioslyons 1:a3f43007030e 148 float Gamepad::read_pot2() const
helioslyons 1:a3f43007030e 149 {
helioslyons 1:a3f43007030e 150 return _pot2->read();
helioslyons 1:a3f43007030e 151 }
helioslyons 1:a3f43007030e 152
helioslyons 1:a3f43007030e 153
helioslyons 1:a3f43007030e 154 // this method gets the magnitude of the joystick movement
helioslyons 1:a3f43007030e 155 float Gamepad::get_mag()
helioslyons 1:a3f43007030e 156 {
helioslyons 1:a3f43007030e 157 Polar p = get_polar();
helioslyons 1:a3f43007030e 158 return p.mag;
helioslyons 1:a3f43007030e 159 }
helioslyons 1:a3f43007030e 160
helioslyons 1:a3f43007030e 161 // this method gets the angle of joystick movement (0 to 360, 0 North)
helioslyons 1:a3f43007030e 162 float Gamepad::get_angle()
helioslyons 1:a3f43007030e 163 {
helioslyons 1:a3f43007030e 164 Polar p = get_polar();
helioslyons 1:a3f43007030e 165 return p.angle;
helioslyons 1:a3f43007030e 166 }
helioslyons 1:a3f43007030e 167
helioslyons 1:a3f43007030e 168 Direction Gamepad::get_direction()
helioslyons 1:a3f43007030e 169 {
helioslyons 1:a3f43007030e 170 float angle = get_angle(); // 0 to 360, -1 for centred
helioslyons 1:a3f43007030e 171
helioslyons 1:a3f43007030e 172 Direction d;
helioslyons 1:a3f43007030e 173 // partition 360 into segments and check which segment the angle is in
helioslyons 1:a3f43007030e 174 if (angle < 0.0f) {
helioslyons 1:a3f43007030e 175 d = CENTRE; // check for -1.0 angle
helioslyons 1:a3f43007030e 176 } else if (angle < 22.5f) { // then keep going in 45 degree increments
helioslyons 1:a3f43007030e 177 d = N;
helioslyons 1:a3f43007030e 178 } else if (angle < 67.5f) {
helioslyons 1:a3f43007030e 179 d = NE;
helioslyons 1:a3f43007030e 180 } else if (angle < 112.5f) {
helioslyons 1:a3f43007030e 181 d = E;
helioslyons 1:a3f43007030e 182 } else if (angle < 157.5f) {
helioslyons 1:a3f43007030e 183 d = SE;
helioslyons 1:a3f43007030e 184 } else if (angle < 202.5f) {
helioslyons 1:a3f43007030e 185 d = S;
helioslyons 1:a3f43007030e 186 } else if (angle < 247.5f) {
helioslyons 1:a3f43007030e 187 d = SW;
helioslyons 1:a3f43007030e 188 } else if (angle < 292.5f) {
helioslyons 1:a3f43007030e 189 d = W;
helioslyons 1:a3f43007030e 190 } else if (angle < 337.5f) {
helioslyons 1:a3f43007030e 191 d = NW;
helioslyons 1:a3f43007030e 192 } else {
helioslyons 1:a3f43007030e 193 d = N;
helioslyons 1:a3f43007030e 194 }
helioslyons 1:a3f43007030e 195
helioslyons 1:a3f43007030e 196 return d;
helioslyons 1:a3f43007030e 197 }
helioslyons 1:a3f43007030e 198
helioslyons 1:a3f43007030e 199 void Gamepad::reset_buttons()
helioslyons 1:a3f43007030e 200 {
helioslyons 1:a3f43007030e 201 A_fall = B_fall = X_fall = Y_fall = start_fall = false;
helioslyons 1:a3f43007030e 202 }
helioslyons 1:a3f43007030e 203
helioslyons 1:a3f43007030e 204 bool Gamepad::A_pressed()
helioslyons 1:a3f43007030e 205 {
helioslyons 1:a3f43007030e 206 if (A_fall) {
helioslyons 1:a3f43007030e 207 A_fall = false;
helioslyons 1:a3f43007030e 208 return true;
helioslyons 1:a3f43007030e 209 } else {
helioslyons 1:a3f43007030e 210 return false;
helioslyons 1:a3f43007030e 211 }
helioslyons 1:a3f43007030e 212 }
helioslyons 1:a3f43007030e 213
helioslyons 1:a3f43007030e 214 bool Gamepad::B_pressed()
helioslyons 1:a3f43007030e 215 {
helioslyons 1:a3f43007030e 216 if (B_fall) {
helioslyons 1:a3f43007030e 217 B_fall = false;
helioslyons 1:a3f43007030e 218 return true;
helioslyons 1:a3f43007030e 219 } else {
helioslyons 1:a3f43007030e 220 return false;
helioslyons 1:a3f43007030e 221 }
helioslyons 1:a3f43007030e 222 }
helioslyons 1:a3f43007030e 223
helioslyons 1:a3f43007030e 224 bool Gamepad::X_pressed()
helioslyons 1:a3f43007030e 225 {
helioslyons 1:a3f43007030e 226 if (X_fall) {
helioslyons 1:a3f43007030e 227 X_fall = false;
helioslyons 1:a3f43007030e 228 return true;
helioslyons 1:a3f43007030e 229 } else {
helioslyons 1:a3f43007030e 230 return false;
helioslyons 1:a3f43007030e 231 }
helioslyons 1:a3f43007030e 232 }
helioslyons 1:a3f43007030e 233
helioslyons 1:a3f43007030e 234 bool Gamepad::Y_pressed()
helioslyons 1:a3f43007030e 235 {
helioslyons 1:a3f43007030e 236 if (Y_fall) {
helioslyons 1:a3f43007030e 237 Y_fall = false;
helioslyons 1:a3f43007030e 238 return true;
helioslyons 1:a3f43007030e 239 } else {
helioslyons 1:a3f43007030e 240 return false;
helioslyons 1:a3f43007030e 241 }
helioslyons 1:a3f43007030e 242 }
helioslyons 1:a3f43007030e 243
helioslyons 1:a3f43007030e 244 bool Gamepad::start_pressed()
helioslyons 1:a3f43007030e 245 {
helioslyons 1:a3f43007030e 246 if (start_fall) {
helioslyons 1:a3f43007030e 247 start_fall = false;
helioslyons 1:a3f43007030e 248 return true;
helioslyons 1:a3f43007030e 249 } else {
helioslyons 1:a3f43007030e 250 return false;
helioslyons 1:a3f43007030e 251 }
helioslyons 1:a3f43007030e 252 }
helioslyons 1:a3f43007030e 253
helioslyons 1:a3f43007030e 254 bool Gamepad::A_held()
helioslyons 1:a3f43007030e 255 {
helioslyons 1:a3f43007030e 256 // Buttons are configured as PullUp hence the not
helioslyons 1:a3f43007030e 257 return !_button_A->read();
helioslyons 1:a3f43007030e 258 }
helioslyons 1:a3f43007030e 259
helioslyons 1:a3f43007030e 260 bool Gamepad::B_held()
helioslyons 1:a3f43007030e 261 {
helioslyons 1:a3f43007030e 262 return !_button_B->read();
helioslyons 1:a3f43007030e 263 }
helioslyons 1:a3f43007030e 264
helioslyons 1:a3f43007030e 265 bool Gamepad::X_held()
helioslyons 1:a3f43007030e 266 {
helioslyons 1:a3f43007030e 267 return !_button_X->read();
helioslyons 1:a3f43007030e 268 }
helioslyons 1:a3f43007030e 269
helioslyons 1:a3f43007030e 270 bool Gamepad::Y_held()
helioslyons 1:a3f43007030e 271 {
helioslyons 1:a3f43007030e 272 return !_button_Y->read();
helioslyons 1:a3f43007030e 273 }
helioslyons 1:a3f43007030e 274
helioslyons 1:a3f43007030e 275 bool Gamepad::start_held()
helioslyons 1:a3f43007030e 276 {
helioslyons 1:a3f43007030e 277 return !_button_start->read();
helioslyons 1:a3f43007030e 278 }
helioslyons 1:a3f43007030e 279
helioslyons 1:a3f43007030e 280 ///////////////////// private methods ////////////////////////
helioslyons 1:a3f43007030e 281
helioslyons 1:a3f43007030e 282 // get raw joystick coordinate in range -1 to 1
helioslyons 1:a3f43007030e 283 // Direction (x,y)
helioslyons 1:a3f43007030e 284 // North (0,1)
helioslyons 1:a3f43007030e 285 // East (1,0)
helioslyons 1:a3f43007030e 286 // South (0,-1)
helioslyons 1:a3f43007030e 287 // West (-1,0)
helioslyons 1:a3f43007030e 288 Vector2D Gamepad::get_coord()
helioslyons 1:a3f43007030e 289 {
helioslyons 1:a3f43007030e 290 // read() returns value in range 0.0 to 1.0 so is scaled and centre value
helioslyons 1:a3f43007030e 291 // substracted to get values in the range -1.0 to 1.0
helioslyons 1:a3f43007030e 292 float x = 2.0f*( _horiz->read() - _x0 );
helioslyons 1:a3f43007030e 293 float y = 2.0f*( _vert->read() - _y0 );
helioslyons 1:a3f43007030e 294
helioslyons 1:a3f43007030e 295 // Note: the y value here is inverted to ensure the positive y is up
helioslyons 1:a3f43007030e 296
helioslyons 1:a3f43007030e 297 Vector2D coord = {x,-y};
helioslyons 1:a3f43007030e 298 return coord;
helioslyons 1:a3f43007030e 299 }
helioslyons 1:a3f43007030e 300
helioslyons 1:a3f43007030e 301 // This maps the raw x,y coord onto a circular grid.
helioslyons 1:a3f43007030e 302 // See: http://mathproofs.blogspot.co.uk/2005/07/mapping-square-to-circle.html
helioslyons 1:a3f43007030e 303 Vector2D Gamepad::get_mapped_coord()
helioslyons 1:a3f43007030e 304 {
helioslyons 1:a3f43007030e 305 Vector2D coord = get_coord();
helioslyons 1:a3f43007030e 306
helioslyons 1:a3f43007030e 307 // do the transformation
helioslyons 1:a3f43007030e 308 float x = coord.x*sqrt(1.0f-pow(coord.y,2.0f)/2.0f);
helioslyons 1:a3f43007030e 309 float y = coord.y*sqrt(1.0f-pow(coord.x,2.0f)/2.0f);
helioslyons 1:a3f43007030e 310
helioslyons 1:a3f43007030e 311 Vector2D mapped_coord = {x,y};
helioslyons 1:a3f43007030e 312 return mapped_coord;
helioslyons 1:a3f43007030e 313 }
helioslyons 1:a3f43007030e 314
helioslyons 1:a3f43007030e 315 // this function converts the mapped coordinates into polar form
helioslyons 1:a3f43007030e 316 Polar Gamepad::get_polar()
helioslyons 1:a3f43007030e 317 {
helioslyons 1:a3f43007030e 318 // get the mapped coordinate
helioslyons 1:a3f43007030e 319 Vector2D coord = get_mapped_coord();
helioslyons 1:a3f43007030e 320
helioslyons 1:a3f43007030e 321 // at this point, 0 degrees (i.e. x-axis) will be defined to the East.
helioslyons 1:a3f43007030e 322 // We want 0 degrees to correspond to North and increase clockwise to 359
helioslyons 1:a3f43007030e 323 // like a compass heading, so we need to swap the axis and invert y
helioslyons 1:a3f43007030e 324 float x = coord.y;
helioslyons 1:a3f43007030e 325 float y = coord.x;
helioslyons 1:a3f43007030e 326
helioslyons 1:a3f43007030e 327 float mag = sqrt(x*x+y*y); // pythagoras
helioslyons 1:a3f43007030e 328 float angle = RAD2DEG*atan2(y,x);
helioslyons 1:a3f43007030e 329 // angle will be in range -180 to 180, so add 360 to negative angles to
helioslyons 1:a3f43007030e 330 // move to 0 to 360 range
helioslyons 1:a3f43007030e 331 if (angle < 0.0f) {
helioslyons 1:a3f43007030e 332 angle+=360.0f;
helioslyons 1:a3f43007030e 333 }
helioslyons 1:a3f43007030e 334
helioslyons 1:a3f43007030e 335 // the noise on the ADC causes the values of x and y to fluctuate slightly
helioslyons 1:a3f43007030e 336 // around the centred values. This causes the random angle values to get
helioslyons 1:a3f43007030e 337 // calculated when the joystick is centred and untouched. This is also when
helioslyons 1:a3f43007030e 338 // the magnitude is very small, so we can check for a small magnitude and then
helioslyons 1:a3f43007030e 339 // set the angle to -1. This will inform us when the angle is invalid and the
helioslyons 1:a3f43007030e 340 // joystick is centred
helioslyons 1:a3f43007030e 341
helioslyons 1:a3f43007030e 342 if (mag < TOL) {
helioslyons 1:a3f43007030e 343 mag = 0.0f;
helioslyons 1:a3f43007030e 344 angle = -1.0f;
helioslyons 1:a3f43007030e 345 }
helioslyons 1:a3f43007030e 346
helioslyons 1:a3f43007030e 347 Polar p = {mag,angle};
helioslyons 1:a3f43007030e 348 return p;
helioslyons 1:a3f43007030e 349 }
helioslyons 1:a3f43007030e 350
helioslyons 1:a3f43007030e 351 // ISRs for buttons
helioslyons 1:a3f43007030e 352 void Gamepad::A_fall_interrupt()
helioslyons 1:a3f43007030e 353 {
helioslyons 1:a3f43007030e 354 A_fall = true;
helioslyons 1:a3f43007030e 355 }
helioslyons 1:a3f43007030e 356 void Gamepad::B_fall_interrupt()
helioslyons 1:a3f43007030e 357 {
helioslyons 1:a3f43007030e 358 B_fall = true;
helioslyons 1:a3f43007030e 359 }
helioslyons 1:a3f43007030e 360 void Gamepad::X_fall_interrupt()
helioslyons 1:a3f43007030e 361 {
helioslyons 1:a3f43007030e 362 X_fall = true;
helioslyons 1:a3f43007030e 363 }
helioslyons 1:a3f43007030e 364 void Gamepad::Y_fall_interrupt()
helioslyons 1:a3f43007030e 365 {
helioslyons 1:a3f43007030e 366 Y_fall = true;
helioslyons 1:a3f43007030e 367 }
helioslyons 1:a3f43007030e 368 void Gamepad::start_fall_interrupt()
helioslyons 1:a3f43007030e 369 {
helioslyons 1:a3f43007030e 370 start_fall = true;
helioslyons 1:a3f43007030e 371 }
helioslyons 1:a3f43007030e 372
helioslyons 1:a3f43007030e 373 void Gamepad::set_bpm(float bpm)
helioslyons 1:a3f43007030e 374 {
helioslyons 1:a3f43007030e 375 _bpm = bpm;
helioslyons 1:a3f43007030e 376 }
helioslyons 1:a3f43007030e 377
helioslyons 1:a3f43007030e 378 void Gamepad::tone(float frequency,float duration)
helioslyons 1:a3f43007030e 379 {
helioslyons 1:a3f43007030e 380 // calculate time step between samples
helioslyons 1:a3f43007030e 381 float dt = 1.0f/(frequency*_n);
helioslyons 1:a3f43007030e 382 // start from beginning of LUT
helioslyons 1:a3f43007030e 383 _sample = 0;
helioslyons 1:a3f43007030e 384
helioslyons 1:a3f43007030e 385 // setup ticker and timeout to stop ticker
helioslyons 1:a3f43007030e 386
helioslyons 1:a3f43007030e 387 // the ticker repeats every dt to plat each sample in turn
helioslyons 1:a3f43007030e 388 ticker->attach(callback(this, &Gamepad::ticker_isr), dt);
helioslyons 1:a3f43007030e 389 // the timeout stops the ticker after the required duration
helioslyons 1:a3f43007030e 390 timeout->attach(callback(this, &Gamepad::timeout_isr), duration );
helioslyons 1:a3f43007030e 391 }
helioslyons 1:a3f43007030e 392
helioslyons 1:a3f43007030e 393 void Gamepad::play_melody(int length,const int *notes,const int *durations,float bpm,bool repeat)
helioslyons 1:a3f43007030e 394 {
helioslyons 1:a3f43007030e 395 // copy arguments to member variables
helioslyons 1:a3f43007030e 396 _bpm = bpm;
helioslyons 1:a3f43007030e 397 _notes = notes; // pointer for array
helioslyons 1:a3f43007030e 398 _durations = durations; // pointer for array
helioslyons 1:a3f43007030e 399 _melody_length = length;
helioslyons 1:a3f43007030e 400 _repeat = repeat;
helioslyons 1:a3f43007030e 401
helioslyons 1:a3f43007030e 402 _note = 0; // start from first note
helioslyons 1:a3f43007030e 403
helioslyons 1:a3f43007030e 404 play_next_note(); // play the next note in the melody
helioslyons 1:a3f43007030e 405 }
helioslyons 1:a3f43007030e 406
helioslyons 1:a3f43007030e 407 void Gamepad::write_dac(float val)
helioslyons 1:a3f43007030e 408 {
helioslyons 1:a3f43007030e 409 if (val < 0.0f) {
helioslyons 1:a3f43007030e 410 val = 0.0f;
helioslyons 1:a3f43007030e 411 } else if (val > 1.0f) {
helioslyons 1:a3f43007030e 412 val = 1.0f;
helioslyons 1:a3f43007030e 413 }
helioslyons 1:a3f43007030e 414 dac->write(val);
helioslyons 1:a3f43007030e 415 }
helioslyons 1:a3f43007030e 416
helioslyons 1:a3f43007030e 417
helioslyons 1:a3f43007030e 418 void Gamepad::play_next_note()
helioslyons 1:a3f43007030e 419 {
helioslyons 1:a3f43007030e 420 // _note is the note index to play
helioslyons 1:a3f43007030e 421
helioslyons 1:a3f43007030e 422 // calculate the duration and frequency of the note
helioslyons 1:a3f43007030e 423 float duration = 60.0f/(_bpm*_durations[_note]);
helioslyons 1:a3f43007030e 424 float frequency = float(_notes[_note]);
helioslyons 1:a3f43007030e 425 //printf("[%i] f = %f d = %f\n",_note,frequency,duration);
helioslyons 1:a3f43007030e 426
helioslyons 1:a3f43007030e 427 // check if the note is not a space and if not then play the note
helioslyons 1:a3f43007030e 428 if (frequency > 0) {
helioslyons 1:a3f43007030e 429 tone(frequency,duration);
helioslyons 1:a3f43007030e 430 }
helioslyons 1:a3f43007030e 431
helioslyons 1:a3f43007030e 432 // the timeout goes to the next note in the melody
helioslyons 1:a3f43007030e 433 // double the duration to leave a bit of a gap in between notes to be better
helioslyons 1:a3f43007030e 434 // able to distinguish them
helioslyons 1:a3f43007030e 435 note_timeout->attach(callback(this, &Gamepad::note_timeout_isr), duration*2.0f );
helioslyons 1:a3f43007030e 436 }
helioslyons 1:a3f43007030e 437
helioslyons 1:a3f43007030e 438 // called when the next note needs playing
helioslyons 1:a3f43007030e 439 void Gamepad::note_timeout_isr()
helioslyons 1:a3f43007030e 440 {
helioslyons 1:a3f43007030e 441 _note++; // go onto next note
helioslyons 1:a3f43007030e 442
helioslyons 1:a3f43007030e 443 // if in repeat mode then reset the note counter when get to end of melody
helioslyons 1:a3f43007030e 444 if (_repeat && _note == _melody_length) {
helioslyons 1:a3f43007030e 445 _note=0;
helioslyons 1:a3f43007030e 446 }
helioslyons 1:a3f43007030e 447
helioslyons 1:a3f43007030e 448 // check if note is within the melody
helioslyons 1:a3f43007030e 449 if (_note < _melody_length) {
helioslyons 1:a3f43007030e 450 play_next_note();
helioslyons 1:a3f43007030e 451 }
helioslyons 1:a3f43007030e 452 }
helioslyons 1:a3f43007030e 453
helioslyons 1:a3f43007030e 454 void Gamepad::ticker_isr()
helioslyons 1:a3f43007030e 455 {
helioslyons 1:a3f43007030e 456 dac->write(_sample_array[_sample%_n]); // use modulo to get index to play
helioslyons 1:a3f43007030e 457 _sample++; // increment the sample ready for next time
helioslyons 1:a3f43007030e 458 }
helioslyons 1:a3f43007030e 459
helioslyons 1:a3f43007030e 460 void Gamepad::timeout_isr()
helioslyons 1:a3f43007030e 461 {
helioslyons 1:a3f43007030e 462 // stops the ticker to end the note
helioslyons 1:a3f43007030e 463 ticker->detach();
helioslyons 1:a3f43007030e 464 }