Discord.js按钮触发RPG战斗阶段循环推进问题
Discord RPG机器人战斗系统:解决while循环不等待按钮交互的问题
你的问题出在while循环的执行逻辑和Discord组件收集器的事件驱动模型不兼容:while会快速迭代执行所有循环体代码,虽然你用了await message.channel.send(),但收集器是通过on("collect")事件触发的,循环根本不会等这个事件发生,直接就进入下一次循环,导致一次性发完所有5回合的消息。
解决思路是把按钮交互的等待逻辑封装成Promise,让while循环每次迭代都等待这个Promise完成(也就是用户点击按钮)后,再进入下一轮。
修改后的代码示例
let turn = 1 let phase = 0 // 封装等待按钮点击的Promise函数 async function waitForValidButton(msg, userId) { return new Promise((resolve) => { const collector = msg.createMessageComponentCollector({ filter: (interaction) => interaction.user.id === userId, time: 60000 // 可选:添加超时时间,防止用户一直不点击 }) collector.on("collect", async (btn) => { await btn.deferUpdate() if (btn.customId === "c") { collector.stop() resolve() // 用户点击有效按钮,resolve Promise } }) // 可选:处理超时情况 collector.on("end", (_, reason) => { if (reason === "time") { msg.channel.send("等待超时,战斗结束。") resolve("timeout") } }) }) } // 改用异步循环,每次等待按钮点击后再迭代 while (turn <= 5) { // 这里写每回合/阶段的游戏逻辑 const stage_embed = new discord.MessageEmbed() .setTitle(`第${turn}回合 - 第${phase+1}阶段`) .setDescription("点击按钮进入下一阶段") // 你的embed配置... const msg = await message.channel.send({ embeds: [stage_embed], components: [row] }) // 等待用户点击按钮 const result = await waitForValidButton(msg, message.author.id) if (result === "timeout") break // 超时则终止循环 // 更新阶段和回合 phase += 1 if (phase > 3) { phase = 0 turn += 1 } } // 战斗结束逻辑 await message.channel.send(`战斗结束!共进行了${turn-1}回合`)
关键改动说明
- Promise封装交互等待:把收集器的逻辑放进Promise里,只有当用户点击指定按钮时才resolve,让循环必须等待这个动作完成。
- 异步循环控制:while循环现在会在每次迭代时等待
waitForValidButton的Promise完成,彻底解决了一次性发送所有消息的问题。 - 可选超时处理:添加了超时逻辑,避免用户长时间不操作导致程序卡住。
- 变量声明优化:把
var改成let,符合现代JS规范,避免变量提升问题。
内容的提问来源于stack exchange,提问作者Ren
相关产品推荐
相关产品推荐

