9.3 KiB
Arkanoid
Autor: Filip Chochol Predmet: Programovanie, TUKE FEI, 2026
Popis projektu
Projekt je terminálová hra Arkanoid napísaná v jazyku C s využitím knižnice ncurses. Hra beží priamo v termináli bez akéhokoľvek grafického rozhrania. Všetka grafika je tvorená ASCII znakmi s farebnými atribútmi ktoré poskytuje ncurses.
Hráč ovláda palku, odráža loptu a ničí tehly usporiadané do špirálového vzoru. Hra obsahuje tri levely s rastúcou rýchlosťou, systém power-upov, bossa s vlastnou logikou správania a automatické ukladanie skóre do textového súboru po každom skončení hry.
Preklad a spustenie
make
./game
Vymazanie skompilovaných súborov:
make clean
Hra sa prekladá kompilátorom gcc s prepínačmi -Wall -Wextra -g a linkuje sa s knižnicami ncurses (-lncurses) a matematickou knižnicou (-lm).
Architektura projektu
Projekt je rozdelený do troch logických vrstiev:
main.c vstupný bod, odovzdá riadenie knižnici world
world.c/h engine – event loop, vykreslovanie, vstup
game.c/h herná logika – všetky herné pravidlá a stav
Táto separácia zabezpečuje že herná logika je úplne nezávislá od konkrétnej implementácie vykreslovania. Keby sa zmenila knižnica world, game.c by ostalo nedotknuté.
Datove struktury
Celý stav hry je uložený v jednej štruktúre Hra ktorá sa alokuje dynamicky pri štarte a uvoľňuje pri ukončení.
Hra – hlavna struktura
typedef struct {
Palka palka;
Lopta lopty[MAX_LOPT];
int pocet_lopt;
Tehla tehly[MAX_RIADKOV][MAX_STLPCOV];
int zivoty;
int skore;
int zostatok_tehiel;
int level;
float rychlost;
StavHry stav;
int sirka, vyska;
char meno[32];
PowerUp powerupy[2];
int hit_counter;
int sirka_timer;
int cas_tikov;
int special_dostupny;
Boss boss;
} Hra;
Tehla
typedef struct {
int ziva;
int farba;
char znak;
} Tehla;
Tehly sú uložené v dvojrozmernom poli tehly[MAX_RIADKOV][MAX_STLPCOV] teda 7x10 pozícií. Nie všetky sú obsadené – rozloženie určuje statické pole spirala[7][10] kde 1 znamená tehla existuje, 0 prázdne. Atribút ziva slúži na označenie zničených tehiel bez nutnosti preusporiadavať pole.
Lopta
typedef struct {
float x, y;
float dx, dy;
int ziva;
} Lopta;
Pozícia a smer sú float aby pohyb bol plynulý a uhly presné. Hra podporuje až MAX_LOPT = 16 lôpt súčasne v jednom statickom poli. Pridávanie lôpt prechádza pole a hľadá prvý slot kde ziva == 0.
Palka
typedef struct {
int x, y;
int sirka;
} Palka;
PowerUp
typedef struct {
int ziva;
float x, y;
char znak;
short farba;
} PowerUp;
Boss
typedef struct {
int ziva;
float x, y;
float dx;
int pada;
} Boss;
StavHry – stavovy automat
Hra funguje ako stavový automat s týmito stavmi:
STAV_UVOD úvodná obrazovka, zadávanie mena
STAV_CAKA lopta čaká na palke pred štartom
STAV_HRAJE hra beží
STAV_KONIEC hráč prehral
STAV_VYHRAL hráč vyhral všetky 3 levely
STAV_DALSI_LEVEL level dokončený, čaká na pokračovanie
Každý stav určuje čo sa vykresluje a aké udalosti sa spracúvajú.
Herna logika
Event loop
Knižnica world.c beží v nekonečnej slučke. Pri každom tiku (každých RYCHLOST_HRY = 120 ms) zavolá funkciu game_event() s informáciou o stlačenom klávesu alebo uplynutom čase. game_event() spracuje vstup, zavolá pohni_lopty() a vykresli_hru().
Fyzika lopty
Každý tick sa pre každú živú loptu zavolá pohni_jednu_loptu():
-
Vypočíta sa nová pozícia: nx = lopta.x + lopta.dx ny = lopta.y + lopta.dy
-
Kontrola narazu na steny – ak lopta dosiahne okraj, príslušná zložka smeru sa neguje: ak nx <= lavy_okraj -> dx = +|dx| ak nx >= pravy_okraj -> dx = -|dx| ak ny <= horny_okraj -> dy = +|dy|
-
Kontrola odrazu od palky – ak lopta dosiahne riadok palky a je v jej horizontálnom rozsahu: offset = (nx - stred_palky) / (sirka_palky / 2) dx = offset * rychlost Čím ďalej od stredu, tým väčší horizontálny smer. dy sa vždy nastaví na -rychlost (lopta ide hore).
-
Kontrola kolízie s tehlami – porovnanie pozície lopty s pozíciou každej živej tehly. Pri zhode sa tehla označí ziva = 0, skóre sa zvýši a dy sa neguje (odraz).
-
Ak ny >= dolna_hranica (pod palkou) – lopta zomrie, pocet_lopt sa zníži.
Pohyb palky
Palka sa pohybuje o 2 znaky na každé stlačenie klávesi. Pri pohybe myšou sa x palky nastaví priamo na pozíciu kurzora mínus polovica šírky palky, čo dáva plynulé sledovanie myši. Pohyb je ohraničený na lavy_okraj až pravy_okraj – sirka_palky.
Boss logika
Boss sa objaví po BOSS_CAS = 240 tikoch od začiatku levelu.
Fáza 1 – horizontálny pohyb: boss.x += boss.dx pri náraze na okraj sa dx neguje
Fáza 2 – pád (keď cas_tikov >= BOSS_CAS): boss.pada = 1 boss.y += 0.15 každý tick ak boss trafí tehlu – tehla zomrie, skore -= 50 ak boss.y >= palka.y – okamžite STAV_KONIEC
Zásah bossa loptou: boss.ziva = 0, skore += 200 vystrelí 5 lôpt rôznymi smermi (vystrel_z_bossa)
Power-upy
hit_counter počíta každú zničenú tehlu. hit_counter % 3 == 0 -> power-up $ (extra lopty) hit_counter % 12 == 0 -> power-up W (siroka palka)
Power-upy padajú dolu (y += 0.5 každý tick). Pri chytení palkou sa aktivuje efekt: $ – pridajú sa 2 nové lopty s mierne odchýleným smerom W – palka.sirka = PALKA_SIRKA_MAX, sirka_timer = 300 tickov po 300 tickoch sa palka vráti na PALKA_SIRKA_MIN
Specialny vystrel
Stlačením E sa vypália 2 lopty pod uhlom od stredu palky. Dostupnosť sa sleduje premennou special_dostupny (1/0). Po použití sa nastaví na 0 a už sa nedá obnoviť.
Skore
Za každú zničenú tehlu: 10 * cislo_levelu bodov. Za zničenie bossa: +200 bodov. Za tehlu zničenú bossom: -50 bodov.
Ukladanie skore
Po každom skončení hry (STAV_KONIEC aj STAV_VYHRAL) sa zavolá funkcia uloz_skore() ktorá otvorí scores.txt v append móde ("a") a pripíše formátovaný záznam s týmito údajmi: - meno hráča - dosiahnuté skóre - level na ktorom hra skončila - čas od začiatku levelu (prepočítaný z cas_tikov) - výsledok (VYHRAL / GAME OVER) - dátum a čas (zo systémovej funkcie localtime)
Súbor sa nevymazáva – každá hra sa pripíše na koniec takže ostáva kompletná história všetkých hier.
Vykreslovanie
Celá hra sa vykresluje funkciou vykresli_hru() ktorá sa volá po každej udalosti. Funkcia najprv vymaže obrazovku (clear_screen) a potom podľa aktuálneho stavu hry vykreslí príslušné prvky.
Súradnicový systém: [0,0] je ľavý horný roh obrazovky. X rastie doprava, Y rastie smerom nadol.
Hracia plocha má dva rámčeky: vonkajší – ohraničuje celú obrazovku (žltý) vnútorný – ohraničuje hernú plochu (biely)
Rozmery hracej plochy sa počítajú dynamicky podľa aktuálnej veľkosti terminálu (h->sirka, h->vyska) čo zabezpečuje že hra funguje správne aj pri zmene veľkosti okna.
Pozície tehiel: tx = tehla_zacatek_x + stlpec * 3 ty = tehla_zac_y + riadok Každá tehla zaberá 3 znaky: [X] kde X je znak z mena hráča.
Ovládanie
| Kláves | Akcia |
|---|---|
| A / sipka vlavo | Pohyb palky vlavo |
| D / sipka vpravo | Pohyb palky vpravo |
| Pohyb mysou | Palka sleduje kurzor |
| Medzernik | Spustenie lopty |
| Lavy klik mysou | Spustenie lopty |
| E | Specialny vystrel |
| Q | Ukoncenie hry |
Bodovanie
| Udalost | Body |
|---|---|
| Znicenie tehly – level 1 | +10 |
| Znicenie tehly – level 2 | +20 |
| Znicenie tehly – level 3 | +30 |
| Znicenie bossa | +200 |
| Boss znici tehlu | -50 |
Levely
| Level | Rychlost lopty | Body za tehlu |
|---|---|---|
| 1 | 0.7 | 10 |
| 2 | 0.9 | 20 |
| 3 | 1.1 | 30 |
Subory projektu
| Subor | Obsah |
|---|---|
| main.c | Vstupny bod, spusta hernu slucku cez world |
| game.c | Cela herna logika – pohyb, kolizie, kreslenie |
| game.h | Struktury, konstanty, deklaracie funkcii |
| world.c | Kniźnica pre vykreslovanie v terminali |
| world.h | Rozhranie kniźnice world |
| Makefile | Preklad projektu prikazom make |
| README.md | Tato dokumentacia |
| scores.txt | Ukladanie skore (vytvori sa automaticky) |