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

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

ただいまの
回答率

90.33%

  • C#

    7705questions

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

  • Unity

    4420questions

    Unityは、ユニティテクノロジーが開発したゲームエンジンです。 主にモバイルやブラウザ向けのゲーム製作に利用されていましたが、3Dの重力付きゲームが簡単に作成できることから需要が増え、現在はマルチプラットフォームに対応しています。 言語はC言語/C++で書かれていますが、C#、JavaScript、Booで書かれたコードにも対応しています。

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

解決済

回答 2

投稿

  • 評価
  • クリップ 0
  • VIEW 156

kanatan1231

score 8

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

やっていることはタイトルシーンについている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();
    }
}


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

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

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

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

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

質問への追記・修正、ベストアンサー選択の依頼

  • kanatan1231

    2018/12/07 09: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 20:53

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

    キャンセル

  • kanatan1231

    2018/12/08 18:14

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

    キャンセル

回答 2

checkベストアンサー

+3

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

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

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2018/12/08 18:22

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

    キャンセル

  • 2018/12/10 10:05

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

    キャンセル

  • 2018/12/10 16:45

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

    キャンセル

  • 2018/12/11 01:16

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

    キャンセル

  • 2018/12/11 11: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);

    キャンセル

  • 2018/12/11 13:45

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

    キャンセル

  • 2018/12/11 14:40

    となるとタイトル画面でRandomSceneChangeが9回呼ばれているということになります。
    これは想定通りの正常な動作でしょうか?(多分違うと思いますが)

    LoadLoop()が想定外のタイミングで呼ばれているのかなーと思いますが、そもそもここで何がしたいのかよく分からないので、count.totalTime含めて見直すといいと思います。

    キャンセル

  • 2018/12/11 15:12

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

    キャンセル

  • 2018/12/11 16: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を呼び、次の乱数を生成し、その数のシーンに切り替え・・・という繰り返しをすることが、ついにできるようになりました!!

    キャンセル

  • 2018/12/11 16:10

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

    キャンセル

  • 2018/12/11 17: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)
    が狂う恐れがあるので考えて設定してください。

    キャンセル

  • 2018/12/11 17:59

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

    キャンセル

  • 2018/12/11 22:05

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

    キャンセル

  • 2018/12/11 22:47

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

    キャンセル

+1

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

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2018/12/10 09:09

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

    キャンセル

  • 2018/12/11 01: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を呼び出しているのですが、そのスクリプトは別のシーンでしか使わないので、必要以上に呼ばれているとは考えにくいです。どうしたらよろしいでしょうか。

    キャンセル

  • 2018/12/11 02:02 編集

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

    キャンセル

  • 2018/12/11 10: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のサイトを参照しながら、変数を参照しようとしているのですが、何を間違えているかわかりますか?もう少し自分でも考えて、参照がうまくでき次第またコメントします!

    キャンセル

同じタグがついた質問を見る

  • C#

    7705questions

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

  • Unity

    4420questions

    Unityは、ユニティテクノロジーが開発したゲームエンジンです。 主にモバイルやブラウザ向けのゲーム製作に利用されていましたが、3Dの重力付きゲームが簡単に作成できることから需要が増え、現在はマルチプラットフォームに対応しています。 言語はC言語/C++で書かれていますが、C#、JavaScript、Booで書かれたコードにも対応しています。

  • トップ
  • C#に関する質問
  • Unity ArgumentOutOfRangeException: Argument is out of range. Parameter name: indexというエラーが出てしまう