iT邦幫忙

2023 iThome 鐵人賽

DAY 21
0

https://ithelp.ithome.com.tw/upload/images/20230915/2011948666FpU5HobR.png

前言

在前一篇我們準備好了 Discord 基本的一些東西與設定,接下來當然要繼續聊 Discord 的部分囉~

Discord

前一篇我們分別認識了官方所提供的註冊指令到 Bot 的程式碼,以及登入 Discord Bot 的程式碼,但實際上來講就這樣嗎?不,其實還有很多東西可以講,就讓我們專注於 Discord Bot 的方便吧!

首先我們先看一下前一篇寫的程式碼:

// index.js
const { Client, Intents } = require('discord.js'); // 引入 discord.js 套件
// 實例化 Client
const client = new Client({
  intents: [
    Intents.FLAGS.GUILDS
  ]
});

// 當機器人準備好時
client.once('ready', () => {
  console.log('Ready!');
});

// 登入機器人
client.login(TOKEN);

我們先專注於 const client = new Client({ ... }) 這裡面的物件

// ... 略過其他程式碼
const client = new Client({
  intents: [
    Intents.FLAGS.GUILDS
  ]
});
// ... 略過其他程式碼

Intents(意圖)

首先 const client = new Client({ ... }) 這行是在建立一個新的 Discord.js 物件,你可以想像它就像是一個接入 Discord API 的橋樑,讓我們可以透過程式碼去操作 Discord。

而裡面是傳入一些地方,先講講 intents 這個參數,這個參數非常的重要,會影響你的機器人可以做哪些事情。

問題來了,intents 主要是幹嘛的呢?簡單來說就是告知 Discord 我們會有哪些「意圖」,例如:我們的機器人會需要接收伺服器的訊息,那麼我們就需要告知 Discord 我們會需要接收伺服器的訊息,這樣 Discord 才會將伺服器的訊息傳送給我們的機器人。

這邊我先舉例一下我先前寫的程式碼:

const { Client, GatewayIntentBits } = require('discord.js');

const client = new Client({
  intents: [
    GatewayIntentBits.Guilds,
    GatewayIntentBits.GuildMessages,
    GatewayIntentBits.MessageContent,
  ],
});

我們可以看到 intents 接收了一個陣列,裡面放了三個參數,這三個參數分別是:

  • GatewayIntentBits.Guilds:可以接收伺服器相關的事件,例如:使用者加入伺服器、使用者離開伺服器等等。
  • GatewayIntentBits.GuildMembers:可以接收伺服器內的聊天訊息事件,例如:使用者傳送訊息、使用者編輯訊息等等。
  • GatewayIntentBits.MessageContent:這個比較特別一點,這是在告知機器人我們需要接收訊息的內容,例如:使用者傳送的訊息內容、使用者編輯的訊息內容等等,這個跟前面的 GatewayIntentBits.GuildMembers 不同的地方在於,GatewayIntentBits.GuildMembers 只會告知我們使用者傳送了訊息,但不會告知我們訊息的內容,所以我們需要另外告知 Discord 我們需要接收訊息的內容。

當然不只有這些,還有...

  • GatewayIntentBits.GuildMessageReactions:可以接收伺服器內的反應事件,例如:使用者給予訊息反應、使用者移除訊息反應等等。
  • GatewayIntentBits.DirectMessages:可以接收私人訊息事件,例如:使用者傳送私人訊息、使用者編輯私人訊息等等。
  • GatewayIntentBits.DirectMessageReactions:可以接收私人訊息的反應事件,例如:使用者給予私人訊息反應、使用者移除私人訊息反應等等。
  • GatewayIntentBits.DirectMessageTyping:可以接收私人訊息的打字事件,例如:使用者正在打字、使用者停止打字等等。

當然這邊只列出一些而已,其他部分可以參考 Discord.js 官方文件。

partials(部分)

partials 有一點特別,它也是 new Client 時會傳入的參數之一:

const { Client, GatewayIntentBits, Partials } = require('discord.js');
const client = new Client({
  intents: [
    GatewayIntentBits.Guilds,
    GatewayIntentBits.GuildMessages,
    GatewayIntentBits.MessageContent,
  ],
  partials: [
    Partials.Channel
  ],
});

partials 這個參數是用來告知 Discord 我們需要接收哪些「部分」的資料,例如:我們需要接收哪些訊息的內容、哪些訊息的反應等等。

那為什麼要特別設定這個呢?主要原因是因為 Discord 會將一些資料分成兩個部分,一個是完整的資料,另一個是部分的資料,例如:我們需要接收訊息的內容,但 Discord 會將訊息的內容分成兩個部分,一個是完整的訊息內容,另一個是部分的訊息內容,這樣就會造成我們無法取得完整的訊息內容,所以我們需要告知 Discord 我們需要接收完整的訊息內容。

那麼我們大致上了解了 Partials 的用途後,就先這樣繼續往下吧~有需要我們再來聊這個。

Discord 方法與事件

接下來我們就來聊聊 Discord 的方法與事件,這邊我們就先來看看 Discord 的方法吧!

我們在範例程式碼中,其實有看到 Client 實例化後,做了一些事情...

// index.js
const { Client, Intents } = require('discord.js'); // 引入 discord.js 套件
// 實例化 Client
const client = new Client({
  // ... 略過其他程式碼
});

// 當機器人準備好時
client.once('ready', () => {
  // ... 略過其他程式碼
});

// 登入機器人
client.login(TOKEN);

分別是...

  • once 註冊了一個事件,但這個事件只會觸發一次。
  • login 登入機器人,就是登入機器人的意思。

但實際上來講,方法不只有這些,詳細可以看 Discord.js 官方文件。

但最常見的莫過於 on 與 once,這兩個方法都是用來註冊事件的,但 on 會持續監聽事件,而 once 則只會監聽一次事件。

講完這些方法後,接下來當然是要聊聊事件了,我們先來看看前面的程式碼:

client.once('ready', () => {
  // ... 略過其他程式碼
});

這邊我們可以看到 once 監聽了一個事件,也就是 ready 事件,這個事件是在機器人準備好時觸發的,所以當機器人準備好時,就會觸發這個事件。

那麼 client.on 跟 client.once 哪裡來的呢?如果你有去翻 Discord.js 官方文件,你會發現你只找得到 client.login 這個方法,但沒有 client.on 與 client.once 這兩個方法,那這兩個方法是哪裡來的呢?

其實主要是來自 EventEmitter 這個類別,EventEmitter 這個類別是 Node.js 內建的類別,而 Client 這個類別繼承了 EventEmitter 這個類別,所以我們才可以使用 client.on 與 client.once 這兩個方法,你可以在這邊 EventEmitter 看到。

那麼 once 跟 on 裡面的事件除了 ready 之外,還有哪些呢?其實非常的多,而且上面寫法也不是唯一的寫法,你可以這樣寫:

const {
  Client,
  GatewayIntentBits,
  Partials,
  Events,
} = require('discord.js');

const client = new Client({
  intents: [
    GatewayIntentBits.Guilds,
    GatewayIntentBits.GuildMessages,
    GatewayIntentBits.MessageContent,
  ],
  partials: [
    Partials.Channel,
  ],
});

client.once(Events.ClientReady, () => {
  console.log('Ready!');
});

client.login(TOKEN);

這邊我們可以看到 once 裡面的事件變成了 Events.ClientReady,這是因為 Events 這個物件是 Discord.js 提供的,裡面包含了所有的事件,你可以在這邊 Events 看到。

那寫字串跟使用 Events 有什麼差嗎?其實我認為沒差很多,只是差別在於你可以直接透過 Events 下拉選單,就可以看到所有的事件,而不用去翻文件,這樣比較方便而已

https://ithelp.ithome.com.tw/upload/images/20230915/20119486z0xAdrCkeA.png

實際上 Events 也是傳入相對應的字串而已,底下是我翻出來的原始碼:

export enum Events {
  ClientReady = 'ready',
  MessageCreate = 'messageCreate',
  MessageDelete = 'messageDelete',
  MessageUpdate = 'messageUpdate',
  // ... 略過其他程式碼
}

所以不論你寫...

client.once('ready', () => {
  console.log('Ready!');
});

或是...

client.once(Events.ClientReady, () => {
  console.log('Ready!');
});

兩者都是相同的結果,只是一個不用特別去查文件,直接下拉就可以選。

接下來我們先來寫一點小東西好了,我們來試著寫監聽訊息的事件,然後輸出到終端機上:

// index.js
const {
  Client,
  GatewayIntentBits,
  Partials,
  Events,
} = require('discord.js');

const client = new Client({
  intents: [
    GatewayIntentBits.Guilds,
    GatewayIntentBits.GuildMessages,
    GatewayIntentBits.MessageContent,
  ],
  partials: [
    Partials.Channel,
  ],
});

client.once(Events.ClientReady, () => {
  console.log('Ready!');
});

// 監聽訊息事件,請使用 on 作為持續監聽事件
client.on(Events.MessageCreate, (message) => {
  console.log('[有人說:」',message.content);
});

client.login(TOKEN);

接著透過 node index.js 啟動後,你在頻道上發送一個訊息就可以看到終端機上輸出了,如下圖:

https://ithelp.ithome.com.tw/upload/images/20230915/20119486GHvBBCeJeA.png

很簡單吧?那我們這一篇也先到這邊結束好了,我們下一篇繼續聊 Discord 的部分。


上一篇
Day20 - Discord Bot?
下一篇
Day22 - Discord Bot 整合
系列文
《Node.js 不負責系列:把前端人員當作後端來用,就算是前端也能嘗試寫的後端~原來 Node.js 可以做這麼多事~》 共 31 篇
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言