5. Fázis · Haladó
5. Fázis · 46. Lecke

💾 localStorage — Mentés a böngészőben

A böngésző tartósan megőrzhet adatokat — felhasználói adatbázis, szerver és internet nélkül. A Castle Siege és a Galactic Conquest ezt használja a pályahaladás és a ranglista mentéséhez.

⏱ 60 perc
📁 localStorage API
🎯 JSON.stringify · JSON.parse · setItem · getItem

1Mi az a localStorage?

🌐 Böngésző API

A localStorage egy kulcs-érték tárhely, amely a böngészőben él, az oldalzárás után is megmarad. Olyan mint egy mini adatbázis, amelyhez JavaScript-ből lehet hozzáférni — szerveroldal nélkül.

HelyszínMegmarad bezárás után?MéretMire jó?
let x = 5❌ NemkorlátlanFutás közbeni adat
sessionStorage❌ Nem (tab záráskor törlődik)~5 MBIdeiglenes munkamenet
localStorage✅ Igen~5 MBMentés, beállítások, ranglista
Szerver adatbázis✅ IgenkorlátlanTöbb felhasználó, szinkronizálás

Az 5 alapfüggvény

localStorage — az 5 alapfüggvényJavaScript
// MENTÉS — szöveget ment kulcs-érték párként
localStorage.setItem('jatekos_neve', 'Zoli');

// OLVASÁS — visszaadja az értéket (vagy null-t, ha nem létezik)
const nev = localStorage.getItem('jatekos_neve'); // 'Zoli'

// TÖRLÉS — egy kulcs törlése
localStorage.removeItem('jatekos_neve');

// ÖSSZES TÖRLÉSE — veszélyes! mindent töröl
localStorage.clear();

// KULCSOK SZÁMA
const darab = localStorage.length; // hány kulcs van elmentve
Fontos: csak szöveget tárol!

A localStorage mindig szöveget (string) vár és ad vissza. Számokat és objektumokat JSON-né kell alakítani. Ezért kell a JSON.stringify() és JSON.parse().

2JSON — objektumok mentése

A játékállapot összetett objektum: pályaszám, arany, tornyok, beállítások. Ezt egyetlen szövegként kell elmenteni — ezt csinálja a JSON.

castle_siege.html — mentés és betöltésJavaScript
// ─── MENTÉS ───────────────────────────────────────────────
function saveGame() {
  const mentett = {
    level:    G.level,      // jelenlegi pálya
    gold:     G.gold,       // arany
    highscore: G.highscore  // legjobb eredmény
  };
  // Objektum → szöveg (JSON)
  const szoveg = JSON.stringify(mentett);
  // Szöveg → localStorage
  localStorage.setItem('castle_siege_save', szoveg);
  console.log('Elmentve!', szoveg);
  // Például: '{"level":7,"gold":340,"highscore":12500}'
}

// ─── BETÖLTÉS ─────────────────────────────────────────────
function loadGame() {
  const szoveg = localStorage.getItem('castle_siege_save');
  // Ha nincs mentett állás, null-t kapunk
  if (!szoveg) {
    console.log('Nincs mentett játék.');
    return;
  }
  // Szöveg → Objektum (JSON)
  const mentett = JSON.parse(szoveg);
  G.level     = mentett.level;
  G.gold      = mentett.gold;
  G.highscore = mentett.highscore;
  console.log('Betöltve! Pálya: ' + G.level);
}
JSON.stringify vs JSON.parse — egymás fordítottjai

stringify(obj) → objektumból szöveget csinál. parse(str) → szövegből objektumot csinál. Ha stringify-vel mentettük, parse-szal kell olvasni.

Biztonságos betöltés — mindig try-catch

Hibabiztos betöltésJavaScript
function loadGame() {
  try {
    const str = localStorage.getItem('castle_siege_save');
    if (!str) return false; // nincs mentés
    const d = JSON.parse(str);
    // Ellenőrzés: érvényes-e a mentett adat?
    if (typeof d.level !== 'number') return false;
    G.level = d.level;
    G.gold  = d.gold || 100; // alapérték, ha hiányzik
    return true;
  } catch(e) {
    // Sérült JSON esetén nem omlik össze a játék
    console.warn('Betöltési hiba:', e);
    localStorage.removeItem('castle_siege_save');
    return false;
  }
}
Miért kell try-catch?

Ha a localStorage-ban lévő szöveg sérült (pl. félbe szakadt mentés, más oldalról átírt adat), a JSON.parse() kivételt dob és a játék összeomlik. A try-catch elkapja a hibát és biztonságosan kezeli.

3Automatikus mentés — autosave

🏰 Castle Siege
castle_siege.html — autosaveJavaScript
// Minden pályaváltáskor automatikusan ment
function nextLevel() {
  G.level++;
  G.gold += 50;        // jutalomra arany
  saveGame();          // ← autosave minden szint után
  genLevel(G.level);   // pályagenerálás
}

// Játék indításakor betöltés
window.addEventListener('load', () => {
  const ok = loadGame();
  if (ok) {
    showMessage('Üdv vissza! ' + G.level + '. pályánál tartasz.');
  }
  genLevel(G.level);
});
✏️ Feladat

Nyisd meg a castle_siege.html-t VS Code-ban, és keresd meg a localStorage hívásokat:

  • Nyomj F12-t böngészőben, majd Application → Local Storage — látod a mentett adatot?
  • Játssz le 2 pályát, majd frissítsd az oldalt — visszatér a pályádra?
  • Írj egy clearSave() függvényt, ami törli a mentést és visszaállítja az 1. pályát
  • Add hozzá ezt egy "Új játék" gombhoz

🧠 Mit ad vissza a localStorage.getItem('kulcs'), ha a kulcs nem létezik?

Üres string ("")
0
null
undefined
5. Fázis · 47. Lecke

🏆 Top 10 ranglista implementálása

Tömb rendezés, slice(), és localStorage kombinációja — így tároljuk a legjobb eredmények listáját névvel és pontszámmal. A Galactic Conquest ranglistája alapján tanulunk.

⏱ 45 perc
🎯 sort() · slice() · tömb rendezés

1A ranglista adatszerkezete

🚀 Galactic Conquest

A ranglista egy tömb, amelynek minden eleme egy objektum: {name, score, date}. A legjobb 10-et tároljuk — rendezve, pontszám szerint csökkenő sorrendben.

galactic_conquest.html — ranglistaJavaScript
// Ranglista betöltése localStorage-ból
function loadScores() {
  try {
    const str = localStorage.getItem('galactic_scores');
    return str ? JSON.parse(str) : [];
  } catch { return []; }
}

// Új eredmény hozzáadása a ranglistához
function addScore(name, score) {
  const scores = loadScores();

  // 1. Hozzáadjuk az új eredményt
  scores.push({
    name:  name,
    score: score,
    date:  new Date().toLocaleDateString('hu-HU')
  });

  // 2. Rendezés: pontszám szerint csökkenő (b-a = nagyobb előre)
  scores.sort((a, b) => b.score - a.score);

  // 3. Csak a legjobb 10-et tartjuk meg
  const top10 = scores.slice(0, 10);

  // 4. Visszamentjük
  localStorage.setItem('galactic_scores', JSON.stringify(top10));
  return top10;
}
sort() — hogyan működik a rendezés?

Az array.sort((a, b) => b.score - a.score) összehasonlít két elemet. Ha az eredmény negatív, a csere nem történik meg. Ha pozitív, felcseréli őket. A b - a képlet mindig a nagyobb értéket rakja előre (csökkenő sorrend).

A slice() — csak a legjobbak

slice() és sort() összehasonlítvaJavaScript
const pontok = [300, 1200, 850, 75, 2100, 440];

// sort: helyben rendez, az eredeti tömböt módosítja
pontok.sort((a, b) => b - a);
// → [2100, 1200, 850, 440, 300, 75]

// slice(start, end): másolatot ad, nem módosítja az eredetit
const top3 = pontok.slice(0, 3); // → [2100, 1200, 850]
// Az eredeti pontok tömb változatlan!

// Különbség splice vs slice:
// splice → módosítja az eredetit (és elemeket tud törölni/szúrni)
// slice  → csak másolatot ad, az eredetit nem bántja

2A ranglista megjelenítése HTML-ben

galactic_conquest.html — ranglista rajzolásJavaScript
// A ranglista kirajzolása a canvasra
function drawLeaderboard() {
  const scores = loadScores();
  const medaliok = ['🥇', '🥈', '🥉'];

  ctx.fillStyle = 'rgba(0,0,0,0.85)';
  ctx.fillRect(0, 0, W, H);    // sötét háttér

  ctx.font = 'bold 28px Inter';
  ctx.fillStyle = '#ffe066';
  ctx.fillText('🏆 TOP 10', W/2, 60);

  scores.forEach((s, i) => {
    const y = 110 + i * 36;
    // Kiemelés az első háromnak
    ctx.fillStyle = i < 3 ? '#fff' : '#8895aa';
    ctx.font = i < 3 ? 'bold 18px Inter' : '16px Inter';
    // Medál az első 3-nak, szám a többinek
    const prefix = i < 3 ? medaliok[i] : `${i+1}. `;
    ctx.fillText(`${prefix} ${s.name} ${s.score} pont`, 60, y);
    // Dátum jobb oldalon
    ctx.fillStyle = '#4a6272';
    ctx.font = '13px Inter';
    ctx.fillText(s.date, W - 110, y);
  });
}
✏️ Feladat

Építs egy egyszerű ranglista rendszert:

  • Hozz létre egy addScore('Teszt', 9999) hívást, és nézd meg F12 → Application → Local Storage-ban az eredményt
  • Hívd meg 5-ször különböző nevekkel és pontokkal — mi marad meg?
  • Módosítsd úgy, hogy Top 5-öt tároljon Top 10 helyett
  • Adj hozzá egy szűrőt: ugyanaz a név csak egyszer szerepelhet (a jobb eredményével)

🧠 Mit csinál az [5,2,8,1].sort((a,b) => b - a) hívás?

[1, 2, 5, 8] — növekvő sorrendbe rendez
[8, 5, 2, 1] — csökkenő sorrendbe rendez
Nem módosítja a tömböt, csak másolatot ad
Hibát dob, mert a sort() nem kap összehasonlító függvényt
5. Fázis · 48. Lecke

🔊 Web Audio API — Zene és hangeffektek

Hang lejátszása böngészőben három megközelítéssel: HTML5 Audio elem, beágyazott base64 hang, és a haladó AudioContext API. Miért nem elég mindig a legegyszerűbb megoldás?

⏱ 75 perc
📁 new Audio() · AudioContext
🎯 base64 hang · play() · resume()

1A legegyszerűbb: new Audio()

🐸 Froggy Rush

Az Audio objektum a böngésző beépített hanglejátszója. Egy fájlnevet kap, és azonnal tudja lejátszani.

Egyszerű hang lejátszásJavaScript
// Hang betöltése fájlból
const bgm = new Audio('frog_music1.mp3');
bgm.loop   = true;    // ismétlés bekapcsolva
bgm.volume = 0.6;    // hangerő: 0.0 – 1.0

// Lejátszás — fontos: felhasználói interakció kell!
document.addEventListener('click', () => {
  bgm.play().catch(e => console.warn('Hang hiba:', e));
}, { once: true }); // csak az első kattintásra

// Megállítás és visszatekerés
bgm.pause();
bgm.currentTime = 0; // visszatekerés az elejére
Autoplay tiltás — miért kell a kattintás?

A böngészők 2018 óta blokkolják az automatikus hanglejátszást — a felhasználónak előbb interakcióba kell lépni az oldallal (kattintás, billentyű). Ezért a legtöbb játékban az első kattintásra indul el a zene.

2Base64 hang beágyazás — mobil megoldás

🏰 Castle Siege

Android esetén a böngésző sokszor nem tölti be a külső mp3 fájlt — különösen ha a játék lokálisan (fájlrendszerből, szerver nélkül) fut. A megoldás: a hangot beágyazzuk közvetlenül a HTML fájlba, base64 kódolással.

castle_siege.html — base64 hangJavaScript
// A base64 kód így néz ki (lerövidítve):
// data:audio/mp3;base64,SUQzBAAAAAAAI1RTU0UAAAAPAAADTGF2...
// (valójában százezres karakterhossz — a teljes hangfájl)

// Ezt az Audio objektumnak adjuk forrásként
const MUSIC_DATA = 'data:audio/mp3;base64,SUQzBAAA...'; // a teljes adat
const bgm = new Audio(MUSIC_DATA);
bgm.loop = true;

// A hangeffektek is ugyanígy — kis hangok base64-ben
const SFX_HIT  = new Audio('data:audio/wav;base64,UklGRiQ...');
const SFX_GOLD = new Audio('data:audio/wav;base64,UklGRjQ...');

// Hangeffekt lejátszása (clone → egyszerre több is szólhat)
function playSound(audio) {
  const klon = audio.cloneNode();
  klon.volume = 0.7;
  klon.play().catch(() => {});
}

Hogyan kódolunk hangot base64-be?

Konvertálás — Node.js parancssori szkriptJavaScript
// Futtasd ezt Node.js-sel: node convert.js
const fs = require('fs');
const data = fs.readFileSync('zene.mp3');
const b64  = 'data:audio/mp3;base64,' + data.toString('base64');
fs.writeFileSync('zene_b64.txt', b64);
console.log('Kész! Méret: ' + b64.length + ' karakter');

// Alternatíva: böngészőben, drag & drop megoldás
// → btoa() függvény nem jó mp3-ra, mert bináris adat
// → FileReader API-t kell használni böngészőben:
const reader = new FileReader();
reader.onload = e => console.log(e.target.result); // a b64 szöveg
reader.readAsDataURL(fajl); // fajl = input[type=file] .files[0]
cloneNode() — miért kell?

Ha ugyanazt az Audio objektumot játszod le kétszer egymás után gyorsan (pl. két ellenség egyszerre hal meg), a második play() az első végére ugrik. A cloneNode() egy másolatot hoz létre — így egyszerre több hangeffekt is szólhat párhuzamosan.

3AudioContext — haladó hangkezelés

Az AudioContext a böngésző teljes hangszerkesztő rendszere: hangerő-szabályozás, effektek, keverés, szintetizált hangok generálása. A játékfejlesztésben főleg a hangerőhöz és a zenei effektekhez használjuk.

Szintetizált hangeffekt — nem kell hangfájlJavaScript
// Létrehozzuk a hangrendszert
const actx = new AudioContext();

// Szintetizált "érem összegyűjtve" hang — hangfájl nélkül!
function beep(hz = 440, hossz = 0.15, hanger = 0.3) {
  const osc  = actx.createOscillator();  // rezgés generátor
  const gain = actx.createGain();        // hangerő szabályozó

  osc.connect(gain).connect(actx.destination);
  osc.frequency.value = hz;       // 440 Hz = A hang (A4)
  osc.type = 'sine';             // hullámforma: sine / square / sawtooth
  gain.gain.value = hanger;       // hangerő

  // Elhalkulás a végén (envelope)
  gain.gain.exponentialRampToValueAtTime(0.001, actx.currentTime + hossz);

  osc.start();
  osc.stop(actx.currentTime + hossz);
}

// Felhasználás:
beep(880, 0.1);  // éles pip — pont szerzés
beep(220, 0.4);  // mély búgás — életvesztés
beep(1047, 0.2); // magas csing — pálya teljesítve
Mikor melyiket?

new Audio(fájl) — egyszerű hangok, külső mp3/wav fájlokból.
new Audio(base64) — mobil/offline kompatibilis, fájl nélkül.
AudioContext beep() — szintetizált hangok, hangfájl nélkül, kis méretű játékokhoz.

✏️ Feladat

Adj hangot a saját mini játékodhoz:

  • Hozz létre egy beep() függvényt a fenti kód alapján
  • Szólaltasd meg pontszerzéskor (magas hang) és életerő-vesztéskor (mély hang)
  • Nyisd meg az F12 → Console-t — kapsz-e "AudioContext was not allowed to start" figyelmeztetést?
  • Javítsd ki: az AudioContext induljon el egy kattintás eseményből

🧠 Miért nem elég az audio.play() a játék indulásakor?

Mert az Audio objektum csak base64 adatot fogad el
Mert a play() csak mp3 fájlokkal működik
Mert a böngésző blokkolja az automatikus hanglejátszást — felhasználói interakció (kattintás) szükséges előtte
Mert az Audio objektum nem elérhető a window.load esemény előtt
5. Fázis · 49. Lecke

📱 Mobilos D-pad és érintésvezérlés

A játékokat mobilon is játszani kell — de billentyűzet nincs. A megoldás: canvas fölé rajzolt irányítógombok, amelyek touch eseményekre reagálnak. Így csináltuk a Froggy Rush és Castle Siege mobilos irányítóját.

⏱ 90 perc
🎯 touchstart · touchend · pointer events
📁 D-pad · virtuális billentyűzet

1Touch vs Pointer events — melyiket használjuk?

Esemény típusKompatibilitásElőnyHátrány
touchstart / touchendCsak érintőképernyőRégebbi eszközök isKülön egér és touch kód kell
pointerdown / pointerupEgér + érintő + tollEgy kód mindháromhozIE11 nem támogatja
clickMindenholLegegyszerűbb~300ms késés mobilon, multi-touch nincs
Ajánlás: pointer events

Modern játékokhoz a pointerdown / pointerup / pointermove eseményeket ajánlott használni — ezek egységesen működnek egérrel és érintőképernyővel is, egy kódbázissal.

2A D-pad implementációja

🐸 Froggy Rush
🏰 Castle Siege
froggy_rush.html — D-pad setupJavaScript
// ─── 1. A D-PAD GOMBOK DEFINÍCIÓJA ─────────────────────────
const DPAD = [
  { id: 'up',    x:75,  y:40,  w:50, h:50, label:'▲' },
  { id: 'down',  x:75,  y:140, w:50, h:50, label:'▼' },
  { id: 'left',  x:20,  y:90,  w:50, h:50, label:'◀' },
  { id: 'right', x:130, y:90,  w:50, h:50, label:'▶' },
];
// Melyik gombok vannak lenyomva
const pressed = new Set();

// ─── 2. CANVAS KOORDINÁTA SZÁMÍTÁS ────────────────────────
function getCanvasPos(e) {
  const r = canvas.getBoundingClientRect();
  // Méretarány: ha a canvas CSS-ben más méretű
  const scaleX = canvas.width  / r.width;
  const scaleY = canvas.height / r.height;
  return {
    x: (e.clientX - r.left) * scaleX,
    y: (e.clientY - r.top)  * scaleY
  };
}

// ─── 3. HIT-TEST: melyik gombra kattintottak? ──────────────
function hitDpad(px, py) {
  // D-pad a canvas bal-alsó sarkában van
  const offX = 10, offY = H - 200; // D-pad bal-felső sarokpontja
  for (const btn of DPAD) {
    if (px >= offX+btn.x && px <= offX+btn.x+btn.w &&
        py >= offY+btn.y && py <= offY+btn.y+btn.h) {
      return btn.id;  // 'up', 'down', 'left' vagy 'right'
    }
  }
  return null;
}

// ─── 4. ESEMÉNYKEZELŐK ────────────────────────────────────
canvas.addEventListener('pointerdown', e => {
  e.preventDefault(); // scroll blokkolása
  const pos = getCanvasPos(e);
  const btn = hitDpad(pos.x, pos.y);
  if (btn) pressed.add(btn);
});

canvas.addEventListener('pointerup', e => {
  const pos = getCanvasPos(e);
  const btn = hitDpad(pos.x, pos.y);
  if (btn) pressed.delete(btn);
});

// A game loop-ban: pressed tartalmazza az aktív gombokat
function update() {
  if (pressed.has('left')  || K.left)  p.vx -= 0.8;
  if (pressed.has('right') || K.right) p.vx += 0.8;
  if (pressed.has('up')    || K.up)    jump();
}
Set vs tömb — miért Set a pressed-hez?

A Set automatikusan szűri a duplikátumokat: ha kétszer nyomod le az "up" gombot, csak egyszer szerepel. Az add() és has() műveletek O(1) gyorsak. Tömbbel ugyanez lehetséges, de Set-tel tisztább és gyorsabb.

3A D-pad kirajzolása canvasra

D-pad rajzolásJavaScript
function drawDpad() {
  // Csak mobilon jelenjen meg
  if (!isMobile()) return;

  const offX = 10, offY = H - 200;

  for (const btn of DPAD) {
    const bx = offX + btn.x, by = offY + btn.y;
    // Lenyomott gomb: más szín
    ctx.fillStyle = pressed.has(btn.id)
      ? 'rgba(255,154,60,0.7)'   // lenyomott: narancssárga
      : 'rgba(255,255,255,0.12)'; // alapállapot: félig átlátszó

    // Lekerekített téglalap (roundRect)
    ctx.beginPath();
    ctx.roundRect(bx, by, btn.w, btn.h, 10);
    ctx.fill();

    // Keret
    ctx.strokeStyle = 'rgba(255,255,255,0.25)';
    ctx.lineWidth = 1.5;
    ctx.stroke();

    // Nyíl ikon
    ctx.fillStyle = 'rgba(255,255,255,0.8)';
    ctx.font = 'bold 20px Inter';
    ctx.textAlign = 'center';
    ctx.textBaseline = 'middle';
    ctx.fillText(btn.label, bx + btn.w/2, by + btn.h/2);
  }
}

// Mobilfelismerés
function isMobile() {
  return 'ontouchstart' in window || navigator.maxTouchPoints > 0;
}

Multitouch — egyszerre több gomb

Pointer capture — multitouch kezelésJavaScript
// Minden pointer (ujj) kap egy ID-t
const activePointers = new Map(); // pointerId → dpad gomb

canvas.addEventListener('pointerdown', e => {
  e.preventDefault();
  const pos = getCanvasPos(e);
  const btn = hitDpad(pos.x, pos.y);
  if (btn) {
    activePointers.set(e.pointerId, btn); // megjegyezzük melyik ujj melyik gombon
    pressed.add(btn);
  }
});

canvas.addEventListener('pointerup', e => {
  const btn = activePointers.get(e.pointerId); // melyik gombhoz tartozik ez az ujj?
  if (btn) {
    pressed.delete(btn);
    activePointers.delete(e.pointerId);
  }
});
✏️ Feladat

Add hozzá a mobilos D-pad-et a saját játékodhoz:

  • Húzd be a DPAD definíciót és a pressed Set-et
  • Regisztráld a pointerdown és pointerup eseményeket
  • A drawDpad()-et hívd meg a draw() végén
  • Teszteld Chrome DevTools → Toggle Device Toolbar (Ctrl+Shift+M) — megjelenik a D-pad?

🧠 Miért Set-et használunk a lenyomott gombok tárolásához?

Mert a Set gyorsabb, mint az objektum
Mert a Set automatikusan kiszűri a duplikátumokat — ha kétszer nyomod le ugyanazt a gombot, csak egyszer szerepel; és has() / add() / delete() műveletei egyszerűek
Mert a tömb nem tud string értékeket tárolni
Mert a Set aszinkron — nem blokkolja az animációt
5. Fázis · 50. Lecke

🚀 Deploy — A játék felkerül az internetre

Az elkészült játékot mindenki ki tudja próbálni a saját telefonján egy link segítségével — szerver, tárhely, programozói tudás nélkül. A Netlify ingyenes és drag-and-drop egyszerűségű.

⏱ 30 perc
🎯 Netlify · statikus hosting · egyedi URL

1Mi az a statikus hosting?

A játékaink statikus fájlok: HTML, CSS, JavaScript — nincs adatbázis, nincs szerver oldali kód. Egy statikus hosting szolgáltatás egyszerűen kiszolgálja ezeket a fájlokat a böngészőnek, mindenki számára elérhetővé téve őket.

SzolgáltatásIngyenes csomagNehézségMegjegyzés
Netlify✅ Igen, korlátlan⭐ LegkönnyebbDrag & drop, egyedi domain lehetséges
GitHub Pages✅ Igen⭐⭐ KönnyűGitHub fiók kell, git push
Vercel✅ Igen⭐⭐ KönnyűFejlesztőknek, automatikus deploy
itch.io✅ Igen⭐ LegkönnyebbKifejezetten játékokhoz, közösség

2Netlify — lépésről lépésre

1
Fiók létrehozása

Látogasd meg a netlify.com oldalt, kattints a "Sign up" gombra. Ingyenes fiókot hozhatsz létre Google vagy GitHub-fiókoddal is.

2
A mappa előkészítése

Győződj meg róla, hogy minden szükséges fájl egy mappában van: index.html, a játék html fájljai, és az mp3 zenék.

3
Drag & Drop feltöltés

A Netlify főoldalán a "Sites" fülön van egy "Drop your site folder here" terület. Húzd rá a teljes projekt mappát erre a területre.

4
Az egyedi URL megszerzése

Néhány másodperc után kapsz egy linket: valami-nev-12345.netlify.app. Ez az oldalad URL-je — bárki elérheti!

5
Saját név beállítása (opcionális)

Site settings → Domain management → Options → Edit site name. Legyen pl. froggy-rush-zoli.netlify.app.

Frissítés — új verzió feltöltése

Ha változtatás után újra fel kell tölteni: a Netlify admin felületen a "Deploys" fülön van egy "Drop your site folder here" terület — ugyanúgy drag & drop-al. Ugyanaz az URL marad, automatikusan frissül.

3Ellenőrzési lista telepítés előtt

Mielőtt feltöltesz, ellenőrizd a következőket:

  • A főoldal neve index.html — ez nyílik meg automatikusan
  • Minden fájlnév kisbetűs, ékezet nélkül, szóköz nélkül (froggy_rush.html ✅, Froggy Rush.html ❌)
  • A hangfájlok base64-be ágyazva vannak, vagy a megfelelő alkönyvtárban vannak
  • Az összes relatív hivatkozás helyes (href="https://superlative-pothos-2c7d49.netlify.app" target="_blank" rel="noopener" nem href="C:/Users/zoli/castle_siege.html")
  • A játékot tesztelted Chrome és Firefox böngészőkben
  • Megnyitottad mobilon (Chrome DevTools → Ctrl+Shift+M) és a D-pad működik
  • A localStorage mentés és betöltés tesztelve van

4Itch.io — játékok megosztása játékosoknak

Az itch.io egy indie játék platform — ha nemcsak link formájában, hanem egy dedikált játékoldalon szeretnéd megosztani a játékot, ez a legjobb választás.

itch.io feltöltés — zip-be csomagolásbash
# Windows: jobb klikk a mappán → Küldés → Tömörített (zip) mappa
# Mac:     jobb klikk → Compress
# Linux:   zip -r jatek.zip jatek_mappa/

# Az itch.io-n:
# 1. Regisztrálj (ingyenes)
# 2. "Create new project" → Pricing: Free
# 3. Kind of project: HTML
# 4. Uploads: feltöltöd a zip-et, pipálod: "This file will be played in the browser"
# 5. Viewport dimensions: 480×700 (portrait) vagy 800×600 (landscape)
# 6. Save & publish → kész!

# A játékod elérhető lesz: https://felhasznalonev.itch.io/jatek-neve
✏️ Feladat — Az igazi végső feladat

Töltsd fel a saját játékodat az internetre:

  • Regisztrálj a Netlify-on (ingyenes)
  • Győződj meg róla, hogy az index.html a főoldal
  • Húzd rá a mappát a Netlify drop területére
  • Másold ki a kapott URL-t és küldd el egy barátodnak mobilon
  • Bónusz: állíts be saját nevet az oldalnak

🧠 Miért fontos, hogy a főoldal neve pontosan index.html legyen?

Mert a Netlify csak ezt a fájlnevet fogadja el
Mert ha egy böngésző mappát kér (pl. froggy-rush.netlify.app/), a webszerver automatikusan az index.html fájlt keresi és szolgálja ki — ez az egyezményes "belépési pont"
Mert a JavaScript csak index.html fájlból töltődik be helyesen
Nincs különösebb oka — bármi megfelelne
🏆

Gratulálunk — elvégezted a kurzust!

50 leckén, 5 fázison és 4 valódi játékon keresztül megtanultad a webprogramozás alapjait a nulláról. Ez nem kevés.

Amit elvégeztél — összefoglaló

FázisTémakörLeckékAmit elsajátítottál
1. HTML & CSS Weboldal szerkezete, stílusok 1–10 DOCTYPE, tagek, CSS, Flexbox, reszponzív design
2. JavaScript Programlogika 11–20 Változók, feltételek, ciklusok, függvények, tömbök, objektumok, események
3. Canvas Grafika és animáció 21–30 Rajzolás, game loop, animáció, ütközés, kamera, sprite animáció
4. Játékok Teljes játékok elemzése 31–45 AI, State Machine, pályagenerálás, strategy pattern, Tower Defense
5. Haladó Mentés, hang, mobil, deploy 46–50 localStorage, JSON, ranglista, Web Audio, D-pad, Netlify

Hogyan tovább?

🎮 SAJÁT JÁTÉK FEJLESZTÉSE

Végy egy ötletet amelyet szeretsz (platform, puzzle, tower defense), és építsd fel a semmiből. Minden ami megakad — Google, MDN docs, vagy a játékok forráskódja a minta.

📚 KÖVETKEZŐ LÉPÉS: REACT

A webfejlesztés következő szintje: React (komponensek, state management) és Node.js (szerveri oldal, valódi adatbázis, több felhasználó).

🔧 ESZKÖZÖK ÉS KÖNYVTÁRAK

Phaser.js — professzionális HTML5 játékmotor. Three.js — 3D grafika WebGL-lel. Howler.js — fejlettebb hangkezelés.

🌐 HASZNOS LINKEK

MDN Web Docs — a legjobb HTML/JS dokumentáció. JavaScript.info — mélyebb JS tanuláshoz. itch.io — játékod megosztása.

💡A legfontosabb tanulság

Programozást programozással tanulnak az emberek

Nem olvasással, nem videók nézésével. A kurzus elvégzése után az igazi fejlődés a kezeidben van: nyiss meg egy üres HTML fájlt, gondolj ki valamit amit szeretnél látni a képernyőn, és kezdj el írni. Az első 10 kísérlet nem fog tökéletesen működni — de a 11. már igen. Mindenki így tanul meg programozni.