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

236 lines
7.9 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": "05be6c37791668e3719c4fba94566367",
"translation_date": "2025-08-29T14:47:07+00:00",
"source_file": "6-space-game/6-end-condition/README.md",
"language_code": "zh"
}
-->
# 构建太空游戏第六部分:结束与重启
## 课前测验
[课前测验](https://ff-quizzes.netlify.app/web/quiz/39)
在游戏中,有多种方式来表达*结束条件*。作为游戏的创作者,你需要决定游戏为何结束。以下是一些可能的原因,假设我们正在讨论你目前正在构建的太空游戏:
- **摧毁了`N`艘敌方飞船**:如果你将游戏分为不同的关卡,那么通常需要摧毁`N`艘敌方飞船才能完成一个关卡。
- **你的飞船被摧毁**:有些游戏中,如果你的飞船被摧毁,你就会输掉游戏。另一种常见的方法是引入“生命”的概念。每次飞船被摧毁时,扣除一条生命。当所有生命耗尽时,游戏结束。
- **收集了`N`分**:另一种常见的结束条件是收集一定的分数。如何获得分数取决于你,但通常会为各种活动分配分数,比如摧毁敌方飞船,或者收集敌方飞船被摧毁后掉落的物品。
- **完成一个关卡**:这可能涉及多个条件,比如摧毁`X`艘敌方飞船、收集`Y`分,或者收集某个特定的物品。
## 重启
如果玩家喜欢你的游戏,他们可能会想要重新玩一次。当游戏因某种原因结束时,你应该提供一个重启的选项。
✅ 想一想,在什么条件下你认为游戏会结束,然后玩家会如何被提示重启。
## 要构建的内容
你需要为游戏添加以下规则:
1. **赢得游戏**。当所有敌方飞船被摧毁时,玩家赢得游戏。此外,显示某种胜利信息。
2. **重启**。当所有生命耗尽或游戏胜利时,你应该提供一种方式来重启游戏。记住!你需要重新初始化游戏,并清除之前的游戏状态。
## 推荐步骤
找到在`your-work`子文件夹中为你创建的文件。它应该包含以下内容:
```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服务器。打开浏览器并输入该地址。你的游戏应该处于可玩的状态。
> 提示为了避免在Visual Studio Code中出现警告编辑`window.onload`函数,使其直接调用`gameLoopId`(不使用`let`),并在文件顶部独立声明`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;
}
```
2. **添加逻辑到消息处理程序**。编辑`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);
});
```
3. **添加新的消息类型**。将这些消息添加到常量对象中:
```javascript
GAME_END_LOSS: "GAME_END_LOSS",
GAME_END_WIN: "GAME_END_WIN",
```
4. **添加重启代码**,以便在按下选定按钮时重启游戏。
1. **监听按键`Enter`**。编辑窗口的事件监听器以监听该按键:
```javascript
else if(evt.key === "Enter") {
eventEmitter.emit(Messages.KEY_EVENT_ENTER);
}
```
2. **添加重启消息**。将此消息添加到你的消息常量中:
```javascript
KEY_EVENT_ENTER: "KEY_EVENT_ENTER",
```
5. **实现游戏规则**。实现以下游戏规则:
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);
}
```
2. 创建一个`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)
}
```
2. **重启逻辑**。当所有生命耗尽或玩家赢得游戏时,显示游戏可以重启。此外,当按下*重启*键时重启游戏(你可以决定哪个键映射到重启)。
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);
}
}
```
2. 在`initGame()`中添加调用`eventEmitter`以重置游戏:
```javascript
eventEmitter.on(Messages.KEY_EVENT_ENTER, () => {
resetGame();
});
```
3. 为EventEmitter添加一个`clear()`函数:
```javascript
clear() {
this.listeners = {};
}
```
👽 💥 🚀 恭喜你,船长!你的游戏完成了!干得好!🚀 💥 👽
---
## 🚀 挑战
添加一个音效!你能为游戏添加音效以增强游戏体验吗?比如在激光命中、英雄飞船死亡或胜利时播放音效?查看这个[sandbox](https://www.w3schools.com/jsref/tryit.asp?filename=tryjsref_audio_play)来学习如何使用JavaScript播放音效。
## 课后测验
[课后测验](https://ff-quizzes.netlify.app/web/quiz/40)
## 复习与自学
你的任务是创建一个全新的样本游戏,因此探索一些有趣的游戏,看看你可能会构建哪种类型的游戏。
## 作业
[构建一个样本游戏](assignment.md)
---
**免责声明**
本文档使用AI翻译服务[Co-op Translator](https://github.com/Azure/co-op-translator)进行翻译。尽管我们努力确保准确性,但请注意,自动翻译可能包含错误或不准确之处。应以原始语言的文档作为权威来源。对于关键信息,建议使用专业人工翻译。因使用本翻译而引起的任何误解或误读,我们概不负责。