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/README.md

402 lines
15 KiB

<!--
CO_OP_TRANSLATOR_METADATA:
{
"original_hash": "a9a161871de7706cb0e23b1bd0c74559",
"translation_date": "2025-08-29T10:27:17+00:00",
"source_file": "6-space-game/3-moving-elements-around/README.md",
"language_code": "hu"
}
-->
# Űrjáték készítése 3. rész: Mozgás hozzáadása
## 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ékok nem igazán szórakoztatóak, amíg nem látunk ide-oda mozgó idegeneket a képernyőn! Ebben a játékban kétféle mozgást fogunk használni:
- **Billentyűzet/egér mozgás**: amikor a felhasználó a billentyűzettel vagy egérrel mozgat egy objektumot a képernyőn.
- **Játék által generált mozgás**: amikor a játék bizonyos időközönként mozgat egy objektumot.
De hogyan mozgatunk dolgokat a képernyőn? Az egész a derékszögű koordinátákról szól: megváltoztatjuk az objektum helyét (x, y), majd újrarajzoljuk a képernyőt.
Általában a következő lépések szükségesek a *mozgás* megvalósításához a képernyőn:
1. **Új hely meghatározása** egy objektum számára; ez szükséges ahhoz, hogy az objektum mozgását érzékeljük.
2. **Képernyő törlése**, a képernyőt minden rajzolás között törölni kell. Ezt úgy tehetjük meg, hogy egy téglalapot rajzolunk, amelyet kitöltünk egy háttérszínnel.
3. **Objektum újrarajzolása** az új helyen. Ezzel végül elérjük, hogy az objektum egyik helyről a másikra mozogjon.
Így nézhet ki ez a kódban:
```javascript
//set the hero's location
hero.x += 5;
// clear the rectangle that hosts the hero
ctx.clearRect(0, 0, canvas.width, canvas.height);
// redraw the game background and hero
ctx.fillRect(0, 0, canvas.width, canvas.height)
ctx.fillStyle = "black";
ctx.drawImage(heroImg, hero.x, hero.y);
```
✅ Gondolkozz el azon, hogy miért okozhat teljesítményproblémákat, ha a hősödet másodpercenként sokszor újrarajzolod? Olvass utána az [alternatív megoldásoknak](https://developer.mozilla.org/en-US/docs/Web/API/Canvas_API/Tutorial/Optimizing_canvas).
## Billentyűesemények kezelése
Az eseményeket úgy kezeljük, hogy specifikus eseményeket kapcsolunk kódhoz. A billentyűesemények az egész ablakra vonatkoznak, míg az egér események, például a `click`, egy adott elemhez kapcsolhatók. Ebben a projektben billentyűeseményeket fogunk használni.
Egy esemény kezeléséhez az ablak `addEventListener()` metódusát kell használnod, és két bemeneti paramétert kell megadnod. Az első paraméter az esemény neve, például `keyup`. A második paraméter az a függvény, amelyet az esemény bekövetkezésekor meg kell hívni.
Íme egy példa:
```javascript
window.addEventListener('keyup', (evt) => {
// `evt.key` = string representation of the key
if (evt.key === 'ArrowUp') {
// do something
}
})
```
A billentyűeseményekhez két tulajdonságot használhatsz az eseményen belül, hogy megtudd, melyik billentyűt nyomták meg:
- `key`: ez a megnyomott billentyű szöveges ábrázolása, például `ArrowUp`.
- `keyCode`: ez a számérték, például `37`, amely az `ArrowLeft`-nek felel meg.
✅ A billentyűesemények kezelése a játékfejlesztésen kívül is hasznos lehet. Milyen más felhasználási módokat tudsz elképzelni ehhez a technikához?
### Speciális billentyűk: egy figyelmeztetés
Vannak bizonyos *speciális* billentyűk, amelyek hatással vannak az ablakra. Ez azt jelenti, hogy ha például egy `keyup` eseményt figyelsz, és ezeket a speciális billentyűket használod a hős mozgatására, akkor vízszintes görgetés is történhet. Emiatt érdemes lehet *kikapcsolni* ezt a beépített böngészői viselkedést, miközben a játékodat építed. Ehhez ilyen kódra van szükséged:
```javascript
let onKeyDown = function (e) {
console.log(e.keyCode);
switch (e.keyCode) {
case 37:
case 39:
case 38:
case 40: // Arrow keys
case 32:
e.preventDefault();
break; // Space
default:
break; // do not block other keys
}
};
window.addEventListener('keydown', onKeyDown);
```
A fenti kód biztosítja, hogy a nyílbillentyűk és a szóköz billentyű *alapértelmezett* viselkedése ki legyen kapcsolva. A *kikapcsolás* a `e.preventDefault()` hívásával történik.
## Játék által generált mozgás
Az objektumokat maguktól is mozgathatjuk időzítők, például a `setTimeout()` vagy `setInterval()` függvények segítségével, amelyek minden időintervallumban frissítik az objektum helyét. Így nézhet ki ez:
```javascript
let id = setInterval(() => {
//move the enemy on the y axis
enemy.y += 10;
})
```
## A játékciklus
A játékciklus egy olyan koncepció, amely lényegében egy rendszeresen meghívott függvény. Azért hívják játékciklusnak, mert minden, amit a felhasználónak látnia kell, ebben a ciklusban kerül kirajzolásra. A játékciklus az összes játékobjektumot használja, amelyek a játék részét képezik, és mindet kirajzolja, kivéve, ha valamilyen okból már nem részei a játéknak. Például, ha egy objektum egy ellenség, amelyet egy lézer eltalált és felrobbant, akkor az már nem része az aktuális játékciklusnak (erről többet tanulsz a következő leckékben).
Így nézhet ki egy játékciklus kódban kifejezve:
```javascript
let 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();
}, 200);
```
A fenti ciklus minden `200` milliszekundumban meghívódik, hogy újrarajzolja a vásznat. Te döntheted el, hogy mi a legjobb időköz a játékod számára.
## Az Űrjáték folytatása
A meglévő kódot fogod bővíteni. Vagy az első részben elkészült kóddal kezdj, vagy használd a [II. rész - kezdő](../../../../6-space-game/3-moving-elements-around/your-work) kódját.
- **Hős mozgatása**: kódot fogsz hozzáadni, hogy a hőst a nyílbillentyűkkel lehessen mozgatni.
- **Ellenségek mozgatása**: kódot kell hozzáadnod, hogy az ellenségek fentről lefelé mozogjanak egy adott sebességgel.
## Ajánlott lépések
Keresd meg azokat a fájlokat, amelyeket a `your-work` almappában hoztak létre számodra. Ezeknek a következőket kell tartalmazniuk:
```bash
-| assets
-| enemyShip.png
-| player.png
-| index.html
-| app.js
-| package.json
```
A projektedet a `your_work` mappában indíthatod el az alábbi parancs beírásával:
```bash
cd your-work
npm start
```
A fenti parancs egy HTTP szervert indít a `http://localhost:5000` címen. Nyiss meg egy böngészőt, és írd be ezt a címet. Jelenleg a hős és az összes ellenség megjelenik; még semmi sem mozog!
### Kód hozzáadása
1. **Hozz létre dedikált objektumokat** a `hero`, `enemy` és `game object` számára, ezeknek legyen `x` és `y` tulajdonságuk. (Emlékezz az [Öröklődés vagy kompozíció](../README.md) részre).
*TIPP*: A `game object` legyen az, amelyik rendelkezik `x` és `y` tulajdonságokkal, és képes önmagát kirajzolni a vászonra.
>tipp: hozz létre 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);
}
}
```
Most bővítsd ki ezt a GameObject-et, hogy létrehozd a Hero-t és az Enemy-t.
```javascript
class Hero extends GameObject {
constructor(x, y) {
...it needs an x, y, type, and speed
}
}
```
```javascript
class Enemy extends GameObject {
constructor(x, y) {
super(x, y);
(this.width = 98), (this.height = 50);
this.type = "Enemy";
let id = setInterval(() => {
if (this.y < canvas.height - this.height) {
this.y += 5;
} else {
console.log('Stopped at', this.y)
clearInterval(id);
}
}, 300)
}
}
```
2. **Adj hozzá billentyűesemény-kezelőket**, hogy kezeld a hős navigációját (mozgatás fel/le, balra/jobbra).
*EMLÉKEZZ*: Ez egy derékszögű rendszer, a bal felső sarok a `0,0`. Ne felejts el kódot hozzáadni az *alapértelmezett viselkedés* leállításához.
>tipp: hozd létre az onKeyDown függvényedet, és csatold az ablakhoz:
```javascript
let onKeyDown = function (e) {
console.log(e.keyCode);
...add the code from the lesson above to stop default behavior
}
};
window.addEventListener("keydown", onKeyDown);
```
Nézd meg a böngésződ konzolját, és figyeld, ahogy a billentyűleütések naplózásra kerülnek.
3. **Valósítsd meg** a [Pub-sub mintát](../README.md), hogy a kódod tiszta maradjon a további részek során.
Ehhez az utolsó részhez:
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);
}
});
```
1. **Hozz létre egy EventEmitter osztályt**, hogy üzeneteket publikálj és iratkozz fel rájuk:
```javascript
class EventEmitter {
constructor() {
this.listeners = {};
}
on(message, listener) {
if (!this.listeners[message]) {
this.listeners[message] = [];
}
this.listeners[message].push(listener);
}
emit(message, payload = null) {
if (this.listeners[message]) {
this.listeners[message].forEach((l) => l(message, payload));
}
}
}
```
1. **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();
```
1. **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;
});
eventEmitter.on(Messages.KEY_EVENT_RIGHT, () => {
hero.x += 5;
});
}
```
1. **Állítsd be a játékciklust**
Refaktoráld az `window.onload` függvényt, hogy inicializálja a játékot, és állíts be egy játékciklust megfelelő időközönként. Adj hozzá egy lézersugarat is:
```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();
let gameLoopId = setInterval(() => {
ctx.clearRect(0, 0, canvas.width, canvas.height);
ctx.fillStyle = "black";
ctx.fillRect(0, 0, canvas.width, canvas.height);
drawGameObjects(ctx);
}, 100)
};
```
5. **Adj hozzá kódot**, hogy az ellenségek bizonyos időközönként mozogjanak.
Refaktoráld a `createEnemies()` függvényt, hogy létrehozza az ellenségeket, és hozzáadja őket az új gameObjects osztályhoz:
```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);
}
}
}
```
és adj hozzá egy `createHero()` függvényt, hogy hasonló folyamatot végezzen 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);
}
```
végül adj hozzá egy `drawGameObjects()` függvényt, hogy elindítsd a rajzolást:
```javascript
function drawGameObjects(ctx) {
gameObjects.forEach(go => go.draw(ctx));
}
```
Az ellenségeid elindulnak a hős űrhajód felé!
---
## 🚀 Kihívás
Ahogy láthatod, a kódod könnyen "spagetti kóddá" válhat, amikor elkezdesz funkciókat, változókat és osztályokat hozzáadni. Hogyan tudnád jobban megszervezni a kódodat, hogy olvashatóbb legyen? Vázolj fel egy rendszert a kódod megszervezésére, még akkor is, ha az egy fájlban marad.
## 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
Bár a játékunkat keretrendszerek használata nélkül írjuk, számos JavaScript-alapú vászon keretrendszer létezik játékfejlesztéshez. Szánj időt arra, hogy [olvass ezekről](https://github.com/collections/javascript-game-engines).
## Feladat
[Kommentáld a kódodat](assignment.md)
---
**Felelősségkizárás**:
Ez a dokumentum az [Co-op Translator](https://github.com/Azure/co-op-translator) AI fordítási szolgáltatás segítségével készült. Bár törekszünk a pontosságra, kérjük, vegye figyelembe, hogy az automatikus fordítások hibákat vagy pontatlanságokat tartalmazhatnak. Az eredeti dokumentum az eredeti nyelvén tekintendő hiteles forrásnak. Kritikus információk esetén javasolt a professzionális, emberi fordítás igénybevétele. 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.