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

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

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

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

Q&A

解決済

1回答

13120閲覧

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

YuzuTf

総合スコア12

C#

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

0グッド

0クリップ

投稿2016/07/14 06:41

###前提・実現したいこと
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になります。

C#

1using UnityEngine; 2using System.Collections; 3 4public class Destroy01 : MonoBehaviour 5{ 6 //public static bool Hit01; //ヒットフラグ 7 public bool Hit01; 8 9 // Use this for initialization 10 void Start() 11 { 12 Hit01 = false; 13 } 14 15 // Update is called once per frame 16 void Update() 17 { 18 } 19 //ブロックと接触時に呼ばれる 20 void OnTriggerEnter2D(Collider2D other) 21 { 22 Hit01 = true; 23 } 24 //ブロックが離れる際に呼ばれる 25 void OnTriggerExit2D(Collider2D other) 26 { 27 Hit01 = false; 28 } 29}

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

C#

1using UnityEngine; 2using System.Collections; 3using UnityEditor; 4 5public class Delete : MonoBehaviour 6{ 7 8 public bool ALL_OK = false; 9 public int Count = 0; 10 11 // Use this for initialization 12 void Start() 13 { 14 15 } 16 17 // Update is called once per frame 18 void Update() 19 { 20 //オブジェクトを読み込む 21 GameObject obj1 = GameObject.Find ("Cube_01"); 22 GameObject obj2 = GameObject.Find ("Cube_02"); 23 GameObject obj3 = GameObject.Find ("Cube_03"); 24 GameObject obj4 = GameObject.Find ("Cube_04"); 25 GameObject obj5 = GameObject.Find ("Cube_05"); 26 GameObject obj6 = GameObject.Find ("Cube_06"); 27 28 //オブジェクトにアタッチされているスクリプトを読み込む 29 Destroy01 d1 = obj1.GetComponent<Destroy01> (); 30 Destroy02 d2 = obj2.GetComponent<Destroy02> (); 31 Destroy03 d3 = obj3.GetComponent<Destroy03> (); 32 Destroy04 d4 = obj4.GetComponent<Destroy04> (); 33 Destroy05 d5 = obj5.GetComponent<Destroy05> (); 34 Destroy06 d6 = obj6.GetComponent<Destroy06> (); 35 36 //ALL_OKのフラグ管理 37 ALL_OK = false; 38 if (d1.Hit01 == true && d2.Hit02 == true && d3.Hit03 == true && 39 d4.Hit04 == true && d5.Hit05 == true && d6.Hit06 == true) 40 { 41 ALL_OK = true; 42 } 43 //Hitフラグが一つでもelseなら,ALL_OKはfalseになる 44 else 45 { 46 ALL_OK = false; 47 } 48 49 //------------------------------------------------ 50 //ブロックを消す処理 51 //------------------------------------------------ 52 53 //ブロックの削除とカウント数減 54 if(ALL_OK == true && Count>0) 55 { 56 //消す際にカウントをマイナスする。 57 Count -= 1; 58 //ここで一番下に作った当たり判定に接触している 59 //ブロックをすべて消す 60 61 //Destroy(other.gameObject); 62 63 //ブロックがヒットした数=カウント数=消したいブロック数なので 64 //0は消したいすべてのブロックが消えている状態 65 if (Count == 0) 66 { 67 Debug.Log ("count=0"); 68 //そろった列のHitをfalseに戻す 69 GameObject.Find("Cube_01").GetComponent<Destroy01>().Hit01 = false; 70 GameObject.Find("Cube_02").GetComponent<Destroy02>().Hit02 = false; 71 GameObject.Find("Cube_03").GetComponent<Destroy03>().Hit03 = false; 72 GameObject.Find("Cube_04").GetComponent<Destroy04>().Hit04 = false; 73 GameObject.Find("Cube_05").GetComponent<Destroy05>().Hit05 = false; 74 GameObject.Find("Cube_06").GetComponent<Destroy06>().Hit06 = false; 75 } 76 } 77 } 78 79 //オレンジ色のブロックと接触した際、カウントをプラスする 80 void OnTriggerEnter2D(Collider2D other) 81 { 82 Count += 1; 83 } 84 85} 86

###試したこと
現在上のコードでコメントにしている

//ここで一番下に作った当たり判定に接触している //ブロックをすべて消す 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です。

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

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

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

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

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

guest

回答1

0

ベストアンサー

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

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

C#

1using UnityEngine; 2using System.Collections; 3 4public class Destroy01 : MonoBehaviour 5{ 6 //public static bool Hit01; //ヒットフラグ 7 public bool Hit01; 8 9 //当たった相手オブジェクト 10 public GameObject hitObj; 11 12 // Use this for initialization 13 void Start() 14 { 15 Hit01 = false; 16 } 17 18 // Update is called once per frame 19 void Update() 20 { 21 } 22 //ブロックと接触時に呼ばれる 23 void OnTriggerEnter2D(Collider2D other) 24 { 25 Hit01 = true; 26 hitObj = other.gameObject; 27 } 28 //ブロックが離れる際に呼ばれる 29 void OnTriggerExit2D(Collider2D other) 30 { 31 Hit01 = false; 32 hitObj = null; 33 } 34}

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

C#

1 if(ALL_OK == true) { 2 //ここで一番下に作った当たり判定に接触している 3 //ブロックをすべて消す 4 5 if (d1.hitObj != null) { Destroy(d1.hitObj); } 6 if (d2.hitObj != null) { Destroy(d2.hitObj); } 7 if (d3.hitObj != null) { Destroy(d3.hitObj); } 8 if (d4.hitObj != null) { Destroy(d4.hitObj); } 9 if (d5.hitObj != null) { Destroy(d5.hitObj); } 10 if (d6.hitObj != null) { Destroy(d6.hitObj); } 11 12 d1.Hit01 = false; 13 d2.Hit01 = false; 14 d3.Hit01 = false; 15 d4.Hit01 = false; 16 d5.Hit01 = false; 17 d6.Hit01 = false; 18 }

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

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

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

C#

1if(ALL_OK == true) { 2 Destroy(obj1); 3 Destroy(obj2); 4 Destroy(obj3); 5 Destroy(obj4); 6 Destroy(obj5); 7 Destroy(obj6); 8}

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

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

投稿2016/07/14 15:11

編集2016/07/15 01:43
sakura_hana

総合スコア11427

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

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

YuzuTf

2016/07/15 00:41

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

2016/07/15 03:51

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

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.48%

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

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

質問する

関連した質問