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

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

ただいまの
回答率

90.00%

Unityにて、特定の範囲内で、特定の条件が満たされたとき、範囲内のオブジェクトを消したい

解決済

回答 1

投稿

  • 評価
  • クリップ 0
  • VIEW 7,321

YuzuTf

score 10

前提・実現したいこと

Hitというフラグの1番目~6番目がtrueの際、
一定の範囲内に接触しているオブジェクトを消そうとしています。イメージ説明
上の図でオレンジ色のブロックに接触している、小さな青色のブロックが、
右から順に「Hit01」「Hit02」...とフラグを持っており、
オレンジ色のブロックの当たり判定範囲に入ると、このフラグがTrueになります。
上の図の場合、Hit01~05はtrue、Hit06はfalseになります。

ブロックを消す際には別の当たり判定をとっており、
こちらには「ALL_OK」というフラグが入っています。
「ALL_OK」は、Hit01~Hit06のフラグが全てtrueになった際、trueになります。
この「ALL_OK」がtrueになった際、
当たり判定に接触しているオブジェクトを全て消すためのスクリプトで悩んでいます。
現在はこの当たり判定にCountの変数を追加し、ヒットした回数分、
当たり判定に接触したブロックを消す処理を作ろうと考えています。
イメージ説明

発生している問題

ブロックを消す際、どのように記述すればブロックが消えるのか分からない

該当のソースコード

こちらが青色のブロックにアタッチされているスクリプトです。
Hitフラグはオレンジ色のブロックと接触時にtrueに、
離れた時にfalseになります。

using UnityEngine;
using System.Collections;

public class Destroy01 : MonoBehaviour
{
    //public static bool Hit01;    //ヒットフラグ
    public bool Hit01;

    // Use this for initialization
    void Start()
    {
        Hit01 = false;
    }

    // Update is called once per frame
    void Update()
    {
    }
    //ブロックと接触時に呼ばれる
    void OnTriggerEnter2D(Collider2D other)
    {
        Hit01 = true;      
    }
    //ブロックが離れる際に呼ばれる
    void OnTriggerExit2D(Collider2D other)
    {
        Hit01 = false;       
    }
}

続いて、こちらが問題のスクリプトになります。
こちらのスクリプトはブロックを消す際の当たり判定にアタッチしています

using UnityEngine;
using System.Collections;
using UnityEditor;

public class Delete : MonoBehaviour
{

    public bool ALL_OK = false;
    public int Count = 0;

    // Use this for initialization
    void Start()
    {

    }

    // Update is called once per frame
    void Update()
    {  
        //オブジェクトを読み込む
        GameObject obj1 = GameObject.Find ("Cube_01");
        GameObject obj2 = GameObject.Find ("Cube_02");
        GameObject obj3 = GameObject.Find ("Cube_03");
        GameObject obj4 = GameObject.Find ("Cube_04");
        GameObject obj5 = GameObject.Find ("Cube_05");
        GameObject obj6 = GameObject.Find ("Cube_06");

        //オブジェクトにアタッチされているスクリプトを読み込む
        Destroy01 d1 = obj1.GetComponent<Destroy01> ();
        Destroy02 d2 = obj2.GetComponent<Destroy02> ();
        Destroy03 d3 = obj3.GetComponent<Destroy03> ();
        Destroy04 d4 = obj4.GetComponent<Destroy04> ();
        Destroy05 d5 = obj5.GetComponent<Destroy05> ();
        Destroy06 d6 = obj6.GetComponent<Destroy06> ();

        //ALL_OKのフラグ管理
        ALL_OK = false;
        if (d1.Hit01 == true && d2.Hit02 == true && d3.Hit03 == true &&
            d4.Hit04 == true && d5.Hit05 == true && d6.Hit06 == true) 
        {
            ALL_OK = true;
        } 
        //Hitフラグが一つでもelseなら,ALL_OKはfalseになる
        else
        {
            ALL_OK = false;
        }

        //------------------------------------------------
        //ブロックを消す処理
        //------------------------------------------------

        //ブロックの削除とカウント数減
        if(ALL_OK == true && Count>0)
        {
           //消す際にカウントをマイナスする。
            Count -= 1;
            //ここで一番下に作った当たり判定に接触している
            //ブロックをすべて消す

            //Destroy(other.gameObject);

            //ブロックがヒットした数=カウント数=消したいブロック数なので
            //0は消したいすべてのブロックが消えている状態
            if (Count == 0)
            {
                Debug.Log ("count=0");
                //そろった列のHitをfalseに戻す
                GameObject.Find("Cube_01").GetComponent<Destroy01>().Hit01 = false;
                GameObject.Find("Cube_02").GetComponent<Destroy02>().Hit02 = false;
                GameObject.Find("Cube_03").GetComponent<Destroy03>().Hit03 = false;
                GameObject.Find("Cube_04").GetComponent<Destroy04>().Hit04 = false;
                GameObject.Find("Cube_05").GetComponent<Destroy05>().Hit05 = false;
                GameObject.Find("Cube_06").GetComponent<Destroy06>().Hit06 = false;
            }
        }
    }

    //オレンジ色のブロックと接触した際、カウントをプラスする
    void OnTriggerEnter2D(Collider2D other)
    {
        Count += 1;
    }

}

試したこと

現在上のコードでコメントにしている

//ここで一番下に作った当たり判定に接触している
//ブロックをすべて消す
Destroy(other.gameObject);


という処理を正常に動かすため、
void Updateのかっこに(Collider2D other)と記述してみましたが
ALL_OKがtrueになるはずの状況でもfalseのまま残ってしまったり、
Countがマイナスされなかったので、現在コメント化しています。

void OnTrigger2D(Collider2D other)
の中で処理を入れた際には一回しか回らず、
目的のオブジェクトを消しきれなかったので、
ブロックを消す処理はvoid Updateに入れて複数回回すようにしています。
OnTriggerEnterとStayの二つを試しました。

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

言語はC#、使用ツールはUnity ver5.3、MonoDevelopです。

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

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

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

    クリップを取り消します

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

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

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

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

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

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

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

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

    質問の評価を下げる

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

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

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

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

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

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

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

    詳細な説明はこちら

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

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

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

回答 1

checkベストアンサー

+1

(7/15 09:41のコメントを受けて追記)
なるほど、消すのはオレンジ色のブロックだったんですね。
それであれば、下記のように変更すればよいかと思います。

Destroyクラス(02〜06も同様)

using UnityEngine;
using System.Collections;

public class Destroy01 : MonoBehaviour
{
    //public static bool Hit01;    //ヒットフラグ
    public bool Hit01;

    //当たった相手オブジェクト
    public GameObject hitObj;

    // Use this for initialization
    void Start()
    {
        Hit01 = false;
    }

    // Update is called once per frame
    void Update()
    {
    }
    //ブロックと接触時に呼ばれる
    void OnTriggerEnter2D(Collider2D other)
    {
        Hit01 = true;      
        hitObj = other.gameObject;
    }
    //ブロックが離れる際に呼ばれる
    void OnTriggerExit2D(Collider2D other)
    {
        Hit01 = false;       
        hitObj = null;
    }
}

Deleteクラス(if(ALL_OK == true && Count>0)の部分を差し替え)

if(ALL_OK == true) {
            //ここで一番下に作った当たり判定に接触している
            //ブロックをすべて消す

            if (d1.hitObj != null) { Destroy(d1.hitObj); }
            if (d2.hitObj != null) { Destroy(d2.hitObj); }
            if (d3.hitObj != null) { Destroy(d3.hitObj); }
            if (d4.hitObj != null) { Destroy(d4.hitObj); }
            if (d5.hitObj != null) { Destroy(d5.hitObj); }
            if (d6.hitObj != null) { Destroy(d6.hitObj); }

            d1.Hit01 = false;
            d2.Hit01 = false;
            d3.Hit01 = false;
            d4.Hit01 = false;
            d5.Hit01 = false;
            d6.Hit01 = false;
        }

(初期投稿分)
まず、UpdateではなくFixedUpdateを使いましょう。
Updateが「1フレームに1回(フレームレートによって逐次変動)」呼ばれるのに対し、FixedUpdateは「一定周期(物理演算と同周期)」で呼ばれます。

OnTriggerEnter2Dなどの物理演算に伴うメソッドはFixedUpdateと同周期で呼ばれる為、Updateと齟齬が発生する場合があります。
大きな処理をさせるとUpdateは遅れるので、例えば以下のような状態になる訳です。
こうなると、両者でカウントを共有している場合は当然ズレます。
Update1回目 → → → → → → →Update2回目
FixedUpdate1回目→FixedUpdate2回目→FixedUpdate3回目

但し今回の場合、「全ての青キューブがオレンジのオブジェクトと衝突していたら、全ての青キューブを消去する」ということでしたら、カウントは必要無いように思います。
以下だけで目的は達成出来るのではないかと。(if(ALL_OK == true && Count>0)の部分を差し替え)

if(ALL_OK == true) {
  Destroy(obj1);
  Destroy(obj2);
  Destroy(obj3);
  Destroy(obj4);
  Destroy(obj5);
  Destroy(obj6);
}

なお、Destroy後はFindもGetComponentも効かなくなるので、nullチェックを挟む必要が出て来ます。

更に言うとUpdateの中でFindやGetComponentは使うべきではありません。
Startで行っておいてUpdate(FixedUpdate)の中ではnullチェックのみ実行、存在していたらフラグを取得、などとやるべきかと思います。
(もっと言えばDestroy01などのクラスをわざわざ6種類作る意味があるのかな?という気がしますが……)

投稿

編集

  • 回答の評価を上げる

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

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

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

  • 回答の評価を下げる

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

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

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

  • 2016/07/15 09:41

    説明不足で申し訳ありません!
    消そうとしているのはオレンジ色のブロックですね。
    青色のブロックは列が揃ったかの判定に使用しています。
    青色のブロックにあるフラグがすべてtrue(=列が揃った)→消去の判定内(二枚目の画像の緑の枠内)にいるオレンジ色のブロックを全て消す
    という処理を作ろうとしています。
    Destroyという処理が6つあるのは、配列の使い方がいまいちよくわからず、一旦動くように作ったものです。知識不足で申し訳ないです…。

    キャンセル

  • 2016/07/15 12:51

    ありがとうございます!
    思っている通りに動かすことができました!

    キャンセル

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

  • ただいまの回答率 90.00%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる
  • トップ
  • C#に関する質問
  • Unityにて、特定の範囲内で、特定の条件が満たされたとき、範囲内のオブジェクトを消したい