在閱讀此篇文章前,作者建議:您已有程式的基礎底子,並且此篇著重於程式碼的部分,其餘皆為概略步驟。
為何要使用 Cog 寫法
在使用這種寫法前,我是既不熟悉 Python 語法,以及其特色(其實是忘記了),所以好一段時間放棄了用 Python 寫。但現在稍微略懂之後,才發現這種寫法有很多好處:
- 好維護
- 事件函式與前綴指令不會衝突
- 前綴指令不用一直重新啟動 Bot
- 指令可分類
總之,其實只需要修改幾行程式碼,就可以讓你的整體結構更清晰易懂,還不快點使用這種寫法。你可以在 discord.py Cogs 官方文檔 中找到更多詳細解說。
Cog 架構
請將你的檔案目錄修改成如下:
1 2 3 4 5 6
| DiscordBot | bot.py | └─cogs event.py main.py
|
也就是請在主目錄下,創建一個 cogs
資料夾,以及在其之中分別創建 event.py
及 main.py
。
main.py
:主要在寫你的前綴指令(或是斜線指令)
event.py
:主要在寫事件觸發函式
等等,已經有指令、有事件偵測了,那 bot.py
要幹嘛?
bot.py
:主要提供 load、unload、reload 的指令,可以讓 Bot 不掉線,也能修改程式,並讓 Bot 收到最新的指令。
Cog 實作
Bot 檔內容
💡小技巧:可以使用 前綴指令+help
來查看可使用的指令
Load 載入
用於將新的程式檔案載入,或是之前未載入的檔案載入。
1 2 3 4
| @bot.command() async def load(ctx, extension): await bot.load_extension(f"cogs.{extension}") await ctx.send(f"Loaded {extension} done.")
|
Unload 卸載
用於若程式碼有問題,可以先卸載避免機器人出錯
1 2 3 4
| @bot.command() async def unload(ctx, extension): await bot.unload_extension(f"cogs.{extension}") await ctx.send(f"UnLoaded {extension} done.")
|
Reload 重新載入
用於更新了某個指令檔案
1 2 3 4
| @bot.command() async def reload(ctx, extension): await bot.reload_extension(f"cogs.{extension}") await ctx.send(f"ReLoaded {extension} done.")
|
完整程式碼
bot.py1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39
| import os import asyncio import discord from discord.ext import commands
intents = discord.Intents.all() bot = commands.Bot(command_prefix = "=", intents = intents)
@bot.event async def on_ready(): print(f"目前登入身份 --> {bot.user}")
@bot.command() async def load(ctx, extension): await bot.load_extension(f"cogs.{extension}") await ctx.send(f"Loaded {extension} done.")
@bot.command() async def unload(ctx, extension): await bot.unload_extension(f"cogs.{extension}") await ctx.send(f"UnLoaded {extension} done.")
@bot.command() async def reload(ctx, extension): await bot.reload_extension(f"cogs.{extension}") await ctx.send(f"ReLoaded {extension} done.")
async def load_extensions(): for filename in os.listdir("./cogs"): if filename.endswith(".py"): await bot.load_extension(f"cogs.{filename[:-3]}")
async def main(): async with bot: await load_extensions() await bot.start("機器人的TOKEN")
if __name__ == "__main__": asyncio.run(main())
|
Main 檔內容
main.py
通常用於存取指令(其實你想放甚麼都行,但主要以易理解的方式撰寫)。但使用 Cog 寫法的話,要注意以下幾點:
注意事項
@bot.event
要改成 @commands.Cog.listener()
@bot.command()
要改成 @commands.command()
- 原指令用 bot 在 Cog 寫法下,都要變成
self.bot
- 每個指令的第一個參數要是
self
基本架構
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| import discord from discord.ext import commands
class Main(commands.Cog): def __init__(self, bot: commands.Bot): self.bot = bot
async def setup(bot): await bot.add_cog(Main(bot))
|
範例
以 ping 指令當作範例,當我們輸入 =ping
時,它就會回答當前機器人的延遲「The Bot Latency: 215ms
」
下方的範例,可以看到符合了注意事項的第二到四點。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| import discord from discord.ext import commands
class Main(commands.Cog): def __init__(self, bot: commands.Bot): self.bot = bot @commands.command() async def ping(self, ctx): await ctx.send(f"The Bot Latency: `{round(self.bot.latency * 1000)}ms`")
async def setup(bot): await bot.add_cog(Main(bot))
|
Event 檔內容
這裡其實就跟 main.py 的寫法一樣,所以就不多加贅述直接寫範例。
範例
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30
| import discord from discord.ext import commands
class Event(commands.Cog): def __init__(self, bot: commands.Bot): self.bot = bot @commands.Cog.listener() async def on_member_join(self, member): wel_channel = self.bot.get_channel(你的歡迎頻道 ID) await wel_channel.send(f"歡迎 {member.mention} 加入!")
@commands.Cog.listener() async def on_member_remove(self, member): leave_channel = self.bot.get_channel(你的離開頻道 ID) await leave_channel.send(f"{member.mention} 期待我們再次相遇")
@commands.Cog.listener() async def on_message(self, msg): if msg.author == self.bot.user: return if msg.content == "qq" or msg.content == "QQ": await msg.channel.send("幫 QQ")
async def setup(bot): await bot.add_cog(Event(bot))
|
參考網站
- discord.py Cogs 官方文檔
- Python Discord Bot 進階教學 — Cog 篇
- YouTube 頻道 Proladon