ユニティーを使用したツムツム風ゲームの作り方のメモです。ゲーム制作の参考にしていただければ嬉しいです。トグルボタンをクリックすると記事が表示されます。小さくて見ずらい画像はクリックで拡大できます。
使用する素材
ボールの作成
用意した画像をヒエラルキーウィンドウにドラッグ&ドロップします。
ボールに必要なコンポーネントを付けていきます。
ボールにつけるコンポーネント |
Rigidbody 2D |
CircleColider 2D |
作成したボールをprefabにしておきます。

壁の作成
空のオブジェクトを作成します。名前はWallにしました。
壁につけるコンポーネント |
Edgecolider2D |
Edgecoliderを編集してかべを作成します。

ボールを跳ねるようにする
Create→2DからphysicsMaterial2Dを作成します。

Bounclnessを設定します。

ボールのrigidbodyのmaterialの項目に設定します。

ボールを増やして再生するとこんな感じになります。
ボールの生成
新しくC#スクリプトを作成します。名前はBallGeneratorにしました。

一個ずつボールを生成したいのでコルーチンを使います。
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class BallGenerator : MonoBehaviour
{
//ボールを生成する
[SerializeField] GameObject ballPrefab = default;
private void Start()
{
StartCoroutine(Spawns(10));
}
public IEnumerator Spawns(int count)
{
//ボールを数個生成する
for (int i = 0; i < count; i++)
{
//ランダムな位置
Vector2 pos = new Vector2(Random.Range(-0.2f, 0.2f), 8f);
//生成する
Instantiate(ballPrefab,pos,Quaternion.identity);
//時間をあける
yield return new WaitForSeconds(0.05f);
}
}
}
ランダムな位置から少し時間を空けてボールが生成されるようになりました。
5種類のボールを生成する
BallGeneratorにコードを追加します。
生成時にボールの画像を設定して5種類のボールを作ります。
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class BallGenerator : MonoBehaviour
{
//ボールを生成する
[SerializeField] GameObject ballPrefab = default;
//設定する画像
[SerializeField] Sprite[] ballSprite = default;
private void Start()
{
StartCoroutine(Spawns(10));
}
public IEnumerator Spawns(int count)
{
//ボールを数個生成する
for (int i = 0; i < count; i++)
{
//ランダムな位置
Vector2 pos = new Vector2(Random.Range(-0.2f, 0.2f), 8f);
//生成する
GameObject ball = Instantiate(ballPrefab,pos,Quaternion.identity);
//ランダムに画像を設定する
int ballID = Random.Range(0, ballSprite.Length);
ball.GetComponent<SpriteRenderer>().sprite= ballSprite[ballID];
//時間をあける
yield return new WaitForSeconds(0.05f);
}
}
}
色の違うボールが生成されるようになりました。
ボールの差別化
スクリプトを使用してボールにIDを持たせて差別化します。
新しくC#スクリプトを作成します。名前はBallにしました。
using UnityEngine;
public class Ball : MonoBehaviour
{
public int id;
}
作成したスクリプトをボールのprefabに設定します。

Ballgeneratorにコードを追加します。
生成した時にIdを設定するようにします。
//Spawnsのfor文の中に書く
ball.GetComponent<Ball>().id= ballID;
再生して確認すると色ごとに別のIDが設定されるようになりました。

ボールをクリックできるようにする
新しくC#スクリプトを作成します。名前はGameSystemにしました。
空のオブジェクトを作成してGameSystemをアタッチしておきます。
using UnityEngine;
public class GameSystem : MonoBehaviour
{
[SerializeField] BallGenerator ballGenerator = default;
bool isDragging;
void Start()
{
//BallGeneratorのStart関数を消してこちらで処理する
StartCoroutine(ballGenerator.Spawns(30));
}
// Update is called once per frame
void Update()
{
if (Input.GetMouseButtonDown(0))
{
//右クリックを押し込んだ時
OnDragBegin();
}
else if (Input.GetMouseButtonUp(0))
{
//右クリックを離したとき
OnDragEnd();
}
else if (isDragging)
{
OnDragging();
}
}
void OnDragBegin()
{
//マウスによるオブジェクトの判定
Vector2 mousePosition = Camera.main.ScreenToWorldPoint(Input.mousePosition);
RaycastHit2D hit = Physics2D.Raycast(mousePosition, Vector2.zero);
if (hit && hit.collider.GetComponent<Ball>())
{
Debug.Log("ボールにヒット");
}
}
void OnDragging()
{
}
void OnDragEnd()
{
Debug.Log("ドラッグ終了");
}
}
inspector画面からBallGeneratorをセットします。

ボールをクリックするとログが表示されるようになりました。

ボールを削除する
クリックしたボールを削除するためにリストを作成して、
そのリストに追加されたボールを削除するようにしていきます。
[SerializeField] List<Ball> removeBalls= new List<Ball>();
void OnDragBegin()
{
//マウスによるオブジェクトの判定
Vector2 mousePosition = Camera.main.ScreenToWorldPoint(Input.mousePosition);
RaycastHit2D hit = Physics2D.Raycast(mousePosition, Vector2.zero);
if (hit && hit.collider.GetComponent<Ball>())
{
Debug.Log("ボールにヒット");
Ball ball = hit.collider.GetComponent<Ball>();
AddRemoveBall(ball);
isDragging= true;
}
}
void OnDragging()
{
Vector2 mousePosition = Camera.main.ScreenToWorldPoint(Input.mousePosition);
RaycastHit2D hit = Physics2D.Raycast(mousePosition, Vector2.zero);
if (hit && hit.collider.GetComponent<Ball>())
{
Debug.Log("ボールにヒット");
Ball ball = hit.collider.GetComponent<Ball>();
AddRemoveBall(ball);
}
}
void OnDragEnd()
{
//removeBallsのボールを消去
int removeCount = removeBalls.Count;
for (int i = 0; i < removeCount; i++)
{
Destroy(removeBalls[i].gameObject);
}
removeBalls.Clear();
Debug.Log("ドラッグ終了");
isDragging= false;
}
void AddRemoveBall(Ball ball)
{
//まだ持ってないボールのみ追加する
if (removeBalls.Contains(ball) == false)
{
removeBalls.Add(ball);
}
}
選択したボールが消えるようになりました。
同じ種類のボールだけリストに追加する
同じ種類のボールで距離の近いものをリストに追加して、3個以上なら消えるようにします。
using System.Collections.Generic;
using UnityEngine;
public class GameSystem : MonoBehaviour
{
[SerializeField] BallGenerator ballGenerator = default;
bool isDragging;
[SerializeField] List<Ball> removeBalls= new List<Ball>();
//現在ドラッグしているボール
Ball currentDraggingBall;
void Start()
{
//BallGeneratorのStart関数を消してこちらで処理する
StartCoroutine(ballGenerator.Spawns(30));
}
// Update is called once per frame
void Update()
{
if (Input.GetMouseButtonDown(0))
{
//右クリックを押し込んだ時
OnDragBegin();
}
else if (Input.GetMouseButtonUp(0))
{
//右クリックを離したとき
OnDragEnd();
}
else if (isDragging)
{
OnDragging();
}
}
void OnDragBegin()
{
//マウスによるオブジェクトの判定
Vector2 mousePosition = Camera.main.ScreenToWorldPoint(Input.mousePosition);
RaycastHit2D hit = Physics2D.Raycast(mousePosition, Vector2.zero);
if (hit && hit.collider.GetComponent<Ball>())
{
Ball ball = hit.collider.GetComponent<Ball>();
AddRemoveBall(ball);
isDragging= true;
}
}
void OnDragging()
{
Vector2 mousePosition = Camera.main.ScreenToWorldPoint(Input.mousePosition);
RaycastHit2D hit = Physics2D.Raycast(mousePosition, Vector2.zero);
if (hit && hit.collider.GetComponent<Ball>())
{
//現在ドラッグしているボールと同じ種類で距離の近いボールをリストに追加する
Ball ball = hit.collider.GetComponent<Ball>();
//ボールのIDが一致したら
if (ball.id == currentDraggingBall.id)
{
//距離が近い
float distance = Vector2.Distance(ball.transform.position, currentDraggingBall.transform.position);
if (distance < 1.5)
{
AddRemoveBall(ball);
}
}
}
}
void OnDragEnd()
{
//removeBallsのボールを消去
int removeCount = removeBalls.Count;
//3個以上なら消す
if (removeCount >= 3)
{
for (int i = 0; i < removeCount; i++)
{
Destroy(removeBalls[i].gameObject);
}
}
removeBalls.Clear();
isDragging= false;
}
void AddRemoveBall(Ball ball)
{
currentDraggingBall = ball;
//まだ持ってないボールのみ追加する
if (removeBalls.Contains(ball) == false)
{
removeBalls.Add(ball);
}
}
}
スコアの実装
ボールを消した数によってスコアを加算するようにしていきます。
スコアを表示するテキストを作成します。私はゲーム画面の左上に配置しました。

GameSystemにスコアを表示するコードを追加していきます。
int score;
[SerializeField] Text scoreText = default;
void Start()
{
//スコアの初期設定
score= 0;
addScore(0);
//BallGeneratorのStart関数を消してこちらで処理する
StartCoroutine(ballGenerator.Spawns(30));
}
void addScore(int point)
{
//スコアの更新
score += point;
scoreText.text = score.ToString();
}
void OnDragEnd()
{
//removeBallsのボールを消去
int removeCount = removeBalls.Count;
//3個以上なら消す
if (removeCount >= 3)
{
for (int i = 0; i < removeCount; i++)
{
Destroy(removeBalls[i].gameObject);
}
//消えた分だけ生成する
StartCoroutine(ballGenerator.Spawns(removeCount));
//スコアを加算する
addScore(removeCount * 100);
}
removeBalls.Clear();
isDragging= false;
}
inspector画面からスコアテキストを設定します。

ボールを消すとスコアが加算されるようになりました。
