Unity入門 - ツムツム風 ラブライブ 2Dパズルゲーム -

ツムツムが流行って結構経ちますが、今回はツムツム風のラブライブパズルゲームを作ってみました!

まずはunityの2Dの勉強として、unityが提供している「シューティングゲームチュートリアル」を
一通りやってみて、それをベースに作成しました。

ツムツム風のラブライブパズルゲームの概要
スクリプトC#で作成
・2Dモードで作成
・パズルを3つ繋げてクリックすると消える
・1パズルごとに100点加算
・3000点に達するとクリア
・リセットボタンを押すとリスタートできる

WebPlayer

手順

1. キャラのスプライトシートを作成
 block_sprite_[0-8] という名前でスライスする

2. Prefabsにブロックを作成
 Sprite Renderer, Crcle Collider 2D, Rigidbody 2D コンポーネントを追加

3. ブロックが外に出ないように、上下左右に枠を作成
 Sprite Renderer,Box Collider 2D コンポーネントを追加

4. クリア用のGUITextを作成

5. スコア用のGUITextを作成

6. リセットボタン用のGUITextureを作成

7, ブロック操作、画面操作、スコア管理、リセットボタン管理のスクリプトを作成して、それぞれにコンポーネント追加

作成したスクリプト

ブロック操作
using UnityEngine;
using System.Collections;
using System.Collections.Generic;

public class BlockManager : MonoBehaviour {

	// blockプレハブを設定
	public GameObject block;

	// テクスチャを指定
	public Sprite[] blockSprites;

	// 初期の出現ブロック数
	public int block_num = 50;

	// 出現するx軸の範囲
	public float drop_pos_range_x = 2.0f;

	// 出現するy軸の範囲
	public float drop_pos_y = 1.5f;

	// 直前にクリックしたブロック
	private GameObject firstBlock;

	// 直前にクリックしたブロック
	private GameObject lastBlock;

	// 現在のブロック名
	private string currentName;

	// 削除するブロックリスト
	List<GameObject> removeBlockList = new List<GameObject>();

	// スコア
	public int point = 100;

	// クリアスコア
	public int clear_point = 3000;

	// Use this for initialization
	void Start () {
		//playSound.PlaySe00 ();
		DropBlock (block_num);
	}
	
	// Update is called once per frame
	void Update () {
		//removeBlockList = new List<GameObject>();
		if (Input.GetMouseButton (0) && firstBlock == null) {
			OnClickFirst ();
		} else if (Input.GetMouseButton (0) && firstBlock) {
			OnClicking ();
		} else if (Input.GetMouseButtonUp(0) && firstBlock) {
			OnClickEnd ();
		}
	}

	// ブロックを出現させる
	private void DropBlock(int count){
	
		for (int i = 0; i < count; i++) {
			// ポジションを取得
			Vector3 position = block.transform.position;
			position.x = Random.Range(position.x - drop_pos_range_x, position.x + drop_pos_range_x);
			position.y = drop_pos_y;

			// テクスチャの変更
			int spriteId = Random.Range(0, 8);
			block.name = "block_sprite_" + spriteId;
			SpriteRenderer spriteObj = block.GetComponent<SpriteRenderer>();
			spriteObj.sprite = blockSprites[spriteId];

			Instantiate (block, position, block.transform.rotation);
		}
	}

	// クリックした時の処理
	private void OnClickFirst(){
		// クリックしたオブジェクト取得
		RaycastHit2D hit = Physics2D.Raycast(Camera.main.ScreenToWorldPoint(Input.mousePosition), Vector2.zero);
		if (hit.collider != null) {
			//Debug.Log (hit.collider.gameObject.name);
			GameObject hitObj = hit.collider.gameObject;

			// オブジェクト名を前方一致で判定
			string stTarget = hitObj.name;
			if (stTarget.StartsWith("block_sprite_")) {
				firstBlock  = hitObj;
				lastBlock   = hitObj;
				currentName = hitObj.name;

				// 削除対象のオブジェクトを格納
				removeBlockList = new List<GameObject>();
				removeBlockList.Add (hitObj);
			}
		}
	}

	// クリックしている途中の処理
	private void OnClicking(){
		// クリックしたオブジェクト取得
		RaycastHit2D hit = Physics2D.Raycast(Camera.main.ScreenToWorldPoint(Input.mousePosition), Vector2.zero);
		if (hit.collider != null) {
			GameObject hitObj = hit.collider.gameObject;

			// 同じブロックをクリックしている時
			if (hitObj.name == currentName && lastBlock != hitObj) {
				float distance = Vector2.Distance(hitObj.transform.position, lastBlock.transform.position);
				if (distance < 1.0f) {
					// 削除対象のオブジェクトを格納
					lastBlock = hitObj;
					removeBlockList.Add (hitObj);
				}
			}
		}
	}

	// クリックをはなした時の処理
	private void OnClickEnd(){
		int remove_cnt = removeBlockList.Count;
		Debug.Log ("Remove Count => " + remove_cnt);
		if (remove_cnt >= 3) {
			for (int i = 0; i < remove_cnt; i++) {
				Destroy (removeBlockList[i]);
			}

			// スコアの加算
			FindObjectOfType<Score>().AddPoint(point * remove_cnt);

			// クリア判定
			int currentPoint = FindObjectOfType<Score> ().GetPoint ();
			if (currentPoint >= clear_point) {
				FindObjectOfType<Manager>().GameClear();
			}

			// ボール新たに生成
			DropBlock (remove_cnt);
		}
		firstBlock = null;
		lastBlock  = null;
	}
}
画面操作
using UnityEngine;
using System.Collections;

public class Manager : MonoBehaviour {

	private GameObject clear;

	// Use this for initialization
	void Start () {
		clear = GameObject.Find ("Clear GUI");
		clear.SetActive (false);
	}
	
	// Update is called once per frame
	void Update () {
	
	}

	public void GameClear(){
		clear.SetActive (true);
	}
}
スコア管理
using UnityEngine;
using System.Collections;

public class Score : MonoBehaviour {

	public GUIText scoreGUIText;

	private int score;

	// Use this for initialization
	void Start () {
		Initialize ();
	}
	
	// Update is called once per frame
	void Update () {
		scoreGUIText.text = score.ToString ();
	}

	private void Initialize ()
	{
		score = 0;
	}

	public void AddPoint (int point)
	{
		score = score + point;
	}

	public int GetPoint ()
	{
		return score;
	}
}
リセットボタン
using UnityEngine;
using System.Collections;

public class ResetButton : MonoBehaviour {

	// Use this for initialization
	void Start () {
	
	}
	
	// Update is called once per frame
	void Update () {
	
	}
		
	void OnMouseDown()
	{
		Application.LoadLevel("Stage");
	}

	void OnMouseUp()
	{
	}
}


ブロック操作の BlockManager.cs が複雑で結構ハマりましたが
なんとか動くところまで実装出来ました。
本家のツムツムのように、時間制限や特別アイテム、フィーバータイムなどがあったら
もっとゲーム性が上がるんですが、次回以降で(笑)