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

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

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

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

Unity

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

Q&A

解決済

2回答

5854閲覧

Unity ArgumentOutOfRangeException: Argument is out of range. Parameter name: indexというエラーが出てしまう

kanatan1231

総合スコア18

C#

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

Unity

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

0グッド

0クリップ

投稿2018/12/06 09:53

最初のシーンでランダムな数を取得し、次々とシーンをランダムに切り替える実装を行なっています。
実際のゲームシーンでは、問題を正解するごとに次々とランダムに問題を出すということをしようとしています。
最初のシーンでランダムな数を取得し、次のシーンで、問題を正解した時に、最初のシーンで扱っている関数を使用するということがしたいのですが、

やっていることはタイトルシーンについているRandomSceneというスクリプトの関数に、問題のシーンについているNiというスクリプトが参照?するということです。

しかし、問題を解答したら

ArgumentOutOfRangeException: Argument is out of range. Parameter name: index

というエラーが出て、シーンを遷移することができません。

調べたところ、このエラーはlistに要素が入っていない時などに出るということがわかりました。
しかし、RandomSceneで乱数を取得してDontDestroyOnLoadとしているので、取得した乱数は消えないと思うのです。何か別の問題があるように思えるのですが、わかりません。書き換える方法などご教授願います。

public class RandomScene : MonoBehaviour { List<int> numbers = new List<int>(); public GameObject gameobject; Count count; void Start() { DontDestroyOnLoad(this); for (int i = 0; i < EditorBuildSettings.scenes.Length; i++) { numbers.Add(i); } numbers.RemoveAt(1); numbers.RemoveAt(2); numbers.RemoveAt(SceneManager.GetActiveScene().buildIndex); count = gameobject.GetComponent<Count>(); } public void Update() { float three = count.totalTime; if (three <= 1) { StartCoroutine("LoadLoop"); } } IEnumerator LoadLoop() { while (numbers.Count > 0) { RandomSceneChange(); } yield return new WaitForSeconds(0.5f); } public void RandomSceneChange() { int ransu = numbers[Random.Range(0, numbers.Count)]; numbers.Remove(ransu); SceneManager.LoadScene(ransu); } }

というスクリプトのRandomSceneChange()という関数を、問題のシーンで使用したいです。↓以下のスクリプトで参照しようとしています。

public class Ni : MonoBehaviour { // 初期化 GameObject refObj; void Start() { manager = FindObjectOfType<Manager>(); for (int i = 0; i < EditorBuildSettings.scenes.Length; i++) { numbers.Add(i); } numbers.RemoveAt(1); numbers.RemoveAt(2); numbers.RemoveAt(SceneManager.GetActiveScene().buildIndex); refObj = GameObject.Find("R"); } public void RandomSceneChangeNi() { public void Correct(GameObject Seikai) { Debug.Log("正解!"); Maru.SetActive(true); //1.0秒後に呼び出す Invoke("RandomSceneChangeNi", 1.0f); } Ichi = false; // 別のオブジェクトのスクリプトを参照する RandomScene r2 = refObj.GetComponent<RandomScene>(); r2.RandomSceneChange(); } }

他にも問題を解答するためのプログラムが複雑に書き込まれていますので、関係している一部分を書きぬきましたが、余計なものが入っていて見づらいです。申し訳ないです。
よろしくお願いいたします。

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

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

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

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

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

papinianus

2018/12/06 10:15

前の回答で指摘のあった、タイトルのシーン番号は0は守っていますか?また、StartでRemoveAtするときは2→1→0と大きいほうから消していく必要があります。
kanatan1231

2018/12/06 10:28

再度ご回答いただきありがとうございます!タイトルのシーン番号は0でしっかり守っています。RemoveAtで順番が逆なのが気持ち悪かったので直してしまっていました。大きい方から順に消しましたが、エラーは以前消えません。。
Gurz1019_MP

2018/12/06 15:27

どこでこの例外が発生しているのかわかりますか? コンソールに出ていると思います。
kanatan1231

2018/12/07 00:45

ArgumentOutOfRangeException: Argument is out of range. Parameter name: index System.Collections.Generic.List`1[System.Int32].get_Item (Int32 index) (at /Users/builduser/buildslave/mono/build/mcs/class/corlib/System.Collections.Generic/List.cs:633) RandomScene.RandomSceneChange () (at Assets/RandomScene.cs:48) Ni.RandomSceneChangeNi () (at Assets/Ni.cs:114)でした!
Gurz1019_MP

2018/12/07 11:53

RandomSceneの48行目は、サンプルコードのどの行ですか?
kanatan1231

2018/12/08 09:14

すみません、実際のコードとこちらのサイトに記載したコードが違うのを忘れていました。下から5行目のint ransu = numbers[Random.Range(0, numbers.Count)];です!
guest

回答2

0

ベストアンサー

int ransu = numbers[Random.Range(0, numbers.Count)];
この行で、「そんなIDはこの配列に存在しないぜ」というエラーです。
Random.Rangeは0〜配列の大きさ-1の値を取るはずなので本来ならこのエラーは吐きません。
吐くとしたらnumbers[0]すらも無い、即ちnumbersに1つも要素が無い時です。

RemoveAtの結果、配列の中身が0になっているのではないでしょうか。
BuildSettingsで登録しているシーン数が4つ以上であることを確認してください。

投稿2018/12/08 01:27

sakura_hana

総合スコア11427

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

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

kanatan1231

2018/12/08 09:22

わかりやすくご回答いただき、ありがとうございます。numbers.Remove(ransu);の行を消して再生してみると、フリーズしてしまいます。また、BuildSettingsで登録しているシーン数は11です。numbersに値が無いということは、やはり何かしらのプログラムが邪魔しているのでしょうか。
sakura_hana

2018/12/10 01:05

RandomSceneクラスのソースがこれだけなら、Gurz1019_MPさんの回答のように「RandomSceneChangeが呼ばれすぎ」という可能性が高いです(numbersは他スクリプトからアクセス出来ない為)。 とりあえず各所にDebug.Logを仕掛けてどう動くか確認するといいと思います。
kanatan1231

2018/12/10 07:45

ありがとうございます。承知しました。Debug.Logでどう動くか確認して何かわかりましたら、またコメントさせていただきます。
kanatan1231

2018/12/10 16:16

Debug.Logで確認したところ、RandomSceneChangeは一度しか呼ばれていませんでした。シーンを切り替えた時に乱数が消えてしまっているという可能性の方が高いように感じます。もしそうでしたらどうすればよろしいでしょうか。
sakura_hana

2018/12/11 02:05

そもそもransuはRandomSceneChangeメソッド内で生成されているので、他のメソッドや他のクラスからは呼び出せません。 メソッド内のメンバ変数なのでシーン遷移どころか、RandomSceneChangeメソッドの終了時点で破棄されます。 (DontDestroyOnLoadで維持されるのは「このクラス(インスタンス)」であって、内部の変数の動きは通常通りな為) RandomSceneChangeメソッドの中身を以下のようにするとどうなりますか? Debug.Log("numbers.Count " + numbers.Count); int ransu = numbers[Random.Range(0, numbers.Count)]; Debug.Log("ransu " + ransu); numbers.Remove(ransu); SceneManager.LoadScene(ransu);
kanatan1231

2018/12/11 04:45

そういうことなんですね!わかりました。RandomSceneChangeメソッドの中身を上記のように変えたところ、Debug.Logではタイトル画面でnumbers.Countが9-1までカウントされた後、一問目のシーンに切り替えて、正解した後さらにシーンを切り替えようとした時に、numbers.Countが0と出て、エラーを吐きました。
sakura_hana

2018/12/11 05:40

となるとタイトル画面でRandomSceneChangeが9回呼ばれているということになります。 これは想定通りの正常な動作でしょうか?(多分違うと思いますが) LoadLoop()が想定外のタイミングで呼ばれているのかなーと思いますが、そもそもここで何がしたいのかよく分からないので、count.totalTime含めて見直すといいと思います。
kanatan1231

2018/12/11 06:12

ありがとうございます。スクリプトがややこしく混乱していたのですが、だいぶ見直すことができました。もう少し考えてみます。
kanatan1231

2018/12/11 07:06

IEnumerator LoadLoop() { while (numbers.Count > 0) { RandomSceneChange(); } yield return null; } この部分でnumbers.Countが0になるまで、乱数を吐いては消し、吐いては消し、乱数の数が0になるまでRandomSceneChangeを呼ぶというスクリプトを書いておりました。 今までこれで正常に動作していたのですが、別のシーンで別のスクリプトから乱数を参照したいので、乱数を全て生成し消してしまっては、乱数がありませんとなってしまうので、 IEnumerator LoadLoop() { while (numbers.Count > 8) { RandomSceneChange(); } yield return null; } とすることで、乱数がタイトル画面で一つ生成され、その数のシーンに切り替え、正解した後またRandomSceneChangeを呼び、次の乱数を生成し、その数のシーンに切り替え・・・という繰り返しをすることが、ついにできるようになりました!!
kanatan1231

2018/12/11 07:10

ほぼほぼ問題は解決したのですが、一番最初のシーン(BuildSettingsで0番目のシーン)が、numbers.RemoveAt(0);をしてしまうと動かないという性質上、0という乱数を消すことができず、タイトル画面でスタートしたものの問題を解いていくうちに、タイトル画面に戻ってしまう(0番目のシーンが呼び出されてしまう)ということが起きてしまいます。さらに調査を進めたいと思うのですが、何かしらヒントがございましたら、頂けますと幸いです。
sakura_hana

2018/12/11 08:19

そもそもnumbers.RemoveAt(0);をすると動かなくなるという理屈がよく分かりませんが 「BuildSettingsで0番目のシーンをnumbersに含まなければいい」ということなら、 for (int i = 0; i < EditorBuildSettings.scenes.Length; i++) ここを for (int i = 1; i < EditorBuildSettings.scenes.Length; i++) にすればいいと思います。 (直後に1と2もRemoveAtしているので「i = 3」でもいいかもしれません) その場合は numbers.RemoveAt(SceneManager.GetActiveScene().buildIndex); と while (numbers.Count > 8) が狂う恐れがあるので考えて設定してください。
kanatan1231

2018/12/11 08:59

i = 3でwhile (numbers.Count > 6)にしたらうまくいきました!本当にありがとうございます!!!!
Gurz1019_MP

2018/12/11 13:05

失礼します。解決されたようなので蛇足かもしれませんが、そのwhileの条件ですと一度しか実行されないと思います。恐らくロードされた後に最初の問題を表示しているだけですが、この挙動が意図するものであれば、RandomSceneのStartの最後でRandomSceneChangeを一度呼ぶだけで同じ挙動が実現できると思います。LoadLoopは使いません。よろしければ確認してみてください。
kanatan1231

2018/12/11 13:47

再度コメントいただきありがとうございます!RandomSceneChangeを別のシーンから呼ぶことで、新たに乱数を作っているので、動作は問題ありません。Gurz1019_MP様のおっしゃる通り、LoadLoopを使わず、StartでRandomSceneChangeを一度呼べば同じ挙動ができるとチラッと思っていました。コードを簡略化し短くするためにも試してみたいと思います!ありがとうございます!
guest

0

おそらく想定以上にRandomSceneChangeが呼ばれているのだと思います。RandomSceneChangeでログを出力し、numbersの数と生成される乱数を確認してみてはいかがでしょうか。RandomSceneChange内でnumbersが空ではないことを確認すれば、ひとまずこの例外は出なくなると思います。

投稿2018/12/08 13:39

Gurz1019_MP

総合スコア196

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

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

kanatan1231

2018/12/10 00:09

ご回答ありがとうございます。その発想はありませんでした。試してからまたコメントさせていただきます。
kanatan1231

2018/12/10 16:15

RandomSceneChangeにDebug.Log(ransu);で取得した乱数を確認したのですが、 public void RandomSceneChange() { int ransu = numbers[Random.Range(0, numbers.Count)]; numbers.Remove(ransu); Debug.Log(ransu); SceneManager.LoadScene(ransu); } デバッグにはしっかり乱数が出ているのですが、やはりシーンが切り替わった後にエラーを吐いてしまいます。スクリプトNiの方にもデバッグを書いてみましたが、RandomSceneChangeは一度しか呼ばれていないようです。しかし、別のスクリプトからもRandomSceneChangeを呼び出しているのですが、そのスクリプトは別のシーンでしか使わないので、必要以上に呼ばれているとは考えにくいです。どうしたらよろしいでしょうか。
Gurz1019_MP

2018/12/10 17:03 編集

切り替わったあとに例外が発生するのでしたら、切り替わった先でもう一度RandomSceneChangeが呼ばれているのかもしれません。というのも、このコードですと例外が発生した時点でメソッドが中断され、ログが出力されないからです。 メソッドの最初にログを書くとどうなりますか? 乱数を生成する部分のみを一旦int型の変数に格納し、それをログで出力してからnumbersのインデクサーに使ってみてください。念のためにnumbers.Countも見て、確実に要素があることを確認してみてください。
kanatan1231

2018/12/11 01:48

ご指示ありがとうございます。スクリプトNiを書き換えて、RandomSceneの変数ransuを取得しようとしているのですが、(RandomSceneが付いているオブジェクト名はRにしています) GameObject refObj; RandomScene r; // 初期化 void Start() { manager = FindObjectOfType<Manager>(); refObj = GameObject.Find("R"); r = refObj.GetComponent<RandomScene>(); int ransu1 = r.ransu; Debug.Log(ransu1); } int ransu1 = r.ransu;の行でransuの下に赤い線が出てしまい、うまく参照できません。。。 https://qiita.com/tsukasa_wear_parker/items/09d4bcc5af3556b9bb3aのサイトを参照しながら、変数を参照しようとしているのですが、何を間違えているかわかりますか?もう少し自分でも考えて、参照がうまくでき次第またコメントします!
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.48%

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

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

質問する

関連した質問