Više o Roster Softu
Sve usluge
Sva gotova rešenja
Svi članci

Rat brojeva – napravi svoju prvu arkadnu igricu pomoću HTML-a, CSS-a i JavaScript-a

Rat brojeva – kompletan vodič za izradu arkadne igre u HTML-u, CSS-u i JavaScript-u Praktična lekcija za početnike | Projekat: 2D platformerska arkadna igra Da li ste nekada poželeli da napravite sopstvenu video-igru, ali niste znali odakle da počnete? U ovoj lekciji napravićemo igru Rat brojeva, u kojoj se plavi broj 0 i narandžasti broj […]

Rat brojeva – kompletan vodič za izradu arkadne igre u HTML-u, CSS-u i JavaScript-u

Praktična lekcija za početnike | Projekat: 2D platformerska arkadna igra

Da li ste nekada poželeli da napravite sopstvenu video-igru, ali niste znali odakle da počnete? U ovoj lekciji napravićemo igru Rat brojeva, u kojoj se plavi broj 0 i narandžasti broj 1 takmiče u prikupljanju poena. Igra ima platforme, skakanje, prepreke, pucanje, zvučne efekte, rezultate i mogućnost igranja protiv računara ili drugog igrača.

Ovaj vodič prati priloženu, izmenjenu igru index.html. Svi primeri i nazivi funkcija odnose se na stvarni kod. Važno: gotova igra ima skoro hiljadu redova; zato ćemo je prvo razumeti po celinama, a zatim napraviti i malu, samostalnu početničku verziju koja funkcioniše bez dodatnih biblioteka. Izvornu datoteku možete otvoriti u VS Code-u i pratiti poglavlja jedno po jedno.

1. Šta ćemo naučiti?

Po završetku, znaćete da: napravite HTML dokument; stilizujete elemente CSS-om; iscrtate grafiku pomoću <canvas>; reagujete na tastaturu; pokrećete animacionu petlju; primenite gravitaciju, skok i kretanje; prepoznate sudare objekata; brojite poene; dodate tajmer, zvuk i protivnika; menjate pravila i objavite igru na internetu.

Ne morate prethodno poznavati programiranje. Dovoljni su računar, internet pregledač i besplatan editor Visual Studio Code. Projekat radi lokalno kao obična HTML datoteka; osnovna igra ne zahteva server, bazu podataka niti instaliranje JavaScript biblioteka. Za fontove iz Google Fonts potreban je pristup internetu, ali se uz rezervne sistemske fontove igra prikazuje i bez njega.

 

DEMO IGRICE

POKRENI IGRICU ONLINE

2. Priprema radnog okruženja

  1. Napravite folder, na primer RatBrojeva.
  2. Otvorite Visual Studio Code, izaberite File → Open Folder i otvorite taj folder.
  3. Kreirajte dokument index.html.
  4. Kopirajte dostavljenu gotovu datoteku index.html u taj folder ako želite da odmah eksperimentišete sa kompletnom verzijom. Ako krećete od nule, koristite primere u poglavlju 5.
  5. Dvaput kliknite na index.html ili ga otvorite u pregledaču. Za automatsko osvežavanje možete koristiti opcioni dodatak Live Server u VS Code-u.

Kako sačuvati izmene: u editoru pritisnite Ctrl+S, vratite se u pregledač i pritisnite Ctrl+R. Ako se promena ne vidi, probajte Ctrl+F5 za potpuno osvežavanje.

Pravilo za početnike: pre većih izmena sačuvajte kopiju index-backup.html, da biste lako mogli da vratite ispravnu verziju.

3. Kako je igra organizovana?

Sve je smešteno u jednu datoteku index.html, koja sadrži tri tehnologije:

  • HTML opisuje elemente stranice: naslov, prostor za igru, kontrole i pravila.
  • CSS kontroliše izgled: boje, fontove, veličine, raspored i prilagođavanje telefonu.
  • JavaScript sadrži logiku igre: kretanje, gravitaciju, kolizije, poene, zvuk, animacije i AI.

U datoteci pronađite: <style> — početak CSS-a; <main class="wrap"> — početak glavnog HTML sadržaja; <script> — početak JavaScript-a. Kraj skripte je označen sa </script>.

Često ćete sretati i funkciju, na primer function shoot(p) { ... }. Funkcija je imenovan blok naredbi koji se izvršava kada je pozovemo. const definiše promenljivu čiju referencu ne menjamo, a let promenljivu čiju vrednost možemo menjati. Komentar // objašnjenje ili /* objašnjenje */ ne izvršava se, već pomaže čitaocu.

4. Prvi HTML ekran i Canvas

U gotovoj igri najvažniji element je:

<div id="screen">
  <canvas id="game" width="320" height="224" tabindex="0"></canvas>
</div>

Canvas je pravougaona površina na kojoj JavaScript crta piksele. id="game" je ime kojim je pronalazimo u JavaScript-u, width="320" znači širinu od 320 internih piksela, a height="224" visinu od 224. tabindex="0" dopušta da canvas dobije fokus tastature. Iako je interna rezolucija mala, na monitoru može da se prikaže mnogo veći zahvaljujući CSS-u. To je osnova retro „pixel art“ stila.

U JavaScript-u se povezujemo sa ekranom:

const cv = document.getElementById('game');
const ctx = cv.getContext('2d');
ctx.imageSmoothingEnabled = false;

cv je HTML canvas, ctx je alat za dvodimenzionalno crtanje, a imageSmoothingEnabled = false čuva oštre piksele prilikom uvećavanja.

Proba crtanja:

ctx.fillStyle = '#2f6bff';
ctx.fillRect(50, 70, 40, 40);

Ovo crta plavi kvadrat. Parametri su redom: horizontalni položaj (x), vertikalni položaj (y), širina i visina. U Canvas-u početak koordinatnog sistema je gore levo. Veći x znači udesno; veći y znači nadole.

5. Napravimo svoju prvu mini-igru od nule

Pre nego što čitamo složenu verziju, napravimo funkcionalnu početničku igru. U novi fajl vezba.html kopirajte sledeći kod i pokrenite ga u pregledaču:

<!doctype html>
<html lang="sr">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width,initial-scale=1">
  <title>Rat brojeva – moja prva igra</title>
  <style>
    body { margin: 0; background: #101634; color: white;
           font: 16px Arial, sans-serif; text-align: center; }
    h1 { margin-top: 24px; }
    canvas { width: min(96vw, 800px); height: auto;
             background: #9bd7ff; image-rendering: pixelated;
             border: 4px solid #3945a8; }
  </style>
</head>
<body>
  <h1>RAT BROJEVA</h1>
  <p>A/D – kretanje, W ili SPACE – skok. Sakupi žute novčiće!</p>
  <canvas id="game" width="320" height="224"></canvas>
  <p id="result">Poeni: 0</p>
  <script>
    const canvas = document.getElementById('game');
    const ctx = canvas.getContext('2d');
    const result = document.getElementById('result');
    const keys = {};
    const floorY = 200;
    const player = { x: 30, y: 184, w: 12, h: 16,
                     vx: 0, vy: 0, onGround: true, score: 0 };
    let coin = { x: 170, y: 180, w: 8, h: 8 };

    document.addEventListener('keydown', e => {
      keys[e.code] = true;
      if (['Space', 'ArrowUp'].includes(e.code)) e.preventDefault();
    });
    document.addEventListener('keyup', e => { keys[e.code] = false; });

    function touch(a, b) {
      return a.x < b.x + b.w && a.x + a.w > b.x &&
             a.y < b.y + b.h && a.y + a.h > b.y;
    }

    function update() {
      player.vx = 0;
      if (keys.KeyA) player.vx = -2;
      if (keys.KeyD) player.vx = 2;
      if ((keys.KeyW || keys.Space) && player.onGround) {
        player.vy = -6.3;
        player.onGround = false;
      }
      player.vy += 0.35;
      player.x += player.vx;
      player.y += player.vy;
      player.x = Math.max(0, Math.min(320 - player.w, player.x));
      if (player.y + player.h >= floorY) {
        player.y = floorY - player.h;
        player.vy = 0;
        player.onGround = true;
      }
      if (touch(player, coin)) {
        player.score += 10;
        coin.x = 10 + Math.random() * 290;
        coin.y = 180;
        result.textContent = 'Poeni: ' + player.score;
      }
    }

    function draw() {
      ctx.fillStyle = '#9bd7ff'; ctx.fillRect(0, 0, 320, 224);
      ctx.fillStyle = '#4a9e43'; ctx.fillRect(0, floorY, 320, 24);
      ctx.fillStyle = '#ffd23f';
      ctx.fillRect(coin.x, coin.y, coin.w, coin.h);
      ctx.fillStyle = '#2f6bff';
      ctx.fillRect(player.x, player.y, player.w, player.h);
      ctx.fillStyle = 'white'; ctx.font = '12px monospace';
      ctx.fillText('0', player.x + 3, player.y + 12);
    }

    // Ova početnička verzija namerno koristi jednostavan okvirni korak.
    function loop() {
      update();
      draw();
      requestAnimationFrame(loop);
    }
    loop();
  </script>
</body>
</html>

Šta ste upravo napravili? Igrač se kreće levo i desno; može da skoči; gravitacija ga vraća na tlo; dodir novčića donosi 10 poena; novčić dobija nov položaj. Ovo je najmanja celina koju možemo nazvati igrom. Sada ćemo razumeti naprednu verziju i naučiti gde se podešava svaki njen deo.

Napomena: u mini-igri se update() poziva jednom po prikazanom frejmu, pa brzina može zavisiti od osvežavanja ekrana. Gotova igra ispod ima preciznije ažuriranje sa fiksnim korakom od 60 puta u sekundi.

6. Glavna podešavanja – dimenzije, vreme i gravitacija

U gotovom index.html, na početku JavaScript-a, stoji:

const W = 320, H = 224, GROUND = 200, ROUND = 60, GRAV = 0.35;
Podešavanje Značenje Efekat promene
W = 320 širina sveta igre menja koordinatni sistem i zahteva proveru položaja ostalih objekata
H = 224 visina sveta menja dimenziju ekrana
GROUND = 200 nivo tla manje vrednosti podižu tlo
ROUND = 60 dužina runde u sekundama 90 produžava rundu na 90 sekundi
GRAV = 0.35 ubrzanje padanja po koraku igre veće vrednosti ubrzavaju padanje

Vežba: promenite ROUND = 60 u ROUND = 90, sačuvajte i otvorite novu rundu. Druga vežba: stavite GRAV = 0.45. Primetićete da su skokovi kraći i padanje brže.

W i H ne menjajte samo na jednom mestu: uskladite ih i sa HTML atributima <canvas width="320" height="224">, a zatim prilagodite pozicije platformi, interfejsa i pozadine. Za prve eksperimente bezbednije je da ostanu 320 × 224.

7. Podešavanje boja i tipografije

U CSS-u pronađite:

:root {
  --bg: #090a1c;
  --panel: #13153a;
  --line: #2a2e6e;
  --fg: #e9ecff;
  --muted: #9097cc;
  --blue: #2f6bff;
  --orange: #ff6a1f;
  --yellow: #ffd23f;
}

Ovo su CSS varijable. Kada promenite --bg, menja se osnovna pozadina sajta. --panel utiče na kartice sa uputstvima, --fg na glavni tekst, a --blue i --orange na akcentne boje. Vrednost #2f6bff je HEX zapis boje: šest heksadecimalnih cifara određuje udeo crvene, zelene i plave.

Boje samih likova dodatno određuje JavaScript objekat PAL. Razlog je jednostavan: likovi se crtaju na canvas-u, pa ne nasleđuju CSS boje običnog HTML teksta.

Za arkadni font koristi se Google font Press Start 2P, a za običan tekst Chakra Petch. Promenom CSS varijabli --pixel i --body birate fontove. Ako želite offline rad bez spoljnog učitavanja, koristite sistemske fontove, na primer monospace i Arial.

8. Kako nastaju likovi brojevi 0 i 1?

U ovoj igri ne koristimo gotove PNG slike likova. Njih crtamo tekstualnim mapama pikselâ:

const PAL = {
  '0': { o: '#0b1440', b: '#2f6bff', h: '#a6ccff', f: '#e8312f' },
  '1': { o: '#3a0d06', b: '#ff6a1f', h: '#ffd08a', f: '#2246c8' }
};

Oznake o, b, h i f nisu specijalne JavaScript naredbe: to su naša imena za boje piksela (kontura, telo, svetliji deo i stopala). Nizovi MAPS['0'] i MAPS['1'] sadrže redove znakova dužine 12; tačka . znači providan piksel.

Primer prvih redova slike nule:

const zeroExample = [
  '...oooooo...',
  '..obbbbbbo..',
  '.obbbbbbbbo.',
  '.obhhbbhhbo.'
];

Funkcija paint(rows, pal, w, h) prolazi kroz svaki red i kolonu, pronalazi boju po slovu i crta kvadratić 1 × 1. Funkcija drawHeroAt(...) zatim prikazuje tako nastalu malu sliku na željenoj poziciji i uvećanju. FEET čuva varijante nogu (stand, w1, w2, jump), a EYES pozicije očiju.

Vežba: pronađite PAL['0'].b i postavite, na primer, '#20b487'. Nula postaje zelena. Zatim promenite jedan znak b u h u mapi i posmatrajte promenu samo jednog piksela. Ako dodajete nove redove, vodite računa da mapa i dalje ima predviđenih 12 kolona, i da se visina slike slaže sa postupkom crtanja.

9. Imena timova i poruke o pobedi

Glavna konfiguracija naziva je:

const SIDE = {
  '0': { name: 'BROJ 0', col: '#7fa8ff', win: 'BROJ 0 POBEDJUJE!' },
  '1': { name: 'BROJ 1', col: '#ff8a4a', win: 'BROJ 1 POBEDJUJE!' }
};

name je kratko ime prikazano na interfejsu, col je boja natpisa, a win tekst pobede. Igra na drugim mestima ima i neposredno upisane natpise BROJ 0 i BROJ 1, posebno u funkcijama drawTitle() i render(). Zato za potpuno preimenovanje nije dovoljno promeniti samo SIDE; izvršite pretragu kroz datoteku (Ctrl+F).

U funkciji scores() rezultat se povezuje sa pravim likom preko hero === '0' ili hero === '1'. Nemojte brisati identifikatore brojeva bez usklađivanja MAPS, PAL, SIDE, SPR, početnih igrača i poređenja.

10. Raspored platformi i osnovna fizika

Platforme su opisane nizom:

const PLATS = [
  { x: 24, y: 156, w: 72 },
  { x: 224, y: 156, w: 72 },
  { x: 112, y: 118, w: 96 },
  { x: 8, y: 80, w: 64 },
  { x: 248, y: 80, w: 64 },
  { x: 128, y: 48, w: 64 }
];

Svaka platforma ima levu koordinatu x, gornju koordinatu y i širinu w. Na primer, { x: 24, y: 156, w: 72 } znači: počinje 24 piksela od leve ivice, 156 od gornje i široka je 72. Visinu grafičke pločice određuje crtež TILE.

Vežba: podignite srednju platformu sa y: 118 na y: 108. Ako želite novu, dodajte { x: 104, y: 174, w: 48 } pre zatvarajuće ]. Vodite računa da platforme budu u dometu skoka i ne zaklanjaju važne delove interfejsa.

Za fiziku likova važni su vx (horizontalna brzina), vy (vertikalna brzina), x, y i onGround (da li lik stoji na podlozi). Svakog koraka primenjuje se gravitacija, zatim se pozicija menja za odgovarajuću brzinu. Funkcija land() proverava da li je lik pri padu presekao nivo tla ili gornju ivicu platforme; kada jeste, spušta ga na površinu i vraća vertikalnu brzinu na nulu. Funkcija wrap() dopušta izlazak sa jedne bočne ivice i ulazak na drugu.

11. Podešavanje brzine, skoka i pucanja

U funkciji updatePlayer(p) pronađite:

const acc = p.onGround ? 0.38 : 0.24,
      max = 2.3,
      fr = p.onGround ? 0.76 : 0.95;

acc određuje ubrzanje pri pritisku tastera, max maksimalnu horizontalnu brzinu, a fr faktor usporavanja kada više ne pritiskate smer. Pošto se vx množi sa fr, vrednost bliža 1 znači sporije zaustavljanje. Primer: promenite max = 2.3 u max = 3.0 za brže igrače.

Skok određuje:

p.vy = -6.3;

Negativna brzina vodi naviše jer koordinata y raste nadole. Vrednost -7.0 daje jači skok, dok -5.5 daje slabiji. U kodu postoje i buffer (kratko pamćenje pritiska skoka) i coyote (nekoliko koraka tolerancije nakon napuštanja ivice). Oni čine upravljanje prijatnijim i nisu greške u fizici.

Funkcija shoot(p) pravi projektil sa početnom pozicijom, horizontalnom brzinom, vlasnikom i trajanjem:

p.fireCd = 26;
shots.push({
  x: p.x + (p.facing > 0 ? 11 : -5),
  y: p.y + 7,
  vx: p.facing * 4.2 + p.vx * 0.3,
  owner: p,
  life: 80,
  t: 0
});

fireCd = 26 je pauza između hitaca u koracima, a life = 80 maksimalno trajanje projektila. Manji fireCd omogućava češće pucanje; veći 4.2 brže projektile. Ipak, kod dodatno ograničava broj metaka jednog igrača na dva, pa sama promena fireCd ne garantuje da će istovremeno biti više metaka.

12. Tastatura i kontrole za dva igrača

Tasteri se čuvaju u objektima keys (da li se drže) i pressed (da li su upravo pritisnuti). Browser šalje događaje keydown i keyup.

U objektu CTRL nalaze se tri rasporeda: solo (jedan igrač), p1 (prvi igrač) i p2 (drugi igrač). Primer:

p1: {
  left: ['KeyA', 'TL'],
  right: ['KeyD', 'TR'],
  jump: ['KeyW', 'Space', 'TJ'],
  down: ['KeyS', 'TD'],
  fire: ['KeyF', 'ShiftLeft', 'TF']
}

U solo režimu igrač može koristiti i strelice; kada igraju dva igrača, broj 0 koristi pre svega A/D/W/S/F, a broj 1 strelice i ShiftRight ili Numpad0. TL, TR, TJ, TD i TF predstavljaju virtuelne mobilne komande povezane sa HTML dugmadima data-k. One se prikazuju na uređajima sa dodirnim upravljanjem.

Vežba: želite da prvi igrač puca i tasterom G? U p1.fire dodajte 'KeyG'. Zatim dopunite uputstvo za igrača u HTML kartici. Nije dovoljno samo napisati slovo G na ekranu; treba ga dodati i u JavaScript konfiguraciju.

13. Sudari, protivnici i poeni

Funkcija overlap(ax, ay, aw, ah, bx, by, bw, bh) proverava da li se dva pravougaonika preklapaju. Svaki ima početnu tačku i dimenzije. Ako se preklapaju, igra odlučuje šta se dogodilo: skupljanje paketa, pogodak projektila ili kontakt sa bagom.

U spawnPacket() nastaje paket na nasumično izabranoj platformi ili tlu. Red:

const gold = Math.random() < 0.08;

znači da približno 8% novoformiranih paketa bude zlatno. Za češće zlatne pakete promenite na 0.20 (oko 20%). To je verovatnoća pri svakom stvaranju, ne garantovani procenat u jednoj rundi.

Kada igrač pokupi paket, dobija osnovnih 10 poena, a za zlatni 50. Kombo se povećava uzastopnim brzim skupljanjem, maksimalno do ×5. U kodu:

p.combo = p.comboT > 0 ? Math.min(5, p.combo + 1) : 1;
p.comboT = 120;
award(p, k.gold ? 50 : 10, k.x + 4, k.y - 4,
      k.gold ? '#ffd23f' : '#7ff3ff');

Zašto 120? Zato što kod radi sa 60 simulacionih koraka u sekundi, pa 120 koraka daje približno dve sekunde za nastavak kombinacije.

load je traka napretka: običan paket je puni za 4, zlatni za 12. Kada dostigne 100, povećava se nivo, aktivira bonus ×2 na osam sekundi i traka kreće ponovo.

Neprijatelji „bagovi“ nastaju u spawnBug(). Skok na njih donosi 25 poena, pogodak metkom 15, a bočni kontakt oduzima do 20 već osvojenih poena. Udarac u drugog igrača prenosi 10% njegovih trenutnih poena na napadača (zaokruženo naviše), umesto da stvara nove poene.

14. Tajmer, kraj runde i procenat rezultata

Runda počinje sa:

timeLeft = ROUND * 60;

Svaki korak funkcije tickPlay() smanjuje timeLeft za jedan. Kada vrednost dođe do nule, poziva se endGame().

Na kraju igre funkcija scores() čita rezultat oba lika. Udeo svakog igrača računa se iz ukupno osvojenih, trenutno važećih poena. Na primer, ako broj 0 ima 150, a broj 1 ima 50, rezultat je 75% prema 25%. To nisu procenti glasanja niti slučajno generisani brojevi: to je udeo poena u odigranoj rundi. Kada oba igrača imaju nula poena, kod prikazuje 50%–50% kao neutralan rezultat.

Pobednička poruka zavisi od poređenja s0 i s1. Ako su jednaki, prikazuje se NERESENO!. Ako je s0 > s1, pobednik je broj 0; inače je broj 1.

15. Kako računar upravlja drugim likom?

Kada izaberete „1 IGRAC VS CPU“, funkcija startGame(1) kreira čoveka i računarskog protivnika. Protivnik dobija objekat ai, a funkcija aiThink(p) određuje njegove poteze. To nije mašinsko učenje niti spoljni AI servis: to je pravilski algoritam ugrađen u JavaScript.

Algoritam pregleda pakete, bira cilj i pomera se ka njemu; pokušava da skoči na višu platformu; može da siđe sa platforme; izbegava opasnosti; ponekad puca na drugog igrača. Odluke o nekim radnjama koriste Math.random(), pa protivnik ne odigrava svaku rundu identično.

Za početnike je najbolje da najpre pronađu uslove if unutar aiThink i menjaju samo jednu verovatnoću. Na primer, deo Math.random() < 0.07 kontroliše šansu da protivnik pokuša pucanje kada su ispunjeni i drugi uslovi. Povećavanje na 0.15 čini takve pokušaje češćim, ali nije direktno „15% pogodaka“.

16. Crtanje pozadine i animacija

Pozadina se ne sastoji od jedne velike fotografije. Funkcija drawBG() crta nijanse neba i pomera slojeve CLOUDS, MOUNT i HILLS. Svaki sloj ima svoju brzinu pomeranja, pa bliski objekti prolaze brže od udaljenih. To zovemo paralaksni efekat.

Funkcija drawPlats() crta platforme, drawPlayer() likove, drawPacket() pakete, drawBug() neprijatelje, drawHUD() rezultat i vreme, a drawTitle() početni meni. Glavna funkcija render() bira šta je u tom trenutku vidljivo.

Zašto imamo odvojeno update() i render()? update() menja stanje sveta (pozicija, vreme, poeni), a render() prikazuje trenutno stanje na ekranu. Ova podela je osnovno pravilo dobrog dizajna igre i olakšava otkrivanje grešaka.

17. Šta su stanja igre?

Promenljiva state može da ima sledeće vrednosti:

Stanje Značenje
title početni meni
ready odbrojavanje pre početka
play aktivna igra
pause pauza
over kraj runde i rezultati

Funkcija startGame(m) postavlja igrače, čisti prethodne objekte, resetuje vreme i prelazi u ready. togglePause() zaustavlja ili nastavlja igru. endGame() prikazuje rezultat i ažurira rekord. Ako dodajete nova stanja (npr. „instrukcije“), potrebno je prilagoditi i update() i render().

18. Dodavanje zvučnih efekata i muzike

Zvuk se generiše pomoću Web Audio API-ja. Funkcija tone() kreira oscilator, određuje frekvenciju, talasni oblik, jačinu i trajanje. Objekat sfx sadrži zvuke skoka (jump), paketa (coin), pogotka (hurt), pucanja (shoot) i drugih događaja.

Na primer:

jump: () => tone(260, 0.13, 'square', 0.04, 380)

Parametri su početna frekvencija, trajanje u sekundama, tip talasa, jačina i pomeraj frekvencije. U browserima je uobičajeno da zvuk postane dostupan tek nakon korisnikove interakcije (klik ili pritisak tastera), zbog čega se ensureAudio() poziva pri unosu.

M uključuje i isključuje zvuk. Muziku pokreće startMusic(), a zaustavlja stopMusic(). Ako menjate muzički korak STEP, promenićete ritam. Za učenje preporučujemo da prvo eksperimentišete sa glasnoćom pojedinačnih efekata.

19. Čuvanje rekorda i podešavanja

Igra koristi localStorage pregledača za rekord i isključen zvuk:

let hiscore = store.get('rat_brojeva_hi', 0);
let muted = store.get('rat_brojeva_mute', false);

Ovo čuva vrednosti lokalno na uređaju i u pregledaču u kojem igrate. Nije internet baza podataka; drugi računar neće automatski imati isti rekord. U privatnom režimu ili pri zabrani čuvanja podataka, ponašanje može biti ograničeno, pa je kod zaštićen try/catch blokovima.

Ako želite da počnete sa novim rekordom tokom razvoja, možete u konzoli pregledača izvršiti localStorage.removeItem('rat_brojeva_hi') pa osvežiti stranicu. Ovo ne menja postignute rekorde drugih korisnika.

20. Prilagođavanje telefonu i većem ekranu

Canvas ima internu rezoluciju 320 × 224, ali funkcija fit() izračunava odgovarajuću prikaznu veličinu prema širini raspoloživog prostora i visini prozora. image-rendering: pixelated sprečava zamućenje pri uvećavanju. Dodirne komande prikazuju se pomoću CSS pravila @media (pointer:coarse).

Ako menjate veličinu interne igre, nije dovoljno samo uvećati CSS: proverite koordinate svih grafičkih elemenata, platformi, početnih položaja i interfejsa. Za početnike je korisnije da veličina platna ostane ista, a da se menjaju boje, raspored platformi i pravila.

21. Ugradnja igre na WordPress ili drugi sajt

Datoteku index.html možete otpremiti u poseban direktorijum sajta, na primer https://vas-domen.rs/igre/rat-brojeva/. Ako imate pristup serveru, u taj direktorijum postavite datoteku pod imenom index.html.

Zatim u WordPress HTML blok ili Elementor HTML widget dodajte:

<iframe
  src="https://vas-domen.rs/igre/rat-brojeva/"
  title="Rat brojeva – arkadna igra"
  style="width:100%;height:760px;border:0;border-radius:12px"
  loading="lazy"
  allow="autoplay">
</iframe>

Zamenite primer URL-a stvarnom adresom. Visinu 760px prilagodite dizajnu svoje stranice. Ugradnja u iframe odvaja CSS i JavaScript igre od ostatka WordPress teme. Neki sajtovi imaju ograničenja iframe učitavanja; tada proverite bezbednosna zaglavlja i politiku ugradnje, umesto da isključujete zaštitu bez razumevanja posledica.

U originalnom projektu postoji i napredni mehanizam kojim portal šalje igri signal da je neki drugi sadržaj spreman. To se radi preko postMessage; obična samostalna igra ne zahteva ovaj dodatak.

22. Najčešće greške i kako ih rešiti

Prazan ekran: proverite da li postoji <canvas id="game"> i da li JavaScript traži isti id. Otvorite Developer Tools (F12) i pogledajte karticu Console. JavaScript sintaksne greške se najčešće prikazuju crvenom bojom.

Lik se ne pomera: kliknite na igru, proverite da li su unosi dodati u objekat CTRL i da li ste taster zapisali kao KeyA, ne kao samo A.

Platforma je vidljiva, ali na nju ne može da se skoči: proverite njen x, y i w, visinu skoka i uslove u land(). Važno je i da igrač dolazi na platformu odozgo, dok pada.

Naziv se nije promenio svuda: pretražite kompletan fajl (Ctrl+F) za starim tekstom; neke oznake se crtaju direktno u JavaScript-u, ne u HTML-u.

Promene nisu vidljive: sačuvajte fajl i uradite Ctrl+F5. Ako koristite lokalni ili serverski keš, proverite da li ste otvorili ispravnu kopiju index.html.

Zvuk ne radi: kliknite ili pritisnite taster u igri, proverite dugme M i podešavanja zvuka pregledača.

Igra je prebrza na monitoru velike frekvencije: početnička mini-igra iz poglavlja 5 koristi jednu simulaciju po animacionom frejmu. Gotova verzija koristi fiksni vremenski korak od 60 simulacija u sekundi; za ozbiljniji projekat upotrebite takvo rešenje.

23. Velika mapa: gde se šta podešava u gotovoj igri?

Šta želite da promenite Gde tražite Primer
Naziv i opis igre HTML <title>, <h1>, tekst uz naslov Rat brojeva
Nazive i boje timova JavaScript SIDE BROJ 0 / BROJ 1
Izgled likova PAL, MAPS, FEET, EYES nova boja ili piksel
Dužinu runde ROUND 60 → 90
Gravitaciju GRAV 0.35 → 0.45
Brzinu trčanja updatePlayer, max 2.3 → 3.0
Jačinu skoka updatePlayer, p.vy = -6.3 -6.3 → -7
Platforme PLATS promenite x, y, w
Tastere CTRL i HTML kartice pomoći dodajte KeyG
Brzinu i interval pucanja shoot, fireCd 26 → 18
Šansu zlatnog paketa spawnPacket, Math.random() 0.08 → 0.20
Broj aktivnih paketa tickPlay, maxPk 5 → 7
Količinu neprijatelja tickPlay, maxBugs prilagodite formulu
Bodovanje award, sudari u tickPlay 10 → 15 poena
Kombo p.combo, p.comboT ×5 → ×3, 120 → 180
Bonus load, bonusT ×2 tokom 8 s
Pamet protivnika aiThink cilj, skok, pucanje
Rezultat na ekranu drawHUD, render boje, tekst, procenat
Nebo, brda, oblake SKY, CLOUDS, MOUNT, HILLS, drawBG nova paleta
Zvuk i muziku tone, sfx, STEP, startMusic druga frekvencija
Čuvanje rekorda store, hiscore ključ u localStorage
Mobilni prikaz CSS .touch, @media, fit() veličina dugmadi

Napomena za izmene: preporučene vrednosti su primeri za učenje, ne nezavisna dugmad u podešavanjima. Posle svake promene testirajte da li i dalje rade skok, sudari, ekran rezultata i solo/duo režim.

24. Samostalni zadaci – proverite šta ste naučili

Zadatak 1 – Lako: promenite pozadinu stranice i boju broja 0. Objasnite razliku između CSS boja i boja koje crta JavaScript.

Zadatak 2 – Lako: produžite rundu na 90 sekundi. Napišite zbog čega se u kodu koristi ROUND * 60.

Zadatak 3 – Srednje: dodajte novu platformu, tako da joj igrač može pristupiti skokom sa tla.

Zadatak 4 – Srednje: omogućite pucanje tasterom G, ali samo za prvog igrača.

Zadatak 5 – Srednje: promenite vrednost običnog paketa sa 10 na 15 i zlatnog sa 50 na 75 poena, pa proverite da li kombo i bonus pravilno računaju ukupne poene.

Zadatak 6 – Teže: smanjite verovatnoću pucanja CPU protivnika i povećajte šansu pojavljivanja zlatnog paketa. Odigrajte pet rundi i zabeležite rezultat.

Zadatak 7 – Teže: pokušajte da napravite treći vizuelni stil lika. Promenite boju, oblike očiju i način animacije nogu, bez narušavanja dimenzija sprite-a.

Zadatak 8 – Izazov: dodajte izbor „laka / normalna / teška“ za solo režim. Za početak podesite različite verovatnoće CPU pucanja i brzine njegovog reagovanja. Novu opciju dodajte i na početni ekran.

25. Šta dalje?

Sada znate kako se od nekoliko HTML elemenata, CSS pravila i JavaScript funkcija pravi interaktivni svet. Najvažnije nije da napamet naučite svih skoro hiljadu redova gotove igre, već da razumete šta je stanje igre, kako funkcioniše petlja, kako se lik kreće, kako se otkrivaju sudari i gde se menjaju pravila.

Predlog sledećeg projekta: napravite igru „Skupljač zvezda“ u kojoj samo jedan lik sakuplja predmete u vremenskom ograničenju. Zatim joj dodajte prepreke, tri nivoa težine i lokalnu tabelu rekorda. Kada te korake možete da izvedete samostalno, spremni ste za složenije 2D igre.

Vaša privatnost nam je važna

Koristimo neophodne kolačiće da bi sajt i forme za upit ispravno radili, a uz vašu dozvolu i opcionalne kolačiće za analitiku, personalizaciju i marketing. Saznajte više.