Pong on Nokia Color LCD Display with PS/2 and mBed
Overview
I wrote a little Pong game to run on the Nokia Color LCD display. It's pretty simple, one player and a computer with one ball. You use the UP and DOWN arrow keys on a PS/2 keyboard to control the paddle. There is a scoreboard that shows lives left and current score.
Necessary Items
mBed | |
Nokia Color LCD Display | |
PS/2 Breakout | |
PS/2 Keyboard |
Schematic
Breakout | Library |
---|---|
PS/2 Breakout | PS/2 Class |
Nokia Color LCD Display | NokiaLCD Class |
Commands
Button | Command |
---|---|
S1 | Play/Pause |
S2 | Reset |
Keyboard UP/DOWN | Move Paddle UP/DOWN |
Video
Code
Import programPong
Simple Pong game on NokiaLCD with PS2
Import program
00001 #include "NokiaLCD.h" 00002 00003 class Ball { 00004 /* This class creates a ball object */ 00005 00006 // Attributes 00007 int x,y,width,height,color,xInc,yInc; 00008 00009 public: 00010 // Constructors 00011 Ball(); 00012 Ball(int x, int y, int w, int h, int c, int xi, int yi); 00013 00014 // Member functions 00015 void move(NokiaLCD &lcd); 00016 void draw(NokiaLCD &lcd, bool isBlack) const; 00017 int getX() const; 00018 int getY() const; 00019 bool hitX(); 00020 bool hitY(); 00021 bool hitP1(int _x, int _y, int _height); 00022 bool hitP2(int _x, int _y, int _height); 00023 int size() const; 00024 void reverseX(); 00025 void reverseY(); 00026 };
Import program
00001 #include "mbed.h" 00002 #include "ball.h" 00003 00004 Ball::Ball() { 00005 int x=y=width=height=color=xInc=yInc=0; 00006 } 00007 00008 Ball::Ball(int x, int y, int w, int h, int c, int xi, int yi) 00009 : x(x), y(y), width(w), height(h), color(c), xInc(xi), yInc(yi) {} 00010 00011 00012 /* 00013 * Member Function move: 00014 * Description: Colors in the previous ball black 00015 * and moves ball to new position. 00016 */ 00017 void Ball::move(NokiaLCD &lcd) { 00018 draw(lcd, true); 00019 x += xInc; y += yInc; 00020 } 00021 00022 /* 00023 * Member Function draw: 00024 * Description: Draws object on screen 00025 * if isBlack, color in black. 00026 */ 00027 void Ball::draw(NokiaLCD &lcd, bool isBlack) const { 00028 lcd.fill(x, y, width, height, (isBlack) ? 0x000000 : color); 00029 } 00030 00031 int Ball::size() const { 00032 return width*height; 00033 } 00034 00035 int Ball::getX() const { 00036 return x; 00037 } 00038 00039 int Ball::getY() const { 00040 return y; 00041 } 00042 00043 bool Ball::hitX() { 00044 return (x+width<=width) || (x+width>=132); 00045 } 00046 00047 bool Ball::hitY() { 00048 return (y<=0) || (y+height>=130); 00049 } 00050 00051 /* 00052 * Member Function hitP1: 00053 * Description: Checks to see if there is 00054 * a collision between paddle1 and the ball. 00055 * Has special functionality for changing 00056 * y-incline based on collision point. 00057 */ 00058 bool Ball::hitP1(int _x, int _y, int _height) { 00059 bool hit = ((_x>=x) && (xInc<0)) && 00060 (((_y<=y) && (_y+_height>=y+height)) || 00061 ((_y>=y) && (_y<=y+height)) || 00062 ((_y+_height>=y) && (_y+_height<=y+height)) 00063 ); 00064 if(hit) { 00065 if(_y+_height-y < 4 && yInc>0) yInc = 2; 00066 if(y-_y < 4 && yInc<0) yInc = -2; 00067 else yInc = (yInc>0) ? 1 : -1; 00068 } 00069 return hit; 00070 } 00071 00072 00073 /* 00074 * Member Function hitP2: 00075 * Description: Checks to see if there is 00076 * a collision between paddle2 and the ball. 00077 * Has special functionality for changing 00078 * y-incline based on collision point. 00079 */ 00080 bool Ball::hitP2(int _x, int _y, int _height) { 00081 bool hit = ((_x<=x+width) && (xInc>0)) && 00082 (((_y<=y) && (_y+_height>=y+height)) || 00083 ((_y>=y) && (_y<=y+height)) || 00084 ((_y+_height>=y) && (_y+_height<=y+height)) 00085 ); 00086 if(hit) { 00087 if(_y+_height-y < 4 && yInc>0) yInc = 2; 00088 if(y-_y < 4 && yInc<0) yInc = -2; 00089 else yInc = (yInc>0) ? 1 : -1; 00090 } 00091 return hit; 00092 } 00093 00094 void Ball::reverseX() { 00095 xInc *= -1; 00096 } 00097 00098 void Ball::reverseY() { 00099 yInc *= -1; 00100 }
Import program
00001 #include "NokiaLCD.h" 00002 00003 class Paddle { 00004 /* This class creates a paddle object */ 00005 00006 // Attributes 00007 int x,y,width,height,color,lives,score; 00008 00009 public: 00010 // Constructors 00011 Paddle(); 00012 Paddle(int x, int y, int w, int h, int c, int l, int s); 00013 00014 // Member functions 00015 void move(NokiaLCD &lcd, int increment); 00016 void moveCPU(NokiaLCD &lcd, int _y); 00017 void draw(NokiaLCD &lcd, bool isBlack) const; 00018 bool loseLife(); 00019 void addPoint(); 00020 int size() const; 00021 int getWidth() const; 00022 int getHeight() const; 00023 int getX() const; 00024 int getY() const; 00025 int getLives() const; 00026 int getScore() const; 00027 void setLives(int l); 00028 00029 };
Import program
00001 #include "mbed.h" 00002 #include "paddle.h" 00003 00004 Paddle::Paddle() { 00005 int x=y=width=height=color=score=0; 00006 lives = 3; 00007 } 00008 00009 Paddle::Paddle(int x, int y, int w, int h, int c, int l, int s) 00010 : x(x), y(y), width(w), height(h), color(c), lives(l), score(s) {} 00011 00012 /* 00013 * Member Function move: 00014 * Description: Colors in the previous paddle black 00015 * and moves paddle to new position. 00016 */ 00017 void Paddle::move(NokiaLCD &lcd, int increment) { 00018 draw(lcd, true); 00019 y += increment; 00020 } 00021 00022 00023 /* 00024 * Member Function moveCPU: 00025 * Description: Colors in the previous paddle black 00026 * and moves paddle to new position. 00027 * inc variable allows paddle to only move every 00028 * other function call. 00029 */ 00030 void Paddle::moveCPU(NokiaLCD &lcd, int _y) { 00031 static int inc = 1; 00032 draw(lcd, true); 00033 if(_y>y+height/2 && y+height<130) y += inc; 00034 else if(_y+5<y+height/2 && y>0) y -= inc; 00035 inc = (inc) ? 0 : 1; 00036 } 00037 00038 void Paddle::draw(NokiaLCD &lcd, bool isBlack) const { 00039 lcd.fill(x, y, width, height, (isBlack) ? 0x000000 : color); 00040 } 00041 00042 bool Paddle::loseLife() { 00043 return --lives; 00044 } 00045 00046 void Paddle::addPoint() { 00047 ++score; 00048 } 00049 00050 int Paddle::size() const { 00051 return width*height; 00052 } 00053 00054 int Paddle::getWidth() const { 00055 return width; 00056 } 00057 00058 int Paddle::getHeight() const { 00059 return height; 00060 } 00061 00062 int Paddle::getX() const { 00063 return x; 00064 } 00065 00066 int Paddle::getY() const { 00067 return y; 00068 } 00069 00070 int Paddle::getLives() const { 00071 return lives; 00072 } 00073 00074 int Paddle::getScore() const { 00075 return score; 00076 } 00077 00078 void Paddle::setLives(int l) { 00079 lives = l; 00080 }
Import program
00001 #include "mbed.h" 00002 #include "NokiaLCD.h" 00003 #include "PS2Keyboard.h" 00004 #include "ball.h" 00005 #include "paddle.h" 00006 00007 // State enumerator 00008 typedef enum { 00009 RESET, RUN, PAUSE 00010 } STATES; 00011 00012 NokiaLCD lcd(p5, p7, p8, p9, NokiaLCD::LCD6610); // mosi, sclk, cs, rst, type 00013 00014 PS2Keyboard ps2kb(p12, p11); // CLK, DAT 00015 00016 DigitalIn sw2(p24); 00017 DigitalIn sw1(p25); 00018 00019 PwmOut g(p21); 00020 PwmOut b(p22); 00021 PwmOut r(p23); 00022 00023 // Button enumerator for PS/2 keyboard 00024 enum BUTTONS{ 00025 UP = 0xe75, 00026 DOWN = 0xe72, 00027 }; 00028 00029 /* 00030 * Subroutine drawScreen: 00031 * Description: Draws both paddles 00032 * and the ball. 00033 */ 00034 void drawScreen(Paddle paddle1, Paddle paddle2, Ball theBall, bool isBlack) { 00035 paddle1.draw(lcd, isBlack); 00036 paddle2.draw(lcd ,isBlack); 00037 theBall.draw(lcd ,isBlack); 00038 } 00039 00040 /* 00041 * Subroutine drawScores: 00042 * Description: Draws the scoreboard 00043 */ 00044 void drawScores(Paddle paddle1, Paddle paddle2) { 00045 lcd.locate(7,0); 00046 lcd.putc('0' + paddle1.getScore()); 00047 lcd.locate(9,0); 00048 lcd.putc('0' + paddle2.getScore()); 00049 lcd.fill(66,0,2,130,0xFFFFFF); 00050 lcd.locate(7,15); 00051 lcd.putc('0' + paddle1.getLives()); 00052 lcd.locate(9,15); 00053 lcd.putc('0' + paddle2.getLives()); 00054 } 00055 00056 int main() { 00057 PS2Keyboard::keyboard_event_t evt_kb; // Setup keyboard interrupt 00058 lcd.background(0x000000); 00059 lcd.cls(); 00060 Paddle paddle1, paddle2; 00061 Ball theBall; 00062 int temp, count=0; 00063 drawScreen(paddle1, paddle2, theBall, false); 00064 drawScores(paddle1, paddle2); 00065 STATES state = RESET; // Initial state is RESET 00066 while(1) { 00067 switch(state) { 00068 case RESET: // Reset objects, draw the screen, state = PAUSE 00069 lcd.cls(); 00070 paddle1 = Paddle(1,10,5,25,0xFFFFFF,paddle1.getLives(),paddle1.getScore()); 00071 paddle2 = Paddle(125,3,5,25,0xFFFFFF,paddle2.getLives(),paddle2.getScore()); 00072 theBall = Ball(6,25,5,5,0xFFFF00,1,1); 00073 drawScreen(paddle1, paddle2, theBall, false); 00074 drawScores(paddle1, paddle2); 00075 state = PAUSE; 00076 break; 00077 case PAUSE: // Set RGB LED to Red, wait for switch input 00078 r = 0; 00079 b = g = 1; 00080 if(!sw2) { 00081 while(!sw2); 00082 paddle2.setLives(3); 00083 paddle1.setLives(3); 00084 state = RESET; 00085 break; 00086 } 00087 if(!sw1) { 00088 while(!sw1); 00089 state = RUN; 00090 } 00091 break; 00092 case RUN: // Set RGB LED to Blue and run program 00093 r = g = 1; 00094 b = 0; 00095 if(!sw2) { // Reset if SW2 is pressed 00096 while(!sw2); 00097 paddle2.setLives(3); 00098 paddle1.setLives(3); 00099 state = RESET; 00100 break; 00101 } 00102 if(!sw1) { // Pause if SW1 is pressed 00103 while(!sw1); 00104 state = PAUSE; 00105 break; 00106 } 00107 if (ps2kb.processing(&evt_kb)) { // Executes if a key is pressed 00108 temp = evt_kb.scancode[0]; 00109 for (int i = 1; i < evt_kb.length; i++) { // Parse keyboard input into a key 00110 temp <<= 4; 00111 temp |= evt_kb.scancode[i]; 00112 } 00113 switch(temp) { // Use key enumerator to move paddle1 00114 case UP: 00115 if(paddle1.getY()>2) 00116 paddle1.move(lcd, -2); 00117 break; 00118 case DOWN: 00119 if(paddle1.getY()+paddle1.getHeight()<128) 00120 paddle1.move(lcd, 2); 00121 break; 00122 } 00123 } 00124 if(count%2) // Only let CPU move once every 2 times through the loop 00125 paddle2.moveCPU(lcd, theBall.getY()); 00126 if(++count==5) { // Only move the ball once every 5 times through the loop 00127 count = 0; 00128 if(theBall.hitP1((paddle1.getX()+paddle1.getWidth()), paddle1.getY(), paddle1.getHeight())) 00129 theBall.reverseX(); 00130 if(theBall.hitP2(paddle2.getX(), paddle2.getY(), paddle2.getHeight())) 00131 theBall.reverseX(); 00132 if(theBall.hitX()) { // If the ball hits one of the sides of the screen 00133 if(theBall.getX()<7) { // If the ball hit paddle1's side 00134 if(!paddle1.loseLife()) { // If paddle1 has no more lives 00135 paddle1.setLives(3); 00136 paddle2.setLives(3); 00137 paddle2.addPoint(); 00138 } 00139 } 00140 else if(theBall.getX()>120) { // If the ball hit paddle2's side 00141 if(!paddle2.loseLife()) { // If paddle2 has no more lives 00142 paddle2.setLives(3); 00143 paddle1.setLives(3); 00144 paddle1.addPoint(); 00145 } 00146 } 00147 theBall.reverseX(); 00148 state = RESET; // Reset the objects 00149 } 00150 if(theBall.hitY()) 00151 theBall.reverseY(); 00152 theBall.move(lcd); 00153 } 00154 break; 00155 } 00156 drawScreen(paddle1, paddle2, theBall, false); 00157 drawScores(paddle1, paddle2); 00158 } 00159 }
Please log in to post comments.