Individální projekty MPOA

Mikroprocesory s architekturou ARM

Uživatelské nástroje

Nástroje pro tento web


2015:pingpong-game

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.

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 && color < 3)
        return m_paddle[pixel][color];
    else
        return 0;
}
 
uint8_t Paddle::getSize(void)
{
    return m_size;
}
 
void Paddle::setSize(uint8_t size)
{
    if(size > 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.

2015/pingpong-game.txt · Poslední úprava: 2016/01/16 15:22 autor: Ruslan Karaganskikh