從零開始的Discord機器人(2) - 斜線指令
本篇會幫Discord機器人新增斜線指令,並能根據指令做出回應。
在上一篇中,我們已經順利建立好環境、新增一個機器人帳號,並成功讓它登入了。接下來我們要幫機器人加上重點的功能──斜線指令(Slash Commands)。
早期的機器人通常是接收成員傳送的訊息,分解訊息的內容,確認成員要執行什麼指令並做出相應的行為。你需要直接送出例如/hello @成員
或是!join
之類的訊息,但如果沒有看過機器人的文件說明,你根本無從得知機器人有什麼指令可以使用。
於是Discord在2022年9月推出了全新的斜線指令作為互動的新標準,只要輸入「/」就可以直接瀏覽能夠使用的指令,使用者可以直接點擊命令並輸入參數來使用,相比傳統的文字指令更加一目了然。
在本文中,我們將一步步幫機器人加上斜線指令,等到熟悉之後,你也可以幫機器人加上各式各樣的指令囉!
1. 新增一個斜線指令
在discord.js v14中,要新增一個斜線指令,我們可以使用SlashCommandBuilder來幫助我們完成。首先先在最上面的require中加入SlashCommandBuilder:
// ---------------START---------------
const { Client, Events, GatewayIntentBits } = require ('discord.js');
// ----------------END----------------
接下來,我們在ClientReady這邊新增一個SlashCommandBuilder來建立新的斜線指令。
client.once (Events.ClientReady, c => {
console.log (`歡迎登入 ${c.user.username}`);
// ---------------START---------------
new SlashCommandBuilder ()
.setName ('ping')
.setDescription ('Replies with "Pong!"');
// ----------------END----------------
});
接著,我們要讓機器人監聽InteractionCreate的事件。不管是觸發斜線指令、送出互動視窗、點擊按鈕、或是使用下拉選單,全部都是屬於InteractionCreate的事件。我們來新增以下內容:
// ---------------START---------------
client.on(Events.InteractionCreate, interaction => {
if (!interaction.isChatInputCommand ()) return;
if (interaction.commandName === "ping") {
interaction.reply ("Pong!");
}
});
// ----------------END----------------
有人使用了斜線指令等一系列動作觸發InteractionCreate的事件後,會得到一個interaction,當我們根據指令完成工作後,可以使用interaction的reply ()
來回應使用者。
特別需要提到的是,interaction的reply ()
只有3秒,超過時間就會被當作沒有回應。如果確定回應時間會超過3秒的話,有幾種方法可以解決:
- 先送出一個
reply ()
,等動作完成後再使用editReply ()
編輯該回應。 - 使用
deferReply ()
,Discord會幫你傳送一個「機器人正在思考」的訊息,並且延長到15分鐘內都可以再編輯回應。 - 先送出一個
reply ()
,等動作完成後再使用followUp ()
傳送第二則回應。當你使用deferReply ()
再使用followUp ()
,此時並不會傳送第二則回應,而是直接編輯「機器人正在思考」的訊息。
我們新增了斜線指令,並且機器人登入之後會開始監聽InteractionCreate事件並做出回應,也許這時候你會想試著使用看看斜線指令了。但你實際上到伺服器輸入「/」之後,並沒有我們剛剛新增的斜線指令可以使用,這是為什麼呢?
除了在這裡新增斜線指令之外,我們還必須另外向Discord註冊斜線指令,這樣Discord才知道我們的機器人身上有什麼指令可以使用。想要註冊斜線指令的話,我們可以這麼做:
client.once (Events.ClientReady, c => {
console.log (`歡迎登入 ${c.user.username}`);
const ping = new SlashCommandBuilder ()
.setName ('ping')
.setDescription ('Replies with "Pong!"');
// ---------------START---------------
client.application.commands.create (ping, "填入伺服器的ID");
// ----------------END----------------
});
如此一來,我們就成功註冊了一個在伺服器內可以使用的斜線指令,你可以在伺服器內使用剛剛新增的指令了!
(請注意這裡將指令註冊給指定伺服器,在其他伺服器內是無法使用這個指令的,後續會說明如何註冊指令讓所有伺服器都能使用。)
2. 再新增一個斜線指令
現在機器人有了第一個指令,就讓我們再新增一個新的指令吧。這次我們來新增一個帶有參數的指令,讓機器人可以獲得成員輸入的參數並加以利用:
client.once (Events.ClientReady, c => {
console.log (`歡迎登入 ${c.user.username}`);
const ping = new SlashCommandBuilder ()
.setName ('ping')
.setDescription ('Replies with "Pong!"');
// ---------------START---------------
const hello = new SlashCommandBuilder ()
.setName ('hello')
.setDescription ('Say hello to someone!')
.addUserOption (option =>
option
.setName ('user')
.setDescription ('The user you want to say hi to')
.setRequired (true)
);
// ----------------END----------------
client.application.commands.create (ping, "填入伺服器的ID");
// ---------------START---------------
client.application.commands.create (hello, "填入伺服器的ID");
// ----------------END----------------
});
在新的指令中加入了新的部分addUserOption
,它的作用是可以新增一個讓使用者輸入成員進去的參數。除了成員之外,Discord共提供了以下類型的參數:
addSubcommand
子命令addSubcommandGroup
子命令群組addStringOption
字串addIntegerOption
整數addBooleanOption
布林值addUserOption
@成員 或 成員的IDaddChannelOption
#頻道 或 頻道的IDaddRoleOption
@身分組 或 身分組的IDaddMentionableOption
@成員/@身分組 或 成員/身分組的IDaddNumberOption
浮點數addAttachmentOption
附加檔案
如果需要擴充參數,我們只要根據需要填入的參數,在最後面插入相對應的方法即可。你可以看到參數本身也可以設定名稱與說明,在我們剛剛新增的指令中,填入成員的參數使用了setRequired
將參數設為必填,如果使用者沒有填入內容將無法送出指令。由於指令與每一種參數所包含的方法太多,這邊就不一一列舉,如果有需要可以閱讀官方文件確認。
子命令與子命令群組可以讓你將同一類的命令包成一個群組。例如Ban人與踢人指令,可以包成/manage
指令底下的user
子命令群組的Ban
子命令與kick
子命令,之後當你想尋找管理使用者相關的指令時,只要輸入/manage user
便會列出底下所有的子命令,是不是很方便呢!
不好意思,扯得有點遠了。讓我們繼續把機器人接收斜線指令後回應的部分完成吧:
client.on(Events.InteractionCreate, interaction => {
if (!interaction.isChatInputCommand ()) return;
if (interaction.commandName === "ping") {
interaction.reply ("Pong!");
}
// ---------------START---------------
if (interaction.commandName === "hello") {
const user = interaction.options.getUser ('user');
interaction.reply (`Hello <@${user.id}>`);
}
// ----------------END----------------
});
當使用了帶有參數的指令,我們可以使用interaction.options
內的一系列get方法去取得那些參數的值。例如我們的指令所包含的參數是填入成員,因此我們使用getUser
來接收,你可以看到getUser
的引數是填入我們剛剛幫option設定的名稱,這樣我們就能抓到想要的參數了。
3. 接下來要做的事情
到目前為止,我們幫機器人新增了斜線指令,並且使用者可以傳遞參數給機器人使用,基本的機器人功能已經算是完成了。但你可能會發現,如果繼續擴充機器人的指令,現在的寫法將會變得很難維護。接下來我們會改善機器人的架構,讓你可以方便擴充與維護機器人的功能。
感謝你看到這邊,我們下次見。