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

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

ただいまの
回答率

90.52%

  • C#

    7105questions

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

  • Unity

    3988questions

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

別の質問でもらったコード(unityで乱数を重複のないように繰り返す)を自分の意図するものに変える

解決済

回答 1

投稿

  • 評価
  • クリップ 1
  • VIEW 385

Hayato555

score 11

前提・実現したいこと

先日 unityで乱数を重複させずにそれを繰り返すというコードの書き方がわからなくて質問させていただきました。(https://teratail.com/questions/94921)
私が書きたかったのは、https://teratail.com/questions/94741
ここを参考にして、テトリスのミノ(ブロック)7つをランダムで重複がなく生成させ、その7つが生成しきったら、またそれを繰り返す、というコードでした。
幸いなことにある方わかりやすいようにコードを書いてくださいました。
しかし、私はUnity及びC#の初心者なので、軽く理解できる程度で、
自分のUnityに組み込むことができませんでした。
実際に何をしたかったのかというと、下記のコードでは テトリスのミノを3秒(おそらく)ごとに重複のないように7つを1つずつ生成し、それを繰り返す となっているのですが、もともと私が自分で書いたコードではspawnNext()というのにしていて、別のオブジェクトからspawnNext()を出力させることで、ミノを生成させていました。 このコードのどの部分を変えれば 別のオブジェクトから出力が来るまで、ミノを出現させず、出力が来たら、生成するというコードに書き換えられますか?

該当のソースコード

using UnityEngine;
using System.Linq;
using System;
using System.Collections;

public class createRandObjs : MonoBehaviour
{
    //とりあえずインスペクタからオブジェクトを追加
    [SerializeField]
    GameObject[] objcts;

    //何秒おきに出力するかを指定
    static readonly float LOOP_INTERVAL = 3f;

    //Coroutineをキャッシュする変数
    Coroutine landObjLoopCorutine;

    void Start()
    {
        // 実行
        startLandObjLoop();
    }


    /// <summary>
    /// ループのスタート
    /// </summary>
    void startLandObjLoop()
    {
        //このGameObjectが非表示の時にlandObjLoopを実行されるとエラーになるのでその場合実行させない
        if (!gameObject.activeInHierarchy)
        {
            #if UNITY_EDITOR
            Debug.Log("このオブジェクト非表示中だから実行できないよ");
            #endif

            return;
        }

        //実行中なら重複するので一旦停止
        stopLandObjLoop();

        //オブジェクトの出力をスタート
        StartCoroutine( landObjLoop() );
    }


    /// <summary>
    /// ループのストップ
    /// </summary>
    void stopLandObjLoop()
    {
        if (landObjLoopCorutine != null) StopCoroutine(landObjLoopCorutine);
    }


    /// <summary>
    /// オブジェクトを出力する
    /// </summary>
    void instantiateObj(int idx)
    {
        //とりあえずVector3.zero地点にオブジェクトを生成
        Instantiate(objcts[idx], Vector3.zero, Quaternion.identity);
    }


    /// <summary>
    /// objctsをランダムに出力し続ける
    /// </summary>
    IEnumerator landObjLoop()
    {
        //オブジェクトが無ければ何もせず終了
        if (objcts.Length == 0) yield break;

        var waitTime = new WaitForSeconds( LOOP_INTERVAL );

        //順番にカウントするための変数
        var idx = 0;
        //ランダムなインデックスを格納する配列
        var objIdxAry = new int[objcts.Length];

        while(true)
        {
            //idxが0またはobjctsの数に達したらリセット
            if(idx == 0 || idx == objcts.Length)
            {
                idx = 0;
                objIdxAry = Enumerable.Range(0, objcts.Length).OrderBy(n => Guid.NewGuid()).Take(objcts.Length).ToArray();
            }

            instantiateObj(objIdxAry[idx]);
            idx++;

            yield return waitTime;
        }
    }
}
  • 気になる質問をクリップする

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

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

    クリップを取り消します

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

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

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

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

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

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

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

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

    質問の評価を下げる

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

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

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

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

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

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

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

    詳細な説明はこちら

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

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

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

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

  • kikukiku

    2017/10/05 09:14

    unityの開発経験がないため意図した具体的な回答はだせませんが、本問題を解決するための方向性だけ、意見させてください。プログラマであるならば質問者さんは自身の書いたコードはせめてすべて理解すべきかと思います。理解できていないと今回のように改修することで出来ません。現在理解できていないのであるならば、現在コードの理解できていない部分を理解してから、今回の質問に取り組んだ方が良いと思います。急がば回れです。なので、まずは現在理解できてない部分を個別に切り出して、具体的に質問した方が良いと思います。

    キャンセル

回答 1

checkベストアンサー

+1

遅くなりました。すみません。

怒られちゃいましたねw
ご自分でわかっていらっしゃると思うので折り合いつくとこまで進めたら少し勉強時間をはさんでみてもいいかもしれませんね。

Unityの本を買って説明を読みながら掲載されているサンプルを手打ちで打っていくとある程度わかってくると思います。Unityはどんどこ進んでいるので今は本で学ぶのが一番です。

ということでspawnNext()で呼ぶタイプに書き直しました。
相変わらず未検証です。コメントをたっぷり入れたので思ったような挙動にならなければご自身で修正してみてください。そして、どうしても分からなければその部分のコードと一緒に質問してみてください。

使い方

  1. 下記コードをコピーしcreateRandObjsという名前でスクリプトとして保存
    createRandObjs

  2. ゲームオブジェクトをヒエラルキーに作成
    ゲームオブジェクト

  3. createRandObjs.csをオブジェクトにアタッチ
    イメージ説明

  4. ゲームオブジェクトのインスペクタに配列が入れられるようになっているのでオブジェクトを追加
    オブジェクトを追加

5. 別スクリプトから「createRandObjs.Instance.spawnNext();」を呼ぶ

以上です。

外から呼ばれるということなのでシングルトンにしました。

using UnityEngine;
using System.Linq;
using System;
using System.Collections;

public class createRandObjs : MonoBehaviour
{
    //とりあえずインスペクタからオブジェクトを追加
    [SerializeField]
    GameObject[] objcts;


    //外部から呼び出せるように静的なフィールドとプロパティを定義
    //そうしておくと外部からcreateRandObjs.Instance.spawnNext()で呼び出せます。
    static createRandObjs instance;
    public static createRandObjs Instance
    {
        get {
            //インスタンスがなければインスタンスを生成 Awakeより先にこのプロパティが呼ばれる可能性があるのでここでもチェックとnullであればインスタンス化します。
            if(instance == null) instance = (createRandObjs) FindObjectOfType( typeof(createRandObjs) );

            return instance;
        }
    }


    // オブジェクトを順番にカウントするための変数
    int objIdx;

    // オブジェクトのランダムなインデックスを格納する配列
    int[] objIdxAry;


    void Awake()
    {
        //インスタンスがなければインスタンス化
        if(instance == null) instance = (createRandObjs) this;
        //すでにインスタンスが存在すれば自身を破棄 インスタンスは1つでいいので重複対策です。
        else if( Instance != this ) Destroy(this);
    }


    /// <summary>
    /// オブジェクトを出力する
    /// </summary>
    void instantiateObj(int idx)
    {
        //とりあえずVector3.zero地点にオブジェクトを生成
        Instantiate(objcts[idx], Vector3.zero, Quaternion.identity);
    }


    /// <summary>
    /// 外部から呼ばれる オブジェクトを出力する
    /// </summary>
    public void spawnNext()
    {
        //オブジェクトが無ければ何もせず終了
        if(objcts.Length == 0) return;

        //objIdxが0またはobjctsの数に達したらリセット
        if(objIdx == 0 || objIdx == objcts.Length)
        {
            //objIdxをリセット
            objIdx = 0;
            //ランダムな配列を生成
            objIdxAry = Enumerable.Range(0, objcts.Length).OrderBy(n => Guid.NewGuid()).ToArray();
        }

        //objIdxAryのインデックスを元にオブジェクトを生成
        instantiateObj( objIdxAry[objIdx] );
        //objIdxを+1する
        objIdx++;
    }
}

呼ぶ側

createRandObjs.Instance.spawnNext();

 [以降は読まなくてもいいです] とりあえずコード量を抑える為、必要最低限にしています。

どこまで完成しているか分からないのでなんとも言えないのですが今のコードでは不十分に感じます。考えられるのはこんな感じです。

  • オブジェクトの移動完了などの状態を直接知ることができない
  • テトリスの場合、マップ的なものを用意してx軸が埋まっていれば(略)などの処理の対応
  • 消える時のアニメーション

などですかね?僕ならオブジェクト一つ一つにスクリプトをつけてそこで、自身の調整や管理と外部への自身の状態や消えるアニメーションのスタートやエンドなどを提供をする形にすると思います。

それをこんな感じでコントロール側で持つと思います。

//これをオブジェクトひとつひとつにアタッチする
public class objScript : MonoBehaviour
{
    public bool destroyAnime(int[] targetYs)
    {
        //略
              //色々して全部消えたらtrueを送る
              return true;
    }
}

//引数などは適当です。実際はint[]を渡す形で組まないかもしれません。
public class createRandObjs : MonoBehaviour
{
        // 生成する時についでにこの配列に参照を渡しておく
    List<objScript> objScripts = new List<objScript>();

    void destroyAnime()
    {
        //略

        //1,2列目を破棄
        var isDeleteObj = objScripts[0].destroyAnime(new int[]{ 1,2 });
               //もしオブジェクトが完全に消えたら何かする
                if(isDeleteObj) objScripts.RemoveAt(0);
    }

投稿

編集

  • 回答の評価を上げる

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

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

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

  • 回答の評価を下げる

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

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

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

  • 2017/10/07 18:26

    ご丁寧な説明 本当にありがとうございます。
    書いていただいたコードを自分のものに合うように少しだけ手を加えた結果、無事自分の思っていたものにできました。
    unityとC#については頑張って学んでいきたいと思います。ですが今作っているゲームをよりよくするためにまたご質問をさせていただくかもしれません。 また機会がありましたら 答えてください。m(_ _)mここまで長い間 初心者の自分にご丁寧に答えてくださり、本当にありがとうございました。

    キャンセル

  • 2017/10/08 23:30

    ベストアンサーにしてからかなり立ちましたが一つ気が付いたことがあります。 このオブジェクトを格納する配列に数字が入れられるときにランダムになっていないのでないでしょうか? テトリスのミノを出現させると、オブジェクトの1から7と出てきます。 
    もし時間がありましたら、もう一度コードを編集してはくれませんか?

    キャンセル

  • 2017/10/08 23:35

    大変申し訳ございません。
    テトリスのミノのネクストというものを作っていて、このコードをいじってしまって、どうやらそれが原因でランダムに出てこなかったようです。 もしこれが自分で解決できないようだったら、別で質問させていただきます。m(_ _)m

    キャンセル

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

  • ただいまの回答率 90.52%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる

関連した質問

  • 解決済

    unityでのキャラクターの復活

    unityで特定のオブジェクトにプレイヤーが触れた時プレイヤーがDestroyさせ、3秒後に初期位置で復活させるといった スクリプトを書きたいのですが、キャラクターをDestro

  • 解決済

    Unity シューティングゲームにオブジェクトプールを導入したい

    今作成中のシューティングゲームがInstantiateとDestroyを繰り返し、モバイル端末だと特に動きがカクカクになってきました。何かいい手はないかと思って調べているとオブジェ

  • 解決済

    Unity-Update上の判定で一度だけメソッドを呼び出す

    Unityでゲームを制作しています。 例えば、ゲーム上でスコアが一定値に達するたびにステージの難易度が上がり、画面に「ステージ〇〇」というテキストのカットインを入れたりするよう

  • 解決済

    Unity2Dでクリックしたオブジェクトの座標を取得したい

    前提・実現したいこと Unity2Dでドラッグ&ドロップではめていくパズルゲームを作成中です。 現在、パズルが出てくるスポーンが一つだけなのですが、三つに増やしたいと考えてお

  • 解決済

    Unityでの乱数を重複なく複数回表示

    Unityでtetrisを作っています。 unity初心者なのでいろんなサイトを見て頑張っているのですが、 一つだけどこを探してもわからないことがあります。 それは 乱数を重複なく

  • 解決済

    Unityで線を描画したい

    Unityで線を描画したいと思っています。 現在、ARを使ってプログラミングをしているのですが、その中でARCameraの子オブジェクトとして使っているcanvasの中で線を描画し

  • 解決済

    ピンチの中心とした拡大縮小について

     前提・実現したいこと unityを始めて1週間くらいの初心者です。 現状、乙女ゲーのようなアプリを作成しようとしており ギャラリー機能としてキャラの立ち画をピンチによる拡大縮小を

  • 解決済

    2つの広告が重なって表示されてしまう。 (ipadで試した場合)

    やりたい事 Admobのバナー広告が(通信環境により)表示されない場合、 3秒毎に再度広告表示をリクエストして、できるだけ表示させるようにしたい。 (Awakeでバナー広告を一番先

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

  • C#

    7105questions

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

  • Unity

    3988questions

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

  • トップ
  • C#に関する質問
  • 別の質問でもらったコード(unityで乱数を重複のないように繰り返す)を自分の意図するものに変える