习题
游戏结束
按照惯例,平台游戏中玩家一开始会有有限数量的生命,每死亡一次就扣去一条生命。当玩家生命耗尽时,游戏就从头开始了。
调整runGame
来实现生命机制。玩家一开始会有 3 条生命。每次启动时输出当前生命数量(使用console.log
)。
<link rel="stylesheet" href="css/game.css">
<body>
<script>
// The old runGame function. Modify it...
async function runGame(plans, Display) {
for (let level = 0; level < plans.length;) {
let status = await runLevel(new Level(plans[level]),
Display);
if (status == "won") level++;
}
console.log("You've won!");
}
runGame(GAME_LEVELS, DOMDisplay);
</script>
</body>
暂停游戏
现在实现一个功能 —— 当用户按下 ESC 键时可以暂停或继续游戏。
我们可以修改runLevel
函数,使用另一个键盘事件处理器来实现在玩家按下 ESC 键的时候中断或恢复动画。
乍看起来,runAnimation
无法完成该任务,但如果我们使用runLevel
来重新安排调度策略,也是可以实现的。
当你完成该功能后,可以尝试加入另一个功能。我们现在注册键盘事件处理器的方法多少有点问题。现在arrows
对象是一个全局绑定,即使游戏没有运行时,事件处理器也是有效的。我们称之为系统泄露。请扩展tracKeys
,提供一种方法来注销事件处理器,接着修改runLevel
在启动游戏时注册事件处理器,并在游戏结束后注销事件处理器。
<link rel="stylesheet" href="css/game.css">
<body>
<script>
// The old runLevel function. Modify this...
function runLevel(level, Display) {
let display = new Display(document.body, level);
let state = State.start(level);
let ending = 1;
return new Promise(resolve => {
runAnimation(time => {
state = state.update(time, arrowKeys);
display.setState(state);
if (state.status == "playing") {
return true;
} else if (ending > 0) {
ending -= time;
return true;
} else {
display.clear();
resolve(state.status);
return false;
}
});
});
}
runGame(GAME_LEVELS, DOMDisplay);
</script>
</body>
怪物
它是传统的平台游戏,里面有敌人,你可以跳到它顶上来打败它。这个练习要求你把这种角色类型添加到游戏中。
我们称之为怪物。怪物只能水平移动。你可以让它们朝着玩家的方向移动,或者像水平岩浆一样来回跳动,或者拥有你想要的任何运动模式。这个类不必处理掉落,但是它应该确保怪物不会穿过墙壁。
当怪物接触玩家时,效果取决于玩家是否跳到它们顶上。你可以通过检查玩家的底部是否接近怪物的顶部来近似它。如果是这样的话,怪物就消失了。如果没有,游戏就输了。
<link rel="stylesheet" href="css/game.css">
<style>.monster { background: purple }</style>
<body>
<script>
// Complete the constructor, update, and collide methods
class Monster {
constructor(pos, /* ... */) {}
get type() { return "monster"; }
static create(pos) {
return new Monster(pos.plus(new Vec(0, -1)));
}
update(time, state) {}
collide(state) {}
}
Monster.prototype.size = new Vec(1.2, 2);
levelChars["M"] = Monster;
runLevel(new Level(`
..................................
.################################.
.#..............................#.
.#..............................#.
.#..............................#.
.#...........................o..#.
.#..@...........................#.
.##########..............########.
..........#..o..o..o..o..#........
..........#...........M..#........
..........################........
..................................
`), DOMDisplay);
</script>
</body>