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

Unity 消消乐教程和源码


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

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

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




1

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


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

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

举个栗子黑白88

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 —— 游戏总控类脚本


控制游戏所有逻辑的实现

举个栗子黑白88

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 —— 物品基础脚本


控制物品的属性

举个栗子黑白88

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 —— 控制物体的移动


控制物体的移动是否可行

举个栗子黑白88

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 —— 清除管控类脚本


控制物品是否可以被清除

举个栗子黑白88

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 —— 清除颜色相同的物品


举个栗子黑白88

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 —— 颜色脚本


管理物品颜色的脚本

举个栗子黑白88

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学院
举个栗子黑白88

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 服务器配置、运行、建站一条龙 !





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


END

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

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

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

原文地址:https://www.cnblogs.com/chinarbolg/p/9601470.html