Unity3D_(游戏)甜品消消乐01_游戏基础界面
甜品消消乐游戏
(脚本源码在游戏UI设计最下方)
三消游戏,存在L型消除有一点小Bug,当甜品在饼干附近消除时会清除饼干
饼干作为游戏障碍物时不可移动的,多块饼干并排时会挡住甜品掉落
发现消除类游戏的算法还是比较复杂的
游戏小道具因算法绕的我头有点晕就没有实现
甜品掉落速度可以在GameManager游戏管理类上设置fill Time值(我这里是0.25)
emm,游戏开始界面有点low,未添加渲染动画
游戏项目已托管到Github上 传送门
甜品消消乐01_游戏基础界面 传送门
甜品消消乐02_游戏核心算法 传送门
甜品消消乐03_游戏UI设计 传送门
(文章最下边有游戏脚本)
实现过程
素材导入,基本预制体的制作
通过Gizmos影藏Scene场景中小摄像机
(点击摄像机进行关闭)
新建一个GameObject->New Sprite,甜甜圈拖动上Sprite上,将游戏分层开发(分为模型层和渲染层)
当不知道甜甜圈尺寸时,可以新建一个3D Object->Cube,Cube默认长宽比例为1m
将甜甜圈长宽缩放比例0.45
将甜甜圈做成预设体
制作格子背景
设置格子缩放比例为0.65
为设置格子背景在甜甜圈背面,将Gird背景的Order in Layout设置为-1
将Gird设置成预设体
(不需要用到Cube我就把它删除了)
游戏管理的创建,巧克力的生成
新建一个GameObject->New Sprite,制作游戏背景
(背景比摄像机范围稍微大一些,放曝光)
添加GameManager游戏管理类脚本,挂在到GameObject(GameManager)上
using System.Collections; using System.Collections.Generic; using UnityEngine;public class GameManager : MonoBehaviour {//单例实例化private static GameManager _instance;public static GameManager Instance{get{return _instance;}set{_instance = value;}}//大网格的行列数public int xColumn;public int yRow;public GameObject gridPrefab;private void Awake(){_instance = this;}// Use this for initializationvoid Start () {for(int x = 0; x < xColumn; x++){for (int y=0;y<yRow;y++){GameObject chocolate = Instantiate(gridPrefab,new Vector3(x,y,0),Quaternion.identity);chocolate.transform.SetParent(transform);}}}// Update is called once per framevoid Update () {} }
GameManager.cs
巧克力块游戏背景
大网格的行列数
public int xColumn;public int yRow;
public GameObject gridPrefab;void Start () {for(int x = 0; x < xColumn; x++){for (int y=0;y<yRow;y++){GameObject chocolate = Instantiate(gridPrefab,new Vector3(x,y,0),Quaternion.identity);chocolate.transform.SetParent(transform);}}}
(为了使背景在巧克力块后面,设置background的Order in Layout 为 -2)
实际需要实例化巧克力的X位置 = GameManager位置的X坐标-大网格长度的一半+行列对应的X坐标
实际需要实例化巧克力的Y位置 = GameManager位置的Y坐标-大网格长度的一半+行列对应的Y坐标
调整巧克力块背景
public Vector3 CorrectPosition(int x ,int y){//实际需要实例化巧克力的X位置 = GameManager位置的X坐标-大网格长度的一半+行列对应的X坐标// 实际需要实例化巧克力的Y位置 = GameManager位置的Y坐标-大网格长度的一半+行列对应的Y坐标return new Vector3(transform.position.x-xColumn/2f+x,transform.position.y+yRow/2f-y);}
。
using System.Collections; using System.Collections.Generic; using UnityEngine;public class GameManager : MonoBehaviour {//单例实例化private static GameManager _instance;public static GameManager Instance{get{return _instance;}set{_instance = value;}}//大网格的行列数public int xColumn;public int yRow;public GameObject gridPrefab;private void Awake(){_instance = this;}// Use this for initializationvoid Start () {for(int x = 0; x < xColumn; x++){for (int y=0;y<yRow;y++){GameObject chocolate = Instantiate(gridPrefab,CorrectPosition(x,y),Quaternion.identity);chocolate.transform.SetParent(transform);}}}// Update is called once per framevoid Update () {}public Vector3 CorrectPosition(int x ,int y){//实际需要实例化巧克力的X位置 = GameManager位置的X坐标-大网格长度的一半+行列对应的X坐标// 实际需要实例化巧克力的Y位置 = GameManager位置的Y坐标-大网格长度的一半+行列对应的Y坐标return new Vector3(transform.position.x-xColumn/2f+x,transform.position.y+yRow/2f-y);}}
GameManager.cs
甜品的类型枚举,结构体,字典的创建
甜品的种类
public enum SweetsType{EMPTY,NORMAL,BARRIER,ROE_CLEAR,COLUMN_CLEAR,RAINBOWCANDY,COUNT //标记类型}
甜品预制体的字典,我们可以通过甜品的种类来得到对应的甜品游戏物体
public Dictionary<SweetsType, GameObject> sweetPrefabDict;[System.Serializable]public struct SweetPrefab{public SweetsType type;public GameObject prefab;}public SweetPrefab[] sweetPrefabs;
字典的实例化
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].prefab);}}
甜品的生成
甜品数组
private GameObject[,] sweets;
void Start () {//字典的实例化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].prefab);}}for(int x = 0; x < xColumn; x++){for (int y=0;y<yRow;y++){GameObject chocolate = Instantiate(gridPrefab,CorrectPosition(x,y),Quaternion.identity);chocolate.transform.SetParent(transform);}}sweets = new GameObject[xColumn, yRow];for (int x = 0; x < xColumn; x++){for (int y = 0; y < yRow; y++){sweets[x,y] = Instantiate(sweetPrefabDict[SweetsType.NORMAL], CorrectPosition(x, y), Quaternion.identity);sweets[x,y].transform.SetParent(transform);}}}
using System.Collections; using System.Collections.Generic; using UnityEngine;public class GameSweet : MonoBehaviour {private int x;public int X{get{return x;}set{x = value;}}private int y;public int Y{get{return y;}set{y = value;}}private GameManager.SweetsType type;public GameManager.SweetsType Type{get{return type;}}public GameManager gameManager;public void Init(int _x,int _y,GameManager _gameManager,GameManager.SweetsType _type){x = _x;y = _y;gameManager = _gameManager;type = _type;}}
GameSweet.cs 管理甜甜圈脚本
using System.Collections; using System.Collections.Generic; using UnityEngine;public class GameManager : MonoBehaviour {//甜品的种类public enum SweetsType{EMPTY,NORMAL,BARRIER,ROE_CLEAR,COLUMN_CLEAR,RAINBOWCANDY,COUNT //标记类型 }//甜品预制体的字典,我们可以通过甜品的种类来得到对应的甜品游戏物体public Dictionary<SweetsType, GameObject> sweetPrefabDict;[System.Serializable]public struct SweetPrefab{public SweetsType type;public GameObject prefab;}public SweetPrefab[] sweetPrefabs;//单例实例化private static GameManager _instance;public static GameManager Instance{get{return _instance;}set{_instance = value;}}//大网格的行列数public int xColumn;public int yRow;public GameObject gridPrefab;//甜品数组private GameSweet[,] sweets;private void Awake(){_instance = this;}// Use this for initializationvoid Start () {//字典的实例化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].prefab);}}for(int x = 0; x < xColumn; x++){for (int y=0;y<yRow;y++){GameObject chocolate = Instantiate(gridPrefab,CorrectPosition(x,y),Quaternion.identity);chocolate.transform.SetParent(transform);}}sweets = new GameSweet[xColumn, yRow];for (int x = 0; x < xColumn; x++){for (int y = 0; y < yRow; y++){GameObject newSweet = Instantiate(sweetPrefabDict[SweetsType.NORMAL], CorrectPosition(x, y), Quaternion.identity);newSweet.transform.SetParent(transform);sweets[x,y] = newSweet.GetComponent<GameSweet>();sweets[x, y].Init(x, y, this, SweetsType.NORMAL);}}}// Update is called once per framevoid Update () {}public Vector3 CorrectPosition(int x ,int y){//实际需要实例化巧克力的X位置 = GameManager位置的X坐标-大网格长度的一半+行列对应的X坐标// 实际需要实例化巧克力的Y位置 = GameManager位置的Y坐标-大网格长度的一半+行列对应的Y坐标return new Vector3(transform.position.x-xColumn/2f+x,transform.position.y+yRow/2f-y);}}
GameManager.cs
甜品移动
添加甜品移动脚本
using System.Collections; using System.Collections.Generic; using UnityEngine;public class MovedSweet : MonoBehaviour {private GameSweet sweet;private void Awake(){sweet = GetComponent<GameSweet>();}public void Move(int newX,int newY){sweet.X = newX;sweet.Y = newY;sweet.transform.localPosition = sweet.gameManager.CorrectPosition(newX, newY);} }
MovedSweet.cs
using System.Collections; using System.Collections.Generic; using UnityEngine;public class GameSweet : MonoBehaviour {private int x;private int y;public int X{get{return x;}set{if (CanMove()){x = value;}}}public int Y{get{return y;}set{if (CanMove()){y = value;}}}private GameManager.SweetsType type;public GameManager.SweetsType Type{get{return type;}}[HideInInspector]public GameManager gameManager;public MovedSweet MovedComponet{get{return movedComponet;}}private MovedSweet movedComponet;//判断甜品是否可以移动public bool CanMove(){return movedComponet != null;}public void Init(int _x,int _y,GameManager _gameManager,GameManager.SweetsType _type){x = _x;y = _y;gameManager = _gameManager;type = _type;}}
GameSweet.cs
判断甜品是否可以移动
public bool CanMove(){return movedComponet != null;}
private int x;private int y;public int X{get{return x;}set{if (CanMove()){x = value;}}}public int Y{get{return y;}set{if (CanMove()){y = value;}}}
移动的测试
测试甜品移动到Vector.zero位置处
using System.Collections; using System.Collections.Generic; using UnityEngine;public class MovedSweet : MonoBehaviour {private GameSweet sweet;private void Awake(){sweet = GetComponent<GameSweet>();}public void Move(int newX,int newY){sweet.X = newX;sweet.Y = newY;sweet.transform.localPosition = sweet.gameManager.CorrectPosition(newX, newY);} }
MovedSweet.cs
using System.Collections; using System.Collections.Generic; using UnityEngine;public class GameSweet : MonoBehaviour {private int x;private int y;public int X{get{return x;}set{if (CanMove()){x = value;}}}public int Y{get{return y;}set{if (CanMove()){y = value;}}}private GameManager.SweetsType type;public GameManager.SweetsType Type{get{return type;}}[HideInInspector]public GameManager gameManager;public MovedSweet MovedComponet{get{return movedComponet;}}private MovedSweet movedComponet;//判断甜品是否可以移动public bool CanMove(){return movedComponet != null;}private void Awake(){movedComponet = GetComponent<MovedSweet>();}public void Init(int _x,int _y,GameManager _gameManager,GameManager.SweetsType _type){x = _x;y = _y;gameManager = _gameManager;type = _type;}}
GameSweet.cs
using System.Collections; using System.Collections.Generic; using UnityEngine;public class GameManager : MonoBehaviour {//甜品的种类public enum SweetsType{EMPTY,NORMAL,BARRIER,ROE_CLEAR,COLUMN_CLEAR,RAINBOWCANDY,COUNT //标记类型 }//甜品预制体的字典,我们可以通过甜品的种类来得到对应的甜品游戏物体public Dictionary<SweetsType, GameObject> sweetPrefabDict;[System.Serializable]public struct SweetPrefab{public SweetsType type;public GameObject prefab;}public SweetPrefab[] sweetPrefabs;//单例实例化private static GameManager _instance;public static GameManager Instance{get{return _instance;}set{_instance = value;}}//大网格的行列数public int xColumn;public int yRow;public GameObject gridPrefab;//甜品数组private GameSweet[,] sweets;private void Awake(){_instance = this;}// Use this for initializationvoid Start () {//字典的实例化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].prefab);}}for(int x = 0; x < xColumn; x++){for (int y=0;y<yRow;y++){GameObject chocolate = Instantiate(gridPrefab,CorrectPosition(x,y),Quaternion.identity);chocolate.transform.SetParent(transform);}}sweets = new GameSweet[xColumn, yRow];for (int x = 0; x < xColumn; x++){for (int y = 0; y < yRow; y++){// CorrectPosition(x, y)GameObject newSweet = Instantiate(sweetPrefabDict[SweetsType.NORMAL],Vector3.zero,Quaternion.identity);newSweet.transform.SetParent(transform);sweets[x,y] = newSweet.GetComponent<GameSweet>();sweets[x, y].Init(x, y, this, SweetsType.NORMAL);// if (sweets[x, y].CanMove())//{// sweets[x, y].MovedComponet.Move();// } }}}// Update is called once per framevoid Update () {}public Vector3 CorrectPosition(int x ,int y){//实际需要实例化巧克力的X位置 = GameManager位置的X坐标-大网格长度的一半+行列对应的X坐标// 实际需要实例化巧克力的Y位置 = GameManager位置的Y坐标-大网格长度的一半+行列对应的Y坐标return new Vector3(transform.position.x-xColumn/2f+x,transform.position.y+yRow/2f-y);}}
GameManager.cs
甜品颜色
添加脚本颜色脚本ColorSweet.cs
通过更改Sweet下的Sprite来更改甜品的种类
using System.Collections; using System.Collections.Generic; using UnityEngine;public class ColorSweet : MonoBehaviour {public enum ColorType{YELLOW,PUPLE,RED,BLUE,GREEN,PNGK,ANY,COUNT}[System.Serializable]public struct ColorSprite{public ColorType color;public Sprite sprite;}public ColorSprite[] colorSprites;private Dictionary<ColorType, Sprite> colorSpriteDict; }
ColorSweet.cs
public enum ColorType{YELLOW,PUPLE,RED,BLUE,GREEN,PNGK,ANY,COUNT}
每一种颜色对应一种甜品类型
using System.Collections; using System.Collections.Generic; using UnityEngine;public class GameManager : MonoBehaviour {//甜品的种类public enum SweetsType{EMPTY,NORMAL,BARRIER,ROE_CLEAR,COLUMN_CLEAR,RAINBOWCANDY,COUNT //标记类型 }//甜品预制体的字典,我们可以通过甜品的种类来得到对应的甜品游戏物体public Dictionary<SweetsType, GameObject> sweetPrefabDict;[System.Serializable]public struct SweetPrefab{public SweetsType type;public GameObject prefab;}public SweetPrefab[] sweetPrefabs;//单例实例化private static GameManager _instance;public static GameManager Instance{get{return _instance;}set{_instance = value;}}//大网格的行列数public int xColumn;public int yRow;public GameObject gridPrefab;//甜品数组private GameSweet[,] sweets;private void Awake(){_instance = this;}// Use this for initializationvoid Start () {//字典的实例化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].prefab);}}for(int x = 0; x < xColumn; x++){for (int y=0;y<yRow;y++){GameObject chocolate = Instantiate(gridPrefab,CorrectPosition(x,y),Quaternion.identity);chocolate.transform.SetParent(transform);}}sweets = new GameSweet[xColumn, yRow];for (int x = 0; x < xColumn; x++){for (int y = 0; y < yRow; y++){// CorrectPosition(x, y)GameObject newSweet = Instantiate(sweetPrefabDict[SweetsType.NORMAL],Vector3.zero,Quaternion.identity);newSweet.transform.SetParent(transform);sweets[x,y] = newSweet.GetComponent<GameSweet>();sweets[x, y].Init(x, y, this, SweetsType.NORMAL);if (sweets[x, y].CanMove()){sweets[x, y].MovedComponet.Move(x,y);}if (sweets[x, y].CanColor()){sweets[x, y].ColorComponet.SetColor((ColorSweet.ColorType)(Random.Range(0, sweets[x, y].ColorComponet.NumColors)));}}}}// Update is called once per framevoid Update () {}public Vector3 CorrectPosition(int x ,int y){//实际需要实例化巧克力的X位置 = GameManager位置的X坐标-大网格长度的一半+行列对应的X坐标// 实际需要实例化巧克力的Y位置 = GameManager位置的Y坐标-大网格长度的一半+行列对应的Y坐标return new Vector3(transform.position.x-xColumn/2f+x,transform.position.y+yRow/2f-y);}}
GameManager.cs
当甜品可以移动时,甜品可以进行移动
if (sweets[x, y].CanMove()){sweets[x, y].MovedComponet.Move(x,y);}
当甜品存在颜色使填充随机色
if (sweets[x, y].CanColor()){sweets[x, y].ColorComponet.SetColor((ColorSweet.ColorType)(Random.Range(0, sweets[x, y].ColorComponet.NumColors)));}
sweets = new GameSweet[xColumn, yRow];for (int x = 0; x < xColumn; x++){for (int y = 0; y < yRow; y++){// CorrectPosition(x, y)GameObject newSweet = Instantiate(sweetPrefabDict[SweetsType.NORMAL],Vector3.zero,Quaternion.identity);newSweet.transform.SetParent(transform);sweets[x,y] = newSweet.GetComponent<GameSweet>();sweets[x, y].Init(x, y, this, SweetsType.NORMAL);//当甜品可以移动时,甜品可以进行移动if (sweets[x, y].CanMove()){sweets[x, y].MovedComponet.Move(x,y);}//当甜品存在颜色使填充随机色if (sweets[x, y].CanColor()){sweets[x, y].ColorComponet.SetColor((ColorSweet.ColorType)(Random.Range(0, sweets[x, y].ColorComponet.NumColors)));}}}
空甜品的生成
创建空游戏物体预制体
产生甜品的方法
public GameSweet CreateNewSweet(int x,int y,SweetsType type){GameObject newSweet = 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];}
void Start () {//字典的实例化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].prefab);}}for(int x = 0; x < xColumn; x++){for (int y=0;y<yRow;y++){GameObject chocolate = Instantiate(gridPrefab,CorrectPosition(x,y),Quaternion.identity);chocolate.transform.SetParent(transform);}}sweets = new GameSweet[xColumn, yRow];for (int x = 0; x < xColumn; x++){for (int y = 0; y < yRow; y++){CreateNewSweet(x, y, SweetsType.EMPTY);}}}
填充核心算法
填充全部甜品的方法
public void AllFill(){while (Fill()){}}
当甜品填充满时返回true
public bool Fill(){bool FilledNotFinshed = false; //用来判断本次是否完成//行遍历for(int y=yRow-2;y>=0;y--){for(int x=0;x<xColumn;x++){GameSweet sweet = sweets[x, y]; //得到当前元素位置//如果无法移动,则无法往下填充if (sweet.CanMove()){GameSweet sweetBelow = sweets[x, y + 1]; if(sweetBelow.Type == SweetsType.EMPTY){sweet.MovedComponet.Move(x,y+1);sweets[x, y + 1] = sweet;CreateNewSweet(x, y, SweetsType.EMPTY);FilledNotFinshed = true;}}}}//最上排的特殊情况for (int x = 0; x < xColumn; x++){GameSweet sweet = sweets[x, 0];if(sweet.Type == SweetsType.EMPTY){GameObject newSweet = 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);sweets[x, 0].ColorComponet.SetColor((ColorSweet.ColorType)Random.Range(0,sweets[x,0].ColorComponet.NumColors));FilledNotFinshed = true; }}return FilledNotFinshed;}
在Start()中调用 AllFill()方法
void Start() {//字典的实例化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].prefab);}}for(int x = 0; x < xColumn; x++){for (int y=0;y<yRow;y++){GameObject chocolate = Instantiate(gridPrefab,CorrectPosition(x,y),Quaternion.identity);chocolate.transform.SetParent(transform);}}sweets = new GameSweet[xColumn, yRow];for (int x = 0; x < xColumn; x++){for (int y = 0; y < yRow; y++){CreateNewSweet(x, y, SweetsType.EMPTY);}}AllFill();}
using System.Collections; using System.Collections.Generic; using UnityEngine;public class GameManager : MonoBehaviour {//甜品的种类public enum SweetsType{EMPTY,NORMAL,BARRIER,ROE_CLEAR,COLUMN_CLEAR,RAINBOWCANDY,COUNT //标记类型 }//甜品预制体的字典,我们可以通过甜品的种类来得到对应的甜品游戏物体public Dictionary<SweetsType, GameObject> sweetPrefabDict;[System.Serializable]public struct SweetPrefab{public SweetsType type;public GameObject prefab;}public SweetPrefab[] sweetPrefabs;//单例实例化private static GameManager _instance;public static GameManager Instance{get{return _instance;}set{_instance = value;}}//大网格的行列数public int xColumn;public int yRow;public GameObject gridPrefab;//甜品数组private GameSweet[,] sweets;private void Awake(){_instance = this;}// Use this for initializationvoid Start() {//字典的实例化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].prefab);}}for(int x = 0; x < xColumn; x++){for (int y=0;y<yRow;y++){GameObject chocolate = Instantiate(gridPrefab,CorrectPosition(x,y),Quaternion.identity);chocolate.transform.SetParent(transform);}}sweets = new GameSweet[xColumn, yRow];for (int x = 0; x < xColumn; x++){for (int y = 0; y < yRow; y++){CreateNewSweet(x, y, SweetsType.EMPTY);}}AllFill();}// Update is called once per framevoid Update () {}public Vector3 CorrectPosition(int x ,int y){//实际需要实例化巧克力的X位置 = GameManager位置的X坐标-大网格长度的一半+行列对应的X坐标// 实际需要实例化巧克力的Y位置 = GameManager位置的Y坐标-大网格长度的一半+行列对应的Y坐标return new Vector3(transform.position.x-xColumn/2f+x,transform.position.y+yRow/2f-y);}//产生甜品的方法public GameSweet CreateNewSweet(int x,int y,SweetsType type){GameObject newSweet = 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 void AllFill(){while (Fill()){}}public bool Fill(){bool FilledNotFinshed = false; //用来判断本次是否完成//行遍历for(int y=yRow-2;y>=0;y--){for(int x=0;x<xColumn;x++){GameSweet sweet = sweets[x, y]; //得到当前元素位置//如果无法移动,则无法往下填充if (sweet.CanMove()){GameSweet sweetBelow = sweets[x, y + 1]; if(sweetBelow.Type == SweetsType.EMPTY){sweet.MovedComponet.Move(x,y+1);sweets[x, y + 1] = sweet;CreateNewSweet(x, y, SweetsType.EMPTY);FilledNotFinshed = true;}}}}//最上排的特殊情况for (int x = 0; x < xColumn; x++){GameSweet sweet = sweets[x, 0];if(sweet.Type == SweetsType.EMPTY){GameObject newSweet = 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);sweets[x, 0].ColorComponet.SetColor((ColorSweet.ColorType)Random.Range(0,sweets[x,0].ColorComponet.NumColors));FilledNotFinshed = true; }}return FilledNotFinshed;} }
GameManager.cs
为了使游戏填充时间肉眼速度看得见,添加移动填充协成
移动填充的协成
填充时间
public float fillTime;
填充甜品的方法
public IEnumerator AllFill(){while (Fill()){yield return new WaitForSeconds(fillTime);}}
void Start() {//字典的实例化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].prefab);}}for(int x = 0; x < xColumn; x++){for (int y=0;y<yRow;y++){GameObject chocolate = Instantiate(gridPrefab,CorrectPosition(x,y),Quaternion.identity);chocolate.transform.SetParent(transform);}}sweets = new GameSweet[xColumn, yRow];for (int x = 0; x < xColumn; x++){for (int y = 0; y < yRow; y++){CreateNewSweet(x, y, SweetsType.EMPTY);}}StartCoroutine(AllFill());}
此时出场动画会出现卡顿现象,通过修改MovedSweet.cs脚本添加协成
使每一帧都会进行出场动画
using System.Collections; using System.Collections.Generic; using UnityEngine;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;} }
MovedSweet.cs
开启或者结束一个协成
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;}
public bool Fill(){bool FilledNotFinshed = false; //用来判断本次是否完成//行遍历for(int y=yRow-2;y>=0;y--){for(int x=0;x<xColumn;x++){GameSweet sweet = sweets[x, y]; //得到当前元素位置//如果无法移动,则无法往下填充if (sweet.CanMove()){GameSweet sweetBelow = sweets[x, y + 1]; if(sweetBelow.Type == SweetsType.EMPTY){sweet.MovedComponet.Move(x,y+1,fillTime);sweets[x, y + 1] = sweet;CreateNewSweet(x, y, SweetsType.EMPTY);FilledNotFinshed = true;}}}}//最上排的特殊情况for (int x = 0; x < xColumn; x++){GameSweet sweet = sweets[x, 0];if(sweet.Type == SweetsType.EMPTY){GameObject newSweet = 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);sweets[x, 0].ColorComponet.SetColor((ColorSweet.ColorType)Random.Range(0,sweets[x,0].ColorComponet.NumColors));FilledNotFinshed = true; }}return FilledNotFinshed;}
障碍物_饼干
制作饼干预制体
void Start() {//字典的实例化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].prefab);}}for(int x = 0; x < xColumn; x++){for (int y=0;y<yRow;y++){GameObject chocolate = Instantiate(gridPrefab,CorrectPosition(x,y),Quaternion.identity);chocolate.transform.SetParent(transform);}}sweets = new GameSweet[xColumn, yRow];for (int x = 0; x < xColumn; x++){for (int y = 0; y < yRow; y++){CreateNewSweet(x, y, SweetsType.EMPTY);}}//在(4,4)这个坐标点生成障碍物Destroy(sweets[4, 4].gameObject);CreateNewSweet(4,4,SweetsType.BARRIER);StartCoroutine(AllFill());}
斜向填充算法
如果无法移动,其它甜品则无法往下填充
public bool Fill(){bool FilledNotFinshed = false; //用来判断本次是否完成//行遍历for(int y=yRow-2;y>=0;y--){for(int x=0;x<xColumn;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);FilledNotFinshed = true;}else{//-1代表左,1代表右for (int down = -1; down <= 1; down++){if (down != 0){int downX = x + down;//排除边界的时候//左下方if (downX >= 0 && downX < xColumn){GameSweet downSweet = sweets[downX, y + 1];if (downSweet.Type == SweetsType.EMPTY){bool canfill = true; //用来判断垂直填充是否可以满足填充要求for (int aboutY = y; aboutY >= 0; aboutY--){GameSweet sweetAbove = sweets[downX, aboutY];if (sweetAbove.CanMove()){break;}else if (!sweetAbove.CanMove() && sweetAbove.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);FilledNotFinshed = true;break;}}}}}}}}}//最上排的特殊情况for (int x = 0; x < xColumn; x++){GameSweet sweet = sweets[x, 0];if(sweet.Type == SweetsType.EMPTY){GameObject newSweet = 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);sweets[x, 0].ColorComponet.SetColor((ColorSweet.ColorType)Random.Range(0,sweets[x,0].ColorComponet.NumColors));FilledNotFinshed = true; }}return FilledNotFinshed;}
using System.Collections; using System.Collections.Generic; using UnityEngine;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;} }
MovedSweet.cs
using System.Collections; using System.Collections.Generic; using UnityEngine;public class ColorSweet : MonoBehaviour {public enum ColorType{YELLOW,PUPLE,RED,BLUE,GREEN,PNGK,ANY,COUNT}[System.Serializable]public struct ColorSprite{public ColorType color;public Sprite sprite;}public ColorSprite[] ColorSprites;private Dictionary<ColorType, Sprite> colorSpriteDict;private SpriteRenderer sprite;public int NumColors{get{ return ColorSprites.Length; }}public ColorType Color{get{return color;}set{SetColor(value);}}private ColorType color;public 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];}}}
ColorSweet.cs
using System.Collections; using System.Collections.Generic; using UnityEngine;public class GameSweet : MonoBehaviour {private int x;private int y;public int X{get{return x;}set{if (CanMove()){x = value;}}}public int Y{get{return y;}set{if (CanMove()){y = value;}}}private GameManager.SweetsType type;public GameManager.SweetsType Type{get{return type;}}[HideInInspector]public GameManager gameManager;public MovedSweet MovedComponet{get{return movedComponet;}}private MovedSweet movedComponet;public ColorSweet ColorComponet{get{return coloredCompent;}}private ColorSweet coloredCompent;//判断甜品是否可以移动public bool CanMove(){return movedComponet != null;}//判断是否可以着色public bool CanColor(){return coloredCompent != null;}private void Awake(){movedComponet = GetComponent<MovedSweet>();coloredCompent = GetComponent<ColorSweet>();}public void Init(int _x,int _y,GameManager _gameManager,GameManager.SweetsType _type){x = _x;y = _y;gameManager = _gameManager;type = _type;}}
GameSweet.cs
using System.Collections; using System.Collections.Generic; using UnityEngine;public class GameManager : MonoBehaviour {//甜品的种类public enum SweetsType{EMPTY,NORMAL,BARRIER,ROE_CLEAR,COLUMN_CLEAR,RAINBOWCANDY,COUNT //标记类型 }//甜品预制体的字典,我们可以通过甜品的种类来得到对应的甜品游戏物体public Dictionary<SweetsType, GameObject> sweetPrefabDict;[System.Serializable]public struct SweetPrefab{public SweetsType type;public GameObject prefab;}public SweetPrefab[] sweetPrefabs;//单例实例化private static GameManager _instance;public static GameManager Instance{get{return _instance;}set{_instance = value;}}//大网格的行列数public int xColumn;public int yRow;//填充时间public float fillTime;public GameObject gridPrefab;//甜品数组private GameSweet[,] sweets;private void Awake(){_instance = this;}// Use this for initializationvoid Start() {//字典的实例化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].prefab);}}for(int x = 0; x < xColumn; x++){for (int y=0;y<yRow;y++){GameObject chocolate = Instantiate(gridPrefab,CorrectPosition(x,y),Quaternion.identity);chocolate.transform.SetParent(transform);}}sweets = new GameSweet[xColumn, yRow];for (int x = 0; x < xColumn; x++){for (int y = 0; y < yRow; y++){CreateNewSweet(x, y, SweetsType.EMPTY);}}//在(4,4)这个坐标点生成障碍物Destroy(sweets[4, 4].gameObject);CreateNewSweet(4,4,SweetsType.BARRIER);StartCoroutine(AllFill());}// Update is called once per framevoid Update () {}public Vector3 CorrectPosition(int x ,int y){//实际需要实例化巧克力的X位置 = GameManager位置的X坐标-大网格长度的一半+行列对应的X坐标// 实际需要实例化巧克力的Y位置 = GameManager位置的Y坐标-大网格长度的一半+行列对应的Y坐标return new Vector3(transform.position.x-xColumn/2f+x,transform.position.y+yRow/2f-y);}//产生甜品的方法public GameSweet CreateNewSweet(int x,int y,SweetsType type){GameObject newSweet = 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(){while (Fill()){yield return new WaitForSeconds(fillTime);}}public bool Fill(){bool FilledNotFinshed = false; //用来判断本次是否完成//行遍历for(int y=yRow-2;y>=0;y--){for(int x=0;x<xColumn;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);FilledNotFinshed = true;}else{//-1代表左,1代表右for (int down = -1; down <= 1; down++){if (down != 0){int downX = x + down;//排除边界的时候//左下方if (downX >= 0 && downX < xColumn){GameSweet downSweet = sweets[downX, y + 1];if (downSweet.Type == SweetsType.EMPTY){bool canfill = true; //用来判断垂直填充是否可以满足填充要求for (int aboutY = y; aboutY >= 0; aboutY--){GameSweet sweetAbove = sweets[downX, aboutY];if (sweetAbove.CanMove()){break;}else if (!sweetAbove.CanMove() && sweetAbove.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);FilledNotFinshed = true;break;}}}}}}}}}//最上排的特殊情况for (int x = 0; x < xColumn; x++){GameSweet sweet = sweets[x, 0];if(sweet.Type == SweetsType.EMPTY){GameObject newSweet = 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);sweets[x, 0].ColorComponet.SetColor((ColorSweet.ColorType)Random.Range(0,sweets[x,0].ColorComponet.NumColors));FilledNotFinshed = true; }}return FilledNotFinshed;} }
GameManager.cs
转载于:https://www.cnblogs.com/1138720556Gary/p/9568817.html
Unity3D_(游戏)甜品消消乐01_游戏基础界面相关推荐
- 乐游游戏盒计算机丢失,乐游游戏盒子加载不出来怎么办
乐游游戏盒子加载不出来怎么办?最近有很多玩家都对此有所疑问,今天安致小编为大家带来了乐游游戏盒子加载不出来解决方法,感兴趣的玩家赶紧来安致网看看吧. 乐游游戏盒子加载不出来解决方法 1.显卡问题,我碰 ...
- 泽诺尼亚传奇3开启乐逗游戏与GAMEVIL合作大门
近日,由GAMEVIL制作的RPG大作游戏<ZENONIA™3>于中国正式推出了官方汉化版,该游戏交由国内游戏发行商乐逗游戏发行.游戏中文名为<泽诺尼亚传奇3>,此次汉化由GA ...
- Unity 3D游戏-消消乐(三消类)教程和源码
Unity 消消乐教程和源码 本文提供全流程,中文翻译. Chinar坚持将简单的生活方式,带给世人! (拥有更好的阅读体验 -- 高分辨率用户请根据需求调整网页缩放比例) 1 Start Game ...
- 猜猜乐游戏php源码,C/C++百行代码实现热门游戏消消乐功能的示例代码
游戏设计 首先我们需要使用第三方框架,这里我使用的是sfml,不会使用sfml在我的上几篇文章当中-扫雷(上)有详细的开发环境搭建介绍 首先准备图片资源 一张背景图片,一张宝石图片 窗口初始化加载图片 ...
- python编程游戏手机版_利用Python开发手机同款游戏:开心消消乐
手机上面的开心消消乐,我想大部分人都是玩过的吧,今天小编就教大家如何用python开发这款游戏 不过只有十个关卡,不像手机里面那么多的关卡!不过游戏的画面和bgm都是同款的哦~ 效果图 基本配置 wi ...
- android飞翔的小鸟游戏素材包_开心消消乐×愤怒的小鸟:为开心而战
手机里总有那么一些游戏,是你一旦不小心打开,就完全停不下来的.在这份"一直玩一直爽游戏清单"里,绝对少不了开心消消乐和愤怒的小鸟的身影. 神奇的是,在2020的夏天,它们合体了!在 ...
- 疯狂动物消消乐html5游戏在线玩,疯狂动物消消乐免费
疯狂动物消消乐免费版这是一个移动端休闲益智手游,疯狂动物消消乐免费版主打消除了玩法,在疯狂动物消消乐免费版游戏当中玩家要经过种种形式移动游戏当中元素来到达相同种类消除了成功的目的. 游戏介绍 疯狂动物 ...
- java开心消消乐代码_Vue实现开心消消乐游戏算法
摘要:这篇Vue栏目下的"Vue实现开心消消乐游戏算法",介绍的技术点是"开心消消乐.Vue.开心.游戏.算法.实现",希望对大家开发技术学习和问题解决有帮助. ...
- 消消乐实现下坠_手把手教你如何实现iOS消消乐小游戏Demo
引言 做消消乐Demo属于一个意外,本想借助学习iOS游戏开发把CoreAnimation学好,并完成第一个游戏Demo:俄罗斯方块.却在这过程中发现了一些实现消消乐的小技巧,于是兴起完成了这个小De ...
最新文章
- firewall添加白名单_firewall的规则设置与命令(白名单设置)
- 职责链模式应用——下机(机房重构知识点总结)
- 详解string容器(应用+模拟实现,string练习题)
- 简述什么是SQL注入,写出简单的SQL注入语句。
- 【OSPF引入直连路由时巧借静态黑洞路由做汇总】
- Unity开发 Photon Pun 多人游戏组件
- cad计算路网密度加调整路线
- 微信“小程序”要来了,简单点,解释的方式简单点
- 【ESP 保姆级教程】疯狂传感器篇 —— 案例:ESP8266 + BH1750 + webserver(局域网内查看曲线变化图)
- 计算机二级考试应用与分值,计算机二级考试题型及分值
- SkyWalking8.4监控跨线程问题解决
- Visual Studio 2019重新安装问题
- Unity家园系统---建筑交互
- 探究L298N模块烧毁的原因
- 掌握一种基本图形元素光栅化算法,利用OpenGL实现直线光栅化的DDA算法。
- Ubuntu 18.04 安装 GeForce RTX 3080
- 访问www.baidu.com完整过程
- 连亏三年!贝壳找房在纽交所上市,市值233亿美元
- FTP服务器架设教程之管理篇
- 【稀饭】react native 实战系列教程之完成首页