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

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

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

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

Q&A

解決済

1回答

252閲覧

Unity C# で[SerializeField] List<Vector3> の内容が吹っ飛ぶ話を解決したい

omotika710

総合スコア1

C#

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

0グッド

0クリップ

投稿2025/04/19 16:01

実現したいこと

Unity C# で起きた問題を解決したいです。
詳しいことは次書きますが、
[SerializeField] List<Vector3> spawnPosList;
の内容が実行中に触っているつもりがないのに吹き飛んでしまうということです。
[SerializeField]なので他スクリプトからの干渉は考えられません。

なお現在は応急措置によって何とかなっています。
また、UnityC#やその他プログラミングは一応2年くらいやっていますが、独学なのでところどころ用語の使い方が変だったり、コードの細かい順番や書き方が変だったりするかもしれませんが、温かい目で見ていただけると幸いです。

発生している問題・分からないこと

ソースコード19行目の
[SerializeField] List<Vector3> spawnPosList;
の内容を消す操作を行っていないにも関わらず、内容が消失してしまう問題です。
コードにもコメントを書きましたが、Start()が実行されたときは長さが2で、ReStart()が実行されたときにもまだ長さが2でした。ですが、OnPlayerJoined()が実行されたときに長さが0となっていることを確認しています。
また、[SerializeField]なので他スクリプトからの干渉は考えられません。
添付したコード内で確実に何かが起きていると考えています。一応他スクリプトも検査しましたが、Listに触るようなコードは見つかりませんでした(privateなので当然ですが...)。

応急措置について。
宣言にインスペクタで設定していた初期値を設定。
List<Vector3> spawnPosList = new List<Vector3>()
{
new Vector3(-5, 3, 0),
new Vector3(5, -3, 0)
};

これだけではだめだったので、
public void ReStart()
{
playerCount = 0;
foreach (var player in playerList)
{
if(player != null)
{
Destroy(player.gameObject);
}
}
playerList.Clear();
spawnPosList = new List<Vector3>()
{
new Vector3(-5, 3, 0),
new Vector3(5, -3, 0)
};
EnableJoining();
}
と、無理やり設定しなおしました。

エラーメッセージ

error

1エラーメッセージはありません。 2しいて言うなら 3if (playerCount >= spawnPosList.Count) 4 { 5 //Start()時点では2,ReStart()時点では0。なので弾かれてしまう。 6 return; 7 } 8を書いていないときに発生した、 9ctrl.Init((PlayerType)playerCount, spawnPosList[playerCount], wallTilemap, bombParent, fireParent,maxBombCount, inputThreshold, moveCooldown); 10です。エラーはたぶん範囲外だと怒られていると思います。 11 12 13 14ArgumentOutOfRangeException: Index was out of range. Must be non-negative and less than the size of the collection. 15Parameter name: index 16System.Collections.Generic.List`1[T].get_Item (System.Int32 index) (at <ed969b0e627d471da4848289f9c322df>:0) 17PlayerSpawner.OnPlayerJoined (UnityEngine.InputSystem.PlayerInput playerInput) (at Assets/Scripts/PlayerSpawner.cs:81) 18UnityEngine.InputSystem.LowLevel.<>c__DisplayClass7_0:<set_onUpdate>b__0(NativeInputUpdateType, NativeInputEventBuffer*) 19UnityEngineInternal.Input.NativeInputSystem:NotifyUpdate(NativeInputUpdateType, IntPtr)

該当のソースコード

C#

1```C# 2using System.Collections.Generic; 3using UnityEngine; 4using UnityEngine.InputSystem; 5using UnityEngine.Tilemaps; 6using static GameManager; 7public class PlayerSpawner : MonoBehaviour 8{ 9 int playerCount = 0; 10 List<PlayerCtrl> playerList = new List<PlayerCtrl>(); 11 PlayerInputManager playerInputManager; 12 13 [SerializeField] Tilemap wallTilemap; 14 [SerializeField] Transform bombParent; 15 [SerializeField] Transform fireParent; 16 [SerializeField][Min(1)] int maxBombCount = 2; 17 [SerializeField][Range(0f,1f)] float inputThreshold = 0.7f; 18 [SerializeField][Min(0)] float moveCooldown = 0.2f; 19 20 [SerializeField] List<Vector3> spawnPosList; ////今回の主役。インスペクタには二つ要素が入ってる 21 22 public static PlayerSpawner playerSpawner; 23 void Awake() 24 { 25 if (playerSpawner == null) 26 { 27 playerSpawner = this; 28 } 29 else 30 { 31 Destroy(gameObject); 32 } 33 34 playerInputManager = GetComponent<PlayerInputManager>(); 35 //Debug.Log($"[Awake] I'm {gameObject.name}, scene: {gameObject.scene.name}, spawnPosList.Count: {spawnPosList.Count}"); 36 } 37 38 public void ReStart() 39 { 40 //この時点でspawnPosList.Count()は2 41 playerCount = 0; 42 foreach (var player in playerList) 43 { 44 if(player != null) 45 { 46 Destroy(player.gameObject); 47 } 48 } 49 playerList.Clear(); 50 EnableJoining(); 51 } 52 53 54 55 56 void OnEnable() 57 { 58 playerInputManager.onPlayerJoined += OnPlayerJoined; 59 } 60 61 void OnDisable() 62 { 63 playerInputManager.onPlayerJoined -= OnPlayerJoined; 64 } 65 66 void OnPlayerJoined(PlayerInput playerInput) 67 { 68 if (playerCount >= spawnPosList.Count) 69 { 70 //Start()時点では2,ReStart()時点では0。なので弾かれてしまう。 71 return; 72 } 73 if (gameManager.IsGameStateBool(GameStateFlag.GameStarted)) 74 { 75 Debug.Log("すでにゲームが始まっています。"); 76 return; 77 } 78 if (gameManager.IsGameStateBool(GameStateFlag.NeededPlayers))//構造上あり得ないが一応書いておく。 79 { 80 Debug.Log("これ以上プレイヤーは参加できません。"); 81 return; 82 } 83 var ctrl = playerInput.GetComponent<PlayerCtrl>(); 84 Debug.Log($"Player {playerCount + 1} joined"); 85 //Debug.Log($"ctrl : {ctrl}"); 86 ctrl.Init((PlayerType)playerCount, spawnPosList[playerCount], wallTilemap, bombParent, fireParent, maxBombCount, inputThreshold, moveCooldown); 87 playerList.Add(ctrl); 88 playerCount++; 89 } 90 91 public List<Vector3> GetSpawnPosList() 92 { 93 return spawnPosList; 94 } 95 96 public void EnableJoining() 97 { 98 playerInputManager.joinBehavior = PlayerJoinBehavior.JoinPlayersWhenButtonIsPressed; 99 } 100 public void DisableJoining() 101 { 102 playerInputManager.joinBehavior = PlayerJoinBehavior.JoinPlayersManually; 103 } 104 105 public int GetPlayerCount() 106 { 107 return playerCount; 108 } 109}
### 試したこと・調べたこと - [ ] teratailやGoogle等で検索した - [x] ソースコードを自分なりに変更した - [ ] 知人に聞いた - [x] その他 ##### 上記の詳細・結果 ChatGpt君にソースコード丸々渡しても解決できませんでした。 ### 補足 特になし

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

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

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

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

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

lehshell

2025/04/19 22:31

> [SerializeField]なので他スクリプトからの干渉は考えられません。 spawnPosList は参照変数です。 public List<Vector3> GetSpawnPosList() {     return spawnPosList; } と spawnPosList への参照を返していますから ★他スクリプトからの干渉は可能です★ List のコピーを返す以下のコードにしてしてここが原因か切り分ける アプローチからしてみましょう。 public List<Vector3> GetSpawnPosList() {     return new List<Vector3>(spawnPosList); }
omotika710

2025/04/20 15:05

コメントありがとうございます。無事解決しました! まさか参照型の変数であることが抜け落ちてるだなんて恥ずかしいミスを...穴があったら入りたい... 他スクリプトで似たような名前の変数があって混同してしまったのも原因の一つでした。 前にもTransformとVector3でミスをしたばかりなのに本当に懲りませんね() 解決したので正式に回答していただけないでしょうか?ベストアンサーに指名したいです。
omotika710

2025/04/20 15:10

はぁ...掲示板でこんな痴態をさらすなんて...ほんとに恥ずかしい誰か助けてくれ()
guest

回答1

0

ベストアンサー

調査のアプローチ方法をコメントして見えている要因を排除しようとしたところ原因だったとのこと

C#の参照変数は、代入やメソッドへの値渡しや return での返却で実体への参照情報を渡せてしまいます。
他スクリプトからの干渉を防ぐには GetSpawnPosList メソッドでリストのコピーを返す必要があります。

C#

1 public List<Vector3> GetSpawnPosList() 2 { 3 //return spawnPosList; 4 return new List<Vector3>(spawnPosList); 5 }

余談
C++の参照変数は、代入やメソッド(C++はメンバー関数というべきかな)への値渡しや return での値返却では実体のコピーが対象になります。
言語で動作が違うため注意が必要ですね。

投稿2025/04/21 14:30

lehshell

総合スコア1178

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

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

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.31%

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

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

質問する

関連した質問