こんにちは、ロブスタのハルです!
前回の講座ではテーブルと配列・連想配列について解説しました。
今回はテーブルに慣れるために演習としてNPCとの会話プログラムを実装します。
前回の講座を見ていない方はこちらからご覧ください。
会話処理の実装
ゲーム上にNPCを登場させたいことがあると思います。ここではテーブルを使ってNPCの会話処理を作ってみたいと思います。
概要
今回作りたいプログラムは以下のようなものです。
- NPCに近づいてボタンを押すと吹き出しが出る
- 吹き出しには会話の内容が表示される
- ボタンを押すたびに会話の内容が変わる
実装
NPCの用意
まずはツールボックスからNoob NPCを選択してください。

そうしたら名前をNPCに変更して、NPCの子にProximityPromptを追加しましょう。さらにProximyPromptの子にScriptを追加してください。

これで下準備は完了です。
ProximityPromptクラス
ProximityPromptクラスはゲーム空間上でインタラクトUIを表示させるためのクラスです。下記は公式から引用した画像ですがこのようなUIを表示させることができます。

Chat()メソッド
ChatクラスのChat()メソッドはオブジェクトに対してテキストを表示させるものです。Chat()メソッドを使うにはまずgame:GetService()メソッドを使ってChatを取得する必要があります。
Triggeredイベント
ChatクラスのTriggeredイベントはキーが押された時に発動されるイベントです。
プログラムを書く
流れを考える
さて下準備ができたら今回のプログラムの流れを考えてみましょう。ただ、今回は少し複雑なので思いつかなかったらすぐに答えを見ても大丈夫です。
…
…
…
今回のプログラムの流れは次のようになります。
- game:GetService()メソッドを使ってChatを取得する
- ProximityPromptクラスとnpcを変数に代入しておく
- テーブルの中に会話内容を入れておく
- Triggeredイベントのイベントリスナーを作る
- イベントリスナーの中身としてChat()メソッドを設定する
コーディング
コーディングの時間です。
local Chat = game:GetService("Chat")
local prompt = script.Parent
local npc = prompt.Parent
local head = npc.Head
local dialogueTable = {"こんにちは", "どうしましたか?", "さようなら"}
local function talk()
local dialogue = dialogueTable[2]
Chat:Chat(head, dialogue) -- Chat:Chat(npc.Head, dialogue)でもOK
end
prompt.Triggered:Connect(talk)
1行目ではゲーム空間からChatサービスを取得し、変数Chatに代入しています。
2行目ではこのスクリプトの親であるProximityPromptオブジェクトを変数promptとして代入し、3行目でさらにその親であるNoobオブジェクトを変数npcに代入しています。
そして、4行目ではnpc(Noob)の中のHeadを取り出して変数headに代入しています。これは吹き出しを表示するパーツを選ぶためであり、この時点で変数に代入しておかずに9行目のChat()メソッドの第一引数に直接npc.Headと書いても大丈夫です。
5行目では変数dialogueTableにテーブルとして会話内容を3つ保管しています。
7~10行目は自作イベント関数talk()です。まず、8行目でdialogueTableから取ってきた会話内容の一つを変数dialogueに代入しています。その後、9行目ではChatクラスのChatメソッドを使ってheadにdialogueを表示させてくださいという命令を与えています。
最後の12行目ではpromptに対してトリガーが発動したらtalkイベントを実施してくださいという命令を出しています。
まずはここまででテストしてみましょう。
NPCに近づいてみるとインタラクトUIが表示され、Eボタンを押すと文章が表示されていると思います。

修正1
それでは少しステップアップして、Eボタンを押すたびにセリフが変わるようにしたいと思います。
テーブルはインデックスを使って中身を取り出すことができると前回説明しました。そこでEボタンを押すたびにインデックスを変えていけば中身も変わるはずです。
local Chat = game:GetService("Chat")
local prompt = script.Parent
local npc = prompt.Parent
local head = npc.Head
local dialogueTable = {"こんにちは", "どうしましたか?", "さようなら"}
local count = 1
local function talk()
local dialogue = dialogueTable[count]
Chat:Chat(head, dialogue)
count += 1
end
prompt.Triggered:Connect(talk)
今回は新たに変数countを宣言して、talk()イベントの中でcount += 1としています。これによってtalk()イベントが呼び出されるたびにcountの値が増えていきます。
一旦テストしてみましょう。

画像のようにEボタンを押すたびにセリフが変わっているのが確認できるかと思います。
修正2
しかし、4回目でおそらくエラーが出たのではないでしょうか?これはcountが4になったとき、”dialogueTableの中身は3つしかないので中身が見つかりませんよ”というエラーを出しているためです。
そこでcountを1, 2, 3, 1, 2, 3, …と繰り返すようにしたいです。ここで使えそうなのはif–else文ですね。count += 1とする前に判定してcountの中身が3だったら1に戻すようにしてあげましょう。
local Chat = game:GetService("Chat")
local prompt = script.Parent
local npc = prompt.Parent
local head = npc.Head
local dialogueTable = {"こんにちは", "どうしましたか?", "さようなら"}
local count = 1
local function talk()
local dialogue = dialogueTable[count]
Chat:Chat(npc.Head, dialogue)
if count == 3 then -- count > 2としてもOK
count = 1
else
count += 1
end
end
prompt.Triggered:Connect(talk)
こうするとcountが1, 2のときはcountに1を足して、3のときは1に戻すことができます。
また、条件式をcount > 2とした人もいるかもしれませんがそれでも大丈夫です。その場合はcount > 3としないように注意しましょう。なぜならif-else文で条件分岐した後に1を足す処理をしているためです。(count = 3はcount > 3ではないのでelseへ流れる。するとcount += 1によってcount = 4となる。結果として次にtalkイベントが呼ばれた時にdialogueTable[4]の部分でエラーが出てしまうため)
これでようやく1~3のセリフをループするようになりました。

修正3(#演算子)
さて、今回はdialogueTableの中身の数が3個と決まっていました。しかし、実際はセリフを追加したいこともあると思います。セリフを追加するたびにコード中の”3″の部分を変えていくのは面倒です。テーブルの中身の数を数えられる関数みたいなものがあれば便利ですよね。
実はあるんです。それが#演算子です。
#テーブル名と書くことでその中身の数を知ることができます。ただし、#演算子は連想配列(辞書)モードのテーブルには使うことができません。なぜなら連想配列は順番がないからです。#演算子は順番のあるものでないと正しい値を返してくれないと覚えておいてください。
-- #テーブル名でテーブルの中身の数(要素数)を取得する
local t = {1, 2, 3, 4}
print(#t)
-- 連想配列には使えない
local t = {
a = 1,
b = 2,
c = 3
}
print(#t) -- スクリプトエディタだと波線で警告が表示される
実際に#演算子を使ったものがこちらです。
local Chat = game:GetService("Chat")
local prompt = script.Parent
local npc = prompt.Parent
local head = npc.Head
local dialogueTable = {"こんにちは", "どうしましたか?", "さようなら"}
local count = 1
local function talk()
local dialogue = dialogueTable[count]
Chat:Chat(npc.Head, dialogue)
if count == #dialogueTable then
count = 1
else
count += 1
end
end
prompt.Triggered:Connect(talk)
テスト
最終的にできたコードをテストしてみましょう。
下の画像のようにNPCに近づくと吹き出しが表示され、ボタンを押すたびに内容が変わっていれば成功です!

まとめ
- ProximityPromptクラスはゲーム空間上でインタラクトUIを表示させることができる
- Chat()メソッドはオブジェクトに対してテキストを表示させる
- game:GetService(“Chat”)でChatサービスを取得できる
- Triggeredイベントはキーが押された時に発動される
- #演算子は配列モードのテーブルの要素数(中身の数)を取得できる
お疲れ様でした。今回は修正が多かったですが、少しは配列モードのテーブルの使い方が分かったかと思います。
次回はテーブルの機能に関して解説します。このシリーズもあと少しで基本編が終わる予定です。その後は応用編と並行してモデル・マップの制作方法やAPI、各クラスの解説などより実践的な内容を解説していきたいと考えています。
画像引用元
[1]ProximityPrompt, Roblox Creator Hub, https://create.roblox.com/docs/ja-jp/reference/engine/classes/ProximityPrompt, 最終閲覧日2024/07/12
コメント