Unity 消消乐教程和源码


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

Chinar坚持将简单的生活方式,带给世人!

(拥有更好的阅读体验 —— 高分辨率用户请根据需求调整网页缩放比例)



1

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

喜欢的朋友,跳转到SiKi学院,观看最新视频:SiKi学院

SiKi学院——是本人发现的网络教程做的很完善的网络课堂,推荐大家多学,多看

using UnityEngine;
using UnityEngine.SceneManagement;
using UnityEngine.UI; /// <summary>
/// 开始游戏脚本
/// </summary>
public class StartGame : MonoBehaviour {
/// <summary>
/// 加载游戏
/// </summary>
public void LoadTheGame()
{
SceneManager.LoadScene(1);
} /// <summary>
/// 退出游戏
/// </summary>
public void ExitGame()
{
Application.Quit();
} /// <summary>
/// 初始化函数
/// </summary>
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; /// <summary>
/// 游戏控制脚本
/// </summary>
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; //最终得分 /// <summary>
/// 初始化函数
/// </summary>
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()); //开启协成
} /// <summary>
/// 更新函数
/// </summary>
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;
}
}
} /// <summary>
/// 背景块的实际位置
/// </summary>
/// <param name="x"></param>
/// <param name="y"></param>
/// <returns></returns>
public Vector3 CorrectPosition(int x, int y)
{
//实例化巧克力的实际位置
return new Vector3(transform.position.x - xLie / 2f + x, transform.position.y + yHang / 2f - y);
} /// <summary>
/// 生成物品方法
/// </summary>
/// <param name="x"></param>
/// <param name="y"></param>
/// <param name="type"></param>
/// <returns></returns>
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];
} /// <summary>
/// 协成-全部填充
/// </summary>
public IEnumerator AllFill()
{
bool needRefill = true; //需要重填 while (needRefill)
{
yield return new WaitForSeconds(fillTime); //等待 while (Fill()) //本次填充
{
yield return new WaitForSeconds(fillTime);
} needRefill = ClearAllMatchedSweet();
}
} /// <summary>
/// 分步填充
/// </summary>
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;
} /// <summary>
/// 物品是否相邻
/// </summary>
/// <param name="sweet1"></param>
/// <param name="sweet2"></param>
/// <returns></returns>
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;
} /// <summary>
/// 交换物品位置
/// </summary>
/// <param name="sweet1"></param>
/// <param name="sweet2"></param>
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;
}
}
} /// <summary>
/// 按下物品
/// </summary>
public void PressedSweet(GameSweet sweet)
{
if (IsGameOver) return; //如果游戏结束,直接跳出
pressedSweet = sweet;
} /// <summary>
/// 进入物品
/// </summary>
public void EnterSweet(GameSweet sweet)
{
if (IsGameOver) return; //如果游戏结束,直接跳出
enterSweet = sweet;
} /// <summary>
/// 释放物品
/// </summary>
public void ReleaseSweet()
{
if (IsGameOver) return; //如果游戏结束,直接跳出
if (IsAdjacent(pressedSweet, enterSweet)) //如果相邻
{
ExChangeSweets(pressedSweet, enterSweet); //调用改变位置的方法
}
} /// <summary>
/// 匹配消除方法
/// </summary>
/// <param name="sweet"></param>
/// <param name="newX"></param>
/// <param name="newY"></param>
/// <returns></returns>
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;
} /// <summary>
/// 清除物品方法
/// </summary>
/// <param name="x"></param>
/// <param name="y"></param>
/// <returns></returns>
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;
} /// <summary>
/// 清除 障碍物
/// </summary>
/// <param name="X"></param>
/// <param name="Y"></param>
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);
}
}
}
} /// <summary>
/// 清除规则里物品的方法
/// </summary>
/// <returns></returns>
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;
} /// <summary>
/// 消除整行
/// </summary>
/// <param name="hang"></param>
/// <returns></returns>
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);
//}
} /// <summary>
/// 消除整列
/// </summary>
/// <param name="lie"></param>
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;
//}
}
}
}
} /// <summary>
/// 清除颜色
/// </summary>
/// <param name="color"></param>
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); //清除颜色
}
}
}
} /// <summary>
/// 返回主界面
/// </summary>
public void ReturnToMain()
{
SceneManager.LoadScene(0);
} /// <summary>
/// 重玩
/// </summary>
public void RePlay()
{
SceneManager.LoadScene(1);
}
}

3

GameSweet —— 物品基础脚本

控制物品的属性

using UnityEngine;

/// <summary>
/// 物品基础脚本
/// </summary>
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>();
} /// <summary>
/// 初始化函数
/// </summary>
/// <param name="_x"></param>
/// <param name="_y"></param>
/// <param name="_gameManager"></param>
/// <param name="_type"></param>
public void Init(int _x, int _y, GameManager _gameManager, GameManager.SweetsType _type)
{
x = -x; //当前的 x 就等于初始化函数,传进来的传入参数的值
y = _y;
gameManager = _gameManager;
type = _type;
} /// <summary>
/// 判断物品能否移动
/// </summary>
/// <returns></returns>
public bool CanMove()
{
return movedComponet != null;
} /// <summary>
/// 判断物品能否作色
/// </summary>
/// <returns></returns>
public bool CanColor()
{
return colorComponet != null;
} /// <summary>
/// 判断是否可以清除
/// </summary>
/// <returns></returns>
public bool CanClear()
{
return clearedComponet != null;
} void Update()
{
transform.Rotate(new Vector3(0, 0, 0));
} /// <summary>
/// 鼠标进入
/// </summary>
private void OnMouseEnter()
{
gameManager.EnterSweet(this);
print("进入");
} /// <summary>
/// 鼠标按下
/// </summary>
private void OnMouseDown()
{
gameManager.PressedSweet(this);
print("按下");
} /// <summary>
/// 鼠标抬起
/// </summary>
private void OnMouseUp()
{
gameManager.ReleaseSweet();
print("抬起");
}
}

4

MovedSweet —— 控制物体的移动

控制物体的移动是否可行

using UnityEngine;
using System.Collections; /// <summary>
/// 控制移动脚本
/// </summary>
public class MovedSweet : MonoBehaviour
{
private GameSweet sweet;
private IEnumerator moveCoroutine; //这样得到其他指令的时候,我们可以终止这个协成 private void Awake()
{
sweet = GetComponent<GameSweet>(); //获取组件
} /// <summary>
/// 开启,或者关闭协成
/// </summary>
/// <param name="newx"></param>
/// <param name="newy"></param>
public void Move(int newx, int newy, float time)
{
if (moveCoroutine != null)
{
StopCoroutine(moveCoroutine);//停止协成
}
moveCoroutine = MoveCoroutine(newx, newy, time);
StartCoroutine(moveCoroutine);//重开协成
} /// <summary>
/// 负责移动的协成
/// </summary>
/// <param name="newx"></param>
/// <param name="newy"></param>
/// <param name="time"></param>
/// <returns></returns>
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; /// <summary>
/// 清除管控类脚本
/// </summary>
public class ClearedSweet : MonoBehaviour
{
public AnimationClip clearAnimation; //动画
public AudioClip DestoryClip; //消除音效
private bool isClearing=false; //是否正在清除
public bool IsClearing
{
get { return isClearing; }
} protected GameSweet sweet; //可扩充 /// <summary>
/// 唤醒函数
/// </summary>
private void Awake()
{
sweet = GetComponent<GameSweet>();
} /// <summary>
/// 清除
/// </summary>
public virtual void Clear()
{
isClearing = true; //正在被清除
StartCoroutine(ClearCoroutine());
} /// <summary>
/// 清除动画协成
/// </summary>
/// <returns></returns>
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; }
} /// <summary>
/// 重写清除方法
/// </summary>
public override void Clear()
{
base.Clear();
sweet.gameManager.ClearColor(clearColor);
}
}

7

ColorSweet —— 颜色脚本

管理物品颜色的脚本

using UnityEngine;
using System.Collections.Generic; /// <summary>
/// 颜色脚本
/// </summary>
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);
}
}
} /// <summary>
/// 设置颜色
/// </summary>
/// <param name="newColor"></param>
public void SetColor(ColorType newColor)
{
color = newColor;
if (colorSpriteDict.ContainsKey(newColor))
{
sprite.sprite = colorSpriteDict[newColor];
}
} }

8

ClearLineSweet —— 清除整行,整列

有耐心的朋友可以跳转到SiKi学院,观看视频:SiKi学院

public class ClearLineSweet : ClearedSweet
{
public bool IsHang;//是不是行 /// <summary>
/// 重写清除虚方法
/// </summary>
public override void Clear()
{
base.Clear();
if (IsHang)//是行
{
sweet.gameManager.ClearHang(sweet.Y);
print("消除整行新"); }
else
{
sweet.gameManager.ClearLie(sweet.X);
print("消除整列新"); }
}
}

支持

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

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

Chinar 提供一站式教程,闭眼式创建!

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

先点击领取 —— 阿里全产品优惠卷 (享受最低优惠)



1 —— 云服务器超全购买流程 (新手必备!)



2 —— Windows 服务器配置、运行、建站一条龙 !



3 —— Linux 服务器配置、运行、建站一条龙 !




" role="presentation">

技术交流群:806091680 ! Chinar 欢迎你的加入


END

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


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


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

Unity 3D游戏-消消乐(三消类)教程和源码的更多相关文章

  1. Unity 3D游戏开发学习路线(方法篇)

    Unity 3D本来是由德国的一些苹果粉丝开发的一款游戏引擎,一直只能用于Mac平台,所以一直不被业外人士所知晓.但是后来也推出了2.5版,同时发布了PC版本,并将其发布方向拓展到手持移动设备.Uni ...

  2. 《Unity 3D游戏客户端基础框架》概述

    框架概述: 做了那么久的业务开发,也做了一年多的核心战斗开发,最近想着自己倒腾一套游戏框架,当然暂不涉及核心玩法类型和战斗框架,核心战斗的设计要根据具体的游戏类型而定制,这里只是一些通用的基础系统的框 ...

  3. Unity 3D 游戏上线之后的流水总结

    原地址:http://tieba.baidu.com/p/2817057297?pn=1 首先.unity 灯光烘焙 :Unity 3D FBX模型导入.选项Model 不导入资源球.Rig 不导入骨 ...

  4. Unity 3d游戏逆向及.NET Reflector工具使用介绍

    移动平台游戏框架主要有unity 3d和cocos 2d.我们首先得识别游戏使用的框架.识别Unity游戏Android平台的apk包可以直接解压,看是否有./assets/bin/Data/Mana ...

  5. 【Unity】1.0 第1章 Unity—3D游戏开发和虚拟现实应用开发的首选

    分类:Unity.C#.VS2015 创建日期:2016-03-23 一.简介 Unity是跨平台2D.3D游戏和虚拟现实高级应用程序的专业开发引擎,是由Unity Technologies公司研制的 ...

  6. Unity 3D游戏开发引擎:最火的插件推荐

    摘要:为了帮助使用Unity引擎的开发人员制作更完美的游戏.我们精心挑选了十款相关开发插件和工具.它们是:2D Toolkit.NGUI.Playmaker.EasyTouch & EasyJ ...

  7. Unity 3D游戏-塔防类游戏源码:重要方法和功能的实现

    Unity-塔防游戏源码 本文提供全流程,中文翻译.Chinar坚持将简单的生活方式,带给世人!(拥有更好的阅读体验 -- 高分辨率用户请根据需求调整网页缩放比例) 1 2 3 4 5 6 7 8 9 ...

  8. Unity 3D游戏-贪吃蛇类游戏源码:重要方法和功能的实现

    贪吃蛇类游戏源码 本文提供全流程,中文翻译.Chinar坚持将简单的生活方式,带给世人!(拥有更好的阅读体验 -- 高分辨率用户请根据需求调整网页缩放比例) 1 头部移动方式 2 生成 Shit 道具 ...

  9. Unity 3D游戏-NPC对话系统With XML

    用XML做的Unity NPC对话系统 本文提供全流程,中文翻译.Chinar坚持将简单的生活方式,带给世人!(拥有更好的阅读体验 -- 高分辨率用户请根据需求调整网页缩放比例) 1 Create X ...

随机推荐

  1. STL_容器共通能力

    1. 来自教程: ◆ 所有容器提供的都是值(value)语意,而非引用(reference)语意.容器执行插入元素的操作时,内部实施拷贝动作.所以STL容器内存储的元素必须能够被拷贝(必须提供拷贝构造 ...

  2. grafana 批量添加图表

    利用grafana做监控展示特别方便,而且界面还很有科技感,一般的使用都是自己手动添加图表,或者使用别人提供好的模板. 在一种情况下就比较尴尬了,我有100个实例的内存数据想展示,如果都放在一个tab ...

  3. 《剑指offer》第十题(斐波那契数列)

    // 面试题:斐波那契数列 // 题目:写一个函数,输入n,求斐波那契(Fibonacci)数列的第n项. #include <iostream> using namespace std; ...

  4. Java 集合-集合介绍

    2017-10-30 00:01:09 一.Java集合的类关系图 二.集合类的概述 集合类出现的原因:面向对象语言对事物的体现都是以对象的形式,所以为了方便对多个对象的操作,Java就提供了集合类. ...

  5. 现在转战c++的领域,纯幼儿园

    C++中: 如果你用#include<iostream.h>就不需写这句话(旧标准).但是如果你用#include<iostream>就必须要写.但是在VS2010中就出现错误 ...

  6. 检测Linux glibc幽灵漏洞和修补漏洞

    1.首先安装rpm : sudo apt-get install rpm   wget -OGHOST-test.sh http://www.antian365.com/lab/linux0day/G ...

  7. HDU-3480 Division (四边形不等式优化DP)

    题目大意:将n个数分成m组,将每组的最大值与最小值的平方差加起来,求最小和. 题目分析:先对数排序.定义状态dp(i,j)表示前 j 个数分成 i 组得到的最小和,则状态转移方程为dp(i,j)=mi ...

  8. 生成输出 URL(16.2)

    1.在视图中生成输出 URL 几乎在每一个 MVC 框架应用程序中,你都会希望让用户能够从一个视图导航到另一个视图 —— 通常的做法是在第一个视图中生成一个指向第二个视图的链接,该链接以第二个视图的动 ...

  9. MVC 模式——第3章

    在深入到 ASP.NET MVC 框架的细节之间,最好熟悉 MVC 的设计模式及其背后的思想.良好地理解 MVC 背后的内容,有助于在阅读本书的过程中将该框架的特性放到相关的情境之中. 3.2 理解 ...

  10. 使用 PM2 管理nodejs进程

    pm2 是一个带有负载均衡功能的Node应用的进程管理器. 当你要把你的独立代码利用全部的服务器上的所有CPU,并保证进程永远都活着,0秒的重载, PM2是完美的. 它非常适合IaaS结构,但不要把它 ...