|
|
# Űrjáték készítése 3. rész: Mozgás hozzáadása
|
|
|
|
|
|
```mermaid
|
|
|
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.
|
|
|
|
|
|
```mermaid
|
|
|
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](https://ff-quizzes.netlify.app/web/quiz/33)
|
|
|
|
|
|
## 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:
|
|
|
|
|
|
```mermaid
|
|
|
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:
|
|
|
|
|
|
```javascript
|
|
|
// Á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](https://developer.mozilla.org/en-US/docs/Web/API/Canvas_API/Tutorial/Optimizing_canvas).
|
|
|
|
|
|
## 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:
|
|
|
|
|
|
```javascript
|
|
|
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?
|
|
|
|
|
|
```mermaid
|
|
|
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:
|
|
|
|
|
|
```javascript
|
|
|
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:
|
|
|
|
|
|
```javascript
|
|
|
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:
|
|
|
|
|
|
```mermaid
|
|
|
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
|
|
|
```
|
|
|
```javascript
|
|
|
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](../../../../6-space-game/3-moving-elements-around/your-work) 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:
|
|
|
|
|
|
```bash
|
|
|
-| assets
|
|
|
-| enemyShip.png
|
|
|
-| player.png
|
|
|
-| index.html
|
|
|
-| app.js
|
|
|
-| package.json
|
|
|
```
|
|
|
|
|
|
A projektedet a `your-work` könyvtárban indítod ezzel a parancssal:
|
|
|
|
|
|
```bash
|
|
|
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](../README.md) 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:
|
|
|
|
|
|
```javascript
|
|
|
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
|
|
|
|
|
|
```mermaid
|
|
|
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
|
|
|
|
|
|
2. **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:
|
|
|
|
|
|
```javascript
|
|
|
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.
|
|
|
|
|
|
3. **Valósítsd meg** a [Pub sub mintát](../README.md), 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:
|
|
|
|
|
|
```javascript
|
|
|
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
|
|
|
|
|
|
```mermaid
|
|
|
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
|
|
|
```
|
|
|
2. **Hozd létre az EventEmitter osztályt** az üzenetek közzétételéhez és feliratkozásához:
|
|
|
|
|
|
```javascript
|
|
|
class EventEmitter {
|
|
|
constructor() {
|
|
|
this.listeners = {};
|
|
|
}
|
|
|
|
|
|
on(message, listener) {
|
|
|
if (!this.listeners[message]) {
|
|
|
this.listeners[message] = [];
|
|
|
}
|
|
|
this.listeners[message].push(listener);
|
|
|
}
|
|
|
|
|
|
3. **Adj hozzá konstansokat**, és állítsd be az EventEmitter-t:
|
|
|
|
|
|
```javascript
|
|
|
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
|
|
|
|
|
|
4. **Inicializáld a játékot**
|
|
|
|
|
|
```javascript
|
|
|
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;
|
|
|
});
|
|
|
|
|
|
4. **Á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:
|
|
|
|
|
|
```javascript
|
|
|
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
|
|
|
|
|
|
5. **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:
|
|
|
|
|
|
```javascript
|
|
|
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.
|
|
|
|
|
|
```javascript
|
|
|
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:
|
|
|
|
|
|
```javascript
|
|
|
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:
|
|
|
|
|
|
```javascript
|
|
|
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](https://code.visualstudio.com/blogs/2025/02/24/introducing-copilot-agent-mode).
|
|
|
|
|
|
## 🚀 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](https://ff-quizzes.netlify.app/web/quiz/34)
|
|
|
|
|
|
## Á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](https://github.com/collections/javascript-game-engines).
|
|
|
|
|
|
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
|
|
|
|
|
|
```mermaid
|
|
|
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](assignment.md)
|
|
|
|
|
|
---
|
|
|
|
|
|
<!-- CO-OP TRANSLATOR DISCLAIMER START -->
|
|
|
**Jogi nyilatkozat**:
|
|
|
Ez a dokumentum az AI fordítási szolgáltatás, a [Co-op Translator](https://github.com/Azure/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.
|
|
|
<!-- CO-OP TRANSLATOR DISCLAIMER END --> |