如何在JavaScript中为英雄斗龙游戏的函数/循环添加延迟?
问题描述
我是编程新手,请多指教。我需要制作一个英雄与龙轮流对战的小游戏,需求如下:
- 双方初始生命值均为10
- 每轮包含3个回合,轮次结束后根据胜负减少对方生命值
- 回合胜负通过随机数模拟掷骰子决定,每回合结果要打印到控制台
- 当前游戏运行太快,不到1秒就结束,希望给控制台输出添加2秒延迟提升趣味性
我尝试过两种方法但都失败了:
- 使用
setTimeout(getTurnPoints,2000),结果导致无限循环 - 用async/await结合Promise实现延迟的
getRoundWinner函数,但控制台只打印"Nobody won"
期望效果:控制台每回合输出后暂停2秒,轮次结束后打印对应结果。以下是带中文注释的完整代码:
function startQuest() { console.log("The Quest got started!"); startGame(); } function restartQuest() { console.log("Restart got clicked!"); } // 用于创建对象的类模板: class Fighter { constructor (name, lifeEnergy) { this.name = name; this.lifeEnergy = lifeEnergy; } getAttack() { let randomNumber = Math.floor(Math.random()*5) + 2; return randomNumber; }; }; // 利用模板创建对象: let dragon = new Fighter("Dragon",10) let hero = new Fighter("Hero",10) // 判断回合胜者的函数: function getTurnWinner(attackHero, attackDragon) { if (attackHero > attackDragon) { return -1; } else if (attackHero < attackDragon) { return 1; } else { return 0; } }; // 用于存储分数的数组: let dragonPointsRoundEnd = []; let heroPointsRoundEnd = []; // 为每个回合分配分数的函数: function getTurnPoints() { // 在此处添加延迟?? let turnWinner = getTurnWinner(hero.getAttack(), dragon.getAttack()); if (turnWinner === -1) { console.log("The Hero won"); heroPointsRoundEnd.push(3); dragonPointsRoundEnd.push(0); } else if (turnWinner === 1) { console.log("The Dragon won") heroPointsRoundEnd.push(0); dragonPointsRoundEnd.push(3); } else { console.log("Nobody won") heroPointsRoundEnd.push(1); dragonPointsRoundEnd.push(1); } }; // 将每个回合的分数存储到上方数组的函数: function getRoundWinner() { for (let i = 0; i < 3; i++) { // 在此处添加延迟?? getTurnPoints(); } }; // 以下变量用于存储每轮计算后的总分: let dragonCalculatedPoints = ""; let heroCalculatedPoints = ""; // 此函数计算分数并存储到上方变量中: function calculateRoundPoints() { getRoundWinner(); dragonCalculatedPoints = dragonPointsRoundEnd[0] + dragonPointsRoundEnd[1] + dragonPointsRoundEnd[2]; heroCalculatedPoints = heroPointsRoundEnd[0] + heroPointsRoundEnd[1] + heroPointsRoundEnd[2]; }; function calculateLifeRoundEnd() { calculateRoundPoints(); if (dragonCalculatedPoints > heroCalculatedPoints && dragonCalculatedPoints >= 7) { console.log("The Dragon won the round"); hero.lifeEnergy -= 3; } else if (dragonCalculatedPoints > heroCalculatedPoints) { console.log("The Dragon won the round"); hero.lifeEnergy -= 1; } else if (heroCalculatedPoints > dragonCalculatedPoints && heroCalculatedPoints >= 7) { console.log("The Hero won the round") dragon.lifeEnergy -= 3; } else if (heroCalculatedPoints > dragonCalculatedPoints) { console.log("The Hero won the round") dragon.lifeEnergy -= 1; } else { console.log("Nobody won the round"); } }; function startGame() { while (dragon.lifeEnergy >= 1 && hero.lifeEnergy >= 1) { calculateLifeRoundEnd(); dragonPointsRoundEnd = []; heroPointsRoundEnd = []; if (dragon.lifeEnergy <= 0) { console.log("The Hero won the battle with " + hero.lifeEnergy + " to 0"); break; } else if (hero.lifeEnergy <= 0) { console.log("The Dragon won the battle with " + dragon.lifeEnergy + " to 0"); break; } }; };
解决方案
原代码的核心问题是同步执行逻辑与异步延迟不兼容:直接用setTimeout会让异步代码脱离同步流程,错误的async/await用法导致分数未被正确收集就执行了结果计算。以下是修正后的完整代码,通过异步流程控制实现预期延迟效果:
function startQuest() { console.log("冒险开始!"); startGame(); } function restartQuest() { console.log("已重新开始!"); } // 战士类模板 class Fighter { constructor(name, lifeEnergy) { this.name = name; this.lifeEnergy = lifeEnergy; } getAttack() { // 生成2-6的随机攻击值 let randomNumber = Math.floor(Math.random() * 5) + 2; return randomNumber; }; }; // 创建对战双方 let dragon = new Fighter("巨龙", 10) let hero = new Fighter("英雄", 10) // 判断单回合胜者:-1英雄胜,1巨龙胜,0平局 function getTurnWinner(attackHero, attackDragon) { if (attackHero > attackDragon) { return -1; } else if (attackHero < attackDragon) { return 1; } else { return 0; } }; // 延迟工具函数:返回指定毫秒后resolve的Promise function delay(ms) { return new Promise(resolve => setTimeout(resolve, ms)); } // 执行单回合并添加延迟 async function getTurnPoints() { const attackHero = hero.getAttack(); const attackDragon = dragon.getAttack(); const turnWinner = getTurnWinner(attackHero, attackDragon); if (turnWinner === -1) { console.log("本回合:英雄获胜"); await delay(2000); // 回合输出后延迟2秒 return { hero: 3, dragon: 0 }; } else if (turnWinner === 1) { console.log("本回合:巨龙获胜"); await delay(2000); return { hero: 0, dragon: 3 }; } else { console.log("本回合:平局"); await delay(2000); return { hero: 1, dragon: 1 }; } }; // 执行一轮3个回合,收集并计算总分 async function getRoundWinner() { let heroTotal = 0; let dragonTotal = 0; for (let i = 0; i < 3; i++) { const points = await getTurnPoints(); heroTotal += points.hero; dragonTotal += points.dragon; } return { heroTotal, dragonTotal }; }; // 计算本轮结果并更新生命值 async function calculateLifeRoundEnd() { const roundResult = await getRoundWinner(); const heroTotal = roundResult.heroTotal; const dragonTotal = roundResult.dragonTotal; if (dragonTotal > heroTotal) { if (dragonTotal >= 7) { console.log("本轮:巨龙大胜!英雄生命值-3"); hero.lifeEnergy -= 3; } else { console.log("本轮:巨龙获胜!英雄生命值-1"); hero.lifeEnergy -= 1; } } else if (heroTotal > dragonTotal) { if (heroTotal >= 7) { console.log("本轮:英雄大胜!巨龙生命值-3"); dragon.lifeEnergy -= 3; } else { console.log("本轮:英雄获胜!巨龙生命值-1"); dragon.lifeEnergy -= 1; } } else { console.log("本轮:平局,双方生命值无变化"); } console.log(`当前状态:英雄 ${hero.lifeEnergy} HP | 巨龙 ${dragon.lifeEnergy} HP\n`); }; // 异步启动游戏循环 async function startGame() { console.log("=== 英雄 vs 巨龙 对战开始 ==="); while (dragon.lifeEnergy > 0 && hero.lifeEnergy > 0) { await calculateLifeRoundEnd(); if (dragon.lifeEnergy <= 0) { console.log(`=== 战斗结束!英雄以 ${hero.lifeEnergy} HP 获胜! ===`); break; } else if (hero.lifeEnergy <= 0) { console.log(`=== 战斗结束!巨龙以 ${dragon.lifeEnergy} HP 获胜! ===`); break; } } };
关键修改说明
- 新增
delay工具函数:封装setTimeout为Promise,用await实现可控延迟,避免回调混乱。 getTurnPoints改为异步函数:执行回合逻辑后添加2秒延迟,同时返回该回合分数,替代原全局数组存储(全局数组在异步流程中易出现数据覆盖)。getRoundWinner改为异步函数:用await逐个执行回合,确保前一回合完成后再进行下一个,同时直接计算本轮总分。startGame改为异步函数:将同步while循环改为异步循环,每轮等待本轮所有回合完成后再进入下一轮,保证流程按延迟顺序执行。- 修复分数计算逻辑:原代码中全局数组未被异步填充就执行计算,导致总分始终为0,现在通过异步返回的分数直接计算,避免数据错误。
内容的提问来源于stack exchange,提问作者Markus Ochsenhofer
相关产品推荐
相关产品推荐

