![](/media/cache/group/default_image.jpg.50x50_q85.jpg)
All there but errors need fixing
Dependencies: mbed
Overview:
Rookie Tetris is a jigsaw style game based on the classic Tetris.
A block will appear at the top of the screen, you must move it (your options for movement are left, right and down - you cannot move up the board). The block will stop when it if placed either on the floor of the board or on-top of another block.
Your goal is to fill a complete row of the board with the blocks; when you do so the row will delete and the pattern above it will drop down. The game is over when your pattern is tall enough to reach to the top of the board!
Controls:
Use the joystick to move your block! Your block cannot move out of the parameters of the board.
Pot 2 controls the contrast of the screen.
Gamepad2/Gamepad.cpp
- Committer:
- el18rs
- Date:
- 2020-06-03
- Revision:
- 26:00e1a6076038
- Parent:
- 1:35dba0833c7d
File content as of revision 26:00e1a6076038:
#include "Gamepad.h" #include "mbed.h" //////////// constructor/destructor //////////// Gamepad::Gamepad() : _led1(new PwmOut(PTA2)), _led2(new PwmOut(PTC2)), _led3(new PwmOut(PTC3)), _led4(new PwmOut(PTA1)), _led5(new PwmOut(PTC10)), _led6(new PwmOut(PTC11)), _button_A(new InterruptIn(PTC7)), _button_B(new InterruptIn(PTC9)), _button_X(new InterruptIn(PTC5)), _button_Y(new InterruptIn(PTC0)), _button_start(new InterruptIn(PTC8)), _vert(new AnalogIn(PTB11)), _horiz(new AnalogIn(PTB10)), _pot1(new AnalogIn(PTB2)), _pot2(new AnalogIn(PTB3)), dac(new AnalogOut(DAC0_OUT)), ticker(new Ticker), timeout(new Timeout), note_timeout(new Timeout), _x0(0), _y0(0) {} ///////////////// public methods ///////////////// void Gamepad::init() { leds_off(); // read centred values of joystick _x0 = _horiz->read(); _y0 = _vert->read(); // Set all buttons to PullUp _button_A->mode(PullUp); _button_B->mode(PullUp); _button_X->mode(PullUp); _button_Y->mode(PullUp); _button_start->mode(PullUp); // Set up interrupts for the fall of buttons _button_A->fall(callback(this,&Gamepad::A_fall_interrupt)); _button_B->fall(callback(this,&Gamepad::B_fall_interrupt)); _button_X->fall(callback(this,&Gamepad::X_fall_interrupt)); _button_Y->fall(callback(this,&Gamepad::Y_fall_interrupt)); _button_start->fall(callback(this,&Gamepad::start_fall_interrupt)); // initalise button flags reset_buttons(); // number of samples _n = 16; _sample_array = new float[_n]; // create sample array for one period between 0.0 and 1.0 for (int i = 0; i < _n ; i++) { _sample_array[i] = 0.5f + 0.5f*sin(i*2*PI/_n); //printf("y[%i] = %f\n",i,_sample_array[i]); } } void Gamepad::leds_off() { leds(0.0); } void Gamepad::leds_on() { leds(1.0); } void Gamepad::leds(float val) const { if (val < 0.0f) { val = 0.0f; } if (val > 1.0f) { val = 1.0f; } // leds are active-low, so subtract from 1.0 // 0.0 corresponds to fully-off, 1.0 to fully-on val = 1.0f - val; _led1->write(val); _led2->write(val); _led3->write(val); _led4->write(val); _led5->write(val); _led6->write(val); } void Gamepad::led(int n,float val) const { // ensure they are within valid range if (val < 0.0f) { val = 0.0f; } if (val > 1.0f) { val = 1.0f; } switch (n) { // check for valid LED number and set value case 1: _led1->write(1.0f-val); // active-low so subtract from 1 break; case 2: _led2->write(1.0f-val); // active-low so subtract from 1 break; case 3: _led3->write(1.0f-val); // active-low so subtract from 1 break; case 4: _led4->write(1.0f-val); // active-low so subtract from 1 break; case 5: _led5->write(1.0f-val); // active-low so subtract from 1 break; case 6: _led6->write(1.0f-val); // active-low so subtract from 1 break; } } float Gamepad::read_pot1() const { return _pot1->read(); } float Gamepad::read_pot2() const { return _pot2->read(); } // this method gets the magnitude of the joystick movement float Gamepad::get_mag() { Polar p = get_polar(); return p.mag; } // this method gets the angle of joystick movement (0 to 360, 0 North) float Gamepad::get_angle() { Polar p = get_polar(); return p.angle; } Direction Gamepad::get_direction() { float angle = get_angle(); // 0 to 360, -1 for centred Direction d; // partition 360 into segments and check which segment the angle is in if (angle < 0.0f) { d = CENTRE; // check for -1.0 angle } else if (angle < 22.5f) { // then keep going in 45 degree increments d = N; } else if (angle < 67.5f) { d = NE; } else if (angle < 112.5f) { d = E; } else if (angle < 157.5f) { d = SE; } else if (angle < 202.5f) { d = S; } else if (angle < 247.5f) { d = SW; } else if (angle < 292.5f) { d = W; } else if (angle < 337.5f) { d = NW; } else { d = N; } return d; } void Gamepad::reset_buttons() { A_fall = B_fall = X_fall = Y_fall = start_fall = false; } bool Gamepad::A_pressed() { if (A_fall) { A_fall = false; return true; } else { return false; } } bool Gamepad::B_pressed() { if (B_fall) { B_fall = false; return true; } else { return false; } } bool Gamepad::X_pressed() { if (X_fall) { X_fall = false; return true; } else { return false; } } bool Gamepad::Y_pressed() { if (Y_fall) { Y_fall = false; return true; } else { return false; } } bool Gamepad::start_pressed() { if (start_fall) { start_fall = false; return true; } else { return false; } } bool Gamepad::A_held() { // Buttons are configured as PullUp hence the not return !_button_A->read(); } bool Gamepad::B_held() { return !_button_B->read(); } bool Gamepad::X_held() { return !_button_X->read(); } bool Gamepad::Y_held() { return !_button_Y->read(); } bool Gamepad::start_held() { return !_button_start->read(); } ///////////////////// private methods //////////////////////// // get raw joystick coordinate in range -1 to 1 // Direction (x,y) // North (0,1) // East (1,0) // South (0,-1) // West (-1,0) Vector2D Gamepad::get_coord() { // read() returns value in range 0.0 to 1.0 so is scaled and centre value // substracted to get values in the range -1.0 to 1.0 float x = 2.0f*( _horiz->read() - _x0 ); float y = 2.0f*( _vert->read() - _y0 ); // Note: the y value here is inverted to ensure the positive y is up Vector2D coord = {x,-y}; return coord; } // This maps the raw x,y coord onto a circular grid. // See: http://mathproofs.blogspot.co.uk/2005/07/mapping-square-to-circle.html Vector2D Gamepad::get_mapped_coord() { Vector2D coord = get_coord(); // do the transformation float x = coord.x*sqrt(1.0f-pow(coord.y,2.0f)/2.0f); float y = coord.y*sqrt(1.0f-pow(coord.x,2.0f)/2.0f); Vector2D mapped_coord = {x,y}; return mapped_coord; } // this function converts the mapped coordinates into polar form Polar Gamepad::get_polar() { // get the mapped coordinate Vector2D coord = get_mapped_coord(); // at this point, 0 degrees (i.e. x-axis) will be defined to the East. // We want 0 degrees to correspond to North and increase clockwise to 359 // like a compass heading, so we need to swap the axis and invert y float x = coord.y; float y = coord.x; float mag = sqrt(x*x+y*y); // pythagoras float angle = RAD2DEG*atan2(y,x); // angle will be in range -180 to 180, so add 360 to negative angles to // move to 0 to 360 range if (angle < 0.0f) { angle+=360.0f; } // the noise on the ADC causes the values of x and y to fluctuate slightly // around the centred values. This causes the random angle values to get // calculated when the joystick is centred and untouched. This is also when // the magnitude is very small, so we can check for a small magnitude and then // set the angle to -1. This will inform us when the angle is invalid and the // joystick is centred if (mag < TOL) { mag = 0.0f; angle = -1.0f; } Polar p = {mag,angle}; return p; } // ISRs for buttons void Gamepad::A_fall_interrupt() { A_fall = true; } void Gamepad::B_fall_interrupt() { B_fall = true; } void Gamepad::X_fall_interrupt() { X_fall = true; } void Gamepad::Y_fall_interrupt() { Y_fall = true; } void Gamepad::start_fall_interrupt() { start_fall = true; } void Gamepad::set_bpm(float bpm) { _bpm = bpm; } void Gamepad::tone(float frequency,float duration) { // calculate time step between samples float dt = 1.0f/(frequency*_n); // start from beginning of LUT _sample = 0; // setup ticker and timeout to stop ticker // the ticker repeats every dt to plat each sample in turn ticker->attach(callback(this, &Gamepad::ticker_isr), dt); // the timeout stops the ticker after the required duration timeout->attach(callback(this, &Gamepad::timeout_isr), duration ); } void Gamepad::play_melody(int length,const int *notes,const int *durations,float bpm,bool repeat) { // copy arguments to member variables _bpm = bpm; _notes = notes; // pointer for array _durations = durations; // pointer for array _melody_length = length; _repeat = repeat; _note = 0; // start from first note play_next_note(); // play the next note in the melody } void Gamepad::write_dac(float val) { if (val < 0.0f) { val = 0.0f; } else if (val > 1.0f) { val = 1.0f; } dac->write(val); } void Gamepad::play_next_note() { // _note is the note index to play // calculate the duration and frequency of the note float duration = 60.0f/(_bpm*_durations[_note]); float frequency = float(_notes[_note]); //printf("[%i] f = %f d = %f\n",_note,frequency,duration); // check if the note is not a space and if not then play the note if (frequency > 0) { tone(frequency,duration); } // the timeout goes to the next note in the melody // double the duration to leave a bit of a gap in between notes to be better // able to distinguish them note_timeout->attach(callback(this, &Gamepad::note_timeout_isr), duration*2.0f ); } // called when the next note needs playing void Gamepad::note_timeout_isr() { _note++; // go onto next note // if in repeat mode then reset the note counter when get to end of melody if (_repeat && _note == _melody_length) { _note=0; } // check if note is within the melody if (_note < _melody_length) { play_next_note(); } } void Gamepad::ticker_isr() { dac->write(_sample_array[_sample%_n]); // use modulo to get index to play _sample++; // increment the sample ready for next time } void Gamepad::timeout_isr() { // stops the ticker to end the note ticker->detach(); }