=====Hra PINP-PONG===== ====Zadání==== Realizovat hru 2D ping-pong s použitím LED matice LPD6803. Hra bude ovládána tlačítky a bude obsahovat minimálně režim pro dva hráče. Využijte vývojovou desku FRDM-KL25Z. ====Hra PING-PONG==== 2D - pong hra je trochu jako staré hry na staré konzole " Pong ". V normální hře musite umístit své " bat " ve správné svislé poloze zasáhnout míč , ale protože to je jednorozměrný prostor není moc pohybovat se ve druhém rozměru. Místo toho, " koule " (v tomto případě linie) se pohybuje podél LED pás z jednoho hráče na druhý (druhé každé ze 2 hráče umístěných na jedné straně ledstrip). Budete muset trefit ho včas, aby ji vrátí. Pokud stisknete příliš brzy nebo příliš pozdě , ztrácíte jeden "soubor". Pokud jste hit " míč " ve správném časovém budete vrátit míč na druhou stranu. Aby hra byla ještě zajímavější : později narazí na " kouli ", tím rychleji budete vrátit míč do svého soupeře. {{:2015:12.png?400|}} Obr.1 Prvky hry PING-PONG ====Hardware==== 2D -pong hra je založena na Freescale FRDM - KL25Z desky, a na základě LPD6803 pixelstrip LED ovladač. Pixelstrip to byl napsán pro měl 50 bodů (150 LED, každý pixel je 3 LED diody v řadě ). Chcete-li řídit pixelů se používá rozhraní SPI na KL25Z. 2 tlačítka slouží k ovládání pádlo, oni jsou oddělené dvěma 100nF kondenzátory ( jak pro zákmitu a být imunní vůči interferující EM polí). * Nečíslovaný seznamJedním tlačítkem mezi PTD0 a GND (by měla být normálně zavřený, takže pokud jej zasáhl by měla být nulová ohm, pokud by to mělo být propuštěn nekonečno ohm). * ostatní tlačítka mezi PTD5 a GND (stejného příběhu jak je uvedeno výše). * Použijte PTD2 pro data a PTD1 pro hodiny na LED pásu. Použime jednoduchý HCT vyrovnávací paměť v mezi ledstrip a mbed pro přepnutí mezi 3v3 a 5V . LDP6803 má pullups na jeho vstupy , takže CLK a DATA jsou vždy vytáhl na 5V. Mbed pracuje na 3V , takže použít něco do vyrovnávací paměti mezi těmito dvěma. ====Software==== Pro realizaci hry v tomto projektu je použit compiler na webu https://developer.mbed.org/, ve kterém je možné vytvořit libovolný projekt na C++. ====Realizace programu hry pomocí jazyka C++==== #include "mbed.h" #include "MODSERIAL.h" #include "paddle.h" #include "GameButton.h" #define NUMBER_OF_PIXELS 50 #define PADDLE_LENGTH 5 #define START_SPEED 19 #define SPEED_FACTOR 7 #define LEFT false #define RIGHT true void Randomblinks(float seconds, bool colored = false); void PaddleDemo(float seconds, uint8_t red, uint8_t green, uint8_t blue); void WinLoose(float seconds, bool side); void UpdateDemoPaddle(void); void Score(uint8_t left, uint8_t right); void DrawGamePaddle(void); void HandleScore(uint8_t *, uint8_t *, bool, Timer *); void DrawLine(uint8_t start, uint8_t end, uint8_t red, uint8_t green, uint8_t blue); uint16_t totalstrip[NUMBER_OF_PIXELS]; volatile int8_t paddlestart= 0; bool strip_drawable = true; SPI ledstrip(PTD2,NC,PTD1); MODSERIAL pc(PTA2,PTA1); Paddle paddle; class PongGameButton : public GameButton { public: PongGameButton(PinName name, float time); void pushhandlercallback(void); int16_t paddlepos; }; PongGameButton::PongGameButton(PinName name, float time) : GameButton(name, time) { paddlepos = 0; } void PongGameButton::pushhandlercallback(void) { paddlepos = paddle.position; } void UpdateLEDstrip(void) { uint8_t pixelcounter; if(strip_drawable) { /*start by writing 32 zeroes */ ledstrip.write(0); ledstrip.write(0); ledstrip.write(0); ledstrip.write(0); for(pixelcounter = 0 ; pixelcounter < NUMBER_OF_PIXELS; pixelcounter++) { ledstrip.write( uint8_t(totalstrip[pixelcounter]>>8));//uint8_t(temp16));//(totalstrip.ledcounter[pixelcounter].red << 2) | (totalstrip.ledcounter[pixelcounter].high << 7) |(totalstrip.ledcounter[pixelcounter].green & 0x << 2) ); ledstrip.write( uint8_t(totalstrip[pixelcounter]));//(*(uint16_t *)(&totalstrip[pixelcounter]))>>8); } } } void write_led(uint16_t * led, uint8_t red, uint8_t green, uint8_t blue) { *led = (1<<15) | ((green >> 3)<<10) | ((red >>3)<< 5) | (blue >>3); } bool rightpushed = false; int16_t rightpushpos = 0; void right_pushed(void) { rightpushpos = paddle.position; if(paddle.direction == 1) rightpushed = true; } int main() { Ticker updater; //Ticker demopaddlepos; Timer gametimer; PongGameButton buttonleft(PTD0,1); PongGameButton buttonright(PTD5, 1); uint8_t ledcounter; uint8_t left_score = 0, right_score = 0; pc.baud(115200); updater.attach(UpdateLEDstrip, .03); ledstrip.format(8,0); //15 bits, mode '0' ledstrip.frequency(1000000); //1MHz clock for(ledcounter = 0; ledcounter < NUMBER_OF_PIXELS; ledcounter++) {//turn off leds write_led(&totalstrip[ledcounter], 0,0,0); } paddle.setSize(6); paddle.setSpeed(START_SPEED); paddle.setColor(255,0,255); paddle.position = NUMBER_OF_PIXELS/2; gametimer.start(); while(1) { static uint8_t naglevel1 = 0, naglevel2 = 0; //paddle.position = 48; //while(1); strip_drawable = false; DrawGamePaddle(); if(buttonleft.getTimeoutActive()) DrawLine(0,1,0,0,255); if(buttonright.getTimeoutActive()) DrawLine(NUMBER_OF_PIXELS-1, NUMBER_OF_PIXELS,0,0,255); strip_drawable = true; if(buttonleft.pushflag || buttonright.pushflag) { if(paddle.direction == 1) { if(buttonright.pushflag) { //printf("\n\rright pushed"); pc.printf("R\n\r"); buttonright.pushflag = false; if(buttonright.paddlepos >= NUMBER_OF_PIXELS-1 ) //also count when hit at last pixel = NUMBER_OF_PIXELS-1 { paddle.direction = 0; paddle.setSpeed(START_SPEED+(buttonright.paddlepos-(NUMBER_OF_PIXELS-1))*SPEED_FACTOR); paddle.position = NUMBER_OF_PIXELS-2; } //pc.printf("\n\rright pushed. Paddle position: %d, registered: %d, speed: %", paddle.position, buttonright.paddlepos,paddle.getSpeed()); } buttonleft.pushflag = false; } else { if(buttonleft.pushflag) { //printf("\n\rleft pushed"); pc.printf("L\n\r"); buttonleft.pushflag = false; if(buttonleft.paddlepos <= 1 ) { paddle.direction = 1; paddle.setSpeed(START_SPEED+(-buttonleft.paddlepos)*SPEED_FACTOR); paddle.position = 0; } //pc.printf("\n\rleft pushed. Paddle position: %d, registered: %d, speed %d", paddle.position, buttonleft.paddlepos, paddle.getSpeed()); } buttonright.pushflag = false; } } else { if(paddle.position > ( NUMBER_OF_PIXELS + paddle.getSize() ) && (paddle.direction == 1)) { //pc.printf("\n\rleft player score. Paddle position: %d", paddle.position); //left player scores! left_score++; pc.printf("S:%2d:%2d\n\r",left_score,right_score); naglevel1=naglevel2 = 0; HandleScore(&left_score,&right_score,false, &gametimer); buttonright.pushflag = false; buttonleft.pushflag = false; } if(paddle.position < -paddle.getSize() && (paddle.direction == 0)) { //pc.printf("\n\rright player score. Paddle position: %d", paddle.position); //right player scores! right_score++; pc.printf("S:%2d:%2d\n\r",left_score,right_score); naglevel1=naglevel2 = 0; HandleScore(&left_score,&right_score,true, &gametimer); buttonright.pushflag = false; buttonleft.pushflag = false; } } if(gametimer.read()>10 && !naglevel1) { naglevel1 = 1; paddle.setSize(8); //paddle.setSpeed(40); } if(gametimer.read()>15 && !naglevel2) { naglevel2 = 1; paddle.setSize(10); //paddle.setSpeed(70); } wait(0.01); } } void HandleScore(uint8_t *leftscore, uint8_t *rightscore, bool last_won, Timer *gametimer) { WinLoose(1.5, last_won); Score(*leftscore, *rightscore); if(*leftscore + *rightscore == 11) { pc.printf("EOG\n\r"); *leftscore = 0; *rightscore = 0; Randomblinks(5,false); pc.printf("S: 0: 0\n\r"); } (*(mbed::Timer *)gametimer).reset(); paddle.setSize(6); (rand()%20)>10?paddle.direction = 1:paddle.direction = 0; paddle.setSpeed(START_SPEED); paddle.position = NUMBER_OF_PIXELS/2; } void DrawGamePaddle(void) { uint8_t ledcounter; uint8_t colorpos; for(ledcounter = 0; ledcounter< NUMBER_OF_PIXELS; ledcounter++) { if(paddle.direction == 1) { if(ledcounter > paddle.position-paddle.getSize() && ledcounter <= paddle.position) { colorpos = paddle.getSize()-(paddle.position - ledcounter);//paddle.getSize()-(ledcounter-paddle.position); write_led(&totalstrip[ledcounter],paddle.getColor(colorpos,0),paddle.getColor(colorpos,1),paddle.getColor(colorpos,2)); } else write_led(&totalstrip[ledcounter], 0,0,0); } else { if(ledcounter >= paddle.position && ledcounter <= paddle.position+paddle.getSize()) { colorpos = paddle.getSize()-(ledcounter-paddle.position); write_led(&totalstrip[ledcounter],paddle.getColor(colorpos,0),paddle.getColor(colorpos,1),paddle.getColor(colorpos,2)); } else write_led(&totalstrip[ledcounter], 0,0,0); } } } void Score(uint8_t left, uint8_t right) { uint8_t maxscore; int8_t ledcounter; uint8_t scorecounter; typedef struct ledcolor { uint8_t red; uint8_t green; uint8_t blue; }ledcolor_t; ledcolor_t rightled={0,0,0}, leftled={0,0,0}; left>=right?maxscore = left: maxscore = right; for(scorecounter = 0 ; scorecounter <= maxscore ; scorecounter++) { uint8_t templeft,tempright; uint8_t sidecounter; templeft = left>scorecounter?scorecounter:left; tempright = right>scorecounter?scorecounter:right; //pc.printf("scorecounter: %d, maxscore: %d\n\r",scorecounter, maxscore); /*Change color on last score update: green is winning, red is losing, yellow is draw*/ if(scorecounter == maxscore) { leftled.green = leftled.red = leftled.blue = rightled.green = rightled.red = rightled.blue = 0; if(left >= right) { leftled.green = 255; rightled.red = 255; } if(right >= left) { leftled.red = 255; rightled.green = 255; } } else { leftled.green = leftled.red = leftled.blue = rightled.green = rightled.red = rightled.blue = 255; } for(ledcounter = 0; ledcounter < NUMBER_OF_PIXELS; ledcounter++)//blank memory { write_led(&totalstrip[ledcounter], 0, 0 ,0); } for(sidecounter = 0 ; sidecounter < templeft; sidecounter++) { write_led(&totalstrip[sidecounter*2],leftled.red,leftled.green,leftled.blue); } for(sidecounter = 0 ; sidecounter < tempright ; sidecounter++) { write_led(&totalstrip[(NUMBER_OF_PIXELS-1)-(sidecounter*2)],rightled.red,rightled.green,rightled.blue); } wait(0.2); } wait(0.7); } //Only writes pixels that are in 'line'. Does not clear, only overwrites. void DrawLine(uint8_t start, uint8_t end, uint8_t red, uint8_t green, uint8_t blue) { uint8_t ledcounter; if(end >= NUMBER_OF_PIXELS) end = NUMBER_OF_PIXELS; if(start < end) { for(ledcounter = start; ledcounter < end ; ledcounter++) { write_led(&totalstrip[ledcounter], red, green, blue); } } } void WinLoose(float seconds, bool side) { uint8_t ledcounter; Timer timer; timer.start(); while( timer.read() < seconds) { uint8_t redvalue = 255-(255.0*(timer.read()/(seconds/2))); for(ledcounter = 0; ledcounter < NUMBER_OF_PIXELS; ledcounter++) { if(ledcounter < NUMBER_OF_PIXELS / 2) { if(side) write_led(&totalstrip[ledcounter], redvalue,0,0); else write_led(&totalstrip[ledcounter], 0,255,0); } else { if(side) write_led(&totalstrip[ledcounter], 0,255,0); else write_led(&totalstrip[ledcounter], redvalue ,0,0); } } } } void PaddleDemo(float seconds, uint8_t red, uint8_t green, uint8_t blue) { uint8_t ledcounter; Timer timer; timer.start(); while( timer.read() < seconds) { for(ledcounter = 0; ledcounter < NUMBER_OF_PIXELS; ledcounter++) { if((ledcounter >= paddlestart) && ( ledcounter <= paddlestart+PADDLE_LENGTH)) write_led(&totalstrip[ledcounter], red,green,blue); else write_led(&totalstrip[ledcounter], 0,0,0); } } } void Randomblinks(float seconds, bool colored) { uint8_t ledcounter; uint8_t test; Timer timer; timer.start(); while( timer.read() < seconds ) { test = 50.0*rand()/(RAND_MAX*1.0); for(ledcounter = 0; ledcounter < NUMBER_OF_PIXELS; ledcounter++) { if(ledcounter == test) { if(colored) write_led(&totalstrip[ledcounter], test*5,(test%10)*25,(test%15)*15); else write_led(&totalstrip[ledcounter], 255,255,255); } else write_led(&totalstrip[ledcounter], 0,0,0); } } } void UpdateDemoPaddle(void) { static uint8_t direction = 1; if(direction) { paddlestart++; } else { paddlestart--; } if(paddlestart > (NUMBER_OF_PIXELS - PADDLE_LENGTH)) direction = 0; if(paddlestart < 0) direction = 1; } Jeste zapišem knihovny pro tlačítko а pádlo. #include "GameButton.h" GameButton::GameButton(PinName pin, float time=0.5) { pushflag = false; intpin = new InterruptIn(pin); (*intpin).mode(PullUp); (*intpin).fall(this, &GameButton::PushHandler); m_time = time; m_timeoutactive = false; inpin = pin; //timeout = new Timeout(m_time); } void GameButton::PushHandler(void) { DigitalIn input(inpin); wait_ms(5); if(!input) { pushflag = true; m_timeoutactive = true; timeout.attach(this, &GameButton::TimeOutHandler, m_time); pushhandlercallback(); } } void GameButton::TimeOutHandler(void) { m_timeoutactive = false; } bool GameButton::getTimeoutActive(void) { return m_timeoutactive; } #include "paddle.h" Paddle::Paddle() { setColor(255,255,255); setSize(4); position = -getSize(); direction = 1; setSpeed(50); } void Paddle::setSpeed(float speed) { //truncate float time; if(speed > 100000) speed = 100000; if(speed <= 0) speed = 0.001; m_speed = speed; time = 1/m_speed; UpdatePosition.detach(); UpdatePosition.attach(this,&Paddle::PositionUpdater, time); } void Paddle::PositionUpdater(void) { if(direction == 1) position++; else position--; } uint8_t Paddle::getColor(uint8_t pixel, uint8_t color) { if(pixel MAX_PADDLE_SIZE) size = MAX_PADDLE_SIZE; m_size = size; setColor(m_red, m_green, m_blue); } void Paddle::setColor(uint8_t red, uint8_t green, uint8_t blue) { uint8_t paddlepixel; m_red = red; m_green = green; m_blue = blue; for(paddlepixel = 0 ; paddlepixel < MAX_PADDLE_SIZE ; paddlepixel++) { float factor; factor = 1.0*paddlepixel/(m_size*1.0); if (factor > 1) factor = 1; factor = factor*factor*factor;// make the effect more dramatic m_paddle[paddlepixel][0] = (float)m_red * factor; m_paddle[paddlepixel][1] = (float)m_green * factor; m_paddle[paddlepixel][2] = (float)m_blue * factor; } } ==== Záver ==== Cílem tohoto individuálního projektu bylo realizovat hru PING-PONG na FRDM-KL25Z s použitím LED matice LPD6803. Při práci na projektu bylo obtížné psát kód pro tlačítka. Býlo obtižne realizovat systému protože stojí to hodně peněz a proste složne pro realizace. Ale celkem je možné říct, že vsechny úkoly tohoto projektu jsou splněny.