【Unreal Engine】BlueprintのArray・Set・Map入門:3つのコンテナの使い分け

作成: 2026-07-20最終更新: 2026-09-05

変数1個では足りなくなったら、コンテナの出番です。Array(順番がある)・Set(重複しない)・Map(キーで引く)の違いと主要ノードを図解し、アイテムIDと所持数をMapで数えるインベントリを作る実践つき。

インベントリを作ろうとして、Item1Item2Item3 という変数を並べる。敵を管理しようとして、Enemy1Enemy2 を作る。数が増えるたびに、変数と同じようなノードを追加することになります。

こういうときに使うのが コンテナ です。Blueprintには Array・Set・Map の3種類があり、どれも「同じ型の値をまとめて持つ」ための入れ物です。選ぶときは、順番を残したいか・種類だけを記録したいか・IDから個数を知りたいか を考えます。今回は同じ拾い物を3種類で記録し、それぞれ何が分かるかを比べます。

Array・Set・Mapの3つの入れ物を並べたイメージ

この記事でわかること

  • Array=順番がある / Set=重複しない / Map=キーで引く
  • コンテナは変数の型の右にある 切り替えボタン で選ぶ
  • Arrayの主要ノードと、 Index out of bounds の直し方
  • ループ中の追加・削除で、次の要素を飛ばす 理由
  • 実践: アイテムIDと所持数をMapで管理するインベントリ

Sponsored

3つのコンテナの違い

3つとも複数のデータをまとめます。中に入る1件を 要素 と呼びます。違うのは、どのように探し、取り出すかです。

コンテナ持ち方得意な質問苦手なこと
Array(配列)順番に並べる。重複OK「3番目は何?」「全部で何個?」含まれる値を探すときは、順に比較する
Set(集合)重複なし。順番なし「これを持っているか?」「3番目」が存在しない
Map(辞書)キーと値のペア。順番なし「このキーの値は?」同じキーを2つ持てない

ゲームの例に置き換えると、選び方はかなりはっきりします。

  • Array: 拾った順のログ、パーティの並び、ウェイポイントの巡回順。 順番そのものが意味を持つ もの
  • Set: 一度取ったアイテムのID、解放済みのステージ、図鑑の登録済みモンスター。 同じものを二重に登録したくない もの
  • Map: アイテムID → 所持数、プレイヤー名 → スコア、キー名 → 設定値。 何かを手がかりに引きたい もの

キー は、取り出したいデータを指定する手がかりです。Mapで「Herb → 3」と持つなら、Herbがキー、3が値です。配列の位置を示す番号とは役割が違います。

Arrayは拾った順、Setは見つけた種類、MapはIDに対応する個数を記録する。薬草とポーションで3つの違いを比べる

コンテナは型の右で切り替える

Blueprintでは、まず中身の型を選び、それを1個持つか、Array・Set・Mapにまとめるかを指定します。

My Blueprintパネルで変数を作ると、詳細パネルに Variable Type の欄があります。型を選ぶドロップダウンの 右側に小さなボタン があり、ここで4つから選べます。

表示意味
Single Variable普通の変数(1個)
Array配列
Set集合
Map辞書。選ぶと 値側の型を選ぶ欄がもう1つ増える
変数の型ドロップダウンの右にあるコンテナ切り替えボタンと、4つの選択肢を示した図

Mapを選んだときだけ、欄が2つになります。 左がキーの型、右が値の型 です。「アイテムID(Name)→ 所持数(Integer)」なら、左にName、右にIntegerを設定します。

Name は、HerbやPotionのような識別名に使う型です。画面に出す「薬草」という文章と、処理で指定するIDを分けたいときに向いています。Setの要素やMapのキーに使えない型もあるため、今回のアイテムIDはNameで揃えます。

Sponsored

Arrayの主要ノード

3つの中でいちばん出番が多いのがArrayです。配列変数をグラフへドラッグして、ピンから線を引き出すと候補が出てきます。

ノードすること注意
Add末尾に追加する追加した位置のインデックスを返す
Insert指定インデックスに割り込ませる後ろの要素が1つずつ後ろへずれる
Remove Index番号を指定して消す後ろの要素が1つずつ前へ詰まる
Remove Item中身を指定して消す一致するものを全部 消す
Get (a copy)番号で取り出す範囲外を指定するとエラーになる
Set Array Elem指定番号の値を書き換えるSize to Fitがオフなら既存の番号を使う。オンなら必要に応じて配列を広げる
Length要素数を返す空なら0
Last Index最後の番号(Length - 1)を返す空の配列では -1 になる
Contains Item含まれているかをBooleanで返す見つかればtrue、なければfalse
Find Item見つかった番号を返す見つからないと -1 を返す
Is Valid Indexその番号が使えるかをboolで返すGetの前の安全確認に使う

インデックス は、Arrayの中の位置を指定する番号です。0から始まる ので、要素が3個なら番号は0・1・2。Lengthは個数の3、Last Indexは最後の番号の2です。Boolean(bool)は、条件が成り立つtrueと、成り立たないfalseを扱う型です。

3個のArrayは番号0・1・2で、番号3は存在しない。空のArrayはLengthが0、Last Indexが-1で、読む要素がない

範囲外の番号でGetすると、Output Logに次のようなメッセージが出ます。文言はノードや版によって異なりますが、indexとlengthを見ると原因を追えます。

Blueprint Runtime Error: "Attempted to access index 3 from array 'PickupLog' of length 3!"

「3個の配列に、番号3を指定した」という意味です。番号3は先頭から数えて4番目なので、存在しません。個数と最後の番号は1つ違います。

防ぎ方は2つです。確認したBooleanをBranchのConditionへ入れ、True側だけでGetを使います。Branchは、条件に応じてTrue/Falseへ実行を分けるノードです。

  • Is Valid Index で確認してからGetする: 番号が外から来る場合(UIのクリック位置、セーブデータの値など)はこちら
  • 最後の要素も、空かを確かめてから読む: Last Index は便利ですが、空配列では-1です。Length > 0 のBranchでTrue側だけGetするか、Last IndexをIs Valid Indexで確認します

Get (a copy)は値をコピーして取り出します。 配列の中身が構造体のとき、取り出したコピーを書き換えるだけでは元の要素は変わりません。書き戻すには Set Array Elem を使います。これは詰まりやすいポイントなので、構造体の記事で仕組みと直し方を詳しく扱っています。

For Each Loopとループ中の書き換え

配列を1つずつ処理するには For Each Loop を使います。配列のピンから引き出すと候補に出ます。

ピン内容
Loop Body1要素ごとに実行される
Array Elementそのときの中身
Array Indexそのときの番号
Completed全部終わったあとに1回だけ実行される

途中で止めたいときは For Each Loop with Break を使います。Break ピンに実行を流すと、その時点でループが終わります。「最初に見つかった1件で処理を打ち切る」ときに便利です。

注意したいのは、For Each Loopの途中で、処理中の配列へ要素を追加・削除すること です。個数や番号が変わるため、想定した順で処理できなくなる場合があります。

ループ中に要素を消すと後ろが前へ詰まり、次の要素が飛ばされる様子を番号付きで示した図

理由は仕組みを見れば分かります。For Each Loopは 番号を0から1つずつ進めている だけです。A, B, C, D の4件があり、番号1の B を消したとします。すると C が番号1へ、D が番号2へ詰まります。ループは次に番号2を見るので、 番号1へ移動した C は一度も処理されません

「HPが0の敵を配列から取り除く」ときも、隣り合う対象を取りこぼす原因になります。

最初は、元の配列を読み終わるまで変えない方法が分かりやすいです。

  • 消す対象を別の配列に集める: ループ中は RemoveTargets に追加するだけにして、Completed の後でまとめて Remove Item する。いちばん素直で読みやすい方法です
  • 残すものだけで新しい配列を作る: 条件に合う要素だけを別の配列に Add して、最後に元の変数へ入れ替えます

追加するときも、別の配列へ集めてから処理後に加えると、今回のループで扱う範囲がはっきりします。既存の要素の値を更新することと、個数や位置を変えることは区別してください。

Sponsored

Set:重複しない入れ物

Setは 同じ値を2つ持てない 入れ物です。すでに入っている値を Add しても、要素数は増えません。エラーにもならず、静かに無視されます。

ノードすること
Add追加する。すでにあれば何も起きない
Remove中身を指定して消す
Contains含まれているかをboolで返す
Length要素数を返す
To Array配列に変換する(ループしたいときはこれ)

Setが向いているのは、 「持っているかどうか」だけを知りたい ケースです。

  • 一度取ったアイテムのID(同じ宝箱を二度開けても増えない)
  • 解放済みステージのID
  • 図鑑に登録済みのモンスターID
  • 会話済みのNPCのID
ArrayとSetの違い。Setは同じ値をAddしても要素数が増えない

Setを選ぶと、「この一覧は同じIDを重ねて持たない」と構造で示せます。Arrayにも Add Unique という重複を追加しないノードがあります。順番も残したいならArray+Add Unique、有無を記録するのが主目的ならSet、という選び方ができます。

Setには 番号がありませんGet(0) のような取り出し方はできず、順番も保証されません。1件ずつ処理したいときは To Array で配列に変換してからループします。

Map:キーで引く入れ物

Mapは キーと値のペア を持つ入れ物です。例えばHerbというIDと、所持数3を1組として持ちます。

ノードすること注意
Addキーと値を登録する同じキーがあれば上書き される
Findキーから値を取り出す値と、見つかったかのboolを返す
Containsキーがあるかをboolで返す
Removeキーを指定して消す
Keysキーの一覧を 配列 で返すループしたいときはこれ
Values値の一覧を配列で返す
Lengthペアの数を返す

今回は アイテムIDから所持数を知る ためにMapを使います。Map<Name, Integer> は「キーがName、値が整数のMap」という表記です。Herbを指定してFindすると、その所持数を取り出せます。

Mapで押さえておく点が2つあります。

1つ目は、Add が上書きだということ。 「すでにあったら何もしない」ではありません。数を増やしたいなら、 Find で今の値を取り、1を足して、Add で入れ直す という流れになります。この形は実践セクションで組みます。

MapからHerbの3を読み、1を足して同じHerbへ4を書き込む。Herbの行は増えず、Potionの1も変わらない

2つ目は、順番が保証されないこと。 Keys で取り出した配列の並びは、追加した順とは限りません。要素を削除すると並びが変わることもあります。表示順を決めたいなら、表示順用のArrayを別に持ちます。 例えばArrayをHerb、Potionの順にし、そのIDでMapをFindすれば、登録順に頼らず並べられます。

Findで取り出した値もコピーです。 値の型が構造体のとき、Findで取ったものを書き換えても元のMapは変わりません。Add で同じキーに入れ直すのが確実です(→ 構造体の記事)。

Sponsored

実践:所持数を数えるインベントリを作る

RPGの所持品、ローグライクの床落ちアイテム、サバイバルゲームのクラフト素材。 「拾って数える」 はジャンルを問わず出てきます。ここでは同じ「拾う」を3つのコンテナで同時に記録して、 それぞれが答えられる質問が違う ことを目で確かめます。

動かすとこうなる

薬草を3回、ポーションを1回拾ったあと、3つのコンテナの中身がこうなります。

薬草3回とポーション1回を拾ったとき、Arrayは4件、Setは2件、Mapは薬草3ポーション1になることを並べて示した図
コンテナ中身答えられる質問
PickupLog(Array)薬草, 薬草, 薬草, ポーション(4件)「3番目に拾ったのは?」
FoundItems(Set)薬草, ポーション(2件)「ポーションを見たことがある?」
Inventory(Map)薬草→3, ポーション→1「薬草を何個持ってる?」

再現条件

Actorを親にしたBlueprint BP_ContainerTester を作り、レベルへ1個配置します。今回は取得処理をBeginPlayから呼ぶ練習なので、床のアイテムや操作入力は不要です。次の変数をVariablesに作り、Compile後の既定値はすべて にします。

変数名コンテナ初期値
PickupLogNameArray(空)
FoundItemsNameSet(空)
InventoryName → IntegerMap(空)

コンテナの切り替えは、詳細パネルの Variable Type の右のボタン です。Inventory はMapを選ぶと欄が2つになるので、 左をName、右をInteger にします。

PickupItem関数を作る

My Blueprintパネルの FunctionsPickupItem を新規作成し、入力ピンを1つ追加します。

入力ピン
ItemIDName

関数のPureはオフにします。履歴をArrayへ追加し、種類をSetへ追加してから、Mapの所持数を更新します。同じAddという名前でも種類が違うので、各コンテナ変数のGetを置き、そのピンからドラッグしてノードを作ってください。

まず、取得の履歴と見つけた種類を記録します。

  1. PickupItemの入口から、Array用のAddへ白い実行線をつなぐ。Target ArrayはPickupLog、New Itemは関数のItemID。
  2. 続けてSet用のAddへつなぐ。Target SetはFoundItems、New Itemは同じItemID。
PickupLogをArrayのAddのTarget Arrayへ、関数のItemIDをNew Itemへ渡す

同じIDを、今度はSetへ入れます。重複は自動で1件にまとまります。

FoundItemsをSetのAddのTarget Setへ、同じItemIDをNew Itemへ渡す

図のGet ItemIDは、関数へ渡された入力値を読むノードです。関数の入口にあるItemIDピンから同じ値をつないでも構いません。新しいClass Variableは作りません。

続いて、所持数を更新します。PickupItemを開いた状態で、Local VariablesにIntegerの NewCount を作り、既定値を0にします。今回書き込む個数を、一度ここへ入れます。Local Variableは、その関数の中でだけ使う変数です(→ Blueprint変数入門)。

InventoryのGetから Find とMap用の Add を作り、次のようにつなぎます。

接続する先渡す値
FindのTarget MapInventory
FindのKeyItemID
Integerの + のAFindのValue
+ のB1
MapのAddのTarget MapInventory
MapのAddのKeyItemID
Set NewCountの値入力+ の結果
MapのAddのValueGet NewCount

Set用Addの白い実行出力をSet NewCountへ、その出力をMap用Addの実行入力へつなぎます。これで、新しい個数を計算してからMapへ書く順番になります。Findと整数の加算には、白い実行線をつなぎません。 Set NewCountへ渡す値が必要になったときに計算されます。

InventoryからItemIDの個数をFindし、1を足してNewCountへ入れる。未登録のInteger値は0なので、最初は1になる

数えた結果を、同じキーへ書き戻します。

NewCountをMapのAddのValueへ渡す。Target MapはInventory、KeyはItemIDで、同じIDの所持数を書き戻す

ポイントは、Findで今の数を読み、1を足し、同じキーで入れ直す ことです。MapのAddは自動で個数を足すノードではありません。Valueへ毎回1を渡すだけだと、何回拾っても1へ上書きしてしまいます。

今回のMapは値がIntegerなので、Findで未登録のキーを探すとValueは0です。0+1で最初の1個になるため、この集計では見つかったかのBoolean出力を使わずに済みます。

一方、「未登録」と「登録されているが0個」を区別したい処理では、FindのBoolean出力もBranchで確認します。0という値だけでは、その違いは分かりません。

呼んで確認する

Event GraphのBeginPlayで4回呼びます。関数の作成後にCompileし、PickupItemの呼び出しノードを4個置いて、白い実行線を順につなぎます。ItemIDは最初の3個を Herb、最後を Potion にします。Herbは薬草、Potionはポーションを表すIDとして使います。

Event BeginPlay
  → PickupItem(ItemID: Herb)
  → PickupItem(ItemID: Herb)
  → PickupItem(ItemID: Herb)
  → PickupItem(ItemID: Potion)

  → Print String(Logの件数)
  → Print String(Foundの種類数)
  → Print String(Herbの所持数)

3つのPrint Stringへ渡す数字は、PickupLogのLength、FoundItemsのLength、InventoryをKey=HerbでFindしたValueです。LengthとFindには実行ピンがないので、数字の出力を表示用につなぎます。

数字をStringへ変換し、Append のBへ入れます。Aには順に Log: Found: Herb: を入れ、Appendの結果をPrint StringのIn Stringへ渡します。Integerの線をString入力へつなぐと、変換ノードが入ります。

Print StringのDurationを10秒にし、Compile・保存してPlayします。次の3つのメッセージが出れば成功です。画面での上下の順ではなく、ラベルと数字を見ます。

Log: 4
Found: 2
Herb: 3

4回拾ったのでArrayは 4 、種類は2つなのでSetは 2 、薬草は3回拾ったのでMapの値は 3 です。 同じ4回の呼び出しから、3つの違う答えが出ている ことがこの実践の要点です。

ここで、4回目のPickupItemと最初のPrint Stringの間へ、PickupItem(Herb) をもう1個足してみてください。 Logは5、Foundは2のまま、Herbは4 になります。Setだけが増えないのが、Setの性質そのものです。

うまくいかないときの切り分けです。

  • Herbが常に1 → Findの結果を足さずに、Add へ直接1を入れている
  • 同じアイテムが別々に数えられるHerbHerbs など、IDのつづりが違わないかを確認する。Nameは大文字・小文字を区別しないので、Herbherb は同じIDとして扱われる
  • Foundが4になるFoundItems がSetではなくArrayになっている。詳細パネルのコンテナ設定を確認する
  • Logが0のままPickupLog への Add の Target が別の変数につながっている
  • Print Stringが何も出ないPickupItem の実行ピンが最後までつながっていない(→ Print Stringデバッグ

実際のゲームでは、触れたアイテムや報酬を受け取る処理からPickupItemを呼びます。今回は4回の呼び出しだけで、同じ出来事から「順番」「種類」「個数」を別々に取り出せることを確かめました。

アイテムの中身が「名前と攻撃力とアイコン」のように増えてきたら、値を構造体にする段階です。構造体(Struct)の記事S_Item を作り、そのまま Data Table の行として使えます。

所持品を画面に並べて使うところへ進むなら、インベントリの実装が次の題材です。

Sponsored

おまけ:先に知っておくと良いこと

  • 大量の検索では調べ方も見直す: ArrayのContains Itemは値を順に比べます。大量のデータを繰り返し探す処理が重い場合は、まず呼ぶ回数を確かめ、用途に合えばSetやMapで管理する方法を検討します。小さな一覧では、必要な順番やデータの意味を優先して選べます
  • 配列は最初から確保しておける: 詳細パネルのDefault Valueで要素をあらかじめ入れておけます。「巡回ポイントを5つ」のように数が決まっているものは、実行時に Add するよりレベル上で設定するほうが確認しやすくなります
  • 所持数を次回へ残すには保存する: 今回のActorのMapは、Playを止めると失われます。SaveGameに同じ型のMapを作って値を写し、保存処理を呼べば、次のプレイへ持ち越せます。変数を作るだけではファイルへ保存されません(→ セーブ/ロードの実装
  • 中身が固定のデータはDataTableへ: 「全アイテムの一覧」のように 設計時に決まっている データは、Blueprintの配列に手で入れるよりDataTableのほうが管理しやすくなります(→ Data Table入門Data Assetでデータ駆動設計
  • 空のときの分岐を忘れない: Length が0の配列に対して Get(0) を呼ぶとエラーになります。「最初の敵を狙う」のような処理は、 Length > 0 の確認をセット にしてください。この手のうっかりはBlueprintのよくあるミスにもまとめてあります

まとめ

質問選ぶコンテナ
順番が意味を持つ?Array
重複を許したくない・有無だけ知りたい?Set
何かを手がかりに引きたい?Map
  • コンテナは 変数の型の右のボタン で切り替える。Mapだけ欄が2つになる
  • Arrayの番号は 0始まりLength と最大の番号は1ずれる
  • ループ中の追加・削除で、処理対象の番号を変えない 。最初は、別配列へ対象を集めてから処理する
  • Mapの Add上書き 。数を増やすなら Find → +1 → Add

複数の値をまとめる方法が分かったら、次は「待機中・移動中・攻撃中」のような状態の整理も試せます。EnumとSwitchで状態を管理するで扱います。

拾った順を残す、見つけた種類を記録する、所持数を数える。同じ拾い物でも、残したい情報に合わせて入れ物を選べます。

参考リンク

Unreal Engine このセクションのノート98