# Space 게임 제작하기 파트 6: 끝과 재시작
## 강의 전 퀴즈
[Pre-lecture quiz ](https://wonderful-flower-063e19f0f.1.azurestaticapps.net/quiz/39?loc=ko )
게임에서 *조건을 표현하고 종료* 하는 여러 방식이 있습니다. 게임이 종료된 이유를 말하는 것은 게임 크리에이터의 일입니다. 지금까지 만든 space 게임에 대해 말하고 있다고 가정하면, 몇 가지 이유가 있습니다:
- **`N`개의 적 배가 파괴되었습니다**: 게임을 여러 레벨로 나누면 레벨을 완료하기 위해 `N` 개의 적 배를 부숴야하는 경우가 매우 흔합니다.
- **배가 파괴되었습니다**: 배가 부서지면 지는 게임이 분명 있습니다. 또 다른 일반적인 접근 방식은 생명의 컨셉을 가지고 있다는 점입니다. 배가 부서질 때마다 생명이 깍입니다. 모든 목숨을 잃으면 게임에서 집니다.
- **`N` 점수를 모았습니다**: 또 다른 종료 조건은 점수를 모으는 것입니다. 점수를 얻는 방법으로 각자 배를 파괴하는 것처럼 다양한 활동에 점수를 할당하거나 아이템이 부서질 때마다 *떨구는* 아이템을 수집하는 것은 매우 일반적입니다.
- **레벨을 완료했습니다**: 적 배를 `X` 번 부시거나, `Y` 점수를 수집하거나 특정 아이템을 수집하는 것처럼 여러 조건들을 여기에 포함할 수 있습니다.
## 다시 시작하기
사람들이 게임을 즐기고 있다면 다시 플레이하고 싶어합니다. 어떤 이유든지 게임이 끝나면 다시 시작할 수 있는 대안을 줘야합니다.
✅ 어떤 조건에서 게임이 끝나는 지에 대하여 찾고, 다시 시작이라는 메시지가 어떻게 보일지 생각해보세요
## 무엇을 만드나요
게임에 다음 규칙을 추가합니다:
1. ** 게임에 우승합니다**. 모든 적의 배가 부서지면, 게임에서 승리합니다. 추가로 일종의 승리 메시지를 출력합니다.
1. ** 다시 시작합니다**. 모든 생명을 잃거나 게임에서 이긴다면, 게임을 다시 시작할 방법을 제공해야 합니다. 생각해보세요! 게임을 다시 초기화하고 이전 게임 상태를 깨끗이 지워야 합니다.
## 권장 단계
`your-work` 하위 폴더에서 생성된 파일을 찾습니다. 다음을 포함해야 합니다:
```bash
-| assets
-| enemyShip.png
-| player.png
-| laserRed.png
-| life.png
-| index.html
-| app.js
-| package.json
```
타이핑해서 `your_work` 폴더에 프로젝트를 시작합니다:
```bash
cd your-work
npm start
```
위 코드는 `http://localhost:5000` 주소에서 HTTP 서버를 시작합니다. 브라우저를 열고 해당 주소를 입력합니다. 게임은 플레이 가능한 상태여야 합니다.
> tip: Visual Studio Code에서 경고를 보이지 않게 하려면, `gameLoopId`를 (`let`없이) 그대로 호출하도록 `window.onload` 함수를 편집하고, 파일 최상단에 gameLoopId를 독립적으로 선언합니다: `let gameLoopId;`
### 코드 추가하기
1. ** 종료 조건을 추적합니다**. 다음 두 함수를 추가하여 적의 수를 추적하거나, 영웅의 배가 부서진 경우도 추적해주는 코드를 추가합니다:
```javascript
function isHeroDead() {
return hero.life < = 0;
}
function isEnemiesDead() {
const enemies = gameObjects.filter((go) => go.type === "Enemy" & & !go.dead);
return enemies.length === 0;
}
```
1. ** 메시지 핸들러에 로직을 추가합니다**. 이 조건을 제어하도록 `eventEmitter` 를 편집합니다:
```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);
});
```
1. ** 새로운 메시지 타입을 추가합니다**. 상수 객체에 이 메시지를 추가합니다:
```javascript
GAME_END_LOSS: "GAME_END_LOSS",
GAME_END_WIN: "GAME_END_WIN",
```
2. ** 재시작 코드를 추가합니다** 선택한 버튼을 누르면 게임을 다시 시작하는 코드입니다.
1. ** `Enter` 누를 키를 수신합니다**. 누르는 것을 수신하도록 윈도우의 이벤트 리스너를 편집합니다:
```javascript
else if(evt.key === "Enter") {
eventEmitter.emit(Messages.KEY_EVENT_ENTER);
}
```
1. ** 재시작 메시지 추가하기**. 메시지를 메시지 상수에 추가합니다:
```javascript
KEY_EVENT_ENTER: "KEY_EVENT_ENTER",
```
1. ** 게임 규칙을 구현합니다**. 다음 게임 규칙을 구현합니다:
1. ** 플레이어 승리 조건입니다**. 적 배가 모두 파괴되면, 승리 메시지를 출력합니다.
1. 먼저, `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);
}
```
1. `endGame()` 함수를 만듭니다:
```javascript
function endGame(win) {
clearInterval(gameLoopId);
// set a delay so we are sure any paints have finished
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)
}
```
1. ** 로직을 다시 시작합니다**. 모든 생명을 잃거나 플레이어가 게임에서 이긴다면, 게임을 다시 시작할 수 있다고 출력합니다. 추가로 *restart* 키를 누르면 게임을 다시 시작합니다 (다시 시작하기 위해 매핑할 키를 고를 수 있습니다).
1. `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);
}
}
```
1. `initGame()` 에서 게임을 다시 설정하기 위해 `eventEmitter` 에 호출하도록 추가합니다:
```javascript
eventEmitter.on(Messages.KEY_EVENT_ENTER, () => {
resetGame();
});
```
1. EventEmitter에 `clear()` 힘수를 추가합니다:
```javascript
clear() {
this.listeners = {};
}
```
👽 💥 🚀 축하합니다, 대장! 게임이 완성되었습니다! 잘 하셨습니다! 🚀 💥 👽
---
## 🚀 도전
소리를 추가해보세요! 레이저가 때리거나, 영웅이 죽고 이길 때, 소리를 추가하여 게임 플레이를 향상시킬 수 있나요? [sandbox ](https://www.w3schools.com/jsref/tryit.asp?filename=tryjsref_audio_play )에서 JavaScript로 소리를 재생하는 방법에 대하여 알아보세요
## 강의 후 퀴즈
[Post-lecture quiz ](https://wonderful-flower-063e19f0f.1.azurestaticapps.net/quiz/40?loc=ko )
## 리뷰 & 자기주도 학습
과제는 새로운 샘플 게임을 만드는 것이므로, 어떤 타입의 게임을 만들 수 있는지 알아보고 흥미로운 게임을 찾아보세요.
## 과제
[Build a Sample Game ](../assignment.md )