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/sr/6-space-game/6-end-condition/README.md

353 lines
23 KiB

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

<!--
CO_OP_TRANSLATOR_METADATA:
{
"original_hash": "46bcdd9a0174031655a49bb062aa279c",
"translation_date": "2025-10-24T23:40:13+00:00",
"source_file": "6-space-game/6-end-condition/README.md",
"language_code": "sr"
}
-->
# Изградња свемирске игре, део 6: Крај и поновни почетак
Свака добра игра треба јасне услове за завршетак и глатки механизам за поновни почетак. Направили сте импресивну свемирску игру са кретањем, борбом и бодовањем - сада је време да додате последње делове који ће је учинити комплетном.
Ваша игра тренутно траје бесконачно, као сонде Voyager које је NASA лансирала 1977. године - и даље путују кроз свемир деценијама касније. Иако је то у реду за свемирска истраживања, играма су потребне дефинисане тачке завршетка како би пружиле задовољавајуће искуство.
Данас ћемо имплементирати одговарајуће услове за победу/пораз и систем за поновни почетак. На крају овог часа, имаћете полиранију игру коју играчи могу завршити и поново играти, баш као класичне аркадне игре које су дефинисале медијум.
## Квиз пре предавања
[Квиз пре предавања](https://ff-quizzes.netlify.app/web/quiz/39)
## Разумевање услова за завршетак игре
Када ваша игра треба да се заврши? Ово фундаментално питање обликовало је дизајн игара још од ране аркадне ере. Pac-Man се завршава када вас ухвате духови или очистите све тачке, док се Space Invaders завршава када ванземаљци стигну до дна или их све уништите.
Као креатор игре, ви дефинишете услове за победу и пораз. За нашу свемирску игру, ево проверених приступа који стварају занимљиве игре:
- **Уништили сте `N` непријатељских бродова**: Ово је прилично уобичајено ако поделите игру на различите нивое, где је потребно уништити `N` непријатељских бродова да бисте завршили ниво.
- **Ваш брод је уништен**: Постоје игре у којима губите ако је ваш брод уништен. Други уобичајени приступ је концепт живота. Сваки пут када је ваш брод уништен, одузима се један живот. Када изгубите све животе, губите игру.
- **Сакупили сте `N` поена**: Други уобичајени услов за завршетак је сакупљање поена. Како добијате поене зависи од вас, али је прилично уобичајено доделити поене за различите активности као што су уништавање непријатељског брода или сакупљање предмета који падају када се униште.
- **Завршили сте ниво**: Ово може укључивати неколико услова као што су уништавање `X` непријатељских бродова, сакупљање `Y` поена или можда сакупљање одређеног предмета.
## Имплементација функције за поновни почетак игре
Добре игре подстичу поновно играње кроз глатке механизме за поновни почетак. Када играчи заврше игру (или доживе пораз), често желе одмах да покушају поново - било да би побољшали свој резултат или своје перформансе.
Тетрис је савршен пример за то: када ваши блокови стигну до врха, можете одмах започети нову игру без проласка кроз сложене меније. Направићемо сличан систем за поновни почетак који чисто ресетује стање игре и брзо враћа играче у акцију.
**Размишљање**: Размислите о играма које сте играли. Под којим условима се завршавају и како вас подстичу да их поново започнете? Шта чини искуство поновног почетка глатким, а шта фрустрирајућим?
## Шта ћете направити
Имплементираћете завршне функције које ће трансформисати ваш пројекат у комплетно искуство игре. Ови елементи разликују полиране игре од основних прототипова.
**Ево шта данас додајемо:**
1. **Услов за победу**: Уништи све непријатеље и добиј заслужену прославу!
2. **Услов за пораз**: Изгуби све животе и суочи се са поразом на екрану
3. **Механизам за поновни почетак**: Притисни Enter да се одмах вратиш у игру - јер једна игра никад није довољна
4. **Управљање стањем**: Чиста табла сваки пут - без преосталих непријатеља или чудних грешака из претходне игре
## Почетак
Припремимо ваш развојни окружење. Требало би да имате све датотеке свемирске игре из претходних лекција спремне.
**Ваш пројекат би требало да изгледа отприлике овако:**
```bash
-| assets
-| enemyShip.png
-| player.png
-| laserRed.png
-| life.png
-| index.html
-| app.js
-| package.json
```
**Покрените ваш развојни сервер:**
```bash
cd your-work
npm start
```
**Ова команда:**
- Покреће локални сервер на `http://localhost:5000`
- Правилно сервира ваше датотеке
- Аутоматски освежава када направите промене
Отворите `http://localhost:5000` у вашем претраживачу и проверите да ли ваша игра ради. Требало би да можете да се крећете, пуцате и интерагујете са непријатељима. Када потврдите, можемо наставити са имплементацијом.
> 💡 **Савет**: Да бисте избегли упозорења у Visual Studio Code, декларишите `gameLoopId` на врху вашег фајла као `let gameLoopId;` уместо да га декларишете унутар функције `window.onload`. Ово прати најбоље праксе модерног JavaScript-а за декларисање променљивих.
## Кораци имплементације
### Корак 1: Креирање функција за праћење услова завршетка
Потребне су нам функције које ће пратити када игра треба да се заврши. Као сензори на Међународној свемирској станици који стално прате критичне системе, ове функције ће континуирано проверавати стање игре.
```javascript
function isHeroDead() {
return hero.life <= 0;
}
function isEnemiesDead() {
const enemies = gameObjects.filter((go) => go.type === "Enemy" && !go.dead);
return enemies.length === 0;
}
```
**Ево шта се дешава у позадини:**
- **Проверава** да ли је наш херој остао без живота (ау!)
- **Броји** колико непријатеља је још увек живо
- **Враћа** `true` када је бојно поље чисто од непријатеља
- **Користи** једноставну логику true/false ради једноставности
- **Филтрира** све објекте игре да би пронашао преживеле
### Корак 2: Ажурирање обрађивача догађаја за услове завршетка
Сада ћемо повезати ове провере услова са системом догађаја игре. Сваки пут када дође до судара, игра ће проценити да ли то покреће услов за завршетак. Ово ствара тренутну повратну информацију за критичне догађаје у игри.
```javascript
eventEmitter.on(Messages.COLLISION_ENEMY_LASER, (_, { first, second }) => {
first.dead = true;
second.dead = true;
hero.incrementPoints();
if (isEnemiesDead()) {
eventEmitter.emit(Messages.GAME_END_WIN);
}
});
eventEmitter.on(Messages.COLLISION_ENEMY_HERO, (_, { enemy }) => {
enemy.dead = true;
hero.decrementLife();
if (isHeroDead()) {
eventEmitter.emit(Messages.GAME_END_LOSS);
return; // loss before victory
}
if (isEnemiesDead()) {
eventEmitter.emit(Messages.GAME_END_WIN);
}
});
eventEmitter.on(Messages.GAME_END_WIN, () => {
endGame(true);
});
eventEmitter.on(Messages.GAME_END_LOSS, () => {
endGame(false);
});
```
**Шта се овде дешава:**
- **Ласер погоди непријатеља**: Оба нестају, добијате поене и проверавамо да ли сте победили
- **Непријатељ вас погоди**: Губите живот и проверавамо да ли сте још увек у игри
- **Паметно редослед**: Прво проверавамо пораз (никоме није драго да победи и изгуби у исто време!)
- **Тренутне реакције**: Чим се нешто важно догоди, игра то зна
### Корак 3: Додавање нових константи за поруке
Мораћете да додате нове типове порука у ваш објекат `Messages`. Ове константе помажу у одржавању конзистентности и спречавају грешке у вашем систему догађаја.
```javascript
GAME_END_LOSS: "GAME_END_LOSS",
GAME_END_WIN: "GAME_END_WIN",
```
**У горњем коду, урадили смо:**
- **Додали** константе за догађаје завршетка игре ради одржавања конзистентности
- **Користили** описне називе који јасно указују на сврху догађаја
- **Пратили** постојећу конвенцију именовања за типове порука
### Корак 4: Имплементација контрола за поновни почетак
Сада ћете додати контроле на тастатури које омогућавају играчима да поново покрену игру. Тастер Enter је природан избор јер се обично повезује са потврђивањем радњи и покретањем нових игара.
**Додајте детекцију тастера Enter у ваш постојећи слушалац догађаја keydown:**
```javascript
else if(evt.key === "Enter") {
eventEmitter.emit(Messages.KEY_EVENT_ENTER);
}
```
**Додајте нову константу поруке:**
```javascript
KEY_EVENT_ENTER: "KEY_EVENT_ENTER",
```
**Шта треба да знате:**
- **Проширује** ваш постојећи систем за обраду догађаја на тастатури
- **Користи** тастер Enter као окидач за поновни почетак ради интуитивног корисничког искуства
- **Емитује** прилагођени догађај који други делови ваше игре могу слушати
- **Одржава** исти образац као и ваше друге контроле на тастатури
### Корак 5: Креирање система за приказ порука
Ваша игра треба јасно да комуницира резултате играчима. Креираћемо систем порука који приказује стања победе и пораза користећи текст у боји, слично интерфејсима терминала раних компјутерских система где је зелена означавала успех, а црвена сигнализирала грешке.
**Креирајте функцију `displayMessage()`:**
```javascript
function displayMessage(message, color = "red") {
ctx.font = "30px Arial";
ctx.fillStyle = color;
ctx.textAlign = "center";
ctx.fillText(message, canvas.width / 2, canvas.height / 2);
}
```
**Корак по корак, ево шта се дешава:**
- **Поставља** величину и стил фонта за јасан, читљив текст
- **Примењује** параметар боје са "црвеном" као подразумеваном за упозорења
- **Центрира** текст хоризонтално и вертикално на платну
- **Користи** модерне JavaScript подразумеване параметре за флексибилне опције боја
- **Користи** 2D контекст платна за директно рендеровање текста
**Креирајте функцију `endGame()`:**
```javascript
function endGame(win) {
clearInterval(gameLoopId);
// Set a delay to ensure any pending renders complete
setTimeout(() => {
ctx.clearRect(0, 0, canvas.width, canvas.height);
ctx.fillStyle = "black";
ctx.fillRect(0, 0, canvas.width, canvas.height);
if (win) {
displayMessage(
"Victory!!! Pew Pew... - Press [Enter] to start a new game Captain Pew Pew",
"green"
);
} else {
displayMessage(
"You died !!! Press [Enter] to start a new game Captain Pew Pew"
);
}
}, 200)
}
```
**Шта ова функција ради:**
- **Замрзава** све на месту - нема више кретања бродова или ласера
- **Прави** кратку паузу (200ms) да заврши цртање последњег кадра
- **Брише** екран и боји га у црно ради драматичног ефекта
- **Приказује** различите поруке за победнике и губитнике
- **Кодира боје** вести - зелена за добро, црвена за... па, не баш добро
- **Каже** играчима тачно како да се поново укључе
### Корак 6: Имплементација функције за ресетовање игре
Систем за ресетовање треба потпуно да очисти тренутно стање игре и иницијализује нову сесију игре. Ово осигурава да играчи добију чист почетак без преосталих података из претходне игре.
**Креирајте функцију `resetGame()`:**
```javascript
function resetGame() {
if (gameLoopId) {
clearInterval(gameLoopId);
eventEmitter.clear();
initGame();
gameLoopId = setInterval(() => {
ctx.clearRect(0, 0, canvas.width, canvas.height);
ctx.fillStyle = "black";
ctx.fillRect(0, 0, canvas.width, canvas.height);
drawPoints();
drawLife();
updateGameObjects();
drawGameObjects(ctx);
}, 100);
}
}
```
**Разумимо сваки део:**
- **Проверава** да ли тренутно ради петља игре пре ресетовања
- **Чисти** постојећу петљу игре да заустави све тренутне активности игре
- **Уклања** све слушаоце догађаја да би спречио цурење меморије
- **Реинцијализује** стање игре са новим објектима и променљивим
- **Покреће** нову петљу игре са свим основним функцијама игре
- **Одржава** исти интервал од 100ms ради конзистентног перформанса игре
**Додајте обрађивач догађаја за тастер Enter у вашу функцију `initGame()`:**
```javascript
eventEmitter.on(Messages.KEY_EVENT_ENTER, () => {
resetGame();
});
```
**Додајте метод `clear()` у вашу класу EventEmitter:**
```javascript
clear() {
this.listeners = {};
}
```
**Кључне тачке за памћење:**
- **Повезује** притисак тастера Enter са функционалношћу ресетовања игре
- **Региструје** овог слушаоца догађаја током иницијализације игре
- **Обезбеђује** чист начин за уклањање свих слушалаца догађаја приликом ресетовања
- **Спречава** цурење меморије чишћењем обрађивача догађаја између игара
- **Ресетује** објекат слушалаца на празно стање ради нове иницијализације
## Честитамо! 🎉
👽 💥 🚀 Успешно сте изградили комплетну игру од самог почетка. Као програмери који су креирали прве видео игре 1970-их, трансформисали сте линије кода у интерактивно искуство са одговарајућим механикама игре и повратним информацијама корисника. 🚀 💥 👽
**Постигли сте:**
- **Имплементирали** комплетне услове за победу и пораз са повратним информацијама корисника
- **Креирали** беспрекорни систем за поновни почетак ради континуиране игре
- **Дизајнирали** јасну визуелну комуникацију за стања игре
- **Управљали** сложеним прелазима стања игре и чишћењем
- **Саставили** све компоненте у кохезивну, играљиву игру
## Изазов GitHub Copilot Agent 🚀
Користите Agent мод да завршите следећи изазов:
**Опис:** Унапредите свемирску игру имплементацијом система за напредовање кроз нивое са повећаном тежином и бонус функцијама.
**Задатак:** Креирајте систем за више нивоа свемирске игре где сваки ниво има више непријатељских бродова са повећаном брзином и здрављем. Додајте множилац бодова који се повећава са сваким нивоом и имплементирајте појачања (као што су брза ватра или штит) која се насумично појављују када се непријатељи униште. Укључите бонус за завршетак нивоа и приказујте тренутни ниво на екрану уз постојеће бодове и животе.
Сазнајте више о [agent mode](https://code.visualstudio.com/blogs/2025/02/24/introducing-copilot-agent-mode) овде.
## 🚀 Опциони изазов за унапређење
**Додајте звук вашој игри**: Унапредите искуство играња имплементацијом звучних ефеката! Размислите о додавању звука за:
- **Ласерске пуцње** када играч пуца
- **Уништавање непријатеља** када су бродови погођени
- **Оштећење хероја** када играч прими ударце
- **Музику победе** када је игра добијена
- **Звук пораза** када је игра изгубљена
**Пример имплементације звука:**
```javascript
// Create audio objects
const laserSound = new Audio('assets/laser.wav');
const explosionSound = new Audio('assets/explosion.wav');
// Play sounds during game events
function playLaserSound() {
laserSound.currentTime = 0; // Reset to beginning
laserSound.play();
}
```
**Шта треба да знате:**
- **Креира** Audio објекте за различите звучне ефекте
- **Ресетује** `currentTime` ради омогућавања брзих звучних ефеката
- **Рукује** политикама
---
**Одрицање од одговорности**:
Овај документ је преведен помоћу услуге за превођење вештачке интелигенције [Co-op Translator](https://github.com/Azure/co-op-translator). Иако настојимо да обезбедимо тачност, молимо вас да имате у виду да аутоматски преводи могу садржати грешке или нетачности. Оригинални документ на његовом изворном језику треба сматрати ауторитативним извором. За критичне информације препоручује се професионални превод од стране људи. Не преузимамо одговорност за било каква погрешна тумачења или неспоразуме који могу произаћи из коришћења овог превода.