スムージーの備忘録

Discord Botのコマンドオプション

動作環境

  • Python 3.11.3
  • discord.py 2.3.2

コマンドオプションとは

DisocrdBotのテンプレート では/testというコマンドを作成しました。
このコマンドは/testで使用できBotがtest!と返すというものでした。
ただ、コマンドを作成する上で何かユーザーに選択肢を与えたいときがあります。

たとえば、じゃんけんBotを作りたいときに、/jankenというコマンドを作成し、Botが手を返すだけではゲームとして成り立ちません。
じゃんけんである以上ユーザーが何を出すかの選択が欲しいですよね?

このようなときに使用するのがコマンドオプションです。

コマンドオプションの作成

せっかくなのでじゃんけんBotを作成してみましょう!と言いたいところですが、
まずは簡単なコマンドオプションを作成してみましょう。

bot.py
コピー
import os

import discord
from discord import app_commands

#Discord Bot Initialize
client = discord.Client(intents=discord.Intents.default())
tree = discord.app_commands.CommandTree(client)

DiscordIDs = 'DiscordKeys/'

with open(os.path.join(DiscordIDs, 'token.txt'), 'r') as t,      open(os.path.join(DiscordIDs, "guild_id.txt"), 'r') as g:
    
    TOKEN = t.read()
    GUILD_ID = g.read()

guild=discord.Object(GUILD_ID)

@tree.command(
    guild=guild,
    name='test',
    description='test'
)
async def test(ctx:discord.Integration,boolean:bool,name:discord.User,number:int=999):
    await ctx.response.send_message(f"{number} {boolean} {name}")

@client.event
async def on_ready():
    print('ready...')
    await tree.sync(guild=guild)
    print('synced...')

client.run(TOKEN)

コードの中身のほとんどは前回と同じです。
注目点はハイライトしている部分です。

ctx:discord.Integrationはコマンドを実行したユーザーだったりコマンドに関する情報が入っています。
この後ろにコマンドオプションを設定できます。
今回はboolean:boolname:discord.Usernumber:int=999を設定しています。

実行結果

コマンドオプションの例 実行例

ユーザー名の後ろにテスト#数字と数字がついて表示されますが、画像中では隠しています。

オプションの設定は変数名:型=デフォルト値という形で設定できます。
デフォルト値は省略可能です。(実行例では1を入力しています。)

ここでコマンドオプションを使用する上での注意点を説明します。

  1. オプションに使用できる変数は小文字のみです。
  2. デフォルト値は省略可能です。省略された場合、必須オプションとなります。
  3. デフォルト値が設定されている場合、他のオプションとなり省略可能になります。
  4. 必須オプションの場合、コマンドを実行する際に必要なオプションとなります。
  5. デフォルト値を設定する際にはオプションの順番を最後に設定する必要があります。
  6. デフォルト値にNoneを設定することで初期値を設定せず、他のオプションにできます。(変数にはNoneが当然入ります。)

エラー例

コマンドオプションが未入力の場合のエラー表示

コマンドオプションエラーの例

注意点5のエラー例
コピー
async def test(ctx:discord.Integration,number:int=999,boolean:bool,name:discord.User):

コマンドオプションで指定できる型はさまざまで挙げきれないので、割愛します。
基本的には以下の型が使用できると知っていればBot作りには困らないと思います。

  • int
  • float
  • bool
  • str
  • Literal

Literalは少し特殊で、
from typing import Literalをインポートする必要があります。
また、Literalでは以下のように選択肢を設定できます。
your_choice:Literal["グー","チョキ","パー"]
このように設定することで、グーチョキパーの3つの選択肢を設定できます。
注意として、選択肢の最大数は25個です。

また、今回例で使用したdiscord.UserはユーザーのIDを取得するためのものです。 他にもdiscord特有の使用できる型があります。

Disocrd.pyのリファレンス

上記のリファレンスを参考にすると幅広いBot作りができると思います。

また、オプションで作成した変数はコマンド内で使用できます。
今回の例ではそのまま出力していますが、変数を使用して処理を行うこともできます。

じゃんけんBotの作成

オプションの機能を理解したところで肝心のじゃんけんBotを作成していきましょう。
といっても今回学んだオプションとじゃんけん部分の処理があるだけなので、
いきなりコードを貼り付けます。

bot.py
コピー
import os
import random
from typing import Literal

import discord
from discord import app_commands

#Discord Bot Initialize
client = discord.Client(intents=discord.Intents.default())
tree = discord.app_commands.CommandTree(client)

DiscordIDs = 'DiscordKeys/'

with open(os.path.join(DiscordIDs, 'token.txt'), 'r') as t,      open(os.path.join(DiscordIDs, "guild_id.txt"), 'r') as g:
    
    TOKEN = t.read()
    GUILD_ID = g.read()

guild=discord.Object(GUILD_ID)

@tree.command(
    guild=guild,
    name='janken',
    description='じゃんけんゲーム'
)
@discord.app_commands.describe(
    your_choice="あなたの手",
)
async def greet(ctx:discord.Integration,your_choice:Literal["グー","チョキ","パー"]):
    cpu_choice=random.choice(["グー","チョキ","パー"])
    if cpu_choice==your_choice:
        await ctx.response.send_message(f"CPUの手は{cpu_choice}、あなたの手は{your_choice}\n結果:あいこ")
    else:
        if (your_choice=="グー" and cpu_choice=="チョキ") or (your_choice=="チョキ" and cpu_choice=="パー") or (your_choice=="パー" and cpu_choice=="グー"):
            await ctx.response.send_message(f"CPUの手は{cpu_choice}、あなたの手は{your_choice}\n結果:あなたの勝ち")
        else:
            await ctx.response.send_message(f"CPUの手は{cpu_choice}、あなたの手は{your_choice}\n結果:あなたの負け")

@client.event
async def on_ready():
    print('ready...')
    await tree.sync(guild=guild)
    print('synced...')

client.run(TOKEN)

じゃんけんBotの処理部分のみ切り抜きます。

コピー
@tree.command(
    guild=guild,
    name='janken',
    description='じゃんけんゲーム'
)
@discord.app_commands.describe(
    your_choice="あなたの手",
)
async def greet(ctx:discord.Integration,your_choice:Literal["グー","チョキ","パー"]):
    cpu_choice=random.choice(["グー","チョキ","パー"])
    if cpu_choice==your_choice:
        await ctx.response.send_message(f"CPUの手は{cpu_choice}、あなたの手は{your_choice}\n結果:あいこ")
    else:
        if (your_choice=="グー" and cpu_choice=="チョキ") or (your_choice=="チョキ" and cpu_choice=="パー") or (your_choice=="パー" and cpu_choice=="グー"):
            await ctx.response.send_message(f"CPUの手は{cpu_choice}、あなたの手は{your_choice}\n結果:あなたの勝ち")
        else:
            await ctx.response.send_message(f"CPUの手は{cpu_choice}、あなたの手は{your_choice}\n結果:あなたの負け")

ただじゃんけんBotを作成しても面白くないので、
新たにオプションの説明追加しました。
そちらの説明もします。

コピー
@discord.app_commands.describe(
    your_choice="あなたの手",
)

実行結果

じゃんけんBot実行結果 オプションで指定した変数名に対して説明を設定できます。
これを設定することでオプションの選択肢部分に説明が追加されます。
今回の場合はあなたの手が選択肢に追加されます。

Botを使用するユーザー目線で使いやすいBotを目指すには覚えておいて損はないです。

じゃんけんBot実行結果 実際に選択肢を選択してコマンドを実行すると、じゃんけんを実行しその結果を返します。

まとめ

今回はコマンドオプションの基本的な使い方を説明しました。
コマンドオプションはBotを作成する上で必須の知識です。

途中でLiteralを使いオプションの選択肢を設定する方法を説明しましたが、
オートコンプリート機能を使い、strの型で似たようなことができます。
こちらもLiteral同様選択肢を25個まで設定が可能で、
違いとしてはLiteralは指定した選択肢のみ使用できるのに対し、
こちらはあくまで型はstrなので選択肢以外の入力も受け付けます。

こちらの機能についてはまた別の記事で紹介できればと思います。

今回説明した内容をまとめると以下のようになります。

  1. オプション機能の記載方法
    async def test(ctx:discord.Integration,option:str):
  2. オプションの設定は変数名:型=デフォルト値という形で設定でき、デフォルト値は省略可能です。
  3. オプションの種類は必須オプションと他のオプションに分かれます。
  4. 必須オプションはデフォルト値を設定されてない場合に自動で設定されコマンド実行時に必要になります。
  5. オプションの値はコマンド中で使用可能です。

これらの知識があれば、スロットBotや今回作成したじゃんけんBotのような応用次第で様々なBotを作成できると思います。

では、良きDiscordBotライフを!

© 2024 Smoothie1023.