*

[Unity]Unity2Dチュートリアル 繰り返しパズルを消す その2

公開日: : C#, Unity, ソース

Unityまとめページはこちら。

前回の続き。

準備が出来たので、ソースを変更致しましょう。

using UnityEngine;
using System.Collections;
using System.Collections.Generic;

public class GameSystem : MonoBehaviour {
	private const int TileLineNum = 5;
	private const int TileColNum = 6;
	private const float TileWidth = 0.5f;
	private const float TileHeight = 0.5f;
	private const float FirstTilePosX = -1.5f;
	private const float FirstTilePosY = -2;
	private int[,] tileTable = new int[TileLineNum,TileColNum];
	private bool[,] deleteTable = new bool[TileLineNum, TileColNum];

	public Sprite[] Tiles;
	public GameObject TileObj;
	public GameObject holdObj;
	public float holdPositionX;
	public float holdPositionY;
	private float z = 10f;
	private GameObject[,] tileSet;
	
	// Use this for initialization
	void Start () {
		SetTileSet();
		InitalizeTile();
	}
	
	// Update is called once per frame
	void Update () {
		if(Input.GetMouseButtonDown(0)){
			LeftClick();
		}
		if(Input.GetMouseButton(0)){
			LeftDrag();
		}
		if(Input.GetMouseButtonUp(0)){
			LeftUp();
		}
	}
	
	private void LeftClick(){
		Vector3 tapPoint = new Vector3(Input.mousePosition.x, Input.mousePosition.y, z);
		if(holdObj == null){
			Collider2D col = Physics2D.OverlapPoint(Camera.main.ScreenToWorldPoint(tapPoint));
			if(col != null){
				this.holdObj = col.gameObject;
				holdPositionX = this.holdObj.transform.position.x;
				holdPositionY = this.holdObj.transform.position.y;
				holdObj.transform.position = Camera.main.ScreenToWorldPoint(tapPoint);
			}
		}
		
	}
	private void LeftDrag(){
		Vector3 tapPoint = Input.mousePosition;
		if(holdObj != null){
			this.holdObj.transform.position = Camera.main.ScreenToWorldPoint(new Vector3(tapPoint.x, tapPoint.y, z));
			Collider2D[] colSet = Physics2D.OverlapPointAll(Camera.main.ScreenToWorldPoint(new Vector3(tapPoint.x, tapPoint.y, z)));
			if(colSet.Length > 1){
				foreach(Collider2D col in colSet){
					if(!col.gameObject.Equals(this.holdObj)){
						float tmpPositionX = holdPositionX;
						float tmpPositionY = holdPositionY;
						holdPositionX = col.gameObject.transform.position.x;
						holdPositionY = col.gameObject.transform.position.y;
						col.gameObject.transform.position = new Vector3(tmpPositionX, tmpPositionY, z);
					}
				}
			}
		}
	}
	private void LeftUp(){
		bool conFlg = true;
		if(holdObj != null){
			holdObj.transform.position = new Vector3(holdPositionX, holdPositionY, z);
			holdObj = null;
		}
		SetTileSet();
		while(conFlg){
			conFlg = false;
			DeleteMatchTile();
			foreach(bool deleteFlg in deleteTable){
				if(deleteFlg){
					conFlg = true;
					break;
				}
			}
			deleteTable = new bool[TileLineNum, TileColNum];
			tileTable = new int[TileLineNum,TileColNum];
		}
	}
	private void SetTileSet(){
		GameObject[,] tileSet = new GameObject[TileLineNum,TileColNum];
		for(int i = 0; i < TileLineNum; i++){
			for(int j = 0; j < TileColNum; j++){
				Collider2D col = Physics2D.OverlapPoint(new Vector2(FirstTilePosX + TileWidth * j, FirstTilePosY + TileHeight * i));
				if("tile".Equals(col.tag)){
					tileSet[i,j] = col.gameObject;
				}
			}
		}
		
		this.tileSet = tileSet;
	}
	
	private void DeleteMatchTile(){
		int cnt = 0;
		for(int i = 0; i < TileLineNum; i++){
			for(int j = 0; j < TileColNum; j++){
				cnt = CompareHorizontal(i, j, cnt);
				cnt = CompareVertical(i, j, cnt);
			}
		}
		
		DeleteTile();
	}
	
	private int CompareHorizontal(int i, int j, int cnt){
		if(j + 1 < TileColNum){
			Sprite nowSprite = GetSprite(this.tileSet[i,j]);
			Sprite nextSprite = GetSprite(this.tileSet[i,j+1]);
			if(nowSprite.Equals(nextSprite)){
				if(tileTable[i, j] > 0){
					tileTable[i,j+1] = tileTable[i,j]; 
				}else{
					int cntInTile = ReCompareHorizontal(i, j, nowSprite);
					if(cntInTile > 0){
						tileTable[i,j] = cntInTile;
						tileTable[i,j+1] = cntInTile; 
					}else{
						cnt++;
						tileTable[i,j] = cnt;
						tileTable[i,j+1] = cnt; 
					}
				}
			}
		}
		return cnt;
	}
	
	private int ReCompareHorizontal(int i, int j, Sprite baseSprite){
		int result = 0; 
		if(j + 1 < TileColNum){
			Sprite nextSprite = GetSprite (this.tileSet[i, j+1]);
			if(baseSprite.Equals(nextSprite)){
				if(tileTable[i,j+1] > 0){
					result = tileTable[i, j+1];
				}else{
					result = ReCompareHorizontal(i, j+1, baseSprite);
				}
			}else{
				result = 0;
			}
		}else{
			result = 0;
		}
		return result;
	}
	
	private int CompareVertical(int i, int j, int cnt){
		for(int k = 1; i + k < TileLineNum; k++){
			Sprite nowSprite = GetSprite (this.tileSet[i,j]);
			Sprite nextSprite = GetSprite(this.tileSet[i+k,j]);
			if(nowSprite.Equals(nextSprite)){
				if(tileTable[i,j] > 0){
					tileTable[i+k, j] = tileTable[i, j];
				}else{
					cnt++;
					tileTable[i,j] = cnt;
					tileTable[i+k,j] = cnt;
				}
			}else{
				break;
			}
		}
		
		return cnt;
	}
	
	private Sprite GetSprite(GameObject obj){
		SpriteRenderer renderer = obj.GetComponent<SpriteRenderer>();
		return renderer.sprite;
	}
	
	private void DeleteTile(){
		SetDeleteTileSet();
		for(int i = 0; i < TileLineNum; i++){
			for(int j = 0; j < TileColNum; j++){
				if(deleteTable[i, j]){
					Destroy(this.tileSet[i,j]);
				}
			}
		}
		for(int i = 0; i < TileLineNum; i++){
			for(int j = 0; j < TileColNum; j++){
				if(deleteTable[i, j]){
					tileSet[i, j] = null;
				}
			}
		}
		FallTile();
		RecreateTile();
	}
	
	private void SetDeleteTileSet(){
		for(int i = 0; i < TileLineNum; i++){
			int cnt = 1;
			for(int j = 1; j < TileColNum; j++){
				if(tileTable[i, j] != 0 && tileTable[i, j - 1] == tileTable[i, j]){
					cnt++;
					if(j == TileColNum - 1){
						if(cnt > 2){
							for(int k = 0; k < cnt; k++){
								deleteTable[i, j - k] = true;
							}
						}
						cnt = 1;
					}
				}else{
					if(cnt > 2){
						for(int k = 1; k <= cnt; k++){
							deleteTable[i, j - k] = true;
						}
					}
					cnt = 1;
				}
			}
		}
		
		for(int i = 0; i < TileColNum; i++){
			int cnt = 1;
			for(int j = 1; j < TileLineNum; j++){
				if (tileTable[j, i] != 0 && tileTable[j - 1, i] == tileTable[j, i]){
					cnt++;
					if(j == TileLineNum - 1){
						if(cnt > 2){
							for(int k = 0; k < cnt; k++){
								deleteTable[j - k, i] = true;
							}
						}
						cnt = 1;
					}
				}else{
					if(cnt > 2){
						for(int k = 1; k <= cnt; k++){
							deleteTable[j - k, i] = true;
						}
					}
					cnt = 1;
				}
			}
		}
	}
	
	private void FallTile(){
		for(int i =0; i < TileColNum; i++){
			for(int j = 1; j < TileLineNum; j++){
				if(tileSet[j-1, i] == null && tileSet[j,i]!= null){
					GameObject obj = tileSet[j, i].gameObject;
					obj.transform.position = new Vector3(obj.transform.position.x, obj.transform.position.y - TileHeight, z);
					tileSet[j-1,i] = obj;
					tileSet[j, i] = null;
					j = 0;
				}
			}
		}
	}
	
	private void RecreateTile(){
		for(int i = 0; i < TileLineNum; i++){
			for(int j = 0; j < TileColNum; j++){
				if(tileSet[i, j] == null){
					GameObject tile = (GameObject)Instantiate(TileObj);
					SpriteRenderer renderer = tile.gameObject.GetComponent<SpriteRenderer>();
					renderer.sprite = Tiles[Random.Range (0, 6)];
					Vector3 pos = new Vector3(FirstTilePosX + TileWidth * j,FirstTilePosY + TileHeight * i,z);
					tile.transform.position = pos;
					tileSet[i, j] = tile;
				}
			}
		}
	}

	private void InitalizeTile(){
		for(int i = 0; i < TileLineNum; i++){
			for(int j = 0; j < TileColNum; j++){
				GameObject tile = tileSet[i, j];
				SpriteRenderer renderer = tile.gameObject.GetComponent<SpriteRenderer>();
				renderer.sprite = Tiles[Random.Range (0, 6)];
			}
		}
	}
}

具体的な変更箇所は以下です。

void Start () {
	SetTileSet();
	InitalizeTile();
}

Startでタイルの初期化を呼び出すように変更。

private void InitalizeTile(){
	for(int i = 0; i < TileLineNum; i++){
		for(int j = 0; j < TileColNum; j++){
			GameObject tile = tileSet[i, j];
			SpriteRenderer renderer = tile.gameObject.GetComponent<SpriteRenderer>();
			renderer.sprite = Tiles[Random.Range (0, 6)];
		}
	}
}

パズルの初期化の処理です。今までそれぞれのスクリプトにやらせていたことをここでやっているだけです。

private void LeftUp(){
	bool conFlg = true;
	if(holdObj != null){
		holdObj.transform.position = new Vector3(holdPositionX, holdPositionY, z);
		holdObj = null;
	}
	SetTileSet();
	while(conFlg){
		conFlg = false;
		DeleteMatchTile();
		foreach(bool deleteFlg in deleteTable){
			if(deleteFlg){
				conFlg = true;
				break;
			}
		}
		deleteTable = new bool[TileLineNum, TileColNum];
		tileTable = new int[TileLineNum,TileColNum];
	}
}

パズドラ並びのチェックおよび、削除部分を、削除するものがなくなるまで繰り返すように処理を変更。
foreachという構文で、配列の中身を順番に取り出して、全て判定しています。
Wannabenote
また、一つでも消去をしていた場合は、breakでループを即抜けています。

実行するとこんな感じ。

では試してみましょう。起動時がこれ。
Wannabenote

この場合ですと、黒線が消えますね。また、青線を引いたところも連鎖して消えるのが見えます。
そして最後にはパズドラ並びをしていない状態になるはず!

Wannabenote

消えていますね。
何度も繰り返すことが出来ます。
というわけでやっとのことで、パズドラの基本ルール部分までは作ることが出来ました。

次回は、ここまで勢いでソースを書いてきたので、かなり汚いソースになっているので、リファクタしたいと思います。

ad

関連記事

VisualStudio_

[C#,Excel]visual studio tools for office(VSTO)を利用してExcelのAddInをC#で作る

いい加減VBAが嫌になってきたので、調べたらC#でExcelのアドインが作れるんですね。 というわ

記事を読む

Unity_

[Unity]Unity4.6 UIチュートリアル Lesson5.UI Text 日本語要約

前回の続き。今回はUI Textについての説明。 とはいえ、さすがにテキストなので、あまり説明

記事を読む

cropped-wannabenote_logo.png

[Unity]Unity4.6 UIチュートリアル Lesson11.UI Mask 日本語要約

Unity関連まとめページはこちら→Unity Unity4.6 UIチュートリアル Less

記事を読む

unity move

[Unity]コードリファレンス GameObjectを移動する。

移動します。 transformプロパティ GameObjectのtransformプロパテ

記事を読む

wannabenote

[Excel,C#]C#でExcelにデータを一括出力する

大体いつも忘れるこのやり方。 Excelにデータを出力する 方法論 単純な方法ではデータを一行

記事を読む

logo

[C#]AS400に対してODBC接続でトランザクションによりSQLを実行する。

データベースに対するトランザクション処理 と銘打ちましたが、要するに安全にinsert文などを実行

記事を読む

logo

[C#, Linq]foreach構文は書けるけど、Linqはよくわからなくて勉強する気がなくなった貴方に

Linq普及委員会エントリです。 いまさらすぎるわ! とか言わないで。 小難しい話はなしに、

記事を読む

Unity_

[Unity]Unity2Dチュートリアル 同じ色のパズルを消去する

前回の続き。 さて、そろそろパズドラみたいにパズルを消すロジックを考えていきましょう。 パズ

記事を読む

logo

[VSTO,Excel,C#]C#のアドインで現在起動しているExcelを取得する。

ExcelのアドインをC#で開発してるんですが、情報少ないですねぇ。 とりあえずMicrosoft

記事を読む

logo

[Unity]コードリファレンス ソケット通信の開始して接続して切断する。

オンラインゲームを作るためにはソケット通信が必要です。 今回はいきなりソースから。解説は下の方に。

記事を読む

ad

Comment

  1. しずえ より:

    最後のスクリプトにしたら、またタイルが全部同じになっちゃったんですけどどうすればいいでしょうか?

  2. わな び より:

    全部同じというとスクリプトが動いていないような?
    Start()のところ通ってますかね。

  3. しずえ より:

    スタートのところは
    void Start () {
    SetTileSet();
    InitalizeTile();
    }
    となっています。間違っていないと思いますが・・超初心者なのでよろしくお願いします><
    あと、プレイを押してみてもタイルが消えたり新たに落ちてこないのはなんでなんですかね?

  4. わな び より:

    多分GameSystemっていうObjectにスクリプトが貼りついていないというのが確率高そうです。

    デバッグで動かして、Start()の中を処理が走るかを確認してみたほうがよさそうですね。

  5. ちよ より:

    はじめまして!!
    詳しく記述してもらいとても勉強になります。
    こちらのサイトを参考に初心者ながらパズルゲームを作ってみたのですが消した色ごとのスコアの獲得をしてみたくて
    色々調べてみたのですがわからなくて…
    いい方法がありましたらご教授していただけたらと思いましてコメントさせてもらいました。よろしくお願いします。

Message

メールアドレスが公開されることはありません。

次のHTML タグと属性が使えます: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code class="" title="" data-url=""> <del datetime=""> <em> <i> <q cite=""> <strike> <strong> <pre class="" title="" data-url=""> <span class="" title="" data-url="">

ad

  •  Auther;わなび

     「オープン系得意だよね? 俺のPCの調子悪いんだけど」という無茶振りから解き放たれゲームエンジニアに。
    C#とかUnityを扱います。
    Twitterフォロー大歓迎です。
    githubアカウント→wannabenote
  • follow us in feedly
PAGE TOP ↑