[177] Pong na oscyloskopie cz. 3
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.
No 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.

Inne artykuły z tej kategorii
Jak wyświetlić cyfry o rozmiarze 10x8 i 10x16 pikseli?























































































































