|
|
7 months ago | |
|---|---|---|
| .. | ||
| README.md | 7 months ago | |
| assignment.md | 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
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
- Pozíció frissítése – Változtasd meg, hol legyen az objektum (például mozgasd 5 pixellel jobbra)
- Régi képkocka eltüntetése – Töröld a képernyőt, hogy ne láss szellemszerű nyomokat
- Ú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ául37, ami azArrowLeft-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éskeyupesemé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:
keysztringek éskeyCodeszá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:5000cí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
-
Adj hozzá dedikált objektumokat a
hero-hoz, aenemy-hez és agame object-hez, melyeknek legyenxésytulajdonsága. (Emlékezz az öröklődés vagy összetétel részre.)TIP A
game objectlegyen az, amely rendelkezikxésytulajdonsággal, és képes magát megrajzolni a vászonra.Tipp: Először adj hozzá egy új
GameObjectosztá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
deadjelző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
-
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
onKeyDownfü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
keydownesemé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.
- Figyel a
-
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:
-
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
-
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); } -
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
-
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; }); -
Állítsd be a játékhurokot
Refaktoráld a
window.onloadfü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
awaithaszná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
-
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
Á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
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.