ELEC2645 (2015/16) / Mbed 2 deprecated HarryPetrovicPong

Dependencies:   N5110 mbed

Fork of 2645_Physics_Engine_Example by Craig Evans

main.cpp

Committer:
eencae
Date:
2016-03-11
Revision:
0:6a561e8d6713
Child:
1:6632d8423c65

File content as of revision 0:6a561e8d6713:

#include "mbed.h"
#include "N5110.h"

#define BALLRADIUS 2

//          VCC,    SCE,  RST,    D/C,   MOSI,  SCLK,   LED
N5110 lcd (PTE26 , PTA0 , PTC4 , PTD0 , PTD2 , PTD1 , PTC3);
// Can also power (VCC) directly from VOUT (3.3 V) -
// Can give better performance due to current limitation from GPIO pin
Ticker game_timer;

// struct used to store 2D vectors
typedef struct vector_t vector_t;
struct vector_t {
    float x;
    float y;
};

// function prototypes
void init_display();
void init_ball();
void game_timer_isr();
void redraw_screen();
void update_physics_engine();
void check_collisions();

vector_t pos;  // ball position
vector_t vel;  // ball velocity
vector_t acc;  // ball acceleration

float refresh_rate = 10.0;  // how often to update display (Hz)
float g_dt = 1.0F/refresh_rate;  // global to store time step (F makes it a float, gets rid of compiler warning)
volatile int g_timer_flag = 0;

int main()
{
    wait(2.0);  // short delay for power to settle
    init_display(); // first need to initialise display
    init_ball();
    // setup ticker
    game_timer.attach(&game_timer_isr,g_dt);

    redraw_screen();  // draw initial screen

    while(1) {

        if ( g_timer_flag ) {  // ticker interrupt
            g_timer_flag = 0;  // clear flag
            update_physics_engine();
            check_collisions();
            redraw_screen();
        }

        sleep();  // sleep until next interrupt

    }
}

void redraw_screen()
{
    lcd.clear();
    lcd.drawCircle(pos.x,pos.y,BALLRADIUS,1);  // x,y,radius,black fill
    lcd.refresh();  // update display
}

void check_collisions()
{
    // see if ball has hit the floor (subtract the radius since the position is the centre of the ball)
    if ( pos.y >= 47 - BALLRADIUS ) {
        pos.y = 47 - BALLRADIUS;  // need to force this or else ball can end up going 'underground'
        vel.y = -0.89 * vel.y;  // y velocity is reflected and dampened 
        // y accleration is still gravity
    }

    // has ball gone off the right-hand side?
    if ( pos.x >= 83 - BALLRADIUS ) {
        pos.x = 83 - BALLRADIUS;  // need to force this or else ball can end up going off screen
        vel.x = -0.5 * vel.x;  // reflect and damp velocity
        acc.x = -acc.x;  // reflect accleration
    }
    
    // what about the left?
    if ( pos.x <= BALLRADIUS ) {
        pos.x = BALLRADIUS;  // need to force this or else ball can end up going off screen
        vel.x = -0.5 * vel.x;  // reflect and damp velocity
        acc.x = -acc.x;  // reflect accleration
    }

}

void update_physics_engine()
{
    // from Newton's Laws

    acc.x = 0.9F*acc.x;  // reduce a little due to air friction

    // calc new velocity (assume 'unit' time)
    vel.x = vel.x + acc.x; // * g_gt;
    vel.y = vel.y + acc.y; // * g_gt;

    // calc new position (assume 'unit' time)
    pos.x = pos.x + vel.x;// * g_gt;
    pos.y = pos.y + vel.y;// * g_dt;
    
    // should really multiply the above by the time-step,
    // but since the pixel can only be a integer value,
    // it makes the motion a little 'jumpy'.

}

void init_ball()
{
    // initial position (top-left)
    pos.x = BALLRADIUS;
    pos.y = BALLRADIUS;
    // initial velocity - still
    vel.x = 0.0;
    vel.y = 0.0;
    // initial acceleration - gravity and a bit of push to right
    acc.x = 0.5;
    acc.y = 2.0;  // +ve so ball accelerates to bottom of display (top of screen is y=0, bottom is y=47)
    // should be 9.8, but can play with value to get a 'nice' ball movement
}

void game_timer_isr()
{
    g_timer_flag = 1;
}

void init_display()
{
    lcd.init();
    lcd.normalMode();      // normal colour mode
    lcd.setBrightness(0.5); // put LED backlight on 50%
}