[177] Pong na oscyloskopie cz. 3

03.png
31.png

Nasz pong jest grywalny, ale ubogi graficznie. Spróbujmy narysować boisko – jak w oryginalnych grach sprzed połowy wieku. Dodamy sobie podprogram, który wyrysuje kontur i osadzimy odwołanie tam, gdzie już odwołujemy się do rysowania paletek i piłki. Do tego zresztą jeszcze wrócę za chwilę.

#include "pwm.h"                            // Biblioteka PWM dla architektury Uno R4
const byte pot = A1;                        // Port potencjometru sterującego prawą paletką (gracz).
PwmOut pwmX(10);                            // Obiekt sterujący sprzętowym PWM dla pinu 10 (oś X).
PwmOut pwmY(9);                             // Obiekt sterujący sprzętowym PWM dla pinu 9 (oś Y).
const byte paddleLength = 8;                // Połowa szerokości paletki.
const byte paddleTop = 100 - paddleLength;  // Górna granica ruchu środka paletki.
byte paddleLCenterY = 50;                   // Środek lewej paletki (komputera).
byte paddleRCenterY = 50;                   // Środek prawej paletki (gracza).
int ballX = 50;                             // Pozycja X piłki.
int ballY = 50;                             // Pozycja Y piłki.
int ballXSpeed = 2;                         // Prędkość pozioma piłki i jej kierunek.
int ballYSpeed = 1;                         // Prędkość pionowa piłki i jej kierunek.
unsigned long prevMillis = 0;               // Czas poprzedniego stanu zegara systemowego.
const unsigned long refresh = 20;           // Czas odświeżania logiki gry w ms.
int ballCount = 0;                          // Licznik odbić piłki od paletek.

void setup() {
  pwmX.begin(480000.0f, 0.0f);  // Częstotliwość pracy X = 480 kHz = 100 kroków.
  pwmY.begin(480000.0f, 0.0f);  // Częstotliwość pracy Y = 480 kHz = 100 kroków.
  randomSeed(analogRead(A0));   // Inicjalizacja generatora losowego szumem z pinu A0.
}
void loop() {
  unsigned long currentMillis = millis();                                     // Sczytaj czas systemowy.
  if (currentMillis - prevMillis >= refresh) {                                // Jeśli minął czas trwania jednej klatki gry...
    prevMillis = currentMillis;                                               // Przenieś sczytany czas systemowy do zmiennej do porównań.
    paddleRCenterY = map(analogRead(pot), 0, 1023, paddleLength, paddleTop);  // Oblicz położenie środka prawej paletki (gracza).
    ballX += ballXSpeed;                                                      // Wyznacz nowy adres X piłki.
    ballY += ballYSpeed;                                                      // Wyznacz nowy adres Y piłki.

    if (ballY > paddleLCenterY) {                                        // Jeśli piłka znajduje się powyżej środka lewej paletki...
      paddleLCenterY += random(1, 3);                                    // Przesuń lewą paletkę (komputera) w górę.
      if (paddleLCenterY > paddleTop) paddleLCenterY = paddleTop;        // Zabezpiecz się na wypadek przekroczenia górnego zakresu ekranu.
    } else if (ballY < paddleLCenterY) {                                 // Jeśli piłka znajduje się poniżej środka lewej paletki...
      paddleLCenterY -= random(1, 3);                                    // Przesuń lewą paletkę (komputera) w dół.
      if (paddleLCenterY < paddleLength) paddleLCenterY = paddleLength;  // Zabezpiecz się na wypadek przekroczenia dolnego zakresu ekranu (chroni przed znikaniem).
    }
    if (ballY >= 100) {          // Jeśli piłka osiągnęła górną krawędź...
      ballYSpeed = -ballYSpeed;  // Zmień kierunek poruszania się piłki w dół.
      ballY = 100;               // W razie przekroczenia zakresu ustaw piłkę na górze ekranu
    } else if (ballY <= 0) {     // Jeśli piłka osiągnęła dolną krawędź...
      ballYSpeed = -ballYSpeed;  // Zmień kierunek poruszania się piłki w górę.
      ballY = 0;                 // W razie przekroczenia zakresu ustaw piłkę na dole ekranu.
    }
    if (ballXSpeed < 0 && ballX <= 2 && abs(ballY - paddleLCenterY) <= paddleLength) {          // Odbij piłkę jeśli leci w lewo i trafia w komputer...
      ballYSpeed = (ballY - paddleLCenterY + random(-4, 5)) / 2;                                // Wyznacz nowy kąt z przesunięcia od środka paletki komputera.
      hitBall();                                                                                // Dokończ działania w podprogramie.
    } else if (ballXSpeed > 0 && ballX >= 98 && abs(ballY - paddleRCenterY) <= paddleLength) {  // Odbij piłkę jeśli leci w prawo i trafia w gracza...
      ballYSpeed = (ballY - paddleRCenterY) / 2;                                                // Wyznacz nowy kąt z przesunięcia od środka paletki gracza.
      hitBall();                                                                                // Dokończ działania w podprogramie.
    }
    if (ballX < 0 || ballX > 100) {  // Jeśli piłka nie została przechwycona paletką (znalazła się poza ekranem w osi X)...
      ballYSpeed = random(-3, 4);    // Losuj kąt rzutu.
      ballCount = 0;                 // Zresetuj licznik odbić piłki dla nowej rundy.
      if (ballX < 0) {               // Jeśli wygrał gracz po prawej stronie...
        ballX = 98;                  // Ustaw piłkę przed paletką gracza.
        ballY = paddleRCenterY;      // Piłka startuje z wysokości środka paletki gracza.
        ballXSpeed = -2;             // Skieruj piłkę w lewo.
      } else {                       // Jeśli wygrał komputer po lewej stronie...
        ballX = 2;                   // Ustaw piłkę przed paletką komputera.
        ballY = paddleLCenterY;      // Piłka startuje z wysokości środka paletki komputera.
        ballXSpeed = 2;              // Skieruj piłkę w prawo.
      }
    }
  }
  drawPaddle(0, paddleLCenterY);    // Rysuj lewą paletkę (komputera).
  drawPaddle(100, paddleRCenterY);  // Rysuj prawą paletkę (gracza).
  pwmX.pulse_perc(ballX);           // Wyślij adres X pozycji piłki.
  pwmY.pulse_perc(ballY);           // Wyślij adres Y pozycji piłki.
  delayMicroseconds(1000);          // Wprowadź opóźnienie dające wyraźny rysunek piłki.
  drawCourt();                      // Rysuj obrys boiska.
}
void drawPaddle(byte positionX, byte centerY) {  // Rysowanie paletki.
  int beginY = centerY - paddleLength;           // Oblicz adres Y początku paletki.
  int endY = centerY + paddleLength;             // Oblicz adres Y końca paletki.
  pwmX.pulse_perc(positionX);                    // Wyślij adres X początku paletki.
  for (int n = beginY; n <= endY; n++) {         // Rysuj paletkę, dobierz liczbę kroków do czytelności.
    pwmY.pulse_perc(n);                          // Stawiaj kolejne kropki na osi Y.
    delayMicroseconds(1000);                     // Wprowadź opóźnienie dające wyraźny rysunek paletki.
  }
}
void hitBall() {
  ballXSpeed = -ballXSpeed;              // Zmień kierunek poruszania piłki.
  ballCount++;                           // Zwiększ licznik odbić.
  if (ballCount == 10) ballXSpeed *= 2;  // Jeśli to dziesiąte odbicie, podwój szybkość poruszania się piłki.
}
void drawCourt() {  // Rysuj obrys boiska.
  byte x = 50;      // Punkty startowe.
  byte y = 0;
  pwmX.pulse_perc(x);  // Środkowa pionowa w górę.
  do {
    pwmY.pulse_perc(y);
    delayMicroseconds(5);
  } while (++y <= 99);
  pwmY.pulse_perc(y);  // Lewa górna w lewo.
  do {
    pwmX.pulse_perc(x);
    delayMicroseconds(5);
  } while (x-- > 1);
  pwmX.pulse_perc(x);  // Lewa pionowa w dół.
  do {
    pwmY.pulse_perc(y);
    delayMicroseconds(5);
  } while (y-- > 1);
  pwmY.pulse_perc(y);  // Dolna w prawo.
  do {
    pwmX.pulse_perc(x);
    delayMicroseconds(5);
  } while (++x <= 99);
  pwmX.pulse_perc(x);  // Prawa pionowa w górę.
  do {
    pwmY.pulse_perc(y);
    delayMicroseconds(5);
  } while (++y <= 99);
  pwmY.pulse_perc(y);  // Prawa górna w lewo.
  do {
    pwmX.pulse_perc(x);
    delayMicroseconds(5);
  } while (x-- > 51);
}

Sam podprogram można napisać na wiele różnych sposobów, jednak należy mieć na uwadze, że im mniej przeskoków podczas rysowania, tym mniej ciągnących się „duchów” – śladów plamki na ekranie oscyloskopu. Wypada więc obrys narysować w jednym ciągnięciu pędzla i tak właśnie zrobię. Zacznę od punktu na dolnej krawędzi, na środku. Pociągnę najpierw linię podziału boiska do góry. Następnie skręcimy w lewo, potem na dół, w prawo, do góry i znowu w lewo – na środek górnej krawędzi. Boisko jest namalowane, a tak wygląda w praktyce.

31.pngNo dobrze, do duchów łączących paletki przybył jeszcze kolejny, który łączy środek dołu boiska z piłką. Ciekawe czy da się coś z tym zrobić? Przyjrzyjmy się kolejności wywoływania procedur kreślących poszczególne elementy. Najpierw mamy lewą paletkę, potem prawą, piłkę i boisko. Zmieńmy kolejność, wstawiając rysowanie piłki między rysowanie paletek.

#include "pwm.h"                            // Biblioteka PWM dla architektury Uno R4
const byte pot = A1;                        // Port potencjometru sterującego prawą paletką (gracz).
PwmOut pwmX(10);                            // Obiekt sterujący sprzętowym PWM dla pinu 10 (oś X).
PwmOut pwmY(9);                             // Obiekt sterujący sprzętowym PWM dla pinu 9 (oś Y).
const byte paddleLength = 8;                // Połowa szerokości paletki.
const byte paddleTop = 100 - paddleLength;  // Górna granica ruchu środka paletki.
byte paddleLCenterY = 50;                   // Środek lewej paletki (komputera).
byte paddleRCenterY = 50;                   // Środek prawej paletki (gracza).
int ballX = 50;                             // Pozycja X piłki.
int ballY = 50;                             // Pozycja Y piłki.
int ballXSpeed = 2;                         // Prędkość pozioma piłki i jej kierunek.
int ballYSpeed = 1;                         // Prędkość pionowa piłki i jej kierunek.
unsigned long prevMillis = 0;               // Czas poprzedniego stanu zegara systemowego.
const unsigned long refresh = 20;           // Czas odświeżania logiki gry w ms.
int ballCount = 0;                          // Licznik odbić piłki od paletek.

void setup() {
  pwmX.begin(480000.0f, 0.0f);  // Częstotliwość pracy X = 480 kHz = 100 kroków.
  pwmY.begin(480000.0f, 0.0f);  // Częstotliwość pracy Y = 480 kHz = 100 kroków.
  randomSeed(analogRead(A0));   // Inicjalizacja generatora losowego szumem z pinu A0.
}
void loop() {
  unsigned long currentMillis = millis();                                     // Sczytaj czas systemowy.
  if (currentMillis - prevMillis >= refresh) {                                // Jeśli minął czas trwania jednej klatki gry...
    prevMillis = currentMillis;                                               // Przenieś sczytany czas systemowy do zmiennej do porównań.
    paddleRCenterY = map(analogRead(pot), 0, 1023, paddleLength, paddleTop);  // Oblicz położenie środka prawej paletki (gracza).
    ballX += ballXSpeed;                                                      // Wyznacz nowy adres X piłki.
    ballY += ballYSpeed;                                                      // Wyznacz nowy adres Y piłki.

    if (ballY > paddleLCenterY) {                                        // Jeśli piłka znajduje się powyżej środka lewej paletki...
      paddleLCenterY += random(1, 3);                                    // Przesuń lewą paletkę (komputera) w górę.
      if (paddleLCenterY > paddleTop) paddleLCenterY = paddleTop;        // Zabezpiecz się na wypadek przekroczenia górnego zakresu ekranu.
    } else if (ballY < paddleLCenterY) {                                 // Jeśli piłka znajduje się poniżej środka lewej paletki...
      paddleLCenterY -= random(1, 3);                                    // Przesuń lewą paletkę (komputera) w dół.
      if (paddleLCenterY < paddleLength) paddleLCenterY = paddleLength;  // Zabezpiecz się na wypadek przekroczenia dolnego zakresu ekranu (chroni przed znikaniem).
    }
    if (ballY >= 100) {          // Jeśli piłka osiągnęła górną krawędź...
      ballYSpeed = -ballYSpeed;  // Zmień kierunek poruszania się piłki w dół.
      ballY = 100;               // W razie przekroczenia zakresu ustaw piłkę na górze ekranu
    } else if (ballY <= 0) {     // Jeśli piłka osiągnęła dolną krawędź...
      ballYSpeed = -ballYSpeed;  // Zmień kierunek poruszania się piłki w górę.
      ballY = 0;                 // W razie przekroczenia zakresu ustaw piłkę na dole ekranu.
    }
    if (ballXSpeed < 0 && ballX <= 2 && abs(ballY - paddleLCenterY) <= paddleLength) {          // Odbij piłkę jeśli leci w lewo i trafia w komputer...
      ballYSpeed = (ballY - paddleLCenterY + random(-4, 5)) / 2;                                // Wyznacz nowy kąt z przesunięcia od środka paletki komputera.
      hitBall();                                                                                // Dokończ działania w podprogramie.
    } else if (ballXSpeed > 0 && ballX >= 98 && abs(ballY - paddleRCenterY) <= paddleLength) {  // Odbij piłkę jeśli leci w prawo i trafia w gracza...
      ballYSpeed = (ballY - paddleRCenterY) / 2;                                                // Wyznacz nowy kąt z przesunięcia od środka paletki gracza.
      hitBall();                                                                                // Dokończ działania w podprogramie.
    }
    if (ballX < 0 || ballX > 100) {  // Jeśli piłka nie została przechwycona paletką (znalazła się poza ekranem w osi X)...
      ballYSpeed = random(-3, 4);    // Losuj kąt rzutu.
      ballCount = 0;                 // Zresetuj licznik odbić piłki dla nowej rundy.
      if (ballX < 0) {               // Jeśli wygrał gracz po prawej stronie...
        ballX = 98;                  // Ustaw piłkę przed paletką gracza.
        ballY = paddleRCenterY;      // Piłka startuje z wysokości środka paletki gracza.
        ballXSpeed = -2;             // Skieruj piłkę w lewo.
      } else {                       // Jeśli wygrał komputer po lewej stronie...
        ballX = 2;                   // Ustaw piłkę przed paletką komputera.
        ballY = paddleLCenterY;      // Piłka startuje z wysokości środka paletki komputera.
        ballXSpeed = 2;              // Skieruj piłkę w prawo.
      }
    }
  }
  drawPaddle(0, paddleLCenterY);    // Rysuj lewą paletkę (komputera).
  pwmX.pulse_perc(ballX);           // Wyślij adres X pozycji piłki.
  pwmY.pulse_perc(ballY);           // Wyślij adres Y pozycji piłki.
  delayMicroseconds(1000);          // Wprowadź opóźnienie dające wyraźny rysunek piłki.
  drawPaddle(100, paddleRCenterY);  // Rysuj prawą paletkę (gracza).
  drawCourt();                      // Rysuj obrys boiska.
}
void drawPaddle(byte positionX, byte centerY) {  // Rysowanie paletki.
  int beginY = centerY - paddleLength;           // Oblicz adres Y początku paletki.
  int endY = centerY + paddleLength;             // Oblicz adres Y końca paletki.
  pwmX.pulse_perc(positionX);                    // Wyślij adres X początku paletki.
  for (int n = beginY; n <= endY; n++) {         // Rysuj paletkę, dobierz liczbę kroków do czytelności.
    pwmY.pulse_perc(n);                          // Stawiaj kolejne kropki na osi Y.
    delayMicroseconds(1000);                     // Wprowadź opóźnienie dające wyraźny rysunek paletki.
  }
}
void hitBall() {
  ballXSpeed = -ballXSpeed;              // Zmień kierunek poruszania piłki.
  ballCount++;                           // Zwiększ licznik odbić.
  if (ballCount == 10) ballXSpeed *= 2;  // Jeśli to dziesiąte odbicie, podwój szybkość poruszania się piłki.
}
void drawCourt() {  // Rysuj obrys boiska.
  byte x = 50;      // Punkty startowe.
  byte y = 0;
  pwmX.pulse_perc(x);  // Środkowa pionowa w górę.
  do {
    pwmY.pulse_perc(y);
    delayMicroseconds(5);
  } while (++y <= 99);
  pwmY.pulse_perc(y);  // Lewa górna w lewo.
  do {
    pwmX.pulse_perc(x);
    delayMicroseconds(5);
  } while (x-- > 1);
  pwmX.pulse_perc(x);  // Lewa pionowa w dół.
  do {
    pwmY.pulse_perc(y);
    delayMicroseconds(5);
  } while (y-- > 1);
  pwmY.pulse_perc(y);  // Dolna w prawo.
  do {
    pwmX.pulse_perc(x);
    delayMicroseconds(5);
  } while (++x <= 99);
  pwmX.pulse_perc(x);  // Prawa pionowa w górę.
  do {
    pwmY.pulse_perc(y);
    delayMicroseconds(5);
  } while (++y <= 99);
  pwmY.pulse_perc(y);  // Prawa górna w lewo.
  do {
    pwmX.pulse_perc(x);
    delayMicroseconds(5);
  } while (x-- > 51);
}

Teraz smuga ciągnie się między paletkami i piłką, co wygląda lepiej, choć oczywiście jeszcze lepiej byłoby, gdyby jej nie było wcale. Fajnie byłoby jeszcze, gdyby smuga symetrycznie ciągnęła się z dolnych części paletki, a nie tak jak teraz: na skos. To już niestety wymaga przekonstruowania podprogramu, a w praktyce jego likwidacji i osadzenia dwóch symetrycznych kopii w miejscu dotychczasowego wywołania tej procedury.

#include "pwm.h"                            // Biblioteka PWM dla architektury Uno R4
const byte pot = A1;                        // Port potencjometru sterującego prawą paletką (gracz).
PwmOut pwmX(10);                            // Obiekt sterujący sprzętowym PWM dla pinu 10 (oś X).
PwmOut pwmY(9);                             // Obiekt sterujący sprzętowym PWM dla pinu 9 (oś Y).
const byte paddleLength = 8;                // Połowa szerokości paletki.
const byte paddleTop = 100 - paddleLength;  // Górna granica ruchu środka paletki.
byte paddleLCenterY = 50;                   // Środek lewej paletki (komputera).
byte paddleRCenterY = 50;                   // Środek prawej paletki (gracza).
int ballX = 50;                             // Pozycja X piłki.
int ballY = 50;                             // Pozycja Y piłki.
int ballXSpeed = 2;                         // Prędkość pozioma piłki i jej kierunek.
int ballYSpeed = 1;                         // Prędkość pionowa piłki i jej kierunek.
unsigned long prevMillis = 0;               // Czas poprzedniego stanu zegara systemowego.
const unsigned long refresh = 20;           // Czas odświeżania logiki gry w ms.
int ballCount = 0;                          // Licznik odbić piłki od paletek.

void setup() {
  pwmX.begin(480000.0f, 0.0f);  // Częstotliwość pracy X = 480 kHz = 100 kroków.
  pwmY.begin(480000.0f, 0.0f);  // Częstotliwość pracy Y = 480 kHz = 100 kroków.
  randomSeed(analogRead(A0));   // Inicjalizacja generatora losowego szumem z pinu A0.
}
void loop() {
  unsigned long currentMillis = millis();                                     // Sczytaj czas systemowy.
  if (currentMillis - prevMillis >= refresh) {                                // Jeśli minął czas trwania jednej klatki gry...
    prevMillis = currentMillis;                                               // Przenieś sczytany czas systemowy do zmiennej do porównań.
    paddleRCenterY = map(analogRead(pot), 0, 1023, paddleLength, paddleTop);  // Oblicz położenie środka prawej paletki (gracza).
    ballX += ballXSpeed;                                                      // Wyznacz nowy adres X piłki.
    ballY += ballYSpeed;                                                      // Wyznacz nowy adres Y piłki.

    if (ballY > paddleLCenterY) {                                        // Jeśli piłka znajduje się powyżej środka lewej paletki...
      paddleLCenterY += random(1, 3);                                    // Przesuń lewą paletkę (komputera) w górę.
      if (paddleLCenterY > paddleTop) paddleLCenterY = paddleTop;        // Zabezpiecz się na wypadek przekroczenia górnego zakresu ekranu.
    } else if (ballY < paddleLCenterY) {                                 // Jeśli piłka znajduje się poniżej środka lewej paletki...
      paddleLCenterY -= random(1, 3);                                    // Przesuń lewą paletkę (komputera) w dół.
      if (paddleLCenterY < paddleLength) paddleLCenterY = paddleLength;  // Zabezpiecz się na wypadek przekroczenia dolnego zakresu ekranu (chroni przed znikaniem).
    }
    if (ballY >= 100) {          // Jeśli piłka osiągnęła górną krawędź...
      ballYSpeed = -ballYSpeed;  // Zmień kierunek poruszania się piłki w dół.
      ballY = 100;               // W razie przekroczenia zakresu ustaw piłkę na górze ekranu
    } else if (ballY <= 0) {     // Jeśli piłka osiągnęła dolną krawędź...
      ballYSpeed = -ballYSpeed;  // Zmień kierunek poruszania się piłki w górę.
      ballY = 0;                 // W razie przekroczenia zakresu ustaw piłkę na dole ekranu.
    }
    if (ballXSpeed < 0 && ballX <= 2 && abs(ballY - paddleLCenterY) <= paddleLength) {          // Odbij piłkę jeśli leci w lewo i trafia w komputer...
      ballYSpeed = (ballY - paddleLCenterY + random(-4, 5)) / 2;                                // Wyznacz nowy kąt z przesunięcia od środka paletki komputera.
      hitBall();                                                                                // Dokończ działania w podprogramie.
    } else if (ballXSpeed > 0 && ballX >= 98 && abs(ballY - paddleRCenterY) <= paddleLength) {  // Odbij piłkę jeśli leci w prawo i trafia w gracza...
      ballYSpeed = (ballY - paddleRCenterY) / 2;                                                // Wyznacz nowy kąt z przesunięcia od środka paletki gracza.
      hitBall();                                                                                // Dokończ działania w podprogramie.
    }
    if (ballX < 0 || ballX > 100) {  // Jeśli piłka nie została przechwycona paletką (znalazła się poza ekranem w osi X)...
      ballYSpeed = random(-3, 4);    // Losuj kąt rzutu.
      ballCount = 0;                 // Zresetuj licznik odbić piłki dla nowej rundy.
      if (ballX < 0) {               // Jeśli wygrał gracz po prawej stronie...
        ballX = 98;                  // Ustaw piłkę przed paletką gracza.
        ballY = paddleRCenterY;      // Piłka startuje z wysokości środka paletki gracza.
        ballXSpeed = -2;             // Skieruj piłkę w lewo.
      } else {                       // Jeśli wygrał komputer po lewej stronie...
        ballX = 2;                   // Ustaw piłkę przed paletką komputera.
        ballY = paddleLCenterY;      // Piłka startuje z wysokości środka paletki komputera.
        ballXSpeed = 2;              // Skieruj piłkę w prawo.
      }
    }
  }
  pwmX.pulse_perc(0);                                // Rysuj lewą paletkę (komputera, od góry do dołu).
  int n = paddleLCenterY + paddleLength;             // Oblicz najwyższy punkt lewej paletki.
  do {                                               // Rysuj serię kropek, które stanowią obraz paletki.
    pwmY.pulse_perc(n);                              // Wyślij adres Y kolejnej kropki paletki.
    delayMicroseconds(1000);                         // Wprowadź opóźnienie dające wyraźny rysunek paletki.
  } while (--n >= (paddleLCenterY - paddleLength));  // Powtarzaj dopóki nie narysujesz całej paletki.

  pwmX.pulse_perc(ballX);   // Wyślij adres X pozycji piłki.
  pwmY.pulse_perc(ballY);   // Wyślij adres Y pozycji piłki.
  delayMicroseconds(1000);  // Wprowadź opóźnienie dające wyraźny rysunek piłki.

  pwmX.pulse_perc(100);                              // Rysuj prawą paletkę (gracza, od dołu do góry).
  n = paddleRCenterY - paddleLength;                 // Oblicz najniższy punkt prawej paletki.
  do {                                               // Rysuj serię kropek, które stanowią obraz paletki.
    pwmY.pulse_perc(n);                              // Wyślij adres Y kolejnej kropki paletki.
    delayMicroseconds(1000);                         // Wprowadź opóźnienie dające wyraźny rysunek paletki.
  } while (++n <= (paddleRCenterY + paddleLength));  // Powtarzaj dopóki nie narysujesz całej paletki.

  drawCourt();  // Rysuj obrys boiska.
}
void hitBall() {
  ballXSpeed = -ballXSpeed;              // Zmień kierunek poruszania piłki.
  ballCount++;                           // Zwiększ licznik odbić.
  if (ballCount == 10) ballXSpeed *= 2;  // Jeśli to dziesiąte odbicie, podwój szybkość poruszania się piłki.
}
void drawCourt() {  // Rysuj obrys boiska.
  byte x = 50;      // Punkty startowe.
  byte y = 0;
  pwmX.pulse_perc(x);  // Środkowa pionowa w górę.
  do {
    pwmY.pulse_perc(y);
    delayMicroseconds(5);
  } while (++y <= 99);
  pwmY.pulse_perc(y);  // Lewa górna w lewo.
  do {
    pwmX.pulse_perc(x);
    delayMicroseconds(5);
  } while (x-- > 1);
  pwmX.pulse_perc(x);  // Lewa pionowa w dół.
  do {
    pwmY.pulse_perc(y);
    delayMicroseconds(5);
  } while (y-- > 1);
  pwmY.pulse_perc(y);  // Dolna w prawo.
  do {
    pwmX.pulse_perc(x);
    delayMicroseconds(5);
  } while (++x <= 99);
  pwmX.pulse_perc(x);  // Prawa pionowa w górę.
  do {
    pwmY.pulse_perc(y);
    delayMicroseconds(5);
  } while (++y <= 99);
  pwmY.pulse_perc(y);  // Prawa górna w lewo.
  do {
    pwmX.pulse_perc(x);
    delayMicroseconds(5);
  } while (x-- > 51);
}

Paletka lewa będzie się rysować od góry do dołu, prawa – na odwrót. Dzięki temu zostaną połączone smugą u podstaw. Troszkę to rozbudowało program, ale efekt wygląda lepiej. Na tym etapie już nie będę zmieniał geometrii gry właściwej, natomiast przydałaby się jakaś punktacja. O tym napiszę w kolejnym artykule.

Płytka edukacyjna TME-EDU-ARD-2Płytka edukacyjna TME-EDU-ARD-2

Inne artykuły z tej kategorii

Nasi partnerzy

TMETech Master EventTME EducationPoweredby
Copyright © 2026 arduino.pl