Simple 'bouncing ball' example. Demonstrates how to use Newton's Law of Motion to implement gravity simulation.
main.cpp@0:6a561e8d6713, 2016-03-11 (annotated)
- Committer:
- eencae
- Date:
- Fri Mar 11 09:52:11 2016 +0000
- Revision:
- 0:6a561e8d6713
Initial commit.
Who changed what in which revision?
User | Revision | Line number | New contents of line |
---|---|---|---|
eencae | 0:6a561e8d6713 | 1 | #include "mbed.h" |
eencae | 0:6a561e8d6713 | 2 | #include "N5110.h" |
eencae | 0:6a561e8d6713 | 3 | |
eencae | 0:6a561e8d6713 | 4 | #define BALLRADIUS 2 |
eencae | 0:6a561e8d6713 | 5 | |
eencae | 0:6a561e8d6713 | 6 | // VCC, SCE, RST, D/C, MOSI, SCLK, LED |
eencae | 0:6a561e8d6713 | 7 | N5110 lcd (PTE26 , PTA0 , PTC4 , PTD0 , PTD2 , PTD1 , PTC3); |
eencae | 0:6a561e8d6713 | 8 | // Can also power (VCC) directly from VOUT (3.3 V) - |
eencae | 0:6a561e8d6713 | 9 | // Can give better performance due to current limitation from GPIO pin |
eencae | 0:6a561e8d6713 | 10 | Ticker game_timer; |
eencae | 0:6a561e8d6713 | 11 | |
eencae | 0:6a561e8d6713 | 12 | // struct used to store 2D vectors |
eencae | 0:6a561e8d6713 | 13 | typedef struct vector_t vector_t; |
eencae | 0:6a561e8d6713 | 14 | struct vector_t { |
eencae | 0:6a561e8d6713 | 15 | float x; |
eencae | 0:6a561e8d6713 | 16 | float y; |
eencae | 0:6a561e8d6713 | 17 | }; |
eencae | 0:6a561e8d6713 | 18 | |
eencae | 0:6a561e8d6713 | 19 | // function prototypes |
eencae | 0:6a561e8d6713 | 20 | void init_display(); |
eencae | 0:6a561e8d6713 | 21 | void init_ball(); |
eencae | 0:6a561e8d6713 | 22 | void game_timer_isr(); |
eencae | 0:6a561e8d6713 | 23 | void redraw_screen(); |
eencae | 0:6a561e8d6713 | 24 | void update_physics_engine(); |
eencae | 0:6a561e8d6713 | 25 | void check_collisions(); |
eencae | 0:6a561e8d6713 | 26 | |
eencae | 0:6a561e8d6713 | 27 | vector_t pos; // ball position |
eencae | 0:6a561e8d6713 | 28 | vector_t vel; // ball velocity |
eencae | 0:6a561e8d6713 | 29 | vector_t acc; // ball acceleration |
eencae | 0:6a561e8d6713 | 30 | |
eencae | 0:6a561e8d6713 | 31 | float refresh_rate = 10.0; // how often to update display (Hz) |
eencae | 0:6a561e8d6713 | 32 | float g_dt = 1.0F/refresh_rate; // global to store time step (F makes it a float, gets rid of compiler warning) |
eencae | 0:6a561e8d6713 | 33 | volatile int g_timer_flag = 0; |
eencae | 0:6a561e8d6713 | 34 | |
eencae | 0:6a561e8d6713 | 35 | int main() |
eencae | 0:6a561e8d6713 | 36 | { |
eencae | 0:6a561e8d6713 | 37 | wait(2.0); // short delay for power to settle |
eencae | 0:6a561e8d6713 | 38 | init_display(); // first need to initialise display |
eencae | 0:6a561e8d6713 | 39 | init_ball(); |
eencae | 0:6a561e8d6713 | 40 | // setup ticker |
eencae | 0:6a561e8d6713 | 41 | game_timer.attach(&game_timer_isr,g_dt); |
eencae | 0:6a561e8d6713 | 42 | |
eencae | 0:6a561e8d6713 | 43 | redraw_screen(); // draw initial screen |
eencae | 0:6a561e8d6713 | 44 | |
eencae | 0:6a561e8d6713 | 45 | while(1) { |
eencae | 0:6a561e8d6713 | 46 | |
eencae | 0:6a561e8d6713 | 47 | if ( g_timer_flag ) { // ticker interrupt |
eencae | 0:6a561e8d6713 | 48 | g_timer_flag = 0; // clear flag |
eencae | 0:6a561e8d6713 | 49 | update_physics_engine(); |
eencae | 0:6a561e8d6713 | 50 | check_collisions(); |
eencae | 0:6a561e8d6713 | 51 | redraw_screen(); |
eencae | 0:6a561e8d6713 | 52 | } |
eencae | 0:6a561e8d6713 | 53 | |
eencae | 0:6a561e8d6713 | 54 | sleep(); // sleep until next interrupt |
eencae | 0:6a561e8d6713 | 55 | |
eencae | 0:6a561e8d6713 | 56 | } |
eencae | 0:6a561e8d6713 | 57 | } |
eencae | 0:6a561e8d6713 | 58 | |
eencae | 0:6a561e8d6713 | 59 | void redraw_screen() |
eencae | 0:6a561e8d6713 | 60 | { |
eencae | 0:6a561e8d6713 | 61 | lcd.clear(); |
eencae | 0:6a561e8d6713 | 62 | lcd.drawCircle(pos.x,pos.y,BALLRADIUS,1); // x,y,radius,black fill |
eencae | 0:6a561e8d6713 | 63 | lcd.refresh(); // update display |
eencae | 0:6a561e8d6713 | 64 | } |
eencae | 0:6a561e8d6713 | 65 | |
eencae | 0:6a561e8d6713 | 66 | void check_collisions() |
eencae | 0:6a561e8d6713 | 67 | { |
eencae | 0:6a561e8d6713 | 68 | // see if ball has hit the floor (subtract the radius since the position is the centre of the ball) |
eencae | 0:6a561e8d6713 | 69 | if ( pos.y >= 47 - BALLRADIUS ) { |
eencae | 0:6a561e8d6713 | 70 | pos.y = 47 - BALLRADIUS; // need to force this or else ball can end up going 'underground' |
eencae | 0:6a561e8d6713 | 71 | vel.y = -0.89 * vel.y; // y velocity is reflected and dampened |
eencae | 0:6a561e8d6713 | 72 | // y accleration is still gravity |
eencae | 0:6a561e8d6713 | 73 | } |
eencae | 0:6a561e8d6713 | 74 | |
eencae | 0:6a561e8d6713 | 75 | // has ball gone off the right-hand side? |
eencae | 0:6a561e8d6713 | 76 | if ( pos.x >= 83 - BALLRADIUS ) { |
eencae | 0:6a561e8d6713 | 77 | pos.x = 83 - BALLRADIUS; // need to force this or else ball can end up going off screen |
eencae | 0:6a561e8d6713 | 78 | vel.x = -0.5 * vel.x; // reflect and damp velocity |
eencae | 0:6a561e8d6713 | 79 | acc.x = -acc.x; // reflect accleration |
eencae | 0:6a561e8d6713 | 80 | } |
eencae | 0:6a561e8d6713 | 81 | |
eencae | 0:6a561e8d6713 | 82 | // what about the left? |
eencae | 0:6a561e8d6713 | 83 | if ( pos.x <= BALLRADIUS ) { |
eencae | 0:6a561e8d6713 | 84 | pos.x = BALLRADIUS; // need to force this or else ball can end up going off screen |
eencae | 0:6a561e8d6713 | 85 | vel.x = -0.5 * vel.x; // reflect and damp velocity |
eencae | 0:6a561e8d6713 | 86 | acc.x = -acc.x; // reflect accleration |
eencae | 0:6a561e8d6713 | 87 | } |
eencae | 0:6a561e8d6713 | 88 | |
eencae | 0:6a561e8d6713 | 89 | } |
eencae | 0:6a561e8d6713 | 90 | |
eencae | 0:6a561e8d6713 | 91 | void update_physics_engine() |
eencae | 0:6a561e8d6713 | 92 | { |
eencae | 0:6a561e8d6713 | 93 | // from Newton's Laws |
eencae | 0:6a561e8d6713 | 94 | |
eencae | 0:6a561e8d6713 | 95 | acc.x = 0.9F*acc.x; // reduce a little due to air friction |
eencae | 0:6a561e8d6713 | 96 | |
eencae | 0:6a561e8d6713 | 97 | // calc new velocity (assume 'unit' time) |
eencae | 0:6a561e8d6713 | 98 | vel.x = vel.x + acc.x; // * g_gt; |
eencae | 0:6a561e8d6713 | 99 | vel.y = vel.y + acc.y; // * g_gt; |
eencae | 0:6a561e8d6713 | 100 | |
eencae | 0:6a561e8d6713 | 101 | // calc new position (assume 'unit' time) |
eencae | 0:6a561e8d6713 | 102 | pos.x = pos.x + vel.x;// * g_gt; |
eencae | 0:6a561e8d6713 | 103 | pos.y = pos.y + vel.y;// * g_dt; |
eencae | 0:6a561e8d6713 | 104 | |
eencae | 0:6a561e8d6713 | 105 | // should really multiply the above by the time-step, |
eencae | 0:6a561e8d6713 | 106 | // but since the pixel can only be a integer value, |
eencae | 0:6a561e8d6713 | 107 | // it makes the motion a little 'jumpy'. |
eencae | 0:6a561e8d6713 | 108 | |
eencae | 0:6a561e8d6713 | 109 | } |
eencae | 0:6a561e8d6713 | 110 | |
eencae | 0:6a561e8d6713 | 111 | void init_ball() |
eencae | 0:6a561e8d6713 | 112 | { |
eencae | 0:6a561e8d6713 | 113 | // initial position (top-left) |
eencae | 0:6a561e8d6713 | 114 | pos.x = BALLRADIUS; |
eencae | 0:6a561e8d6713 | 115 | pos.y = BALLRADIUS; |
eencae | 0:6a561e8d6713 | 116 | // initial velocity - still |
eencae | 0:6a561e8d6713 | 117 | vel.x = 0.0; |
eencae | 0:6a561e8d6713 | 118 | vel.y = 0.0; |
eencae | 0:6a561e8d6713 | 119 | // initial acceleration - gravity and a bit of push to right |
eencae | 0:6a561e8d6713 | 120 | acc.x = 0.5; |
eencae | 0:6a561e8d6713 | 121 | acc.y = 2.0; // +ve so ball accelerates to bottom of display (top of screen is y=0, bottom is y=47) |
eencae | 0:6a561e8d6713 | 122 | // should be 9.8, but can play with value to get a 'nice' ball movement |
eencae | 0:6a561e8d6713 | 123 | } |
eencae | 0:6a561e8d6713 | 124 | |
eencae | 0:6a561e8d6713 | 125 | void game_timer_isr() |
eencae | 0:6a561e8d6713 | 126 | { |
eencae | 0:6a561e8d6713 | 127 | g_timer_flag = 1; |
eencae | 0:6a561e8d6713 | 128 | } |
eencae | 0:6a561e8d6713 | 129 | |
eencae | 0:6a561e8d6713 | 130 | void init_display() |
eencae | 0:6a561e8d6713 | 131 | { |
eencae | 0:6a561e8d6713 | 132 | lcd.init(); |
eencae | 0:6a561e8d6713 | 133 | lcd.normalMode(); // normal colour mode |
eencae | 0:6a561e8d6713 | 134 | lcd.setBrightness(0.5); // put LED backlight on 50% |
eencae | 0:6a561e8d6713 | 135 | } |