Discord.py使用Cog开发反应类石头剪刀布游戏时wait_for异常问题
问题定位
check函数参数顺序错误:discord.py的reaction_add事件返回参数顺序为(reaction, user),你定义的check(user, reaction)参数顺序颠倒,导致校验逻辑完全失效,永远无法匹配触发条件,所以频繁触发TimeoutError
check内的判断逻辑错误:你写的reaction == str(reaction.emoji)是将整个Reaction对象和表情字符串对比,结果永远为假,正确写法应该是校验触发的表情属于允许的三个游戏表情
- 装饰器使用错误:给指令函数同时加了
@command和@Cog.listener,二者逻辑冲突,指令函数不需要加监听器装饰器
- 装饰器使用错误:给指令函数同时加了
- 随机答案逻辑错误:
shuffle()方法只支持列表等序列结构,不能直接作用于字典,且你后续直接将answer写死为石头表情,注释掉了随机取值的代码
- 随机答案逻辑错误:
- 多余的重复校验:你已经可以在
check函数内过滤掉bot自身的反应,无需后续再做判断
- 多余的重复校验:你已经可以在
修复方案
修正后的miniGames.py完整代码:
from discord.ext.commands import Cog, command from discord import Message, Embed, Color from random import choice class miniGames(Cog, name='miniGames module'): def __init__(self, bot): self.bot = bot @command(name='rsp') # 移除多余的Cog.listener装饰器 async def RockscissorsPaper(self, message: Message): # 定义三个表情 rock, scissor, paper = '\U0001FAA8', '\U00002702', '\U0001F4C4' emojis = [rock, scissor, paper] # 随机生成bot的出拳 bot_choice = choice(emojis) print(f"Bot出拳:{bot_choice}") # 生成游戏Embed embed = Embed(color=Color.blurple()) embed.title = '石头剪刀布' embed.description = '请点击下方表情进行选择,30秒内未选择游戏自动结束' # 发送消息并添加反应 game_msg = await message.channel.send(embed=embed) await game_msg.add_reaction(rock) await game_msg.add_reaction(scissor) await game_msg.add_reaction(paper) # 修正check函数参数顺序和判断逻辑 def check(reaction, user): # 条件:触发用户是指令发起者、反应的消息是游戏消息、表情属于允许的三个、不是bot触发 return user == message.author and reaction.message.id == game_msg.id and str(reaction.emoji) in emojis and user != self.bot.user try: reaction, user = await self.bot.wait_for('reaction_add', timeout=30, check=check) except TimeoutError: await message.channel.send("游戏超时,已自动结束") return # 拿到用户选择 user_choice = str(reaction.emoji) # 胜负判断逻辑 if user_choice == bot_choice: res = "平局!" elif (user_choice == rock and bot_choice == scissor) or \ (user_choice == scissor and bot_choice == paper) or \ (user_choice == paper and bot_choice == rock): res = "你赢了!" else: res = "你输了!" # 发送结果 await message.channel.send(f"你出了{user_choice},Bot出了{bot_choice},{res}")
改动说明
- 修正了
check函数的参数顺序和校验逻辑,新增了消息ID校验,避免用户在其他消息发的表情触发当前游戏的逻辑 - 优化了随机出拳逻辑,直接从表情列表随机取值,避免操作字典出错
- 补全了完整的胜负判断分支,所有情况都能对应正确的返回结果
- 移除了多余的
@Cog.listener装饰器,避免指令逻辑冲突 - 超时后增加了用户可见的提示,而不是只在控制台打印错误
内容的提问来源于stack exchange,提问作者krigjo25
相关产品推荐
相关产品推荐

