首页 > 解决方案 > Discord bot 添加并等待问答游戏的反应

问题描述

我正在使用 discordpy 编写一个不和谐的测验机器人。机器人会发送一条消息,其中包含问题和 4 个可能的答案。该机器人还使用表情符号 1️⃣、2️⃣、3️⃣ 和 4️⃣ 添加对他的消息的反应。这个想法是,机器人等待 30 秒,让人们点击一个反应。如果点击的反应是正确/错误的答案,机器人会回复正确或错误。一旦有人回答,机器人也应该停止等待新的反应。Aka:一旦有人点击了 4 个反应表情符号之一,机器人应该回复,而不是处理任何未来对此消息的反应。

目前,我让机器人发送消息(嵌入)并向其添加反应表情符号。但是,从人们那里获得结果是我遇到的问题。

一方面,由于某种原因,机器人似乎仍然被他自己的反应触发,即使我在检查功能中排除了这一点。(或者我是这么认为的)。

总的来说,我希望为此采用一种结构良好的方法。我熟悉所有 api 调用/事件,例如on_message()and on_reaction_add(),但我无法将所有内容正确组合在一起。

这是我到目前为止所拥有的:

@commands.command(name="quiz")
    async def on_command_quiz(ctx):

        #if ctx.message.author.bot:
        #    return   

        print("Quiz command!")
        quiz = QuizGame()

        # Send quiz
        reply = await ctx.message.channel.send(embed=quiz.format())

        # Add reply emojis
        for x in range(0, len(quiz.quiz_answers)):
            await reply.add_reaction(Utils.get_number_emoji_by_number(x + 1))
        print("Correct Answer:", quiz.quiz_correct_answer)

        # Evaluate replies
        async def check_answer(reaction, user):        
            emojis = ["1️⃣","2️⃣","3️⃣","4️⃣"]
            return user != ctx.message.author and str(reaction.emoji) in emojis

        # Wait for replies
        try:
            reaction, user = await bot.wait_for('reaction_add', timeout=30.0, check=check_answer)
        except asyncio.TimeoutError:
            print("Timeout")
        else:
            if user != ctx.message.author:
                if str(reaction.emoji) == "1️⃣":
                    print("1")
                elif str(reaction.emoji) == "2️⃣":
                    print("2")
                elif str(reaction.emoji) == "3️⃣":
                    print("3")
                elif str(reaction.emoji) == "4️⃣":
                    print("4")
                else:
                    print("Unknown reaction")

我怎样才能做到这一点?

标签: pythonapidiscordbots

解决方案


您的代码中有几个错误和一些不准确之处;首先,我将列出它们,然后我将向您展示我认为设置此类命令的最佳方式。请注意,以下一些不是实际的修复,而是组织代码的更有效方法。

- 你应该使用装饰器来定义机器人命令,而不是使用如下函数on_command

@bot.command()
async def quiz(ctx)

-ctxchannel已经提供了属性,所以ctx.message.channel有点多余,ctx.channel改为使用。

同样适用于ctx.message.author

- 如果答案的数量始终相同,那么您可以使用非常简单的 for 循环添加数字表情符号(另外,无需调用Utils即可获取相关表情符号):

for emoji in ["1️⃣","2️⃣","3️⃣","4️⃣"]:
    reply.add_reaction(emoji)

- 该check_answer功能也是多余的,逻辑上也是错误的。

这是多余的,因为不需要验证反应表情符号是否是 4 个可用表情符号之一,因为无论如何稍后都会在 try 块中确定它。

这在逻辑上是错误的,因为如果添加反应的用户与命令的作者匹配,它应该返回True,而不是相反(你会注意到这也会阻止机器人被自己的反应触发)。

那么,函数就不需要是异步的了。

def check_answer(reaction, user):
    return user == ctx.author

-最后,整个 try-except-else 块在这里并没有真正起作用。为了让机器人在特定用户的第一个反应或 30 秒超时到期之前保持响应,您应该将 try-except 块集成到无限 while 循环中

while True:
    try:
        reaction, user = await bot.wait_for("reaction_add", timeout=30, check=check_answer)
    
        # The following line is optional: it removes the reaction added by the user 
        # to let them react again with the same emoji; not really necessary in your case, 
        # but very helpful if your bot would still be responsive after the first reaction.
        await reply.remove_reaction(reaction, user) 

        # Here goes the if-else block of reactions.

    except asyncio.TimeoutError:
        print("Timeout")

请记住,在 try 块中的某处,当操作完成时,您必须使用 break 语句停止循环,否则它将无限期地继续。

我也在开发一个 Discord 机器人,但我还是个初学者,所以我希望我能够很好地解释。无论如何,总而言之,这是我个人如何实现该命令的示例:

@bot.command()
async def quiz(ctx):

    print("Quiz command!")
    quiz = QuizGame()

    reply = await ctx.send(embed=quiz.format())

    emojis = ["1️⃣","2️⃣","3️⃣","4️⃣"]
    for emoji in emojis:
        await reply.add_reaction(emoji)

    def check_answer(reaction, user):
        return user == ctx.author

    while True:
        try:
            reaction, user = await bot.wait_for("reaction_add", timeout=30, check=check_answer)
            await reply.remove_reaction(reaction, user)

            # Shorter representation of that if-else block.
            if reaction.emoji in emojis:
                print(emojis.index(reaction.emoji) + 1)
                break
            else:
                print("Unknown reaction")

        except asyncio.TimeoutError:
            print("Timeout")

那么当然你应该定义如何识别正确答案以及如何通知用户。如果您需要对我写的内容进行澄清,请随时对此答案发表评论,我很乐意为您解答。


推荐阅读