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

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

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

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

Q&A

解決済

2回答

845閲覧

ブロックと当たり判定をとった時特定の条件が満たされたら範囲内のオブジェクトを消す処理が知りたい

isimasa

総合スコア295

C#

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

0グッド

0クリップ

投稿2022/03/22 06:44

編集2022/04/08 08:10

前提

5枚のブロック画像がランダムに(-7~8*50)配置されている
ブロックが上からスクロールしてくる
プレイヤーが下に表示されていて左右移動できる

実現したいこと

ブロックと当たり判定をとった時特定の条件が満たされたら範囲内のオブジェクトを消す処理が知りたい
もし配列の同じ画像が2枚以上揃っていたらプレイヤーに当たった時揃ったものをすべて消す
上の条件をループさせて連鎖消えを実現させる

発生している問題・エラーメッセージ

当たったら連結しているすべてのブロックが削除されてしまう。

該当のソースコード

追記

C#

1//Playerにアタッチ 2public float playerSpeed; 3private Vector2 player_pos; 4public int width; 5public int height; 6public GameObject[] blocks; 7public GameObject[,] fieldBlocks; 8[SerializeField] List<GameObject> checkZumiFieldBlocks = new List<GameObject>(); 9GameObject piece; 10private int randomNum; 11void Start() 12{ 13 fieldBlocks = new GameObject[width, height]; 14} 15 16void Hairetu()// ブロックを作っているところ 17{ 18 for (int x = 0; x < width; x += 2) 19 { 20 for (int y = 0; y < height; y += 2) 21 { 22 randomNum = Random.Range(0, 5);// 0,1,2,3,4 23 piece = Instantiate(blocks[randomNum]) as GameObject; 24 piece.transform.position = new Vector3(x, y, 0); 25 fieldBlocks[x, y] = piece; 26 } 27 } 28} 29 30void Begin() 31 { 32 float moveX = Input.GetAxis("Horizontal") * Time.deltaTime * playerSpeed; 33 float moveY = Input.GetAxis("Vertical") * Time.deltaTime * playerSpeed; 34 35 transform.position = new Vector2( 36 //エリア指定して移動する 37 Mathf.Clamp(transform.position.x + moveX, 0.0f, 20.0f), 38 Mathf.Clamp(transform.position.y + moveY, -4.0f, 18.0f) 39 ); 40 41 player_pos = transform.position; //プレイヤーの位置を取得 42 43 player_pos.x = Mathf.Clamp(player_pos.x, 0.0f, 20.0f); //x位置が常に範囲内か監視 44 player_pos.y = Mathf.Clamp(player_pos.y, -4.0f, 18.0f); //y位置が常に範囲内か監視 45 transform.position = new Vector2(player_pos.x, player_pos.y); 46 47public void Drop()// ブロックの落下処理 48{ 49 int nullCount = 0; 50 for (int x = 0; x < width; x += 2) 51 { 52 for (int y = 0; y < height; y += 2) 53 { 54 if (fieldBlocks[x, y] == null) 55 { 56 nullCount += 2; 57 } 58 else if (nullCount > 0) 59 { 60 fieldBlocks[x, y].transform.position += new Vector3(0, -nullCount, 0); 61 fieldBlocks[x, y - nullCount] = fieldBlocks[x, y]; 62 fieldBlocks[x, y] = null; 63 } 64 } 65 nullCount = 0; 66 } 67 if (RenketuAri()) 68 { 69 StartCoroutine(Erase()); 70 } 71} 72 73public bool RenketuAri()// 連結を確認 74{ 75 for (int x = 0; x < width; x += 2) 76 { 77 for (int y = 0; y < height; y += 2) 78 { 79 checkZumiFieldBlocks.Clear(); 80 if (Renketusuu(x, y, 0) > 1 && fieldBlocks[x, y] != null) 81 { 82 return true; 83 } 84 } 85 } 86 return false; 87} 88 89public IEnumerator Erase()// 1つ以上そろったら削除 90{ 91 yield return new WaitForSeconds(0.5f); 92 for (int x = 0; x < width; x += 2) 93 { 94 for (int y = 0; y < height; y += 2) 95 { 96 checkZumiFieldBlocks.Clear();// Listをクリア 97 // 同じ種類が1以上だったら配列を削除 98 if (Renketusuu(x, y, 0) > 1 && fieldBlocks[x, y] != null) 99 { 100 Destroy(fieldBlocks[x, y]); 101 } 102 } 103 } 104 yield return new WaitForSeconds(0.5f); 105 Drop(); 106} 107 108int Renketusuu(int x, int y, int rennketusuu)// 連結しているか調べる 109{ 110 if (fieldBlocks[x, y] == null || checkZumiFieldBlocks.Contains(fieldBlocks[x, y])) 111 { 112 return rennketusuu; 113 } 114 checkZumiFieldBlocks.Add(fieldBlocks[x, y]); 115 116 rennketusuu++; 117 118 if (x != width - 2 && fieldBlocks[x + 2, y] != null && fieldBlocks[x, y].name == fieldBlocks[x + 2, y].name)// 右 119 { 120 Debug.Log(fieldBlocks[x + 2, y].name); 121 rennketusuu = Renketusuu(x + 2, y, rennketusuu); 122 } 123 if (x != 0 && fieldBlocks[x - 2, y] != null && fieldBlocks[x, y].name == fieldBlocks[x - 2, y].name)// 左 124 { 125 Debug.Log(fieldBlocks[x - 2, y].name); 126 rennketusuu = Renketusuu(x - 2, y, rennketusuu); 127 } 128 if (y != 0 && fieldBlocks[x, y - 2] != null && fieldBlocks[x, y].name == fieldBlocks[x, y - 2].name)// 下 129 { 130 Debug.Log(fieldBlocks[x, y - 2].name); 131 rennketusuu = Renketusuu(x, y - 2, rennketusuu); 132 } 133 if (y != height - 2 && fieldBlocks[x, y + 2] != null && fieldBlocks[x, y].name == fieldBlocks[x, y + 2].name)// 上 134 { 135 Debug.Log(fieldBlocks[x, y + 2].name); 136 rennketusuu = Renketusuu(x, y + 2, rennketusuu); 137 } 138 139 return rennketusuu; 140} 141 142private void OnCollisionEnter2D(Collision2D collision) 143{ 144 if (collision.gameObject.tag == "Block_B" || 145 collision.gameObject.tag == "Block_G" || 146 collision.gameObject.tag == "Block_Y" || 147 collision.gameObject.tag == "Block_R") 148 { 149 for (int x = 0; x < width; x += 2) 150 { 151 for (int y = 0; y < height; y += 2) 152 { 153 // Listをクリア 154 checkZumiFieldBlocks.Clear(); 155 // 同じ種類が1以上だったら配列を削除 156 if (Renketusuu(x, y, 0) > 1 && fieldBlocks[x, y] != null) 157 { 158 Debug.Log(fieldBlocks[x, y] + "_" + "連結数_①"); 159 Destroy(fieldBlocks[x, y]); 160 } 161 } 162 } 163 } 164}

試したこと

現在の状況
↑一つのコードでブロックの生成から削除までをやっています。プレイヤーが当たったら連結しているブロックをすべて消すことができました。ただ、これにプレイヤーが当たったブロックの連結数を調べ削除する条件を追加したいです。

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

2021.2.13f1
Unity2D(コア)

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

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

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

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

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

guest

回答2

0

自己解決

C#

1private void OnCollisionEnter2D(Collision2D collision) 2{ 3 if (collision.gameObject.tag == "Block_B" || 4 collision.gameObject.tag == "Block_G" || 5 collision.gameObject.tag == "Block_Y" || 6 collision.gameObject.tag == "Block_R") 7 { 8 for (int x = 0; x < width; x += 2) 9 { 10 for (int y = 0; y < height; y += 2) 11 { 12 // Listをクリア 13 checkZumiFieldBlocks.Clear(); 14 // 同じ種類が1以上だったら配列を削除 15 if (Renketusuu(x, y, 0) > 1 && fieldBlocks[x, y] != null) 16 { 17 Debug.Log(fieldBlocks[x, y] + "_" + "連結数_R"); 18 Destroy(fieldBlocks[x, y],6f); 19 } 20 } 21 } 22 } 23}

当たり判定を書き換えました。これだと、当たったら連結しているブロックをすべて消すことができます。プレイヤーが当たったブロックを起点とするのは自分で試行錯誤してやってみます。ありがとうございました。

投稿2022/03/27 15:21

編集2022/04/08 08:26
isimasa

総合スコア295

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

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

0

いわゆる連鎖処理ですよね。
こういうのは起点から再帰処理にて波状走査して調べるのが多いかなと思います。

ぷよぷよの作り方
http://www13.plala.or.jp/kymats/study/game_other/TOKOPUYO/tokopuyo.html

ブロックを生成している処理があるので、それを二次元配列かなんかで管理してあげて
該当するブロックから、隣接している&同じ色 のオブジェクトを探してあげると良いかもしれません。
(別に2次元配列が必須ではないので好きなアプローチで問題ありません)

***

私あんまり再帰処理の書き方わかってないのであれなんですがサンプルです。
Prefab用意するのめんどくさかったので質問の内容には沿ってないんですがご容赦いただければと思います。

適当なスクリプトにアタッチすると、自動的にCubeが生成されます。
マウスでCubeクリックすると同じ色でつながっているやつは消えます

cs

1using System.Collections; 2using System.Collections.Generic; 3using UnityEngine; 4 5public class Test : MonoBehaviour { 6 7 public int fieldSizeX = 10; 8 public int fieldSizeY = 10; 9 public GameObject[,] cells; 10 List<GameObject> vanishList = new List<GameObject>(); 11 List<Color> cellColors = new List<Color>() { Color.red, Color.blue, Color.green, Color.cyan }; 12 private RaycastHit hit; 13 14 private void Start() { 15 16 // フィールドサイズで二次元配列を初期化 17 cells = new GameObject[fieldSizeX, fieldSizeY]; 18 19 // カメラをなんかいい感じの位置においとく 20 Camera.main.transform.position = new Vector3(fieldSizeX / 2, fieldSizeY / 2, -12); 21 22 // Cube生成 23 for (int y = 0; y < fieldSizeY; y++) { 24 for (int x = 0; x < fieldSizeX; x++) { 25 var go = GameObject.CreatePrimitive(PrimitiveType.Cube); 26 27 go.transform.position = new Vector3(x, y, 0); 28 29 // 色を適当に変えておく 30 go.GetComponent<Renderer>().material.color = cellColors[Random.Range(0, cellColors.Count)]; 31 32 // 二次元配列に記憶しておく 33 cells[x, y] = go; 34 } 35 } 36 37 38 } 39 40 private void Update() { 41 42 // マウスクリックされたら 43 if (Input.GetMouseButtonDown(0)) { 44 Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition); 45 46 // Raycastでぶつかったら 47 if (Physics.Raycast(ray, out hit)) { 48 Debug.Log(hit.collider.gameObject.name); 49 var x = (int)hit.collider.gameObject.transform.position.x; 50 var y = (int)hit.collider.gameObject.transform.position.y; 51 52 // 起点を決めて再帰的に走査 53 SearchCells(x, y); 54 55 // バニッシュ! 56 Vanish(); 57 } 58 } 59 60 } 61 62 private void SearchCells(int x, int y) { 63 64 // 自分の色を記憶 65 var myCol = cells[x, y].GetComponent<Renderer>().material.color; 66 67 // ダブってチェックしないように一旦色をかえる 68 cells[x, y].GetComponent<Renderer>().material.color = Color.white; 69 70 // 消去リストに追加 71 vanishList.Add(cells[x, y]); 72 73 // 上下左右のマスが存在し、かつ同じ色なら再帰処理へ 74 if (x + 1 < fieldSizeX && cells[x + 1, y] != null && cells[x + 1, y].GetComponent<Renderer>().material.color == myCol) SearchCells(x + 1, y); 75 if (y + 1 < fieldSizeY && cells[x, y + 1] != null && cells[x, y + 1].GetComponent<Renderer>().material.color == myCol) SearchCells(x, y + 1); 76 if (x - 1 >= 0 && cells[x - 1, y] != null && cells[x - 1, y].GetComponent<Renderer>().material.color == myCol) SearchCells(x - 1, y); 77 if (y - 1 >= 0 && cells[x, y - 1] != null && cells[x, y - 1].GetComponent<Renderer>().material.color == myCol) SearchCells(x, y - 1); 78 } 79 80 private void Vanish() { 81 82 // リストにいるやつを消滅させる 83 vanishList.ForEach(x => { 84 Destroy(x); 85 }); 86 vanishList.Clear(); 87 } 88 89} 90

投稿2022/03/24 04:30

hogefugapiyo

総合スコア3302

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

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

isimasa

2022/03/26 06:18

回答ありがとうございます。自分で調べてたどり着いたのが、自分の子オブジェクトをすべて削除というものです。コードを書いたのですがエラーが発生してしまいます。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.48%

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

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

質問する

関連した質問