You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
Web-Dev-For-Beginners/translations/hu/6-space-game/3-moving-elements-around
localizeflow[bot] d01b0740e4
chore(i18n): sync translations with latest source changes (chunk 1/1, 291 changes)
7 months ago
..
README.md chore(i18n): sync translations with latest source changes (chunk 1/1, 291 changes) 7 months ago
assignment.md chore(i18n): sync translations with latest source changes (chunk 1/1, 291 changes) 7 months ago

README.md

Űrjáték készítése 3. rész: Mozgás hozzáadása

journey
    title A játékanimációs utad
    section Mozgás alapjai
      Ismerd meg a mozgás elveit: 3: Student
      Tanuld meg a koordináták frissítését: 4: Student
      Valósítsd meg az alapvető mozgást: 4: Student
    section Játékos irányítás
      Kezeld a billentyűzetes eseményeket: 4: Student
      Előzd meg az alapértelmezett viselkedést: 5: Student
      Hozz létre reszponzív irányítást: 5: Student
    section Játékrendszerek
      Építs játékmenet ciklust: 5: Student
      Kezeld az objektum életciklusát: 5: Student
      Valósítsd meg a pub/sub mintát: 5: Student

Gondolj a kedvenc játékodra ami lenyűgözővé teszi, az nem csupán a szép grafikák, hanem az, ahogyan minden mozog és reagál a műveleteidre. Jelenleg az űrjátékod olyan, mint egy gyönyörű festmény, de most hozzáadunk egy mozgást, ami életre kelti.

Amikor a NASA mérnökei programozták az Apollo küldetések irányító számítógépét, hasonló kihívással szembesültek: hogyan lehet úgy reagáltatni az űrhajót a pilóta parancsaira, hogy közben automatikusan javítsa az útvonalat? A mai leckében tanult elvek visszhangozzák ezeket a koncepciókat a játékos által vezérelt mozgás kezelése az automatikus rendszer viselkedéssel együtt.

Ebben a leckében megtanulod, hogyan csússzanak az űrhajók a képernyőn, hogyan reagáljanak a játékos parancsaira, és hogyan hozz létre sima mozgásmintákat. Mindezt kezelhető fogalmakra bontjuk, amelyek természetes módon épülnek egymásra.

A végére a játékosok a hős hajóval repülnek a képernyőn, miközben ellenséges hajók járőröznek felette. Ami még fontosabb: megérted a játékmozgás rendszerek alapelveit.

mindmap
  root((Játék Animáció))
    Movement Types
      Játékos Által Irányított
      Automatikus Mozgás
      Fizikán Alapuló
      Szkriptelt Útvonalak
    Event Handling
      Billentyűzet Bemenet
      Egér Események
      Érintésvezérlés
      Alapértelmezett Megelőzés
    Game Loop
      Logika Frissítése
      Kép Kirajzolása
      Vászon Törlése
      Képkocka Sebesség Szabályozás
    Object Management
      Pozíció Frissítések
      Ütközés Észlelés
      Életciklus Kezelés
      Állapot Követés
    Communication
      Pub/Sub Minta
      Esemény Kibocsátók
      Üzenet Átadás
      Laza Csatolás

Előadás előtti kvíz

Előadás előtti kvíz

A játékmozgás megértése

A játékok akkor kelnek életre, amikor a dolgok mozogni kezdenek, és alapvetően két módon történik ez:

  • Játékos által vezérelt mozgás: Amikor lenyomsz egy gombot vagy kattintasz az egérrel, valami mozog. Ez a közvetlen kapcsolat közted és a játékvilág között.
  • Automatikus mozgás: Amikor maga a játék dönt a mozgásról például azok az ellenséges hajók, amelyek járőröznek a képernyőn akkor is, ha semmit nem csinálsz.

Az objektumok mozgatása a képernyőn egyszerűbb, mint gondolnád. Emlékszel arra az x és y koordinátára matekóráról? Pontosan azzal dolgozunk itt. Amikor Galileo 1610-ben a Jupiter holdjait figyelte, valójában ugyanezt tette időbeli pozíciókat rajzolt, hogy megértse a mozgásmintákat.

Dolgozni a képernyőn mozgó dolgokkal olyan, mint egy flipbook animációt készíteni három egyszerű lépést kell követni:

flowchart LR
    A["Kép N"] --> B["Pozíciók frissítése"]
    B --> C["Vászon törlése"]
    C --> D["Objektumok rajzolása"]
    D --> E["Kép N+1"]
    E --> F{Folytatódik?}
    F -->|Igen| B
    F -->|Nem| G["Játék vége"]
    
    subgraph "Animációs ciklus"
        H["1. Új pozíciók kiszámítása"]
        I["2. Előző kép eltüntetése"]
        J["3. Új kép kirajzolása"]
    end
    
    style B fill:#e1f5fe
    style C fill:#ffebee
    style D fill:#e8f5e8
  1. Pozíció frissítése Változtasd meg, hol legyen az objektum (például mozgasd 5 pixellel jobbra)
  2. Régi képkocka eltüntetése Töröld a képernyőt, hogy ne láss szellemszerű nyomokat
  3. Új képkocka kirajzolása Tegyél az objektumot az új helyére

Ha ezt elég gyorsan csinálod, hopp, kész is a sima mozgás, amely természetes érzést ad a játékosoknak.

Így nézhet ez ki kódban:

// Állítsd be a hős helyét
hero.x += 5;
// Tisztítsd meg a téglalapot, amely a hőst tartalmazza
ctx.clearRect(0, 0, canvas.width, canvas.height);
// Rajzold újra a játék hátterét és a hőst
ctx.fillRect(0, 0, canvas.width, canvas.height);
ctx.fillStyle = "black";
ctx.drawImage(heroImg, hero.x, hero.y);

Mit csinál ez a kód:

  • Frissíti a hős x-koordinátáját 5 pixellel, hogy vízszintesen mozogjon
  • Kitörli a teljes vászon területét, hogy eltávolítsa az előző képkockát
  • Kitölti a vásznat fekete háttérrel
  • Újrarajzolja a hős képet az új pozícióban

Tudsz mondani egy okot, hogy miért okozhat a hős sok képkocka per másodperc alatti újrarajzolása teljesítménybeli problémákat? Olvass erről az alternatívákról.

Billentyűzet események kezelése

Itt kapcsoljuk össze a játékos bemenetét a játék eseményeivel. Amikor valaki megnyomja a szóköz billentyűt lézer lövéséhez, vagy lenyom egy nyílbillentyűt, hogy kikerüljön egy aszteroidát, a játékodnak érzékelnie kell és reagálnia kell erre a bemenetre.

A billentyűzet események az ablak szintjén történnek, ami azt jelenti, hogy a böngésző teljes ablaka figyel a billentyűleütésekre. Az egérkattintások ezzel szemben konkrét elemekhez köthetők (például gombokra kattintás). A mi űrjátékunkban a billentyűzet vezérlésre koncentrálunk, mert ez adja a játékosoknak az igazi arcade érzést.

Ez emlékeztet arra, ahogy a 1800-as évek távírókezelői a Morse kódot értelmes üzenetekké kellett átalakítsák mi is valami hasonlót csinálunk, a billentyűleütéseket játék parancsokká fordítjuk.

Egy esemény kezeléséhez használd az ablak addEventListener() metódusát, és add meg neki a két bemeneti paramétert. Az első paraméter az esemény neve, például keyup. A második a funkció, amelyet az esemény bekövetkeztekor kell végrehajtani.

Íme egy példa:

window.addEventListener('keyup', (evt) => {
  // evt.key = a billentyű sztring reprezentációja
  if (evt.key === 'ArrowUp') {
    // csinálj valamit
  }
});

Mit csinál itt a kód:

  • Figyel a billentyűzet eseményekre az egész ablakon
  • Elkapja az esemény objektumot, amely tudatja, hogy melyik gombot nyomták meg
  • Ellenőrzi, hogy a megnyomott gomb egyezik-e egy specifikus billentyűvel (ebben az esetben a fel nyíl)
  • Futtat kódot, ha a feltétel teljesül

A billentyű eseményeknél két tulajdonságot használhatsz, hogy kiderítsd, melyik gomb lett lenyomva:

  • key ez a gomb sztring reprezentációja, például 'ArrowUp'
  • keyCode ez egy numerikus reprezentáció, például 37, ami az ArrowLeft-hez tartozik

A billentyű események kezelése hasznos a játékfejlesztésen kívül is. Milyen más felhasználási módját tudod elképzelni ennek a technikának?

sequenceDiagram
    participant User
    participant Browser
    participant EventSystem
    participant GameLogic
    participant Hero
    
    User->>Browser: Megnyomja a Fel nyíl billentyűt
    Browser->>EventSystem: keydown esemény
    EventSystem->>EventSystem: preventDefault()
    EventSystem->>GameLogic: emit('KEY_EVENT_UP')
    GameLogic->>Hero: hero.y -= 5
    Hero->>Hero: Pozíció frissítése
    
    Note over Browser,GameLogic: Az eseményfolyam megakadályozza a böngésző alapértelmezett műveleteit
    Note over GameLogic,Hero: A pub/sub minta lehetővé teszi a tiszta kommunikációt

Különleges gombok: egy figyelmeztetés!

Néhány billentyűnek beépített böngésző viselkedése van, ami zavarhatja a játékod. A nyílbillentyűk görgetik az oldalt, a szóköz pedig legörget lefelé ezek a viselkedések nem kellenek, mikor valaki az űrhajóját irányítja.

Megakadályozhatjuk ezeket az alapértelmezett működéseket, és inkább a játék kezelje a bemenetet. Ez hasonló ahhoz, ahogy a korai programozók felülírták a rendszer megszakításokat, hogy egyedi viselkedést hozzanak létre mi ezt böngésző szinten tesszük. Így:

const onKeyDown = function (e) {
  console.log(e.keyCode);
  switch (e.keyCode) {
    case 37:
    case 39:
    case 38:
    case 40: // Nyíl billentyűk
    case 32:
      e.preventDefault();
      break; // Szóköz
    default:
      break; // ne blokkolja a többi billentyűt
  }
};

window.addEventListener('keydown', onKeyDown);

Mit csinál ez a tiltó kód:

  • Ellenőrzi a specifikus billentyű kódokat, amelyek nem kívánt böngésző viselkedést okozhatnak
  • Megakadályozza az alapértelmezett böngésző műveleteket a nyílbillentyűkre és a szóközre
  • Engedi más gombok normál működését
  • Használja az e.preventDefault()-ot a böngésző beépített viselkedésének megállítására

🔄 Pedagógiai ellenőrzés

Eseménykezelés megértése: Mielőtt az automatikus mozgásra lépnénk, győződj meg róla, hogy tudsz:

  • Magyarázatot adni a keydown és keyup események közti különbségre
  • Megérteni, miért akadályozzuk meg az alapértelmezett böngésző viselkedést
  • Leírni, hogyan kapcsolódnak az eseményfigyelők a felhasználói bemenethez és a játéklogikához
  • Meghatározni, mely gombok zavarhatják a játék vezérlést

Gyors önteszt: Mi történne, ha nem akadályoznád meg az alapértelmezett működést a nyílbillentyűknél? Válasz: A böngésző legörgetné az oldalt, ami zavarja a játék mozgását

Eseményrendszer architektúra: Most már érted:

  • Ablak-szintű figyelés: események elkapása böngésző szinten
  • Esemény objektum tulajdonságok: key sztringek és keyCode számok
  • Alapértelmezett megakadályozás: nem kívánt böngésző viselkedések leállítása
  • Feltételes logika: reakció adott billentyűkombinációkra

Játék által vezérelt mozgás

Most beszéljünk azokról az objektumokról, amelyek a játékos bemenete nélkül mozognak. Gondolj az ellenséges hajókra, amelyek a képernyőn átperegnek, a repülő golyókra, vagy a háttérben sodródó felhőkre. Ez az autonóm mozgás élettel tölti meg a játékvilágot akkor is, amikor senki nem vezérel.

JavaScript beépített időzítőit használjuk, hogy rendszeresen frissítsük a pozíciókat. Ez hasonló ahhoz, ahogy a ingaórák működnek egy rendszeres mechanizmus, amely állandó, időzített műveleteket vált ki. Íme, milyen egyszerű lehet:

const id = setInterval(() => {
  // Mozgasd az ellenséget az y tengely mentén
  enemy.y += 10;
}, 100);

Mit csinál ez a mozgás kód:

  • Létrehoz egy időzítőt, amely 100 milliszekundumonként fut
  • Frissíti az ellenség y-koordinátáját minden alkalommal 10 pixellel
  • Tárolja az intervallum azonosítót, hogy később szükség esetén megállíthassuk
  • Mozgatja az ellenséget automatikusan lefelé a képernyőn

A játék ciklus

Ez az a koncepció, ami mindent összeköt a játék ciklus. Ha a játék egy film lenne, akkor a játék ciklus lenne a filmvetítő, amely képkockánként gyorsan vetít, így minden simán mozog.

Minden játéknak van egy ilyen ciklusa a háttérben. Ez egy olyan függvény, amely frissíti az összes játékelem állapotát, újrarajzolja a képernyőt, és folyton ismétli ezt a folyamatot. Ez tartja nyilván a hőst, az összes ellenséget, a lézerek repülését az egész játék állapotát.

Ez a koncepció emlékeztet arra, ahogyan a korai film animátorok, mint Walt Disney, képkockánként rajzolták újra a karaktereket, hogy mozgás illúzióját keltsék. Mi ugyanezt tesszük, csak kód formájában, nem ceruzával.

Így nézhet ki egy tipikus játék ciklus kód:

flowchart TD
    A["Játékhurok Indítása"] --> B["Vászon Törlése"]
    B --> C["Háttér Kitöltése"]
    C --> D["Játéktárgyak Frissítése"]
    D --> E["Hős Kirajzolása"]
    E --> F["Ellenségek Kirajzolása"]
    F --> G["Felhasználói Felület Elemeinek Kirajzolása"]
    G --> H["Várakozás a Következő Képkockára"]
    H --> I{Fut a Játék?}
    I -->|Igen| B
    I -->|Nem| J["Játék Befejezése"]
    
    subgraph "Képkocka Sebesség Szabályozás"
        K["60 FPS = 16.67ms"]
        L["30 FPS = 33.33ms"]
        M["10 FPS = 100ms"]
    end
    
    style B fill:#ffebee
    style D fill:#e1f5fe
    style E fill:#e8f5e8
    style F fill:#e8f5e8
const gameLoopId = setInterval(() => {
  function gameLoop() {
    ctx.clearRect(0, 0, canvas.width, canvas.height);
    ctx.fillStyle = "black";
    ctx.fillRect(0, 0, canvas.width, canvas.height);
    drawHero();
    drawEnemies();
    drawStaticObjects();
  }
  gameLoop();
}, 200);

A játék ciklus szerkezetének megértése:

  • Kitörli a teljes vásznat a korábbi képkocka eltávolításához
  • Kitölti a hátteret egyszínű színnel
  • Kirajzolja az összes játékobjektumot a jelenlegi helyükön
  • Ismétli ezt a folyamatot 200 milliszekundumonként, hogy sima animációt hozzon létre
  • Kezeli a képkocka sebességet az időzítővel

Az Űrjáték folytatása

Most mozgást adunk a korábban létrehozott statikus jelenethez. Átalakítjuk képernyőképből interaktív élményt. Lépésről lépésre haladunk, hogy minden elem természetesen épüljön a másikra.

Vedd elő a kódot a korábbi leckéből (vagy kezd az elejéről a Part II- starter mappában, ha friss kezdésre van szükséged).

Amit ma építünk:

  • Hős vezérlés: Nyilakkal irányítod az űrhajódat a képernyőn
  • Ellenséges mozgás: Az idegen hajók megkezdik támadásukat

Kezdjük el megvalósítani ezeket a funkciókat.

Ajánlott lépések

Keresd meg a fájlokat, amelyeket a your-work alkönyvtárban létrehoztak. Ezek a következők:

-| assets
  -| enemyShip.png
  -| player.png
-| index.html
-| app.js
-| package.json

A projektedet a your-work könyvtárban indítod ezzel a parancssal:

cd your-work
npm start

Mit csinál ez a parancs:

  • Átlép a projekt könyvtáradba
  • Elindít egy HTTP szervert az http://localhost:5000 címen
  • Kiszolgálja a játék fájlokat, hogy böngészőben tesztelhesd őket

Ezzel egy HTTP szervert indítasz az http://localhost:5000 címen. Nyisd meg a böngészőt és írd be ezt a címet, most a hős és az összes ellenség látszik majd, de még semmi sem mozog - még!

Kód hozzáadása

  1. Adj hozzá dedikált objektumokat a hero-hoz, a enemy-hez és a game object-hez, melyeknek legyen x és y tulajdonsága. (Emlékezz az öröklődés vagy összetétel részre.)

    TIP A game object legyen az, amely rendelkezik x és y tulajdonsággal, és képes magát megrajzolni a vászonra.

    Tipp: Először adj hozzá egy új GameObject osztályt az alábbi konstruktorral, majd rajzold ki a vászonra:

    class GameObject {
      constructor(x, y) {
        this.x = x;
        this.y = y;
        this.dead = false;
        this.type = "";
        this.width = 0;
        this.height = 0;
        this.img = undefined;
      }
    
      draw(ctx) {
        ctx.drawImage(this.img, this.x, this.y, this.width, this.height);
      }
    }
    

    Mit tesz ez az alap osztály:

    • Definiál közös tulajdonságokat, amelyeket az összes játékobjektum megoszt (pozíció, méret, kép)
    • Tartalmaz egy dead jelzőt, amivel követni lehet, hogy az objektumot el kell-e távolítani
    • Biztosít egy draw() metódust, amely kirajzolja az objektumot a vászonra
    • Beállít alapértelmezett értékeket minden tulajdonságra, amelyeket a leszármazott osztályok felülírhatnak
classDiagram
    class GameObject {
        +x: szám
        +y: szám
        +dead: logikai
        +type: szöveg
        +width: szám
        +height: szám
        +img: Kép
        +draw(ctx)
    }
    
    class Hero {
        +speed: szám
        +type: "Hős"
        +width: 98
        +height: 75
    }
    
    class Enemy {
        +type: "Ellenség"
        +width: 98
        +height: 50
        +setInterval()
    }
    
    GameObject <|-- Hero
    GameObject <|-- Enemy
    
    class EventEmitter {
        +listeners: objektum
        +on(uzenet, hallgato)
        +emit(uzenet, teher)
    }
Most bővítsd ezt a `GameObject`-et a `Hero` és `Enemy` osztályok létrehozásával:

```javascript
class Hero extends GameObject {
  constructor(x, y) {
    super(x, y);
    this.width = 98;
    this.height = 75;
    this.type = "Hero";
    this.speed = 5;
  }
}
```

```javascript
class Enemy extends GameObject {
  constructor(x, y) {
    super(x, y);
    this.width = 98;
    this.height = 50;
    this.type = "Enemy";
    const id = setInterval(() => {
      if (this.y < canvas.height - this.height) {
        this.y += 5;
      } else {
        console.log('Stopped at', this.y);
        clearInterval(id);
      }
    }, 300);
  }
}
```

**Fontos fogalmak ezekben az osztályokban:**
- **Örököl** a `GameObject`-ből az `extends` kulcsszóval
- **Meghívja** a szülő konstruktorát a `super(x, y)` hívással
- **Beállít** specifikus méreteket és tulajdonságokat minden objektumtípushoz
- **Megvalósítja** az ellenségek automatikus mozgását `setInterval()` használatával
  1. Adj hozzá billentyű eseménykezelőket az irányításhoz (mozgasd a hőst fel/le, balra/jobbra)

    EMLÉKEZZ ez egy Descartes-i rendszer, a bal felső sarok a 0,0. Ne felejtsd el letiltani az alapértelmezett viselkedést!

    Tipp: Hozd létre az onKeyDown függvényt, és csatold az ablakhoz:

    const onKeyDown = function (e) {
      console.log(e.keyCode);
      // Add hozzá a fenti leckében szereplő kódot az alapértelmezett viselkedés megállításához
      switch (e.keyCode) {
        case 37:
        case 39:
        case 38:
        case 40: // Nyílbillentyűk
        case 32:
          e.preventDefault();
          break; // Szóköz
        default:
          break; // ne blokkolja más billentyűket
      }
    };
    
    window.addEventListener("keydown", onKeyDown);
    

    Mit csinál ez az eseménykezelő:

    • Figyel a keydown eseményekre az egész ablakon
    • Naplózza a billentyű kódját, hogy segítsen hibakereséskor, mely gombokat nyomják meg
    • Megakadályozza az alapértelmezett böngésző viselkedést a nyíl billentyűknél és a szóköznél
    • Engedi más gombok normál működését

    Nézd meg a böngésződ konzolját ebben a pontban, és figyeld a naplózott billentyűleütéseket.

  2. Valósítsd meg a Pub sub mintát, ez tisztán tartja a kódodat, miközben haladsz tovább.

    A Publish-Subscribe minta segít szervezni a kódot az események és azok kezelésének szétválasztásával. Ezáltal modulárisabb és könnyebben karbantartható lesz a kód.

    Ehhez az utolsó lépéshez megteheted:

    1. Adj hozzá egy eseményfigyelőt az ablakhoz:

      window.addEventListener("keyup", (evt) => {
        if (evt.key === "ArrowUp") {
          eventEmitter.emit(Messages.KEY_EVENT_UP);
        } else if (evt.key === "ArrowDown") {
          eventEmitter.emit(Messages.KEY_EVENT_DOWN);
        } else if (evt.key === "ArrowLeft") {
          eventEmitter.emit(Messages.KEY_EVENT_LEFT);
        } else if (evt.key === "ArrowRight") {
          eventEmitter.emit(Messages.KEY_EVENT_RIGHT);
        }
      });
      

    Mit csinál ez az eseményrendszer:

    • Érzékeli a billentyűzet bemenetet, és átalakítja egyedi játék eseményekké
    • Elválasztja a bemeneti érzékelést a játék logikától
    • Könnyíti a vezérlések módosítását anélkül, hogy a játék kódját meg kéne változtatni
    • Engedi, hogy több rendszer is reagáljon ugyanarra a bemenetre
flowchart TD
    A["Billentyűzetbemenet"] --> B["Ablak eseményfigyelő"]
    B --> C["Esemény kibocsátó"]
    C --> D["KULCS_ESMÉNY_FEL"]
    C --> E["KULCS_ESMÉNY_LE"]
    C --> F["KULCS_ESMÉNY_BALRA"]
    C --> G["KULCS_ESMÉNY_JOBBRA"]
    
    D --> H["Hős mozgatása"]
    D --> I["Hangrendszer"]
    D --> J["Vizuális effektek"]
    
    E --> H
    F --> H
    G --> H
    
    style A fill:#e1f5fe
    style C fill:#e8f5e8
    style H fill:#fff3e0
  1. Hozd létre az EventEmitter osztályt az üzenetek közzétételéhez és feliratkozásához:

    class EventEmitter {
      constructor() {
        this.listeners = {};
      }
    
      on(message, listener) {
        if (!this.listeners[message]) {
          this.listeners[message] = [];
        }
        this.listeners[message].push(listener);
      }
    
    
  2. Adj hozzá konstansokat, és állítsd be az EventEmitter-t:

    const Messages = {
      KEY_EVENT_UP: "KEY_EVENT_UP",
      KEY_EVENT_DOWN: "KEY_EVENT_DOWN",
      KEY_EVENT_LEFT: "KEY_EVENT_LEFT",
      KEY_EVENT_RIGHT: "KEY_EVENT_RIGHT",
    };
    
    let heroImg, 
        enemyImg, 
        laserImg,
        canvas, ctx, 
        gameObjects = [], 
        hero, 
        eventEmitter = new EventEmitter();
    

A beállítás megértése:

  • Definiál üzenet konstansokat, hogy elkerüld az elírásokat és megkönnyítsd az átrendezést
  • Deklarál változókat képek, vászon kontextus és játék állapotához
  • Létrehoz egy globális esemény emittert a pub-sub rendszerhez
  • Inicializál egy tömböt az összes játéktárgy tárolására
  1. Inicializáld a játékot

    function initGame() {
      gameObjects = [];
      createEnemies();
      createHero();
    
      eventEmitter.on(Messages.KEY_EVENT_UP, () => {
        hero.y -= 5;
      });
    
      eventEmitter.on(Messages.KEY_EVENT_DOWN, () => {
        hero.y += 5;
      });
    
      eventEmitter.on(Messages.KEY_EVENT_LEFT, () => {
        hero.x -= 5;
      });
    
    
  2. Állítsd be a játékhurokot

    Refaktoráld a window.onload függvényt, hogy inicializálja a játékot, és állítson be egy megfelelő időközönként futó játékhurokot. Ezután hozzáadsz egy lézersugarat:

    window.onload = async () => {
      canvas = document.getElementById("canvas");
      ctx = canvas.getContext("2d");
      heroImg = await loadTexture("assets/player.png");
      enemyImg = await loadTexture("assets/enemyShip.png");
      laserImg = await loadTexture("assets/laserRed.png");
    
      initGame();
      const gameLoopId = setInterval(() => {
        ctx.clearRect(0, 0, canvas.width, canvas.height);
        ctx.fillStyle = "black";
        ctx.fillRect(0, 0, canvas.width, canvas.height);
        drawGameObjects(ctx);
      }, 100);
    };
    

    A játék beállításának megértése:

    • Megvárja, hogy az oldal teljesen betöltődjön, mielőtt elindulna
    • Lekéri a vászon elemet és annak 2D megjelenítő kontextusát
    • Aszinkron módon betölti az összes képi erőforrást await használatával
    • Elindítja a játékhurok futását 100 ms-os időközönként (10 FPS)
    • Kitörli és újrarajzolja a teljes képernyőt minden frame-ben
  3. Adj hozzá kódot az ellenségek mozgatásához egy bizonyos időközönként

    Refaktoráld a createEnemies() függvényt, hogy létrehozza az ellenségeket és betolja őket az új gameObjects osztályba:

    function createEnemies() {
      const MONSTER_TOTAL = 5;
      const MONSTER_WIDTH = MONSTER_TOTAL * 98;
      const START_X = (canvas.width - MONSTER_WIDTH) / 2;
      const STOP_X = START_X + MONSTER_WIDTH;
    
      for (let x = START_X; x < STOP_X; x += 98) {
        for (let y = 0; y < 50 * 5; y += 50) {
          const enemy = new Enemy(x, y);
          enemy.img = enemyImg;
          gameObjects.push(enemy);
        }
      }
    }
    

    Az ellenség létrehozásának működése:

    • Számolja ki az ellenségek pozícióját a képernyő közepére igazítva
    • Létrehoz egy ellenség rácsot beágyazott ciklusokkal
    • Hozzárendeli az ellenség képet minden egyes ellenség objektumhoz
    • Hozzáadja az összes ellenséget a globális játéktárgy tömbhöz

    és adj hozzá egy createHero() függvényt, ami hasonló folyamatot végez a hős számára.

    function createHero() {
      hero = new Hero(
        canvas.width / 2 - 45,
        canvas.height - canvas.height / 4
      );
      hero.img = heroImg;
      gameObjects.push(hero);
    }
    

    A hős létrehozásának működése:

    • Pozicionálja a hőst a képernyő alsó közepén
    • Hozzárendeli a hős képét a hős objektumhoz
    • Hozzáadja a hőst a játéktárgy tömbhöz megjelenítéshez

    végül adj hozzá egy drawGameObjects() függvényt a rajzolás elindításához:

    function drawGameObjects(ctx) {
      gameObjects.forEach(go => go.draw(ctx));
    }
    

    A rajzoló függvény megértése:

    • Bejárja az összes játéktárgyat a tömbben
    • Meghívja mindegyik objektum draw() metódusát
    • Átadja a vászon kontextust, hogy az objektumok meg tudják jeleníteni magukat

    🔄 Didaktikai állapotfelmérés

    A teljes játékrendszer megértése: Ellenőrizd a teljes architektúra elsajátítását:

    • Hogyan teszi lehetővé az öröklődés, hogy a Hero és az Enemy közös GameObject tulajdonságokat osszanak meg?
    • Miért teszi a pub/sub mintázat fenntarthatóbbá a kódodat?
    • Milyen szerepet játszik a játékhurok a folyamatos animáció létrehozásában?
    • Hogyan kapcsolja össze a felhasználói bemenetet az eseményfigyelők a játéktárgy viselkedésével?

    Rendszerintegráció: A játékod most bemutatja:

    • Objektumorientált tervezés: Alaposztályok specializált öröklődéssel
    • Eseményvezérelt architektúra: Pub/sub minta laza csatoláshoz
    • Animációs keretrendszer: Játékhurok következetes frame frissítésekkel
    • Bemenetkezelés: Billentyűzet események alapértelmezett megakadályozással
    • Erőforrás kezelés: Kép betöltés és sprite megjelenítés

    Professzionális minták: Megvalósítottad:

    • Felelősségek elkülönítése: Bemenet, logika és megjelenítés szétválasztása
    • Polimorfizmus: Az összes játéktárgynak közös rajzoló interfésze van
    • Üzenetküldés: Tiszta kommunikáció komponensek között
    • Erőforrás menedzsment: Hatékony sprite és animáció kezelés

    Az ellenségeidnek már el kell kezdeniük haladni a hős űrhajód felé! } }

    
    and add a `createHero()` function to do a similar process for the hero.
    
    ```javascript
    function createHero() {
      hero = new Hero(
        canvas.width / 2 - 45,
        canvas.height - canvas.height / 4
      );
      hero.img = heroImg;
      gameObjects.push(hero);
    }
    

    végül adj hozzá egy drawGameObjects() függvényt a rajzolás elindításához:

    function drawGameObjects(ctx) {
      gameObjects.forEach(go => go.draw(ctx));
    }
    

    Az ellenségeidnek már el kell kezdeniük haladni a hős űrhajód felé!


GitHub Copilot Agent Kihívás 🚀

Itt egy kihívás, ami tovább csiszolja a játékodat: határok és sima irányítások hozzáadása. Jelenleg a hősöd elrepülhet a képernyőről, és a mozgás rendetlen érzésű lehet.

A küldetésed: Tegye a űrhajódat valósághűbbé a képernyőhatárok és a folyékony mozgás megvalósításával. Ez hasonló ahhoz, ahogy a NASA repülésirányító rendszerei megakadályozzák az űrhajók biztonságos működési paraméterek túllépését.

Amit meg kell alkotni: Készíts egy rendszert, ami a hős űrhajót a képernyőn tartja, és tegye az irányítást folyamatosabbá. Amikor a játékos lenyomja egy nyíl billentyűt, a hajó folyamatosan csúszkáljon, ne ugráljon darabokban. Fontold meg, hogy vizuális visszajelzést is adj, amikor a hajó a képernyőhatárhoz ér talán egy finom effektust, ami jelzi a játéktér szélét.

Tudj meg többet az ügynök módjáról.

🚀 Kihívás

A kód szervezése egyre fontosabb, ahogy a projektek nőnek. Észrevehetted, hogy a fájl kezd zsúfolttá válni a funkciókból, változókból és osztályokból összekeverve. Ez arra emlékeztet, ahogy az Apollo küldetés mérnökei tiszta, fenntartható rendszereket hoztak létre, amelyeken több csapat is hatékonyan dolgozhat egyszerre.

A küldetésed: Gondolkodj szoftverarchitektként. Hogyan szerveznéd a kódot, hogy hat hónap múlva te (vagy egy csapattársad) is könnyen megértsd? Még ha minden egy fájlban is marad most, jobb szervezettséget kialakíthatsz:

  • Kapcsolódó funkciók csoportosítása egyértelmű komment fejléc alatt
  • Felelősségek szétválasztása különítsd el a játékmenet logikáját a megjelenítéstől
  • Következetes névhasználat változók és függvények számára
  • Modulok vagy névterek létrehozása a játék különböző aspektusainak rendezéséhez
  • Dokumentáció hozzáadása amely megmagyarázza az egyes fő szakaszok célját

Reflexiós kérdések:

  • A kódod mely részei a legnehezebben érthetőek, amikor később visszatérsz hozzájuk?
  • Hogyan szerveznéd meg, hogy mások könnyebben tudjanak hozzájárulni?
  • Mi történne, ha új funkciókat, például power-upokat vagy különböző ellenségtípusokat szeretnél hozzáadni?

Előadás utáni kvíz

Előadás utáni kvíz

Áttekintés és önálló tanulás

Mindent a nulláról építettünk fel, ami nagyszerű a tanuláshoz, de itt egy kis titok számos csodálatos JavaScript keretrendszer létezik, amelyek sok nehézséget levesznek a válladról. Ha már kényelmesen használod az eddig tanult alapokat, érdemes felfedezni, mi érhető el.

Gondolj a keretrendszerekre úgy, mint egy jól felszerelt szerszámosládára ahelyett, hogy minden szerszámot kézzel készítenél el. Sok olyan kód-szervezési problémát megoldanak, amiket említettünk, és olyan funkciókat is adnak, amik hetekbe telnének saját maga megalkotni.

Érdemes felfedezni:

  • Hogyan szervezik a játékmotorok a kódot csodálkozni fogsz az okos mintázatokon
  • Teljesítmény-optimalizálási trükkök a vászon alapú játékok zökkenőmentes futtatásához
  • Modern JavaScript funkciók, melyek tisztább és fenntarthatóbb kódot eredményeznek
  • Különböző megközelítések a játéktárgyak és kapcsolataik kezelésére

🎯 A játék animáció mesteri idővonala

timeline
    title Játék Animáció és Interakció Tanulási Folyamata
    
    section Mozgás Alapjai (20 perc)
        Animációs Elvek: Képkocka-alapú animáció
                            : Pozíció frissítések
                            : Koordináta rendszerek
                            : Sima mozgás
        
    section Eseményrendszerek (25 perc)
        Felhasználói Bemenet: Billentyűzet eseménykezelés
                  : Alapértelmezett viselkedés megakadályozása
                  : Esemény objektum tulajdonságai
                  : Ablakszintű hallgatás
        
    section Játék Architektúra (30 perc)
        Objektum Tervezés: Öröklődés minták
                     : Alaposztály létrehozása
                     : Specializált viselkedések
                     : Polimorf interfészek
        
    section Kommunikációs Minták (35 perc)
        Pub/Sub Megvalósítás: Esemény kibocsátók
                              : Üzenet állandók
                              : Laza kapcsolódás
                              : Rendszer integráció
        
    section Játék Ciklus Mesterfogás (40 perc)
        Valós idejű rendszerek: Képkocka sebesség vezérlés
                         : Frissítés/megjelenítés ciklus
                         : Állapot kezelés
                         : Teljesítmény optimalizálás
        
    section Fejlett Technikai (45 perc)
        Professzionális Funkciók: Ütközés érzékelés
                             : Fizika szimuláció
                             : Állapotgép
                             : Komponens rendszerek
        
    section Játék Motor Fogalmak (1 hét)
        Keretrendszer Megértés: Entitás-komponens rendszerek
                               : Jelenet gráfok
                               : Eszköz feldolgozó csövek
                               : Teljesítmény profilozás
        
    section Termelési Készségek (1 hónap)
        Professzionális Fejlődés: Kód szervezés
                                : Csapat együttműködés
                                : Tesztelési stratégiák
                                : Telepítés optimalizálás

🛠️ Játékfejlesztési eszköztár összefoglaló

A leckét teljesítve most már mestere vagy:

  • Animációs alapelvek: Frame-alapú mozgás és sima átmenetek
  • Eseményvezérelt programozás: Billentyűzet bemenet kezelése megfelelő eseménykezeléssel
  • Objektumorientált tervezés: Öröklődési hierarchiák és polimorfikus interfészek
  • Kommunikációs minták: Pub/sub architektúra a fenntartható kódhoz
  • Játékhurok architektúra: Valós idejű frissítési és megjelenítési ciklusok
  • Bemeneti rendszerek: Felhasználói vezérlés leképezése alapértelmezett viselkedés megakadályozásával
  • Erőforrás kezelés: Sprite-k betöltése és hatékony megjelenítés

Mit tehetsz a következő 5 percben

  • Nyisd meg a böngésző konzolt és próbáld ki az addEventListener('keydown', console.log) eseményt a billentyűzet események megfigyelésére
  • Hozz létre egy egyszerű div elemet és mozgasd nyíl billentyűkkel
  • Kísérletezz setInterval-lel a folyamatos mozgás létrehozásához
  • Próbáld ki az alapértelmezett viselkedés megakadályozását event.preventDefault()-tal

🎯 Mit érhetsz el ezen az órán

  • Teljesítsd az előadás utáni kvízt és értsd meg az eseményvezérelt programozást
  • Építsd meg a mozgó hős űrhajót teljes billentyűzetes vezérléssel
  • Valósítsd meg az ellenség mozgásának sima mintáit
  • Adj hozzá határokat, hogy a játéktárgyak ne lépjék túl a képernyőt
  • Készíts alapvető ütközés-detektálást a játéktárgyak között

📅 Heti animációs utazás

  • Készítsd el a teljes űrjátékot csiszolt mozgással és interakciókkal
  • Adj hozzá fejlett mozgásmintákat, például íveket, gyorsulást és fizikát
  • Valósíts meg sima átmeneteket és könnyítő függvényeket
  • Készíts részecske effektusokat és vizuális visszajelző rendszereket
  • Optimalizáld a játék teljesítményét a zökkenőmentes 60fps eléréséhez
  • Adj hozzá mobil érintésvezérlést és reszponzív dizájnt

🌟 Havi interaktív fejlesztés

  • Építs összetett interaktív alkalmazásokat fejlett animációs rendszerekkel
  • Tanulj animációs könyvtárakat, mint a GSAP, vagy készíts saját animációs motort
  • Vegyél részt nyílt forráskódú játékfejlesztési és animációs projektekben
  • Sajátítsd el a grafika-intenzív alkalmazások teljesítményoptimalizálását
  • Készíts oktató anyagokat a játékfejlesztés és animáció témájában
  • Építs portfóliót fejlett interaktív programozási készségekkel

Valós alkalmazások: A játék animációs tudásod közvetlenül alkalmazható:

  • Interaktív webalkalmazásokban: Dinamikus műszerfalak és valós idejű felületek
  • Adatvizualizációban: Animált grafikonok és interaktív képek
  • Oktató szoftverekben: Interaktív szimulációk és tanuló eszközök
  • Mobil fejlesztésben: Érintésalapú játékok és gesztuskezelés
  • Asztali alkalmazásokban: Electron alkalmazások sima animációkkal
  • Web animációkban: CSS és JavaScript animációs könyvtárak

Professzionális készségek: Most már tudsz:

  • Tervezni eseményvezérelt rendszereket, amik skálázódnak a komplexitással
  • Megvalósítani sima animációkat matematikai elvekkel
  • Hibakeresni összetett interakciós rendszereket a böngésző fejlesztői eszközökkel
  • Optimalizálni a játék teljesítményét különböző eszközökön és böngészőkben
  • Tervezni fenntartható kódszerkezeteket bevált minták alapján

Játékfejlesztési fogalmak elsajátítva:

  • Képkocka sebesség kezelés: FPS és időzítés megértése
  • Bemenetkezelés: Platformok közötti billentyűzet és esemény rendszerek
  • Objektum életciklus: Létrehozás, frissítés és megsemmisítési minták
  • Állapot szinkronizáció: Játék állapotának következetes megtartása frame-ek között
  • Esemény architektúra: Laza csatolású kommunikáció játékrendszerek között

Következő szint: Készen állsz ütközés detektálás, pontozórendszerek, hanghatások hozzáadására, vagy modern játékmotorok, mint a Phaser vagy a Three.js felfedezésére!

🌟 Teljesítmény elérve: Felépítettél egy komplett interaktív játékrendszert professzionális architektúra mintákkal!

Házi feladat

Kódod kommentálása


Jogi nyilatkozat:
Ez a dokumentum az AI fordítási szolgáltatás, a Co-op Translator segítségével készült. Bár igyekszünk a pontosságra, kérjük, vegye figyelembe, hogy az automatikus fordítások tartalmazhatnak hibákat vagy pontatlanságokat. Az eredeti dokumentum a saját nyelvén a hiteles forrásnak tekintendő. Fontos információk esetén szakmai, emberi fordítást javaslunk. Nem vállalunk felelősséget a fordítás használatából eredő félreértésekért vagy téves értelmezésekért.