JavaScript战斗模拟器中window.prompt提前执行,页面内容未先显示的解决求助
JavaScript战斗模拟器中window.prompt提前执行,页面内容未先显示的解决求助
嘿,我来帮你搞定这个问题!你遇到的情况其实是window.prompt的特性导致的,还有几个小代码问题需要调整,我一步步给你拆解:
为什么prompt会先弹出来?
window.prompt(包括alert、confirm)是同步阻塞式的API——意思是,当代码执行到它时,浏览器会立刻暂停所有页面渲染和后续JS执行,直到你在prompt里输入内容确认。
你现在的代码里,所有document.write和yourTurn()调用都在同一个JS执行块里。浏览器会先执行document.write语句,但不会立刻渲染到页面——它要等当前JS执行块跑完才会开始渲染。但你紧接着就调用了yourTurn(),里面的prompt直接卡住浏览器,导致之前的document.write内容根本没机会显示,所以你先看到prompt,看不到敌人攻击和你的状态。
另外还有两个小bug:
switch里的case "FIGHT" || "fight" || "Fight"写法错了——逻辑或||会返回第一个真值(也就是"FIGHT"),所以这个case其实只匹配"FIGHT",不过你已经把yourMove转成大写了,其实只需要写case "FIGHT":就够了。document.write不是现代浏览器的推荐写法,它容易重写页面,渲染时机也不好控制。
解决方法
我给你调整了代码,解决了这些问题,你可以直接参考:
首先在HTML里加一个专门放游戏日志的容器(代替document.write):
<div id="game-log"></div>
然后修改JS代码:
const enemy = 'Mettaton'.toUpperCase(); const player = window.prompt("Enter your Name, Player").toUpperCase(); let enemyHP = 500; let enemyMercy = 0; let playerHP = 150; // 获取游戏日志容器 const gameLog = document.getElementById('game-log'); // 封装添加日志的函数,方便重复使用 function addLog(text) { gameLog.innerHTML += text + '<br>'; } // 先输出初始游戏内容 addLog(`${enemy} attacks!`); addLog(`YOUR STATS:`); addLog(`${playerHP} HP`); function yourTurn() { let yourMove = window.prompt("FIGHT, ACT, CHECK, or SPARE").toUpperCase(); switch (yourMove) { case "FIGHT": addLog(`${player} used FIGHT!`); const fightPower = Math.floor(Math.random() * 100 / 5); addLog(`${enemy} took ${fightPower} damage!`); enemyHP -= fightPower; break; case "ACT": addLog(`${player} chose to ACT! (可以根据Undertale设定完善这里的怜悯值逻辑)`); enemyMercy += 20; // 示例:ACT增加怜悯值 break; case "CHECK": addLog(`You checked ${enemy}! HP: ${enemyHP} | Mercy: ${enemyMercy}`); break; case "SPARE": addLog(`${player} tried to SPARE!`); break; default: addLog(`Invalid move! Please enter FIGHT, ACT, CHECK, or SPARE.`); // 让用户重新输入 yourTurn(); } } function enemyTurn() { const enemyPower = Math.floor(Math.random() * 100 / 3); addLog(`<br>${enemy} attacks back!`); addLog(`${player} took ${enemyPower} damage!`); playerHP -= enemyPower; addLog(`Your HP is now ${playerHP}`); } // 用setTimeout让浏览器先渲染初始内容,再执行你的回合 setTimeout(() => { yourTurn(); // 可以在这里加游戏循环逻辑,比如判断是否继续战斗 enemyTurn(); }, 0);
关键改动说明
- 替换document.write为DOM容器:用
game-logdiv管理所有游戏文本,避免内容被意外覆盖,浏览器也能更及时地更新DOM。 - 解决阻塞渲染问题:
setTimeout(() => {}, 0)把yourTurn()的调用放到事件队列末尾——让浏览器先渲染完初始的游戏日志,再弹出操作选择的prompt,这样你就能先看到页面内容再输入了。 - 修复switch条件错误:因为
yourMove已经转成大写,直接匹配大写字符串即可,不需要多余的逻辑或写法。 - 补全其他操作逻辑:给ACT、CHECK、SPARE加了示例代码,你可以根据Undertale的设定继续完善。
- 修复敌人回合逻辑:原来的代码里敌人攻击后没有减少你的HP,现在补上了
playerHP -= enemyPower的逻辑。
额外小建议
如果想让游戏体验更好,还可以:
- 把原生prompt换成页面上的按钮/自定义输入框(非阻塞式UI),避免打断页面渲染。
- 增加游戏循环,比如判断
enemyHP是否为0、怜悯值是否满,自动继续战斗轮次,而不是只执行一次回合。
这样调整后,你就能先看到敌人攻击信息和自己的状态,再进行操作选择啦!
备注:内容来源于stack exchange,提问作者Cyrus
相关产品推荐
相关产品推荐

