使用discord.py开发Discord猜数字小游戏时遇参数错误
解决Discord机器人猜数字游戏的报错问题
首先看你的错误信息:Destination must be Channel... Received NoneType,这是因为你在on_message事件里用了drone.say()——这个方法是命令上下文专属的,它需要从commands.Context对象里获取频道信息,而在on_message事件中直接调用drone.say()的话,没有对应的上下文,自然找不到频道,就返回了None。
除此之外,你的代码还有几个关键问题:
- 在
chat命令函数内部嵌套定义on_message事件,这会导致事件注册混乱,Discord.py会覆盖之前的事件处理逻辑,运行时肯定出问题。 wait_for_message(int)的用法完全错误,这个方法的参数不是类型,而是用于过滤消息的检查函数。- 没有处理用户输入非数字的情况,容易触发
ValueError。
修正后的完整代码示例
我帮你重构了代码,把猜数字功能做成一个独立的命令(或者你也可以改成on_message触发,这里用命令更规范):
import random import discord from discord.ext import commands import asyncio drone = commands.Bot(command_prefix="!") # 猜数字命令 @drone.command(name="guess", help="猜数字游戏:1-100,有7次机会") async def guess_game(ctx): z = random.randint(1, 100) await ctx.send("我想了一个1到100之间的数字,来猜吧!你有7次机会~") for gT in range(1, 8): await ctx.send(f"第{gT}次猜测:输入你的数字") # 等待用户输入,只接收发起命令的用户的消息,且内容是数字 def check(msg): return msg.author == ctx.author and msg.content.isdigit() try: guess_msg = await drone.wait_for("message", check=check, timeout=30.0) g = int(guess_msg.content) except asyncio.TimeoutError: await ctx.send("超时啦!游戏结束,正确数字是:" + str(z)) return except ValueError: await ctx.send("请输入有效的数字!") continue # 跳过当前循环,不消耗次数 if g > z: await ctx.send("太大啦!") elif g < z: await ctx.send("太小啦!") else: await ctx.send(f"恭喜你猜对了!就是{z}!你用了{gT}次机会~") return # 循环结束没猜对 await ctx.send(f"7次机会用完啦,正确数字是:{str(z)}") # 启动机器人(记得替换成你的token) drone.run("YOUR_BOT_TOKEN")
关键修改点说明
- 移除嵌套的事件定义:把猜数字功能做成独立的
!guess命令,避免事件和命令的逻辑混乱。 - 用
ctx.send()替代drone.say()/drone.send_message():在命令里使用ctx(上下文)的send方法,能正确获取当前频道,不会出现NoneType错误。 - 修正
wait_for的用法:用wait_for("message")替代旧的wait_for_message(旧方法在新版本已废弃),并通过check函数确保只接收发起命令的用户的数字输入。 - 增加异常处理:处理超时和非数字输入的情况,让游戏更健壮。
- 优化循环逻辑:猜对后直接
return结束命令,不用等到循环结束。
如果你还是想通过on_message事件触发(比如用户发"guess number"时启动游戏),可以这样写:
@drone.event async def on_message(message): # 避免机器人自己触发 if message.author == drone.user: return if message.content.lower().startswith("guess number"): z = random.randint(1, 100) await message.channel.send("我想了一个1到100之间的数字,来猜吧!你有7次机会~") for gT in range(1, 8): await message.channel.send(f"第{gT}次猜测:输入你的数字") def check(msg): return msg.author == message.author and msg.content.isdigit() try: guess_msg = await drone.wait_for("message", check=check, timeout=30.0) g = int(guess_msg.content) except asyncio.TimeoutError: await message.channel.send("超时啦!游戏结束,正确数字是:" + str(z)) return except ValueError: await message.channel.send("请输入有效的数字!") continue if g > z: await message.channel.send("太大啦!") elif g < z: await message.channel.send("太小啦!") else: await message.channel.send(f"恭喜你猜对了!就是{z}!你用了{gT}次机会~") return await message.channel.send(f"7次机会用完啦,正确数字是:{str(z)}") # 必须加这一行,否则命令会失效 await drone.process_commands(message)
注意:如果用on_message处理,最后一定要加await drone.process_commands(message),否则你的其他命令(比如!chat)会无法触发。
内容的提问来源于stack exchange,提问作者PsychoRhano
相关产品推荐
相关产品推荐

