pvjc26/final/README.md
2026-05-10 10:44:22 +02:00

9.3 KiB
Raw Blame History

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():

  1. Vypočíta sa nová pozícia: nx = lopta.x + lopta.dx ny = lopta.y + lopta.dy

  2. 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|

  3. 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).

  4. 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).

  5. 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)