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

简介: Unity 消消乐教程和源码本文提供全流程,中文翻译。Chinar坚持将简单的生活方式,带给世人!(拥有更好的阅读体验 —— 高分辨率用户请根据需求调整网页缩放比例)...

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





Chinar


相关文章
|
3月前
|
图形学 C#
超实用!深度解析Unity引擎,手把手教你从零开始构建精美的2D平面冒险游戏,涵盖资源导入、角色控制与动画、碰撞检测等核心技巧,打造沉浸式游戏体验完全指南
【8月更文挑战第31天】本文是 Unity 2D 游戏开发的全面指南,手把手教你从零开始构建精美的平面冒险游戏。首先,通过 Unity Hub 创建 2D 项目并导入游戏资源。接着,编写 `PlayerController` 脚本来实现角色移动,并添加动画以增强视觉效果。最后,通过 Collider 2D 组件实现碰撞检测等游戏机制。每一步均展示 Unity 在 2D 游戏开发中的强大功能。
172 6
|
2月前
|
测试技术 C# 图形学
掌握Unity调试与测试的终极指南:从内置调试工具到自动化测试框架,全方位保障游戏品质不踩坑,打造流畅游戏体验的必备技能大揭秘!
【9月更文挑战第1天】在开发游戏时,Unity 引擎让创意变为现实。但软件开发中难免遇到 Bug,若不解决,将严重影响用户体验。调试与测试成为确保游戏质量的最后一道防线。本文介绍如何利用 Unity 的调试工具高效排查问题,并通过 Profiler 分析性能瓶颈。此外,Unity Test Framework 支持自动化测试,提高开发效率。结合单元测试与集成测试,确保游戏逻辑正确无误。对于在线游戏,还需进行压力测试以验证服务器稳定性。总之,调试与测试贯穿游戏开发全流程,确保最终作品既好玩又稳定。
98 4
|
3月前
|
图形学 缓存 算法
掌握这五大绝招,让您的Unity游戏瞬间加载完毕,从此告别漫长等待,大幅提升玩家首次体验的满意度与留存率!
【8月更文挑战第31天】游戏的加载时间是影响玩家初次体验的关键因素,特别是在移动设备上。本文介绍了几种常见的Unity游戏加载优化方法,包括资源的预加载与异步加载、使用AssetBundles管理动态资源、纹理和模型优化、合理利用缓存系统以及脚本优化。通过具体示例代码展示了如何实现异步加载场景,并提出了针对不同资源的优化策略。综合运用这些技术可以显著缩短加载时间,提升玩家满意度。
136 5
|
2月前
|
前端开发 图形学 开发者
【独家揭秘】那些让你的游戏瞬间鲜活起来的Unity UI动画技巧:从零开始打造动态按钮,提升玩家交互体验的绝招大公开!
【9月更文挑战第1天】在游戏开发领域,Unity 是最受欢迎的游戏引擎之一,其强大的跨平台发布能力和丰富的功能集让开发者能够迅速打造出高质量的游戏。优秀的 UI 设计对于游戏至关重要,尤其是在手游市场,出色的 UI 能给玩家留下深刻的第一印象。Unity 的 UGUI 系统提供了一整套解决方案,包括 Canvas、Image 和 Button 等组件,支持添加各种动画效果。
132 3
|
2月前
|
设计模式 存储 人工智能
深度解析Unity游戏开发:从零构建可扩展与可维护的游戏架构,让你的游戏项目在模块化设计、脚本对象运用及状态模式处理中焕发新生,实现高效迭代与团队协作的完美平衡之路
【9月更文挑战第1天】游戏开发中的架构设计是项目成功的关键。良好的架构能提升开发效率并确保项目的长期可维护性和可扩展性。在使用Unity引擎时,合理的架构尤为重要。本文探讨了如何在Unity中实现可扩展且易维护的游戏架构,包括模块化设计、使用脚本对象管理数据、应用设计模式(如状态模式)及采用MVC/MVVM架构模式。通过这些方法,可以显著提高开发效率和游戏质量。例如,模块化设计将游戏拆分为独立模块。
180 3
|
3月前
|
图形学 开发者 存储
超越基础教程:深度拆解Unity地形编辑器的每一个隐藏角落,让你的游戏世界既浩瀚无垠又细节满满——从新手到高手的全面技巧升级秘籍
【8月更文挑战第31天】Unity地形编辑器是游戏开发中的重要工具,可快速创建复杂多变的游戏环境。本文通过比较不同地形编辑技术,详细介绍如何利用其功能构建广阔且精细的游戏世界,并提供具体示例代码,展示从基础地形绘制到植被与纹理添加的全过程。通过学习这些技巧,开发者能显著提升游戏画面质量和玩家体验。
147 3
|
2月前
|
图形学 C++ C#
Unity插件开发全攻略:从零起步教你用C++扩展游戏功能,解锁Unity新玩法的详细步骤与实战技巧大公开
【8月更文挑战第31天】Unity 是一款功能强大的游戏开发引擎,支持多平台发布并拥有丰富的插件生态系统。本文介绍 Unity 插件开发基础,帮助读者从零开始编写自定义插件以扩展其功能。插件通常用 C++ 编写,通过 Mono C# 运行时调用,需在不同平台上编译。文中详细讲解了开发环境搭建、简单插件编写及在 Unity 中调用的方法,包括创建 C# 封装脚本和处理跨平台问题,助力开发者提升游戏开发效率。
200 0
|
2月前
|
vr&ar 图形学 API
Unity与VR控制器交互全解:从基础配置到力反馈应用,多角度提升虚拟现实游戏的真实感与沉浸体验大揭秘
【8月更文挑战第31天】虚拟现实(VR)技术迅猛发展,Unity作为主流游戏开发引擎,支持多种VR硬件并提供丰富的API,尤其在VR控制器交互设计上具备高度灵活性。本文详细介绍了如何在Unity中配置VR支持、设置控制器、实现按钮交互及力反馈,结合碰撞检测和物理引擎提升真实感,助力开发者创造沉浸式体验。
147 0
|
2月前
|
图形学 开发者
【独家揭秘】Unity游戏开发秘籍:从基础到进阶,掌握材质与纹理的艺术,打造超现实游戏视效的全过程剖析——案例教你如何让每一面墙都会“说话”
【8月更文挑战第31天】Unity 是全球领先的跨平台游戏开发引擎,以其高效性能和丰富的工具集著称,尤其在提升游戏视觉效果方面表现突出。本文通过具体案例分析,介绍如何利用 Unity 中的材质与纹理技术打造逼真且具艺术感的游戏世界。材质定义物体表面属性,如颜色、光滑度等;纹理则用于模拟真实细节。结合使用两者可显著增强场景真实感。以 FPS 游戏为例,通过调整材质参数和编写脚本动态改变属性,可实现自然视觉效果。此外,Unity 还提供了多种高级技术和优化方法供开发者探索。
52 0
|
3月前
|
图形学 机器学习/深度学习 人工智能
颠覆传统游戏开发,解锁未来娱乐新纪元:深度解析如何运用Unity引擎结合机器学习技术,打造具备自我进化能力的智能游戏角色,彻底改变你的游戏体验——从基础设置到高级应用全面指南
【8月更文挑战第31天】本文探讨了如何在Unity中利用机器学习增强游戏智能。作为领先的游戏开发引擎,Unity通过ML-Agents Toolkit等工具支持AI代理的强化学习训练,使游戏角色能自主学习完成任务。文章提供了一个迷宫游戏示例及其C#脚本,展示了环境观察、动作响应及奖励机制的设计,并介绍了如何设置训练流程。此外,还提到了Unity与其他机器学习框架(如TensorFlow和PyTorch)的集成,以实现更复杂的游戏玩法。通过这些技术,游戏的智能化程度得以显著提升,为玩家带来更丰富的体验。
64 1