質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.50%
C#

C#はマルチパラダイムプログラミング言語の1つで、命令形・宣言型・関数型・ジェネリック型・コンポーネント指向・オブジェクティブ指向のプログラミング開発すべてに対応しています。

Unity

Unityは、Unity Technologiesが開発・販売している、IDEを内蔵するゲームエンジンです。主にC#を用いたプログラミングでコンテンツの開発が可能です。

Q&A

1回答

481閲覧

【Unity2D】List内に入れたアイテムの名前が正常に読み込めない

fhyu6872

総合スコア0

C#

C#はマルチパラダイムプログラミング言語の1つで、命令形・宣言型・関数型・ジェネリック型・コンポーネント指向・オブジェクティブ指向のプログラミング開発すべてに対応しています。

Unity

Unityは、Unity Technologiesが開発・販売している、IDEを内蔵するゲームエンジンです。主にC#を用いたプログラミングでコンテンツの開発が可能です。

0グッド

0クリップ

投稿2022/07/21 11:15

編集2022/07/26 22:57

問題

Unityに関する質問です。
アイテム管理クラスを動かすためにアイテムを取得した時に
以下の実行時エラーが発生してしまい、改善の仕方が
分からないので質問します。

発生している問題・エラーメッセージ

ArgumentOutOfRangeException: Index was out of range. Must be non-negative and less than the size of the collection. Parameter name: index System.Collections.Generic.List`1[T].get_Item (System.Int32 index) (at <6073cf49ed704e958b8a66d540dea948>:0) Platformer.Mechanics.SimpleInventory.Update () (at Assets/Scripts/Mechanics/SimpleInventory.cs:45)

該当のソースコード

C#

1using System.Collections.Generic; 2using UnityEngine; 3using UnityEngine.UI; 4using Platformer.Mechanics; 5 6namespace Platformer.Mechanics 7{ 8 public class SimpleInventory : MonoBehaviour 9 { 10 11 [SerializeField] 12 GameObject iconPrefab = null; 13 [SerializeField] 14 Transform iconParent = null; 15 [SerializeField] 16 InventoryItem[] items = null; 17 18 // アイテムを持ってるかどうかのフラグ 19 bool[] itemFlags = new bool[10000]; 20 21 // アイテムのアイコンを管理するためのディクショナリ 22 Dictionary<int, GameObject> icons = new Dictionary<int, GameObject>(); 23 24 //アイテムを名前で管理するリスト 25 List<string> itemManager = new List<string>(); 26 27 CircleController cir; 28 public static bool itemAddEvent = false; 29 public static bool itemUseEvent = false; 30 31 void Start() 32 { 33 for (int i = 0; i < items.Length; i++) 34 { 35 itemFlags[i] = false; 36 } 37 //itemFlags = new bool[items.Length]; 38 cir = GameObject.FindWithTag("Circle").GetComponent<CircleController>(); 39 } 40 41 void Update() 42 { 43 if (itemAddEvent || itemUseEvent) 44 { 45 Debug.Log("アイテムを取得:"+itemManager[0]); //45行目 46 cir.setItem(itemManager); 47 } 48 if (CircleController.endSet) 49 { 50 itemAddEvent = false; 51 itemUseEvent = false; 52 } 53 } 54 55 /// <summary> 56 /// アイテムを持ってるかどうかを確認するメソッド 57 /// </summary> 58 /// <param name="itemName"></param> 59 /// <returns></returns> 60 public bool GetItemFlag(string itemName) 61 { 62 int index = GetItemIndexFromName(itemName); 63 64 return itemFlags[index]; 65 } 66 67 public void SetItem(string itemName, bool isOn) 68 { 69 int index = GetItemIndexFromName(itemName); 70 71 if (!itemFlags[index] && isOn) 72 { 73 // アイテム未所持の状態で新しく入手したとき 74 // 新しいアイコンを生成し、インベントリのキャンバスの子に設定 75 GameObject icon = Instantiate(iconPrefab, iconParent); 76 icon.AddComponent<Image>(); 77 78 // アイコンの画像を設定 79 icon.GetComponent<Image>().sprite = items[index].itemSprite; 80 81 icons.Add(index, icon); 82 83 itemManager.Add(items[index].itemName); 84 itemAddEvent = true; 85 } 86 else if (itemFlags[index] && !isOn) 87 { 88 // アイテム所持中に削除するとき 89 GameObject icon = icons[index]; 90 91 // アイテムのアイコンを削除 92 Destroy(icon); 93 94 // アイコンのディクショナリから対象のアイテムを削除 95 icons.Remove(index); 96 97 itemManager.RemoveAt(index); 98 itemUseEvent = true; 99 } 100 101 itemFlags[index] = isOn; 102 } 103 104 /// <summary> 105 /// items内に指定のアイテム名があるかを確認する 106 /// </summary> 107 /// <param name="itemName"></param> 108 /// <returns></returns> 109 int GetItemIndexFromName(string itemName) 110 { 111 for (int i = 0; i < items.Length; i++) 112 { 113 if (items[i].itemName == itemName) 114 { 115 return i; 116 } 117 } 118 119 Debug.LogWarning("指定されたアイテム名が間違っているか存在しません"); 120 return 0; 121 } 122 123 } 124 125 /// <summary> 126 /// インベントリに登録できるアイテムを定義するためのクラス 127 /// </summary> 128 [System.Serializable] 129 public class InventoryItem 130 { 131 public string itemName = ""; 132 public Sprite itemSprite = null; 133 } 134}

C#

1 /// <summary> 2 /// アイテム取得時や使用時に呼び出される 3 /// </summary> 4 /// <param name="items"></param> 5 public void setItem(List<string> items) 6 { 7 if (SimpleInventory.itemAddEvent) 8 { 9 for (int i = 0; i < items.Count; i++) 10 { 11 useItems.Add(items[i]); 12 } 13 } 14 if (SimpleInventory.itemUseEvent) 15 { 16 useItems.Clear(); 17 for (int i = 0; i < items.Count; i++) 18 { 19 useItems.Add(items[i]); 20 } 21 if (items.Count == 0) 22 getItem = false; 23 } 24 endSet = true; 25 Debug.Log("アイテムを取得:"+items.Count); //なんでCountが0? 26 if (!(items.Count == 0)) 27 { 28 getItem = true; 29 } 30 items.Clear(); 31 }

詳細内容

ゲーム画面内でアイテムを取得した時に
外部クラスからSetItemメソッドが呼び出されます。
アイテム取得時はif文の上を通るので、else if側は関係ない構文です。
SetItemに渡される引数 ("Return",true)

下の方にあるInventoryItemクラスに定義されているのは以下です。
要素0
itemName → Return
itemSprite → アイテムのアイコン画像

itemAddEventがtrueの時にUpdateメソッドで
外部のメソッドに取得したアイテムの名前を渡しますが、
実行時エラーの内容だとitemManagerリスト内に
正常にアイテム名が入っていないという認識でいいでしょうか?
Addでアイテム名を入れていると思っていますが・・・。

補足情報(FW/ツールのバージョンなど)

Unity 2021.3.2f1 Personal

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

y_waiwai

2022/07/21 11:52

どこのAddでいれてるんでしょうか
fhyu6872

2022/07/21 11:58

SetItemメソッド内の上側のifの以下のコードで入れています。 itemManager.Add(items[index].itemName);
y_waiwai

2022/07/21 12:22

そのコードのところで実行を止め、itemsになにが入ってるかチェックしてみてはどうでしょう
fhyu6872

2022/07/21 12:53

上記のコードの下にDebug.Logで確認したところ、正常にアイテム名が表示されました。 Debug.Log("アイテムを取得:" + items[index].itemName); →アイテムを取得:Return 同じ要領で以下の確認もしました。 Debug.Log("アイテムを取得:" + itemManager.Count); →アイテムを取得:1 しかし、本文のコードの位置の45行目に以下のコードを確認をすると・・・ Debug.Log("アイテムを取得:" + itemManager.Count); →アイテムを取得:0
KomoriGameDev

2022/07/25 05:02

itemManagerを使っているところで46行目のコードが気になります。 46行目 cir.setItem(itemManager); CircleControllerのソースコードも提示された方が良いと思います。
fhyu6872

2022/07/25 10:52

CircleControllerクラスは行が多いので、setItemメソッドだけ開示しました。
guest

回答1

0

CircleControllerクラスの提示ありがとうございます。
setItemメソッドの最終行のコードが原因だと思うのですが…

cs

1items.Clear();

setItemメソッドの引数itemsに渡されるのはitemManagerのコピーではなく、itemManager自体への参照ですので、itemsをクリアするということはitemManagerをクリアしていることと同じです。
それが毎フレーム呼び出されるわけですから、毎フレームitemManagerがクリアされていることになります。

投稿2022/07/25 11:47

編集2022/07/25 12:32
KomoriGameDev

総合スコア433

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

fhyu6872

2022/07/25 22:30

回答ありがとうございます。 上記のClear部分を消してみましたが、特にエラーの解消にはならないようです。 ただ、Clearの記述がいらないことには気付きました。 SimpleInventoryクラスの45行目付近に以下のコードを入れると アイテムを取得したことになるようです。(場当たり的な解決法ですが) itemManager.Add(items[0].itemName);
KomoriGameDev

2022/07/26 08:26

それはおかしいですね… itemManagerを操作している部分というと、 itemManager.Add(items[index].itemName); itemManager.RemoveAt(index); items.Clear(); この3つしかないのでRemoveAtも関係ないとなると、何も操作していないのに勝手にリストがクリアされていることになります…そんなことは普通ありえない現象です。 あと思いつく方法としては、デバッガーを使ってプログラミングを1行1行進めながらitemManagerがどの時点でクリアされるのか追っかけていくしかないですね…
fhyu6872

2022/07/26 13:57

あと思いついた解決法は、SimpleInventoryクラスのSetItemメソッド内の itemFlags[index] = isOn; の後に以下のコード(46行目と同じ)を記述しましたが、NullReferenceExceptionとなってしまいますね。何故かわかりません・・・ cir.setItem(itemManager);
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

まだベストアンサーが選ばれていません

会員登録して回答してみよう

アカウントをお持ちの方は

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.50%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問