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/cs/6-space-game/4-collision-detection/README.md

311 lines
11 KiB

<!--
CO_OP_TRANSLATOR_METADATA:
{
"original_hash": "2e83e38c35dc003f046d7cc0bbfd4920",
"translation_date": "2025-08-28T03:57:28+00:00",
"source_file": "6-space-game/4-collision-detection/README.md",
"language_code": "cs"
}
-->
# Vytvořte vesmírnou hru, část 4: Přidání laseru a detekce kolizí
## Kvíz před lekcí
[Kvíz před lekcí](https://ff-quizzes.netlify.app/web/quiz/35)
V této lekci se naučíte střílet lasery pomocí JavaScriptu! Do naší hry přidáme dvě věci:
- **Laser**: tento laser bude vystřelen z lodi vašeho hrdiny a bude se pohybovat vertikálně nahoru
- **Detekce kolizí**, jako součást implementace schopnosti *střílet* přidáme také několik herních pravidel:
- **Laser zasáhne nepřítele**: Nepřítel zemře, pokud ho zasáhne laser
- **Laser zasáhne horní část obrazovky**: Laser bude zničen, pokud zasáhne horní část obrazovky
- **Kolize nepřítele a hrdiny**: Nepřítel i hrdina budou zničeni, pokud do sebe narazí
- **Nepřítel zasáhne spodní část obrazovky**: Nepřítel i hrdina budou zničeni, pokud nepřítel zasáhne spodní část obrazovky
Stručně řečeno, vy -- *hrdina* -- musíte zasáhnout všechny nepřátele laserem, než se dostanou na spodní část obrazovky.
✅ Udělejte si malý průzkum o úplně první počítačové hře, která byla kdy napsána. Jaká byla její funkčnost?
Buďme hrdinové společně!
## Detekce kolizí
Jak provádíme detekci kolizí? Musíme si představit herní objekty jako obdélníky, které se pohybují. Proč? Protože obrázek použitý k vykreslení herního objektu je obdélník: má `x`, `y`, `šířku` a `výšku`.
Pokud se dva obdélníky, například hrdina a nepřítel, *protnou*, dojde ke kolizi. Co by se mělo stát, záleží na pravidlech hry. K implementaci detekce kolizí tedy potřebujete následující:
1. Způsob, jak získat obdélníkové vyjádření herního objektu, například takto:
```javascript
rectFromGameObject() {
return {
top: this.y,
left: this.x,
bottom: this.y + this.height,
right: this.x + this.width
}
}
```
2. Porovnávací funkci, která může vypadat takto:
```javascript
function intersectRect(r1, r2) {
return !(r2.left > r1.right ||
r2.right < r1.left ||
r2.top > r1.bottom ||
r2.bottom < r1.top);
}
```
## Jak ničíme objekty
Abychom mohli ve hře něco zničit, musíme hře sdělit, že tento objekt již nemá být vykreslen v herní smyčce, která se spouští v určitém intervalu. Jedním ze způsobů je označit herní objekt jako *mrtvý*, když se něco stane, například takto:
```javascript
// collision happened
enemy.dead = true
```
Poté můžete *mrtvé* objekty odstranit před opětovným vykreslením obrazovky, například takto:
```javascript
gameObjects = gameObject.filter(go => !go.dead);
```
## Jak vystřelit laser
Vystřelení laseru znamená reagovat na klávesovou událost a vytvořit objekt, který se pohybuje určitým směrem. Musíme tedy provést následující kroky:
1. **Vytvořit laserový objekt**: z horní části lodi našeho hrdiny, který se po vytvoření začne pohybovat směrem nahoru k horní části obrazovky.
2. **Přiřadit kód ke klávesové události**: musíme vybrat klávesu na klávesnici, která bude představovat střelbu laseru hráčem.
3. **Vytvořit herní objekt, který vypadá jako laser**, když je klávesa stisknuta.
## Časový limit pro laser
Laser musí být vystřelen pokaždé, když stisknete klávesu, například *mezerník*. Aby hra nevytvářela příliš mnoho laserů v krátkém čase, musíme to opravit. Řešením je implementace tzv. *časového limitu*, časovače, který zajistí, že laser může být vystřelen jen v určitých intervalech. To můžete implementovat následujícím způsobem:
```javascript
class Cooldown {
constructor(time) {
this.cool = false;
setTimeout(() => {
this.cool = true;
}, time)
}
}
class Weapon {
constructor {
}
fire() {
if (!this.cooldown || this.cooldown.cool) {
// produce a laser
this.cooldown = new Cooldown(500);
} else {
// do nothing - it hasn't cooled down yet.
}
}
}
```
Podívejte se na lekci 1 v sérii vesmírných her, abyste si připomněli, jak fungují *časové limity*.
## Co vytvořit
Vezmete stávající kód (který byste měli vyčistit a refaktorovat) z předchozí lekce a rozšíříte ho. Buď začněte s kódem z části II, nebo použijte kód z [části III - startovací](../../../../6-space-game/4-collision-detection/your-work).
> tip: laser, se kterým budete pracovat, je již ve vaší složce s prostředky a je odkazován vaším kódem
- **Přidejte detekci kolizí**, když laser narazí na něco, měla by platit následující pravidla:
1. **Laser zasáhne nepřítele**: nepřítel zemře, pokud ho zasáhne laser
2. **Laser zasáhne horní část obrazovky**: laser bude zničen, pokud zasáhne horní část obrazovky
3. **Kolize nepřítele a hrdiny**: nepřítel i hrdina budou zničeni, pokud do sebe narazí
4. **Nepřítel zasáhne spodní část obrazovky**: nepřítel i hrdina budou zničeni, pokud nepřítel zasáhne spodní část obrazovky
## Doporučené kroky
Najděte soubory, které byly pro vás vytvořeny ve složce `your-work`. Měla by obsahovat následující:
```bash
-| assets
-| enemyShip.png
-| player.png
-| laserRed.png
-| index.html
-| app.js
-| package.json
```
Spusťte svůj projekt ve složce `your_work` zadáním:
```bash
cd your-work
npm start
```
Tím se spustí HTTP server na adrese `http://localhost:5000`. Otevřete prohlížeč a zadejte tuto adresu, aktuálně by se měl zobrazit hrdina a všichni nepřátelé, nic se však zatím nehýbe :).
### Přidání kódu
1. **Nastavte obdélníkové vyjádření svého herního objektu pro zpracování kolizí**. Následující kód umožňuje získat obdélníkové vyjádření `GameObject`. Upravte svou třídu GameObject, aby ji rozšířila:
```javascript
rectFromGameObject() {
return {
top: this.y,
left: this.x,
bottom: this.y + this.height,
right: this.x + this.width,
};
}
```
2. **Přidejte kód, který kontroluje kolize**. Toto bude nová funkce, která testuje, zda se dva obdélníky protínají:
```javascript
function intersectRect(r1, r2) {
return !(
r2.left > r1.right ||
r2.right < r1.left ||
r2.top > r1.bottom ||
r2.bottom < r1.top
);
}
```
3. **Přidejte schopnost střílet laser**
1. **Přidejte zprávu pro klávesovou událost**. Klávesa *mezerník* by měla vytvořit laser těsně nad lodí hrdiny. Přidejte tři konstanty do objektu Messages:
```javascript
KEY_EVENT_SPACE: "KEY_EVENT_SPACE",
COLLISION_ENEMY_LASER: "COLLISION_ENEMY_LASER",
COLLISION_ENEMY_HERO: "COLLISION_ENEMY_HERO",
```
1. **Zpracujte klávesu mezerník**. Upravte funkci `window.addEventListener` pro událost keyup, aby zpracovávala mezerník:
```javascript
} else if(evt.keyCode === 32) {
eventEmitter.emit(Messages.KEY_EVENT_SPACE);
}
```
1. **Přidejte posluchače**. Upravte funkci `initGame()`, aby hrdina mohl střílet, když je stisknut mezerník:
```javascript
eventEmitter.on(Messages.KEY_EVENT_SPACE, () => {
if (hero.canFire()) {
hero.fire();
}
```
a přidejte novou funkci `eventEmitter.on()`, aby se zajistilo chování, když nepřítel narazí na laser:
```javascript
eventEmitter.on(Messages.COLLISION_ENEMY_LASER, (_, { first, second }) => {
first.dead = true;
second.dead = true;
})
```
1. **Pohyb objektu**, zajistěte, aby se laser postupně pohyboval k horní části obrazovky. Vytvoříte novou třídu Laser, která rozšiřuje `GameObject`, stejně jako dříve:
```javascript
class Laser extends GameObject {
constructor(x, y) {
super(x,y);
(this.width = 9), (this.height = 33);
this.type = 'Laser';
this.img = laserImg;
let id = setInterval(() => {
if (this.y > 0) {
this.y -= 15;
} else {
this.dead = true;
clearInterval(id);
}
}, 100)
}
}
```
1. **Zpracování kolizí**, implementujte pravidla kolizí pro laser. Přidejte funkci `updateGameObjects()`, která testuje kolidující objekty:
```javascript
function updateGameObjects() {
const enemies = gameObjects.filter(go => go.type === 'Enemy');
const lasers = gameObjects.filter((go) => go.type === "Laser");
// laser hit something
lasers.forEach((l) => {
enemies.forEach((m) => {
if (intersectRect(l.rectFromGameObject(), m.rectFromGameObject())) {
eventEmitter.emit(Messages.COLLISION_ENEMY_LASER, {
first: l,
second: m,
});
}
});
});
gameObjects = gameObjects.filter(go => !go.dead);
}
```
Ujistěte se, že jste přidali `updateGameObjects()` do herní smyčky v `window.onload`.
4. **Implementujte časový limit** pro laser, aby mohl být vystřelen jen v určitých intervalech.
Nakonec upravte třídu Hero, aby mohla používat časový limit:
```javascript
class Hero extends GameObject {
constructor(x, y) {
super(x, y);
(this.width = 99), (this.height = 75);
this.type = "Hero";
this.speed = { x: 0, y: 0 };
this.cooldown = 0;
}
fire() {
gameObjects.push(new Laser(this.x + 45, this.y - 10));
this.cooldown = 500;
let id = setInterval(() => {
if (this.cooldown > 0) {
this.cooldown -= 100;
} else {
clearInterval(id);
}
}, 200);
}
canFire() {
return this.cooldown === 0;
}
}
```
V tomto bodě má vaše hra určitou funkčnost! Můžete se pohybovat pomocí šipek, střílet laser mezerníkem a nepřátelé zmizí, když je zasáhnete. Skvělá práce!
---
## 🚀 Výzva
Přidejte explozi! Podívejte se na herní prostředky v [repozitáři Space Art](../../../../6-space-game/solution/spaceArt/readme.txt) a zkuste přidat explozi, když laser zasáhne mimozemšťana.
## Kvíz po lekci
[Kvíz po lekci](https://ff-quizzes.netlify.app/web/quiz/36)
## Přehled a samostudium
Experimentujte s intervaly ve své hře. Co se stane, když je změníte? Přečtěte si více o [časových událostech v JavaScriptu](https://www.freecodecamp.org/news/javascript-timing-events-settimeout-and-setinterval/).
## Zadání
[Prozkoumejte kolize](assignment.md)
---
**Prohlášení**:
Tento dokument byl přeložen pomocí služby pro automatický překlad [Co-op Translator](https://github.com/Azure/co-op-translator). Ačkoli se snažíme o přesnost, mějte prosím na paměti, že automatické překlady mohou obsahovat chyby nebo nepřesnosti. Původní dokument v jeho původním jazyce by měl být považován za závazný zdroj. Pro důležité informace doporučujeme profesionální lidský překlad. Neodpovídáme za žádná nedorozumění nebo nesprávné interpretace vyplývající z použití tohoto překladu.