Unity 3D游戏-消消乐(三消类)教程和源码

Chinar blog www.chinar.xin

Unity 消消乐教程和源码


本文提供全流程,中文翻译

Chinar 的初衷是将一种简单的生活方式带给世人

使有限时间 具备无限可能

Chinar —— 心分享、心创新!

助力学习三消类游戏开发

为新手节省宝贵的时间,避免采坑!

文章目录

  • 1
    • Start Game —— 游戏逻辑稍复杂,先贴代码,抽空慢慢讲
  • 2
    • GameManager —— 游戏总控类脚本
  • 3
    • GameSweet —— 物品基础脚本
  • 4
    • MovedSweet —— 控制物体的移动
  • 5
    • ClearedSweet —— 清除管控类脚本
  • 6
    • ClearColorSweet —— 清除颜色相同的物品
  • 7
    • ColorSweet —— 颜色脚本
  • 8
    • ClearLineSweet —— 清除整行,整列
  • 支持
    • May Be —— 开发者,总有一天要做的事!


1

Start Game —— 游戏逻辑稍复杂,先贴代码,抽空慢慢讲


Chinar 博客

举个例子

using UnityEngine;
using UnityEngine.SceneManagement;
using UnityEngine.UI;

/// 
/// 开始游戏脚本
/// 
public class StartGame : MonoBehaviour {
	/// 
	/// 加载游戏
	/// 
	public void LoadTheGame()
	{
		SceneManager.LoadScene(1);
	}

	/// 
	/// 退出游戏
	/// 
	public void ExitGame()
	{
		Application.Quit();
	}

	/// 
	/// 初始化函数
	/// 
	void Start()
	{
		Button button = GameObject.Find("Exit_Button").GetComponent<Button>();
		button.onClick.AddListener(ExitGame);
		button = GameObject.Find("Start_Button").GetComponent<Button>();
		button.onClick.AddListener(LoadTheGame);
	}
}


2

GameManager —— 游戏总控类脚本


控制游戏所有逻辑的实现

举个例子

using UnityEngine;
using System.Collections;
using System.Collections.Generic;
using UnityEngine.UI;
using UnityEngine.SceneManagement;


/// 
/// 游戏控制脚本
/// 
public class GameManager : MonoBehaviour
{
	private static GameManager _instance; //单例
	public static  GameManager Instance
	{
		get { return _instance; }
		set { _instance = value; }
	}


	private void Awake()
	{
		_instance = this;
	}


	//大网格的行列数
	public int        xLie;
	public int        yHang;
	public float      fillTime;   //填充时间
	public GameObject gridPrefab; //背景块


	//消消乐物品的种类
	public enum SweetsType
	{
		EMPTY,        //空物体
		NORMAL,       //普通
		BARRIER,      //障碍物
		HANG_CLEAR,   //行消除
		LIE_CLEAR,    //列消除
		RAINBOWCANDY, //彩虹糖
		COUNT         //标记类型
	}


	//物品的预制体的字典 —— 可以通过物品的种类,来得到相对应的物体
	private Dictionary<SweetsType, GameObject> sweetPrefabDict;


	//由于字典不会直接在 Inspector面板上显示,所以需要用结构体(因为结构体,经过序列化,可以显示)
	[System.Serializable] //加上可序列化特性
	public struct SweetPrefab
	{
		public SweetsType type;
		public GameObject prefabs;
	}


	public                   SweetPrefab[]  sweetPrefabs;       //结构体数组
	private                  GameSweet[ , ] sweets;             //物品的数组,二维数组,中间必须加逗号
	private                  GameSweet      pressedSweet;       //按下的物品
	private                  GameSweet      enterSweet;         //松开的物品
	private                  Text           TimeText;           //倒计时文本框
	private                  float          TimeCountDown = 60; //倒计时,时间
	private                  bool           IsGameOver;         //是否结束游戏
	[HideInInspector] public int            PlayerScore;        //分数
	private                  Text           PlayerScoreText;    //玩家分数文本框
	private                  float          AddScoreTime;       //累加时间
	private                  float          CurrentScore;       //当前分数
	public                   GameObject     GameOverPanel;      //结束游戏界面
	private                  Text           FinalScoreText;     //最终得分


	/// 
	/// 初始化函数
	/// 
	void Start()
	{
		TimeText        = GameObject.Find("Time_Text").GetComponent<Text>(); //获取文本框
		PlayerScoreText = GameObject.Find("Score_Internal_Text").GetComponent<Text>();
		Button button   = GameObject.Find("ReTurn_Button").GetComponent<Button>(); //添加重玩按钮方法
		button.onClick.AddListener(RePlay);

		//实例化字典
		sweetPrefabDict = new Dictionary<SweetsType, GameObject>();
		for (int i = 0; i < sweetPrefabs.Length; i++) //遍历结构体数组
		{
			if (!sweetPrefabDict.ContainsKey(sweetPrefabs[i].type)) //如果字典里,不包含结构体里 对应的类型
			{
				sweetPrefabDict.Add(sweetPrefabs[i].type, sweetPrefabs[i].prefabs); //添加 结构体 到字典里
			}
		}


		sweets = new GameSweet[ xLie, yHang ]; //实例化二维数据,第一个维度是列,第二个是行
		for (int x = 0; x < xLie; x++)
		{
			for (int y = 0; y < yHang; y++)
			{
				CreateNewSweet(x, y, SweetsType.EMPTY); //调用创建按钮的方法
			}
		}

		Destroy(sweets[4, 4].gameObject);
		CreateNewSweet(4, 4, SweetsType.BARRIER);
		Destroy(sweets[4, 3].gameObject);
		CreateNewSweet(4, 3, SweetsType.BARRIER);
		Destroy(sweets[1, 1].gameObject);
		CreateNewSweet(1, 1, SweetsType.BARRIER);
		Destroy(sweets[7, 1].gameObject);
		CreateNewSweet(7, 1, SweetsType.BARRIER);
		Destroy(sweets[1, 6].gameObject);
		CreateNewSweet(1, 6, SweetsType.BARRIER);
		Destroy(sweets[7, 6].gameObject);
		CreateNewSweet(7, 6, SweetsType.BARRIER);

		for (int x = 0; x < xLie; x++) //实例化背景
		{
			for (int y = 0; y < yHang; y++)
			{
				//实例化方块背景
				GameObject chocolate       = (GameObject) Instantiate(gridPrefab, CorrectPosition(x, y), Quaternion.identity);
				chocolate.transform.parent = transform; //设置父物体
			}
		}





		StartCoroutine(AllFill()); //开启协成
	}


	/// 
	/// 更新函数
	/// 
	void Update()
	{
		if (IsGameOver) return;          //如果游戏结束,直接跳出
		TimeCountDown -= Time.deltaTime; //倒计时
		if (TimeCountDown <= 0)
		{
			TimeCountDown = 0;

			IsGameOver = true;
			GameOverPanel.SetActive(true); //激活结束游戏界面

			FinalScoreText      = GameObject.Find("LastScore_Text").GetComponent<Text>();
			FinalScoreText.text = PlayerScore.ToString(); //最终得分:赋值

			Button button = GameObject.Find("RePlay_Button").GetComponent<Button>(); //添加游戏结束界面:按钮方法
			button.onClick.AddListener(RePlay);
			button = GameObject.Find("ReturnMain_Button").GetComponent<Button>();
			button.onClick.AddListener(ReturnToMain);
			return;
		}
		TimeText.text = TimeCountDown.ToString("0"); //由于,是浮点型变量,所以强转取整数
		if (AddScoreTime <= 0.03f)
		{
			AddScoreTime += Time.deltaTime;
		}
		else
		{
			if (CurrentScore < PlayerScore)
			{
				CurrentScore++;
				PlayerScoreText.text = CurrentScore.ToString();
				AddScoreTime         = 0;
			}
		}
	}


	/// 
	/// 背景块的实际位置
	/// 
	/// 
	/// 
	/// 
	public Vector3 CorrectPosition(int x, int y)
	{
		//实例化巧克力的实际位置
		return new Vector3(transform.position.x - xLie / 2f + x, transform.position.y + yHang / 2f - y);
	}


	/// 
	/// 生成物品方法
	/// 
	/// 
	/// 
	/// 
	/// 
	public GameSweet CreateNewSweet(int x, int y, SweetsType type)
	{
		GameObject newSweet =
			(GameObject) Instantiate(sweetPrefabDict[type], CorrectPosition(x, y), Quaternion.identity); //实例化+强转
		newSweet.transform.parent = transform;
		sweets[x, y]              = newSweet.GetComponent<GameSweet>();
		sweets[x, y].Init(x, y, this, type);
		return sweets[x, y];
	}


	/// 
	/// 协成-全部填充
	/// 
	public IEnumerator AllFill()
	{
		bool needRefill = true; //需要重填

		while (needRefill)
		{
			yield return new WaitForSeconds(fillTime); //等待

			while (Fill()) //本次填充
			{
				yield return new WaitForSeconds(fillTime);
			}

			needRefill = ClearAllMatchedSweet();
		}
	}


	/// 
	/// 分步填充
	/// 
	public bool Fill()
	{
		bool filledNotFinished = false;      //判断本次否填,是否完成
		for (int y = yHang - 2; y >= 0; y--) //从下往上
		{
			for (int x = 0; x < xLie; x++) //从左到右
			{
				GameSweet sweet = sweets[x, y]; //得到当前元素位置的物品对象
				if (sweet.CanMove())            //如果能移动就填充
				{
					GameSweet sweetBelow = sweets[x, y + 1]; //下边元素位置
					if (sweetBelow.Type == SweetsType.EMPTY) //如果下方是空格子,就垂直向下填充
					{
						Destroy(sweetBelow.gameObject);
						sweet.MovedComponet.Move(x, y + 1, fillTime); //上边的元素,往下移动
						sweets[x, y                   + 1] = sweet;   //二维数组,对应位置更新。
						CreateNewSweet(x, y, SweetsType.EMPTY);
						filledNotFinished = true;
					}
					else //斜着填充
					{
						for (int down = -1; down < 1; down++)
						{
							if (down != 0) //不是正下方
							{
								int downX = x + down;
								if (downX >= 0 && downX < xLie) //规定范围,排除边缘情况
								{
									GameSweet downSweet = sweets[downX, y + 1]; //左下方甜品
									if (downSweet.Type == SweetsType.EMPTY)     //左下方为空
									{
										bool canfill = true; //用来判断是否可以垂直填充
										for (int upY = y; upY >= 0; upY--)
										{
											GameSweet upSweet = sweets[downX, upY]; //正上方元素
											if (upSweet.CanMove())
											{
												break; //能移动直接跳出
											}
											else if (!upSweet.CanMove() && upSweet.Type != SweetsType.EMPTY)
											{
												canfill = false;
												break;
											}
										}

										if (!canfill) //不能垂直填充
										{
											Destroy(downSweet.gameObject); //删除下边游戏的物体
											sweet.MovedComponet.Move(downX, y + 1, fillTime);
											sweets[downX, y                   + 1] = sweet;
											CreateNewSweet(x, y, SweetsType.EMPTY);
											filledNotFinished = true;
											break;
										}
									}
								}
							}
						}
					}
				}
			}
		}

		//最上排的特殊情况
		for (int x = 0; x < xLie; x++)
		{
			GameSweet sweet = sweets[x, 0];
			if (sweet.Type == SweetsType.EMPTY)//第一行,只要有空格子
			{
				Destroy(sweet.gameObject);
				GameObject newSweet =
					(GameObject) Instantiate(sweetPrefabDict[SweetsType.NORMAL], CorrectPosition(x, -1), Quaternion.identity);//就实例化一个普通物品
				newSweet.transform.parent = transform;
				sweets[x, 0]              = newSweet.GetComponent<GameSweet>();
				sweets[x, 0].Init(x, -1, this, SweetsType.NORMAL);
				sweets[x, 0].MovedComponet.Move(x, 0, fillTime);//移动-1行物品,到第一行
				sweets[x, 0].ColorComponet.SetColor((ColorSweet.ColorType)Random.Range(0, sweets[x, 0].ColorComponet.NumColors));
				filledNotFinished = true;
			}
		}

		return filledNotFinished;
	}


	/// 
	/// 物品是否相邻
	/// 
	/// 
	/// 
	/// 
	private bool IsAdjacent(GameSweet sweet1, GameSweet sweet2)
	{
		return sweet1.X == sweet2.X && Mathf.Abs(sweet1.Y - sweet2.Y) == 1 ||
		       sweet1.Y == sweet2.Y && Mathf.Abs(sweet1.X - sweet2.X) == 1;
	}


	/// 
	/// 交换物品位置
	/// 
	/// 
	/// 
	private void ExChangeSweets(GameSweet sweet1, GameSweet sweet2)
	{
		if (sweet1.CanMove() && sweet2.CanMove()) //如果2个物品都能移动
		{
			sweets[sweet1.X, sweet1.Y] = sweet2;
			sweets[sweet2.X, sweet2.Y] = sweet1;

			if (MatchSweets(sweet1, sweet2.X, sweet2.Y) != null                    ||
			    MatchSweets(sweet2, sweet1.X, sweet1.Y) != null                    ||
			    sweet1.Type                             == SweetsType.RAINBOWCANDY ||
			    sweet2.Type                             == SweetsType.RAINBOWCANDY) //如果完成匹配
			{


				int tempX = sweet1.X;
				int tempY = sweet1.Y;

				sweet1.MovedComponet.Move(sweet2.X, sweet2.Y, fillTime);
				sweet2.MovedComponet.Move(tempX, tempY, fillTime);

				if (sweet1.Type == SweetsType.RAINBOWCANDY && sweet1.CanClear() && sweet2.CanClear()) //如果物品1是 特殊物品:消除颜色
				{
					ClearColorSweet clearColor = sweet1.GetComponent<ClearColorSweet>();
					if (clearColor != null) //容错
					{
						clearColor.ClearColor = sweet2.ColorComponet.Color;
					}
					ClearSweet(sweet1.X, sweet1.Y);
				}
				if (sweet2.Type == SweetsType.RAINBOWCANDY && sweet2.CanClear() && sweet2.CanClear()) //如果物品2是 特殊物品:消除颜色
				{
					ClearColorSweet clearColor = sweet2.GetComponent<ClearColorSweet>();
					if (clearColor != null)
					{
						clearColor.ClearColor = sweet1.ColorComponet.Color;
					}
					ClearSweet(sweet2.X, sweet2.Y);
				}


				ClearAllMatchedSweet();    //交换位置后,清除物品,并生成空格
				StartCoroutine(AllFill()); //交换位置后填充

				pressedSweet = null;
				enterSweet = null;
			}
			else
			{
				sweets[sweet1.X, sweet1.Y] = sweet1;
				sweets[sweet2.X, sweet1.Y] = sweet2;
			}
		}
	}


	/// 
	/// 按下物品
	/// 
	public void PressedSweet(GameSweet sweet)
	{
		if (IsGameOver) return; //如果游戏结束,直接跳出
		pressedSweet = sweet;
	}


	/// 
	/// 进入物品
	/// 
	public void EnterSweet(GameSweet sweet)
	{
		if (IsGameOver) return; //如果游戏结束,直接跳出
		enterSweet = sweet;
	}


	/// 
	/// 释放物品
	/// 
	public void ReleaseSweet()
	{
		if (IsGameOver) return;                   //如果游戏结束,直接跳出
		if (IsAdjacent(pressedSweet, enterSweet)) //如果相邻
		{
			ExChangeSweets(pressedSweet, enterSweet); //调用改变位置的方法
		}
	}


	/// 
	/// 匹配消除方法
	/// 
	/// 
	/// 
	/// 
	/// 
	public List<GameSweet> MatchSweets(GameSweet sweet, int newX, int newY)
	{
		if (sweet.CanColor()) //如果可以着色
		{
			ColorSweet.ColorType color               = sweet.ColorComponet.Color; //上色
			List<GameSweet>      matchHangSweets     = new List<GameSweet>();     //物品行 列表
			List<GameSweet>      matchLieSweets      = new List<GameSweet>();     //物品列 列表
			List<GameSweet>      finishedMatchSweets = new List<GameSweet>();     //完成待删物品 列表

			//检查行消除匹配
			matchHangSweets.Add(sweet);
			for (int i = 0; i <= 1; i++) //i等于0,往左,1往右
			{
				for (int xDistance = 1; xDistance < xLie; xDistance++)
				{
					int x; //偏移后的 x 坐标
					if (i == 0)
					{
						x = newX - xDistance;
					}
					else
					{
						x = newX + xDistance;
					}
					if (x < 0 || x >= xLie)
					{
						break; //限定边界
					}


					if (sweets[x, newY].CanColor() && sweets[x, newY].ColorComponet.Color == color) //如果物品颜色一样
					{
						matchHangSweets.Add(sweets[x, newY]);
						//如果添加其他类型消除,在这里判断
					}
					else
					{
						break;
					}
				}
			}

			if (matchHangSweets.Count >= 3) //行列表元素的添加
			{
				for (int i = 0; i < matchHangSweets.Count; i++)
				{
					finishedMatchSweets.Add(matchHangSweets[i]);
				}
			}


			//L T形状匹配
			//遍历后,检测当前行遍历元素数量是否大于3
			if (matchHangSweets.Count >= 3)
			{
				for (int i = 0; i < matchHangSweets.Count; i++)
				{
					//行检查后,检测L和T形状。 检查元素上下元素,是否可以消除:0是上,1是下
					for (int j = 0; j <= 1; j++)
					{
						for (int yDistance = 1; yDistance < yHang; yDistance++)
						{
							int y;      //被检测物体的,Y轴偏移坐标
							if (j == 0) //如果是上方
							{
								y = newY - yDistance; //每次向上递增(物体Y轴坐标,自上而下是0--10)
							}
							else
							{
								y = newY + yDistance; //每次向下递增()
							}
							if (y < 0 || y >= yHang)
							{
								break; //限定边界
							}

							if (sweets[matchHangSweets[i].X, y].CanColor() &&
							    sweets[matchHangSweets[i].X, y].ColorComponet.Color == color) //如果列方向,颜色一致
							{
								matchLieSweets.Add(sweets[matchHangSweets[i].X, y]); //添加甜品对象到 列表中 
							}
							else
							{
								break;
							}
						}
					}

					if (matchLieSweets.Count < 2) //如果在 行列表中的,垂直方向列 数组中,相同元素小于2
					{
						matchLieSweets.Clear(); //清除
					}
					else //满足条件就加到完成列表
					{
						for (int j = 0; j < matchLieSweets.Count; j++)
						{
							finishedMatchSweets.Add(matchLieSweets[j]);
						}
						break;
					}
				}
			}

			if (finishedMatchSweets.Count >= 3)
			{
				return finishedMatchSweets; //返回  行LT 列表
			}

			matchHangSweets.Clear(); //开始列检查之前:清除列表
			matchLieSweets.Clear();


			//列消除匹配
			matchLieSweets.Add(sweet);
			for (int i = 0; i <= 1; i++) //i等于0,往左,1往右
			{
				for (int yDistance = 1; yDistance < yHang; yDistance++)
				{
					int y; //偏移后的 y 坐标
					if (i == 0)
					{
						y = newY - yDistance;
					}
					else
					{
						y = newY + yDistance;
					}
					if (y < 0 || y >= yHang)
					{
						break; //限定边界
					}


					if (sweets[newX, y].CanColor() && sweets[newX, y].ColorComponet.Color == color) //如果物品颜色一样
					{
						matchLieSweets.Add(sweets[newX, y]);
					}
					else
					{
						break;
					}
				}
			}

			if (matchLieSweets.Count >= 3) //LIE 列表元素的添加
			{
				for (int i = 0; i < matchLieSweets.Count; i++)
				{
					finishedMatchSweets.Add(matchLieSweets[i]);
				}
			}


			//垂直列表中,横向L T形状匹配
			//遍历后,检测当前行遍历元素数量是否大于3
			if (matchLieSweets.Count >= 3)
			{
				for (int i = 0; i < matchLieSweets.Count; i++)
				{
					//行检查后,检测L和T形状。 检查元素上下元素,是否可以消除:0是上,1是下
					for (int j = 0; j <= 1; j++)
					{
						for (int xDistance = 1; xDistance < xLie; xDistance++)
						{
							int x;      //被检测物体的,Y轴偏移坐标
							if (j == 0) //如果是上方
							{
								x = newX - xDistance; //每次向上递增(物体Y轴坐标,自上而下是0--10)
							}
							else
							{
								x = newX + xDistance; //每次向下递增()
							}
							if (x < 0 || x >= xLie)
							{
								break; //限定边界
							}

							if (sweets[x, matchLieSweets[i].Y].CanColor() &&
							    sweets[x, matchLieSweets[i].Y].ColorComponet.Color == color) //如果列方向,颜色一致
							{
								matchHangSweets.Add(sweets[x, matchLieSweets[i].Y]); //添加甜品对象到 列表中 
							}
							else
							{
								break;
							}
						}
					}

					if (matchHangSweets.Count < 2) //如果在 列列表中的,左右方向行 数组中,相同元素小于2
					{
						matchHangSweets.Clear(); //清除
					}
					else //满足条件就加到完成列表
					{
						for (int j = 0; j < matchHangSweets.Count; j++)
						{
							finishedMatchSweets.Add(matchHangSweets[j]);
						}
						break;
					}
				}
			}

			//这里
			if (finishedMatchSweets.Count >= 3)
			{
				return finishedMatchSweets;
			}
		}

		return null;
	}


	/// 
	/// 清除物品方法
	/// 
	/// 
	/// 
	/// 
	public bool ClearSweet(int x, int y)
	{
		if (sweets[x, y].CanClear() && !sweets[x, y].ClearedComponet.IsClearing)
		{
			sweets[x, y].ClearedComponet.Clear(); //调用自身方法,开始清除
			CreateNewSweet(x, y, SweetsType.EMPTY);
			ClearBarrier(x, y); //调用清除障碍物函数
			return true;
		}
		return false;
	}


	/// 
	/// 清除 障碍物
	/// 
	/// 
	/// 
	private void ClearBarrier(int X, int Y) //传入坐标是:消除掉物品的坐标
	{
		for (int friendX = X - 1; friendX <= X + 1; friendX++) //左右遍历
		{
			if (friendX != X && friendX >= 0 && friendX < xLie)
			{
				if (sweets[friendX, Y].Type == SweetsType.BARRIER && sweets[friendX, Y].CanClear()) //判断
				{
					sweets[friendX, Y].ClearedComponet.Clear();
					CreateNewSweet(friendX, Y, SweetsType.EMPTY);
				}
			}
		}

		for (int friendY = Y - 1; friendY <= Y + 1; friendY++) //上下遍历
		{
			if (friendY != Y && friendY >= 0 && friendY < yHang)
			{
				if (sweets[X, friendY].Type == SweetsType.BARRIER && sweets[X, friendY].CanClear()) //判断
				{
					sweets[X, friendY].ClearedComponet.Clear();
					CreateNewSweet(X, friendY, SweetsType.EMPTY);
				}
			}
		}
	}


	/// 
	/// 清除规则里物品的方法
	/// 
	/// 
	private bool ClearAllMatchedSweet()
	{
		bool needRefill = false; //是否需要填充
		for (int y = 0; y < yHang; y++)
		{
			for (int x = 0; x < xLie; x++)
			{
				if (sweets[x, y].CanClear()) //如果可以清除
				{
					List<GameSweet> matchList = MatchSweets(sweets[x, y], x, y);

					if (matchList != null) //需要消除
					{
						SweetsType specialSweetsType = SweetsType.COUNT; //定义一个枚举类型:COUNT——是否产生特殊甜品:默认是Count类型

						GameSweet randomSweet   = matchList[Random.Range(0, matchList.Count)]; //随机产生位置
						int       specialSweetX = randomSweet.X;
						int       specialSweetY = randomSweet.Y;


						if (matchList.Count == 4) //消除的4个物品
						{
							specialSweetsType = (SweetsType) Random.Range( (int) SweetsType.HANG_CLEAR,(int) SweetsType.LIE_CLEAR+1); //特殊类型赋值:取左不取右,所以+1
						}
						if (matchList.Count >= 5)
						{
							specialSweetsType = SweetsType.RAINBOWCANDY;
						}
						//5个

						for (int i = 0; i < matchList.Count; i++) //遍历数组:清楚元素
						{
							if (ClearSweet(matchList[i].X, matchList[i].Y))
							{
								needRefill = true; //填充
							}
						}


						if (specialSweetsType != SweetsType.COUNT) //有特殊类型
						{
							Destroy(sweets[specialSweetX, specialSweetY]);                                        //删除空白物品
							GameSweet newSweet = CreateNewSweet(specialSweetX, specialSweetY, specialSweetsType); //生成特殊甜品


							//给特殊物品着色
							if (specialSweetsType == SweetsType.HANG_CLEAR || specialSweetsType == SweetsType.LIE_CLEAR &&
							    newSweet.CanColor()                                                                     &&
							    matchList[0].CanColor()) //种类的确定
							{
								newSweet.ColorComponet.SetColor(matchList[0].ColorComponet.Color); //给特殊物品,着色:第一个物品的颜色
							}
							if (specialSweetsType == SweetsType.RAINBOWCANDY && newSweet.CanColor()) //如果是彩虹堂
							{
								newSweet.ColorComponet.SetColor(ColorSweet.ColorType.ANY);
							}
						}





					}
				}
			}
		}
		return needRefill;
	}


	/// 
	/// 消除整行
	/// 
	/// 
	/// 
	public void ClearHang(int hang)
	{

		for (int order = 0; order <= 1; order++)
		{
			for (int xoffset = 0; xoffset <= xLie; xoffset++)
			{
				int xPos;
				if (order==0)//左边
				{
					xPos = hang - xoffset;
				}
				else
				{
					xPos = hang + xoffset;
				}
				if (xPos<0||xPos>=xLie)
				{
					break;
				}

				if (sweets[xPos,hang].CanClear())
				{

					SweetsType type = sweets[xPos, hang].Type;
					ClearSweet(xPos, hang);
					print("消除整行");

					//if (type=="扩展类性")
					//{
					//	break;
					//}
				}
			}
		}

		//for (int x = 0; x < xLie; x++)
		//{
		//	ClearSweet(x, hang);
		//}
	}


	/// 
	/// 消除整列
	/// 
	/// 
	public void ClearLie(int lie)
	{
		for (int order = 0; order <= 1; order++)
		{
			for (int xoffset = 0; xoffset <= yHang; xoffset++)
			{
				int xPos;
				if (order == 0) //左边
				{
					xPos = lie - xoffset;
				}
				else
				{
					xPos = lie + xoffset;
				}
				if (xPos < 0 || xPos >= yHang)
				{
					break;
				}

				if (sweets[lie, xPos].CanClear())
				{
					SweetsType type = sweets[lie,xPos].Type;
					ClearSweet(lie, xPos);
					print("消除整列");
					//if (type=="扩展类性")
					//{
					//	break;
					//}
				}
			}
		}
	}


	/// 
	/// 清除颜色
	/// 
	/// 
	public void ClearColor(ColorSweet.ColorType color)
	{
		for (int x = 0; x < xLie; x++)
		{
			for (int y = 0; y < yHang; y++)
			{
				if (sweets[x, y].CanColor() && (sweets[x, y].ColorComponet.Color == color || color == ColorSweet.ColorType.ANY))
				{
					ClearSweet(x, y); //清除颜色
				}
			}
		}
	}


	/// 
	/// 返回主界面
	/// 
	public void ReturnToMain()
	{
		SceneManager.LoadScene(0);
	}


	/// 
	/// 重玩
	/// 
	public void RePlay()
	{
		SceneManager.LoadScene(1);
	}
}

3

GameSweet —— 物品基础脚本


控制物品的属性

举个例子

using UnityEngine;


/// 
/// 物品基础脚本
/// 
public class GameSweet : MonoBehaviour
{
	private int x; //物品列数量
	public  int X
	{
		get { return x; }

		set
		{
			if (CanMove())
			{
				x = value;
			}
		}
	}
	private int y; //物品行数量
	public  int Y
	{
		get { return y; }

		set
		{
			if (CanMove())
			{
				y = value;
			}
		}
	}
	private GameManager.SweetsType type; //物品种类
	public  GameManager.SweetsType Type
	{
		get { return type; }
	}
	private MovedSweet movedComponet; //移动组件
	public  MovedSweet MovedComponet
	{
		get { return movedComponet; }
	}
	private ColorSweet colorComponet; //颜色组件
	public  ColorSweet ColorComponet
	{
		get { return colorComponet; }
	}
	private ClearedSweet clearedComponet; //消除组件
	public  ClearedSweet ClearedComponet
	{
		get { return clearedComponet; }
	}

	[HideInInspector]               //在Inspector面板隐藏
	public GameManager gameManager; //控制脚本对象


	private void Awake()
	{
		movedComponet   = GetComponent<MovedSweet>(); //初始化之前就获取移动组件
		colorComponet   = GetComponent<ColorSweet>();
		clearedComponet = GetComponent<ClearedSweet>();
	}


	/// 
	/// 初始化函数
	/// 
	/// 
	/// 
	/// 
	/// 
	public void Init(int _x, int _y, GameManager _gameManager, GameManager.SweetsType _type)
	{
		x           = -x; //当前的 x 就等于初始化函数,传进来的传入参数的值
		y           = _y;
		gameManager = _gameManager;
		type        = _type;
	}


	/// 
	/// 判断物品能否移动
	/// 
	/// 
	public bool CanMove()
	{
		return movedComponet != null;
	}


	/// 
	/// 判断物品能否作色
	/// 
	/// 
	public bool CanColor()
	{
		return colorComponet != null;
	}

	/// 
	/// 判断是否可以清除
	/// 
	/// 
	public bool CanClear()
	{
		return clearedComponet != null;
	}


	void Update()
	{
		transform.Rotate(new Vector3(0, 0, 0));
	}


	/// 
	/// 鼠标进入
	/// 
	private void OnMouseEnter()
	{
		gameManager.EnterSweet(this);
		print("进入");
	}


	/// 
	/// 鼠标按下
	/// 
	private void OnMouseDown()
	{
		gameManager.PressedSweet(this);
		print("按下");
	}


	/// 
	/// 鼠标抬起
	/// 
	private void OnMouseUp()
	{
		gameManager.ReleaseSweet();
		print("抬起");
	}
}

4

MovedSweet —— 控制物体的移动


控制物体的移动是否可行

举个例子

using UnityEngine;
using System.Collections;


/// 
/// 控制移动脚本
/// 
public class MovedSweet : MonoBehaviour
{
	private GameSweet   sweet;
	private IEnumerator moveCoroutine; //这样得到其他指令的时候,我们可以终止这个协成


	private void Awake()
	{
		sweet = GetComponent<GameSweet>(); //获取组件
	}


	/// 
	/// 开启,或者关闭协成
	/// 
	/// 
	/// 
	public void Move(int newx, int newy, float time)
	{
		if (moveCoroutine != null)
		{
			StopCoroutine(moveCoroutine);//停止协成
		}
		moveCoroutine = MoveCoroutine(newx, newy, time);
		StartCoroutine(moveCoroutine);//重开协成
	}


	/// 
	/// 负责移动的协成
	/// 
	/// 
	/// 
	/// 
	/// 
	private IEnumerator MoveCoroutine(int newx, int newy, float time)
	{
		sweet.X          = newx;
		sweet.Y          = newy;
		Vector3 startPos = transform.position;//每一帧移动一点
		Vector3 endPos   = sweet.gameManager.CorrectPosition(newx, newy);
		for (float t = 0; t < time; t += Time.deltaTime)
		{
			sweet.transform.position = Vector3.Lerp(startPos, endPos, t / time);
			yield return 0;//等待一帧
		}
		sweet.transform.position = endPos; //如果发生意外 没移动,就直接赋值
	}



}

5

ClearedSweet —— 清除管控类脚本


控制物品是否可以被清除

举个例子

using UnityEngine;
using System.Collections;


/// 
/// 清除管控类脚本
/// 
public class ClearedSweet : MonoBehaviour
{
	public  AnimationClip clearAnimation; //动画
	public  AudioClip     DestoryClip;    //消除音效
	private bool          isClearing=false;     //是否正在清除
	public  bool          IsClearing
	{
		get { return isClearing; }
	}

	protected GameSweet sweet; //可扩充


	/// 
	/// 唤醒函数
	/// 
	private void Awake()
	{
		sweet = GetComponent<GameSweet>();
	}


	/// 
	/// 清除
	/// 
	public virtual void Clear()
	{
		isClearing = true; //正在被清除
		StartCoroutine(ClearCoroutine());
	}


	/// 
	/// 清除动画协成
	/// 
	/// 
	private IEnumerator ClearCoroutine()
	{
		BoxCollider collider = GetComponent<BoxCollider>();
		if (collider!=null)//容错
		{
			collider.enabled = false;
		}

		Animator animator = GetComponent<Animator>();
		if (animator != null)
		{
			animator.Play(clearAnimation.name); //播放清除动画

			GameManager.Instance.PlayerScore++;                           //得分
			AudioSource.PlayClipAtPoint(DestoryClip, transform.position); //播放消除音效
			yield return new WaitForSeconds(clearAnimation.length);

			Destroy(gameObject);
		}
	}
}

6

ClearColorSweet —— 清除颜色相同的物品


举个例子

public class ClearColorSweet : ClearedSweet
{
	private ColorSweet.ColorType clearColor; //颜色类型对象

	public ColorSweet.ColorType ClearColor
	{
		get { return clearColor; }

		set { clearColor = value; }
	}


	/// 
	/// 重写清除方法
	/// 
	public override void Clear()
	{
		base.Clear();
		sweet.gameManager.ClearColor(clearColor);
	}
}

7

ColorSweet —— 颜色脚本


管理物品颜色的脚本

举个例子

using UnityEngine;
using System.Collections.Generic;


/// 
/// 颜色脚本
/// 
public class ColorSweet : MonoBehaviour
{
	public enum ColorType
	{
		YELLOW, //黄
		PURPLE, //紫
		RED,    //红
		BLUE,   //蓝
		GREEN,  //绿
		PINK,   //棒棒糖
		ANY,    //彩虹糖
		COUNT   //预留
	}

	private Dictionary<ColorType, Sprite> colorSpriteDict; //颜色字典
	public  ColorSprite[]                 ColorSprites;    //结构体数组
	[System.Serializable]                                  //序列化
	public struct ColorSprite                              //结构体
	{
		public ColorType color;
		public Sprite    sprite;
	}

	private SpriteRenderer sprite;   //渲染器对象
	public  int            NumColors //颜色长度:多少种颜色
	{
		get { return ColorSprites.Length; }
	}

	private ColorType color; //物品颜色
	public  ColorType Color
	{
		get { return color; }

		set { SetColor(value); }
	}


	private void Awake()
	{
		sprite          = transform.Find("Sweet").GetComponent<SpriteRenderer>(); //获取渲染组件
		colorSpriteDict = new Dictionary<ColorType, Sprite>();                    //实例化字典对象
		for (int i = 0; i < ColorSprites.Length; i++)                             //遍历字典,在字典中添加图片
		{
			if (!colorSpriteDict.ContainsKey(ColorSprites[i].color))
			{
				colorSpriteDict.Add(ColorSprites[i].color, ColorSprites[i].sprite);
			}
		}
	}


	/// 
	/// 设置颜色
	/// 
	/// 
	public void SetColor(ColorType newColor)
	{
		color = newColor;
		if (colorSpriteDict.ContainsKey(newColor))
		{
			sprite.sprite = colorSpriteDict[newColor];
		}
	}



}

8

ClearLineSweet —— 清除整行,整列


举个例子

public class ClearLineSweet : ClearedSweet
{
	public bool IsHang;//是不是行


	/// 
	/// 重写清除虚方法
	/// 
	public override void Clear()
	{
		base.Clear();
		if (IsHang)//是行
		{
			sweet.gameManager.ClearHang(sweet.Y);
			print("消除整行新");

		}
		else
		{
			sweet.gameManager.ClearLie(sweet.X);
			print("消除整列新");

		}
	}
}



支持

May Be —— 开发者,总有一天要做的事!


拥有自己的服务器,无需再找攻略

Chinar 提供一站式《零》基础教程

使有限时间 具备无限可能!

Chinar 知你所想,予你所求!( Chinar Blog )


Unity 3D游戏-消消乐(三消类)教程和源码_第1张图片
Chinar

END

本博客为非营利性个人原创,除部分有明确署名的作品外,所刊登的所有作品的著作权均为本人所拥有,本人保留所有法定权利。违者必究

对于需要复制、转载、链接和传播博客文章或内容的,请及时和本博主进行联系,留言,Email: [email protected]

对于经本博主明确授权和许可使用文章及内容的,使用时请注明文章或内容出处并注明网址

你可能感兴趣的:(Unity,3D,游戏,Unity3D初级入门必学)