5-1 配列の概要

配列とは?

配列とは、複数の値をグループ化する方法です。1つの数字や文字列を格納できる変数と比較して、配列には大きさがなく、複数の値を含めることができます。配列を使えば、ゲーム内アイテムのステータスをグループ化したり、数千人のプレイヤー名のリストを作成したりすることができます。
スプレッドシートの「表」を思い描いていただくと分かりやすいでしょう。

配列は下記のように作成できます。「local 変数名=」とし、その後に中括弧 { } を使用します。この中に様々な値をカンマで区切って入れていきます。
下記の例では、「アイテム1」と「アイテム2」が文字列、「10」が数値、「workplace.Part」がオブジェクト、「myVariable」が他の変数の値ということになります。このように、多種類のデータを混在させることはあまりありませんが、配列には複数の様々なデータが格納できるということを覚えておきましょう。

local myArray = { “アイテム1”, “アイテム2”, 10, workplace.Part, myVariable }

テーブルとは?

この章では、今から学ぶ「配列」と、もう1つ「辞書」と呼ばれるものを解説します。順番に格納されるのが配列で、順不同で保管場所に名称を付けて格納するのが辞書ということになります。この配列と辞書をまとめて、「テーブル」という呼ぶことがありますので覚えておきましょう。

話すキャラクターの作成

それでは早速、配列について学びます。
例として、NPC をクリックすると、配列に保存しているセリフを次々と表示するというプログラムを作成してみます。

プロジェクトの設定

あらかじめ作成してあるNPCモデルを使用して学習します。

  1. 既製の NPC をダウンロードします。こちらはNPCのモデルデータになります。
  1. エクスプローラーで、Workspace を右クリックし、「Insert From File…(ファイルから挿入)」 をクリックして先ほどダウンロードしたファイルを選択します。
  1. テスト実行してみましょう。NPCの近くまで行き、「E]キーもしくはクリックすると「I’ve got one thing to say!」というセリフを発すると思います。

dialogueArrayのコーディング

キャラクターが発するすべてのセリフは、個々の文字列として配列に格納します。NPCをクリックすると、フレーズを表示する吹き出しが表示されます。

  1. TemplateNPC の ProximityPrompt の中に ChatManager というスクリプトが入っていますので、それを開きます。
  1. 「local dialogueArray = {}」 と入力してください。これで何も入っていない空の配列ができました。
-- Cycles through chat dialogue when prompt is used

   local Chat = game:GetService("Chat")

   local prompt = script.Parent

   local npc = prompt.Parent
   local characterParts = npc.CharacterParts
   local head = characterParts.Head

   -- Add array here
   local dialogueArray = {}

   local function speak()
      local dialogue = "I've got one thing to say!"
      Chat:Chat(head, dialogue)
   end

   prompt.Triggered:Connect(speak)
  1. 今作成した配列の中括弧の間に、カンマで区切られた少なくとも 3 つのセリフを文字列で入力します。
local dialogueArray = { "Hi!", "Do I know you?", "Good bye!" }

配列の内容を取得する

配列を作成したところで、その中に入れた個々の値を取得したいと思います。
この表のように「Hi!」は1番目、「Do I know you?」は2番目、「Good bye!」は3番目になります。この番号をインデックス(要素番号)と呼びます。今回の例では、「Hi!」はインデックス 1 で、「Good bye!」はインデックス 3ということになります。

インデックス
1Hi!
2Do I know you?
3Good bye!
他のプログラミング言語では、インデックスが0から始まるものもありますが、Lha は1から始まります。

セリフの取得

配列から値を取得するには、このインデックスを使用します。dialogArray[1] のように、配列名の後ろに角カッコを付け、その中で取得したいインデックス番号を指定します。

  1. 「local dialogue = dialogueArray[2]」としてみましょう。インデックス2の文字列を取得するという意味です。
local dialogueArray= { "Hi!", "Do I know you?", "Good bye!" }

local function speak()
    local dialogue = dialogueArray[2]
    Chat:Chat(head, dialogue)
end
インデックスが存在しない場合は、nil エラーが発生します。今回の例では配列の中身は3つです。よってdialogueArray[4] と、インデックス4で値を取得しようとするとエラーが発生するということです。
  1. プロジェクトを再生し、NPC をクリックして「Do I know you?」と表示されると思います。コードを変更して、他のインデックスもテストしてみてください。

配列と変数

コードをより柔軟にするために、インデックス番号の代わりに変数が使用できます。たとえば、変数を使用してランダムなインデックス番号を取得したり、関数が呼び出されるたびに値を増やして配列内の次の値を取得したりできます。

セリフの変更

現在、プレイヤーがNPCと対話するときは、いつも同じセリフを言います。セリフをより動的にするために、変数を使って現在のインデックスを追跡し、プレーヤーが対話するたびに、その変数を操作して次のセリフを話すようにしたいと思います。

  1. 現在のインデックスを追跡するには、dialogIndex という名前の新しい変数を追加します。配列のインデックスは1から始まりますので変数に1を代入しておきます。
local dialogueArray= { "Hi!", "Do I know you?", "Good bye!" }
local dialogueIndex = 1
  1. speak()で、dialogArray[2] の部分の2を、dialogueIndex に置き換えます。現在、dialogueIndex には1が入っていますので、dialogArray[1] とするのと同じ意味になります。
 local function speak()
     local dialogue = dialogueArray[dialogueIndex]
     Chat:Chat(head, dialogue)
 end
  1. 関数の最後で、dialogIndex に 1 を加算します。そうすれば、次に speak() が呼び出されたときに、配列内の次の文字列が表示されます。
 local function speak()
     local dialogue = dialogueArray[dialogueIndex]
     Chat:Chat(head, dialogue)

     dialogueIndex += 1
 end
dialogueIndex += 1 は、dialogueIndex = dialogueIndex + 1 と同じ意味になります。
  1. NPC をクリックし、セリフの変化を確認してください。

最後のセリフ「Good bye!」を発したあと、再度NPCをクリックすると、出力ウィンドウにエラーが表示されると思います。

プログラムを修正して、「Good bye!」を表示した後に再び最初のセリフを話すようにしたいと思います。

配列サイズ

今回は3つのセリフなので、加算したインデックスが4になったら1に戻すという処理を加えれば完成となりますが、セリフはたくさん追加したいものです。数が多くなるとセリフの数を数えるのも大変になります。そこで、配列のサイズを簡単に取得する方法を教えます。
配列名の前にスペースを入れずに「#」と指定すれば、それは配列の要素数になります。

例: #dialogArray

これを使用すれば、配列にセリフをたくさん追加しても、条件式の数字を変更する必要はなくなります。

対話の再開

最初のセリフに戻すには、dialogIndex の値が、配列の最後のインデックスになっているかどうかを調べ、最初に戻るかどうかを判断すれば良いわけです。if/else ステートメントを使用すれば簡単です。

  1. dialogIndex が #dialogueArray (この配列の合計サイズ) と等しいかどうかを確認するため、if ステートメントを追加します。もし、dialogIndex が最後のインデックスだった場合は、dialogIndex に1 を代入し、最初のセリフに戻します。
local function speak()
    local dialogue = dialogueArray[dialogueIndex]
    Chat:Chat(head, dialogue)

    if dialogueIndex == #dialogueArray then
        dialogueIndex = 1
    end

    dialogueIndex += 1
 end
  1. このままではdialogIndex に1 を代入した後でも、 dialogIndexに 1 を加算してしまいます。よって、DialogIndex += 1 をelse ステートメントの下に移動します。
local function speak()
    local dialogue = dialogueArray[dialogueIndex]
    Chat:Chat(head, dialogue)

    if dialogueIndex == #dialogueArray then
       dialogueIndex = 1
    else
       dialogueIndex += 1
    end
 end
  1. プロジェクトを再生します。今度はエラーにならず、最後の「Good bye!」を表示した後、最初の「Hi!」に戻るのが確認できると思います。

まとめ

データ構造は、データのセットを格納する方法です。Lua はテーブルを使用してデータ構造を作成します。配列は、情報の順序付きリストを保持できるテーブルの一種です。配列内の各値には、インデックス 1 から始まるインデックス番号が割り当てられます。

このスクリプトは、配列を使用して、ノンプレイアブル キャラクター (NPC) の可能な会話のリストを作成しました。

-- Cycles through chat dialogue when prompt is used

   local Chat = game:GetService("Chat")

   local prompt = script.Parent

   local npc = prompt.Parent
   local characterParts = npc.CharacterParts
   local head = characterParts.Head

   -- Add array here
   local dialogueArray = {"Hi!",  "Do I know you?",  "Goodbye!"}
   local dialogueIndex = 1

   local function speak()
      local dialogue = dialogueArray[dialogueIndex]
      Chat:Chat(head, dialogue)

      if dialogueIndex == #dialogueArray then
         dialogueIndex = 1

      else
         dialogueIndex += 1
      end
   end

   prompt.Triggered:Connect(speak)

トラブルシューティング 

NPCが一連のダイアログを表示しない場合は、次の点を確認してください。

  • dialogIndex が1 に戻されていることを if ステートメントで確認します。else ステートメントで、dialogIndex 変数に1 が加算されていることを確認します。
  • 配列のサイズを取得するときは、 #dialogueArray の「#」の後にスペースがないことを確認してください。

チャレンジ

さらに学習したい方は、以下の課題に挑戦しましょう。

  • NPC のダイアログが配列を逆方向に進むように変更してみます。dialogIndex は配列から開始し、加算する代わりに毎回減算する必要があります。
  • セリフを順番に表示する代わりに、 Random.new()を使用して NPC に毎回ランダムなセリフを表示させます。このサンプルは下記のようになります。
local randomGenerator = Random.new()

-- NPCがクリックされるたびに新しいダイアログを表示します
local function speak()
   local randomIndex = randomGenerator:NextInteger(1, #dialogueArray)
   local dialogue = dialogueArray[randomIndex]
   Chat:Chat(head, dialogue)
end
4 thoughts on “5-1 配列の概要”
  1. おはようございます。
    うえのNPCをダウンロードできませんでした。
    以下のエラーが表示されました。
    〜〜〜〜〜〜
    This XML file does not appear to have any style information associated with it. The document tree is shown below.

    AccessDenied
    Access Denied
    9XVB2XMK21M555Q9
    rY3JRdmLPIIAPBioopHNLO4n/Y5jqAFY/QG3+XW6Rjwk4WwC6SvgazlOBVOZ8FGElhTkIlsxNYNDE8LYvqQIeDWi7Oip4MsVL65L7p7qAI4=

  2. ありがとうございます。無事にダウンロードできました。
    冒頭の ”2.「local dialogArray = {}」 と入力してください。”の文章のところ
    「local dialogueArray = {}」ですね。プログラム中の変数名と異なっていました。

    また、スクリプトを見つけるのが難しかったです。
    編集するスクリプトは、DialogueScript ではなく、ProximityPromptの中にある「ChatManager」ですね。

    無事に 5-1のフォローを終えました。

    1. ご指摘ありがとうございます。修正させていただきました。
      こちらはかなり前に作成したもので、その後、アップデートがあったようですね。
      すぐに対応させていただきますので、また何か問題がありましたらお知らせください。

コメントを残す