问题描述
我正在使用 discordpy 编写一个不和谐测验机器人.机器人发送一条消息,其中包含问题和 4 个可能的答案.机器人还使用表情符号 1️⃣、2️⃣、3️⃣ 和 4️⃣ 添加对他的消息的反应.这个想法是,机器人等待 30 秒,让人们点击一个反应.如果点击的反应是正确/错误的答案,机器人会回复正确或错误.一旦有人回答,机器人也应该停止等待新的反应.Aka:一旦有人点击了 4 个反应表情符号中的一个,机器人就应该回复,并且不会处理未来对此消息的任何反应.
I am writing a discord quiz bot using discordpy.The bot sends a message that contains the questions and the 4 possible answers.The bot also adds reactions to his message with the emojis 1️⃣, 2️⃣, 3️⃣ and 4️⃣.The idea is, that the bot waits 30 seconds for people to click on one fo the reactions. If the clicked reaction is the correct/wrong answer, the bot replies with either correct or wrong. The bot should also stop waiting for new reaction once one person answered. Aka: Once a person clicks on one of the 4 reaction emojis, the bot should reply, and not process any future reactions to this message.
目前,我让机器人发送消息(嵌入)并向其添加反应表情符号.然而,从人们那里获得结果是我遇到问题的地方.
Currently, I got the bot to send the message (an embed) and add the reaction emojis to it. However, obtaining the results from the people is where I have problems with.
一方面,由于某种原因,机器人似乎仍然被他自己的反应触发,即使我在检查功能中排除了这一点.(或者我是这么认为的).
For one, the bot still seems to get triggered by his own reactions for some reason, even I excluded that in the check function. (Or so I thought).
一般来说,我希望有一个结构良好的方法来解决这个问题.我熟悉所有 api 调用/事件,例如 on_message()
和 on_reaction_add()
,但我无法将所有内容正确组合在一起.
In general, I'd like to have a very well structured approach for this. I am familiar with all the api calls/events, such as on_message()
and on_reaction_add()
, but I have trouble putting everything together correctly.
这是我目前所拥有的:
@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")
我怎样才能做到这一点?
How can I get this right?
推荐答案
您的代码中有几个错误和一些不准确之处;首先,我将列出它们,然后我将向您展示我认为设置此类命令的最佳方法.请注意,以下一些方法并非实际修复,而是组织代码的更有效方法.
There are several errors and some inaccuracies in your code; first I'll list them and then I'll show you what I think is the best way to set up this type of commands.Please note that some of the following are not actual fixes but more efficient ways to organize your code.
-您应该使用装饰器来定义机器人命令,而不是使用像on_command
这样的函数:
-You should use decorators to define bot commands, instead of using functions like on_command
:
@bot.command()
async def quiz(ctx)
-ctx
类已经提供了 channel
属性,所以 ctx.message.channel
有点多余,使用 ctx.channel
代替.
-The ctx
class provides the channel
attribute already, so ctx.message.channel
is kind of redundant, use ctx.channel
instead.
同样适用于 ctx.message.author
.
-如果答案数量始终相同,那么您可以使用非常简单的 for 循环添加数字表情符号(此外,无需调用 Utils
来获取相关表情符号):
-If the number of answers is always the same, then you can add the numeric emojis with a very simple for loop (also, there is no need to call Utils
to get the relevant emojis):
for emoji in ["1️⃣","2️⃣","3️⃣","4️⃣"]:
reply.add_reaction(emoji)
-check_answer
函数也是多余的,逻辑上也是错误的.
-The check_answer
function is redundant as well, and logically wrong too.
这是多余的,因为不需要验证反应表情符号是 4 个可用表情符号之一,因为无论如何它将在稍后的 try 块中确定.
It is redundant because there is no need to verify that the reaction emoji is one of the 4 available, since it will be determined later in the try block anyway.
这在逻辑上是错误的,因为如果添加反应的用户与命令的作者匹配,它应该返回 True
,而不是相反(你会注意到这也将阻止机器人被由它自己的反应触发).
It is logically wrong because it should return True
if the user who added the reaction matches the author of the command, and not the opposite (you will notice that this will also prevent the bot from being triggered by its own reactions).
那么,函数就不需要异步了.
Then, there is no need for the function to be asynchronous.
def check_answer(reaction, user):
return user == ctx.author
-最后,整个 try-except-else 块在这里并没有真正起作用.为了让机器人保持响应直到特定用户的第一反应或直到 30 秒超时到期,您应该将 try-except 块集成到无限 while 循环:
-Finally, the whole try-except-else block is not really functional here. In order for the bot to remain responsive until the first reaction of the specific user or until the 30 seconds timeout expires, you should integrate the try-except block into an infinite while loop:
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 语句停止循环,否则它将无限期地继续.
Remember that somewhere in the try block you will have to stop the loop with a break statement when the operation is finished, otherwise it will continue indefinitely.
我也在开发一个 Discord 机器人,但我还是个初学者,所以我希望我能解释得很好.无论如何,总而言之,以下是我个人如何实施该命令的示例:
I am developing a Discord bot too and am still a beginner, so I hope I've been able to explain well.Anyway, to sum it up, here is an example of how I would personally implement that command:
@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")
然后当然应该定义如何识别正确答案以及如何通知用户.如果您需要对我所写的内容进行澄清,请随时对此答案发表评论,我将很乐意为您解答.
Then of course you should define how to recognize the correct answer and how to notify the user.If you need some clarification on what I wrote, feel free to comment on this answer and I will be happy to answer you.
这篇关于Discord bot 添加并等待测验游戏的反应的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!