You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Discord.py使用Cog开发反应类石头剪刀布游戏时wait_for异常问题

问题定位
    1. check函数参数顺序错误:discord.py的reaction_add事件返回参数顺序为(reaction, user),你定义的check(user, reaction)参数顺序颠倒,导致校验逻辑完全失效,永远无法匹配触发条件,所以频繁触发TimeoutError
    1. check内的判断逻辑错误:你写的reaction == str(reaction.emoji)是将整个Reaction对象和表情字符串对比,结果永远为假,正确写法应该是校验触发的表情属于允许的三个游戏表情
    1. 装饰器使用错误:给指令函数同时加了@command和@Cog.listener,二者逻辑冲突,指令函数不需要加监听器装饰器
    1. 随机答案逻辑错误:shuffle()方法只支持列表等序列结构,不能直接作用于字典,且你后续直接将answer写死为石头表情,注释掉了随机取值的代码
    1. 多余的重复校验:你已经可以在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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.25 16:15:04