【Lua言語講座】19.演習-テーブル-

Lua言語講座

こんにちは、ロブスタのハルです!
前回の講座ではテーブルと配列・連想配列について解説しました。
今回はテーブルに慣れるために演習としてNPCとの会話プログラムを実装します。
前回の講座を見ていない方はこちらからご覧ください。

会話処理の実装

ゲーム上にNPCを登場させたいことがあると思います。ここではテーブルを使ってNPCの会話処理しょりを作ってみたいと思います。

概要

今回作りたいプログラムは以下のようなものです。

  • NPCに近づいてボタンを押すとき出しが出る
  • 吹き出しには会話の内容が表示される
  • ボタンを押すたびに会話の内容が変わる

実装

NPCの用意

まずはツールボックスからNoobヌーブ NPCを選択せんたくしてください。

toolbox

そうしたら名前をNPCに変更して、NPCの子にProximityプロキシミティPromptプロンプトを追加しましょう。さらにProximyPromptの子にScriptスクリプトを追加してください。

exploler

これで下準備は完了です。

ProximityPromptクラス

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

proximity prompt UI

Chat()メソッド

ChatチャットクラスのChat()メソッドはオブジェクトに対してテキストを表示させるものです。Chat()メソッドを使うにはまずgameゲーム:GetゲットServiceサービス()メソッドを使ってChatを取得しゅとくする必要があります。

Triggeredイベント

ChatクラスのTriggeredトリガードイベントはキーがされた時に発動はつどうされるイベントです。

プログラムを書く

流れを考える

さて下準備したじゅんびができたら今回のプログラムの流れを考えてみましょう。ただ、今回は少し複雑ふくざつなので思いつかなかったらすぐに答えを見ても大丈夫です。

今回のプログラムの流れは次のようになります。

  1. game:GetService()メソッドを使ってChatを取得する
  2. ProximityPromptクラスとnpcを変数に代入しておく
  3. テーブルの中に会話内容を入れておく
  4. Triggeredイベントのイベントリスナーを作る
  5. イベントリスナーの中身として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行目では変数dialogueダイアログTableテーブルにテーブルとして会話内容を3つ保管ほかんしています。

7~10行目は自作イベント関数talkトーク()です。まず、8行目でdialogueTableから取ってきた会話内容の一つを変数dialogueに代入しています。その後、9行目ではChatクラスのChatメソッドを使ってheadにdialogueを表示させてくださいという命令めいれいあたえています。

最後の12行目ではpromptに対してトリガーが発動したらtalkイベントを実施じっししてくださいという命令を出しています。

まずはここまででテストしてみましょう。
NPCに近づいてみるとインタラクトUIが表示され、Eボタンを押すと文章が表示されていると思います。

hello, noob!
修正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の値が増えていきます。

一旦テストしてみましょう。

test talking noob

画像のように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のセリフをループするようになりました。

check the beautiful noob face
修正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に近づくと吹き出しが表示され、ボタンを押すたびに内容が変わっていれば成功です!

noooob!3

まとめ

  • 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

コメント

タイトルとURLをコピーしました