Gra Pong i gra Driver

Te dwie proste gry powstały jednego wolnego wieczora. Każdą pisałem około dwóch godzin, czyli całkiem szybko. Ich poziom skomplikowania też nie jest ogromny. Mam nadzieję, że zrozumienie kodu nie przysporzy problemów.

Opiszę może pokrótce obie gry. Pierwsza to typowy Pong. Jedna paletka, jedna piłka poruszająca się tylko pod kątem 45 stopni i odbijająca się od ścian. W programie występują trzy zadania. Pierwsze, główne, służy do liczenia wyników i zmieniania trudności gry. Co 2 sekundy zmniejsza się długość paletki, albo kulka przyspiesza. Co 2 sekundy też dodawane są punkty. Końcowy wynik zależy więc od czasu gry.

Drugie zadanie obsługuje kulkę. Zapewnia, że odbija się od ścian i sprawdza czy odbija się od paletki. Jeżeli kulka znajduje się przy krawędzi ekranu, zmieniany jest odpowiednio kierunek ruchu. Ostatnie zadanie rysuje paletkę i zmienia jej położenie w zależności od wciśniętego na kostce przycisku.

Ciekawym fragmentem kodu rysującego jest LineOut(0, PADDLE_HEIGHT, 99, PADDLE_HEIGHT, DRAW_OPT_CLEAR); LineOut(x1, PADDLE_HEIGHT, x2, PADDLE_HEIGHT); Pierwsza linijka rysuje linię na biało skutecznie wymazując paletkę. Następna linijka rysuje paletkę w nowym położeniu. Napisałem to w ten sposób z dwóch powodów. Po pierwsze mazanie całego ekranu jest operacją niezwykle czasochłonną i powoduje miganie wyświetlacza. Po drugie wymazałbym też kulkę. Rysowanie na biało jest bardzo przydatną sztuczką.

Przejdę do drugiej gry. Nazwałem ją Driver. Zasady są proste: należy sterować kulką-pojazdem tak aby nie opuściła losowo generowanego toru. W programie znów wykorzystałem trzy zadania. Pierwsze z nich odpowiada za rysowanie drogi na całym ekranie. Kształt drogi przechowywany jest w tablicy ROAD_CENTER, która w tym programie traktowana jest jako bufor cykliczny. Łatwo zauważyć, że w każdym kolejnym kroku gry wygenerowany zostaje jedynie jeden nowy jej segment, natomiast 63 pozostałe się nie zmieniają. Wykorzystałem tą informację i nowy segment zapisuję na miejscu ostatniego wygenerowanego w tablicy oraz zapamiętuję nowy początek tejże tablicy. Przykładowo w jednym kroku gry odczytuję drogę od pozycji 13 do 63 i dalej od 0 do 12, gdzie 13 jest początkiem, a w następnym kroku losuję nowy segment na pozycji 13 i odczytuję trasę od 14 do 63 i dalej od 0 do 13. Nie muszę przestawiać żadnych liczb w tablicy, co jest ogromnym usprawnieniem.

Drugie zadanie w programie kontroluje pozycję pojazdu. Przyciskami na kostce można przesuwać go w lewo i w prawo. Ostatnie zadanie monitoruje pozycję pojazdu i jeżeli wyjechało ono za wyznaczoną trasę, to kończy grę.

Oba programy są niezmiernie proste w swej idei. Implementacja może nie należy do najłatwiejszych, ale nie po to pracuję nad nowymi projektami, żeby robić rzeczy łatwe. Obie gry można oczywiście usprawniać. Trasa dla Drivera może być generowana w bardziej przemyślany sposób. W grze Pong kulka mogłaby odbijać się pod kątem innym niż prosty. Można również zmienić grę tak, aby umożliwić zbijanie statycznych elementów na ekranie, albo dodać paletki u góry i po bokach. Może kiedyś dopiszę te funkcjonalności.

Polecam ściągnąć gry na swoje kostki i wypróbować.

Wideo


Galeria

Galeria 3D

Obrazy w tej galerii możesz oglądać jedynie przy użyciu specjalnych czerwono-niebieskich okularów. Można je nabyć w wielu sklepach internetowych za bardzo małe pieniądze.


Brak zdjęć.

Kod programu

//author: Krzysztof Kapusta, All rights reserved // PONG - The Game #define PADDLE_HEIGHT 4 #define BALL_SIZE 2 int PADDLE_PERIOD = 20; int PADDLE_WIDTH = 15; int PADDLE_X = 50; int BALL_X = 50; int BALL_Y = 32; int BALL_PERIOD = 100; bool BALL_GOING_LEFT = true; bool BALL_GOING_UP = true; int SCORE = 0; safecall void drawPaddle() { int x1, x2; x1 = PADDLE_X - PADDLE_WIDTH/2; if (x1 < 0) x1 = 0; x2 = PADDLE_X + PADDLE_WIDTH/2; if (x2 > 99) x2 = 99; LineOut(0, PADDLE_HEIGHT, 99, PADDLE_HEIGHT, DRAW_OPT_CLEAR); LineOut(x1, PADDLE_HEIGHT, x2, PADDLE_HEIGHT); } task main(); task paddle() { drawPaddle(); while(true) { while (!ButtonPressed(BTNLEFT, false) && !ButtonPressed(BTNRIGHT, false)); if (ButtonPressed(BTNLEFT, false)) { while (ButtonPressed(BTNLEFT, false)) { if (PADDLE_X > 0) PADDLE_X--; drawPaddle(); Wait(PADDLE_PERIOD); } } else if (ButtonPressed(BTNRIGHT, false)) { while (ButtonPressed(BTNRIGHT, false)) { if (PADDLE_X < 99) PADDLE_X++; drawPaddle(); Wait(PADDLE_PERIOD); } } } } task ball() { int left, bottom; while(true) { left = BALL_X - BALL_SIZE/2 + (BALL_SIZE%2 == 0 ? 1 : 0); bottom = BALL_Y - BALL_SIZE/2 + (BALL_SIZE%2 == 0 ? 1 : 0); RectOut(left, bottom, BALL_SIZE, BALL_SIZE, DRAW_OPT_CLEAR); if (BALL_GOING_LEFT) { if (left > 0) BALL_X--; else { BALL_GOING_LEFT = false; BALL_X++; } } else { if (left+BALL_SIZE-1 < 99) BALL_X++; else { BALL_GOING_LEFT = true; BALL_X--; } } if (BALL_GOING_UP) { if (bottom+BALL_SIZE-1 < 63) BALL_Y++; else { BALL_GOING_UP = false; BALL_Y--; } } else { if (bottom > PADDLE_HEIGHT) BALL_Y--; else { if (left+BALL_SIZE-1 < PADDLE_X + PADDLE_WIDTH/2 + 1 && left > PADDLE_X - PADDLE_WIDTH/2 - 1) { BALL_GOING_UP = true; BALL_Y++; drawPaddle(); } else { StopTask(paddle); StopTask(main); ClearScreen(); TextOut(25, LCD_LINE4, "GAME OVER"); TextOut(15, LCD_LINE5, FormatNum("Score: %d", SCORE)); Wait(5000); StopAllTasks(); } } } RectOut(BALL_X, BALL_Y, 2, 2); Wait(BALL_PERIOD); } } task main() { StartTask(paddle); StartTask(ball); while(true) { for (int i = 0; i<5; i++) { Wait(SEC_2); SCORE++; if (BALL_PERIOD >= 10) BALL_PERIOD -= 5; if (PADDLE_PERIOD > BALL_PERIOD+2) PADDLE_PERIOD = BALL_PERIOD+2; } Wait(SEC_2); SCORE++; if (PADDLE_WIDTH > 5) PADDLE_WIDTH -= 2; } }

//author: Krzysztof Kapusta, All rights reserved // Driver - The Game #define CAR_SIZE 3 #define CAR_HEIGHT 8 int CAR_PERIOD = 80; int ROAD_WIDTH = 9; int CAR_X = 50; int ROAD_CENTER[]; int ROAD_TAB_POS = 0; int ROAD_PERIOD = 40; int prev_x = 50; safecall void drawCar() { int left; left = prev_x - CAR_SIZE/2 + (CAR_SIZE % 2 == 0 ? 1 : 0); RectOut(left, CAR_HEIGHT, CAR_SIZE - 1, CAR_SIZE - 1, DRAW_OPT_CLEAR | DRAW_OPT_FILL_SHAPE); left = CAR_X - CAR_SIZE/2 + (CAR_SIZE % 2 == 0 ? 1 : 0); RectOut(left, CAR_HEIGHT, CAR_SIZE - 1, CAR_SIZE - 1, DRAW_OPT_FILL_SHAPE); prev_x = CAR_X; } void drawRoad() { int pos = ROAD_TAB_POS; for (int i = 0; i<64; i++) { LineOut(0, i, 99, i, DRAW_OPT_CLEAR); PointOut(ROAD_CENTER[pos] - ROAD_WIDTH/2, i); PointOut(ROAD_CENTER[pos] + (ROAD_WIDTH-1)/2, i); if (i == CAR_HEIGHT + CAR_SIZE - 1) drawCar(); pos = (pos + 1) % 64; } } task generateRoad() { int newval; while (true) { newval = ROAD_CENTER[ROAD_TAB_POS-2 < 0 ? ROAD_TAB_POS+62 : ROAD_TAB_POS-2] + (Random(5)-2)/2; if (newval < 0) newval = 0; else if (newval > 99) newval = 99; ROAD_CENTER[ROAD_TAB_POS-1 < 0 ? 63 : ROAD_TAB_POS-1] = newval; ROAD_TAB_POS = (ROAD_TAB_POS+1)%64; Wait(ROAD_PERIOD); } } task car() { drawCar(); while(true) { while (!ButtonPressed(BTNLEFT, false) && !ButtonPressed(BTNRIGHT, false)); if (ButtonPressed(BTNLEFT, false)) { while (ButtonPressed(BTNLEFT, false)) { if (CAR_X > 0) CAR_X--; drawCar(); Wait(CAR_PERIOD); } } else if (ButtonPressed(BTNRIGHT, false)) { while (ButtonPressed(BTNRIGHT, false)) { if (CAR_X < 99) CAR_X++; drawCar(); Wait(CAR_PERIOD); } } } } task road() { ArrayInit(ROAD_CENTER, 50, 64); while (true) { drawRoad(); if (CAR_X - CAR_SIZE/2 + (CAR_SIZE % 2 == 0 ? 1 : 0) < ROAD_CENTER[(ROAD_TAB_POS+CAR_HEIGHT)%64] - ROAD_WIDTH/2 || CAR_X + CAR_SIZE/2 > ROAD_CENTER[(ROAD_TAB_POS+CAR_HEIGHT)%64] + (ROAD_WIDTH-1)/2) { StopAllTasks(); } } } task main() { StartTask(generateRoad); StartTask(car); StartTask(road); }

Pokaż/ukryj cały kod

Komentarze

to jeeeeeeeeeeeeeeeeeeeeeeeeeeest suuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuper

Dodane przez: kuba | 2013-11-06

OOO nareszcie działa trzeba było dać NXT... :P Ale wielkie THX za to :)

Dodane przez: RedstonePL | 2013-01-16

A w BrixCC jak to włączam to co mam zaznaczyć? Bo reszte chyba ogarniam :)

Dodane przez: RedstonePL | 2013-01-16

bricxcc.sourceforge.net/test_releases/test_release20121101.zip Wystarczy poszukać

Dodane przez: Admin | 2013-01-16

A gdzie dokładniej można pobrać enhanced?

Dodane przez: RedstonePL | 2013-01-16

Zobacz wszystkie

Dodaj swój komentarz