【方块消除】(附加工程)

一.引擎

游戏工程地址在文末

开发:unity3d 2020.1.1
音乐:au
美术:ps

二.游戏流程

图示

在这里插入图片描述

游戏

主要分为两个大的部分:
游戏部分:
市面上的方块消除游戏主要分为:
1.方块生成区
2.游戏放置区
UI部分:
UI部分我们统一使用我们自己封装的DLFramwork框架管理!

三.研发阶段

1.导入框架DLFramwork

这个是自己封装的框架!主要作用是封装了一些通用的内容,比如音频系统,ui系统,数据存储系统,游戏系统等等

2.Game游戏入口

在这里插入图片描述
这里我强调一点,我们写代码尽量拥有自己的名称空间,不然多人开发的时候容易乱!我的是DLAM什么意思呢,你们猜猜??(文末有注解)

Game脚本是整个游戏的唯一入口:
Init函数:初始化框架
Onstart函数:通过框架创建游戏

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using DLBASE;

namespace DLAM
{
    public class Game : GameBase
    {
        public override void _Init()
        {
            SysManager.InitSys();
            SysManager.LoadSys<GameSys>(SysEnum.GameSys);
            SysManager.LoadSys<UISys>(SysEnum.GameSys);
            SysManager.LoadSys<AudioSys>(SysEnum.GameSys);
            SysManager.LoadSys<GameDataSys>(SysEnum.GameSys);
        }

        public override void _OnStart()
        {
            GameMgr gameMgr = SysManager.GetSys<GameSys>(SysEnum.GameSys).CreatGame<GameMgr>();
            gameMgr.InitMgr();
            gameMgr.StartMgr();
        }
    }
}

3.GameMgr游戏管理类

这个类是通过游戏系统创建出来的,所以我继承了GameSys基类和IMgr接口
主要用来管理游戏进程,管理其他的管理器!

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using DLBASE;

namespace DLAM
{
    /// <summary>
    /// 游戏管理类
    /// </summary>
    public class GameMgr : GameSys, IMgr
    {
        public  GameBoradMgr GameBoradMgr;
        public  OperatingMgr OperatingMgr;
        public  EffectMgr EffectMgr;

        public void InitMgr()
        {
            GameBoradMgr = new GameBoradMgr();
            OperatingMgr = new OperatingMgr();
            EffectMgr = new EffectMgr();
            GameBoradMgr.InitMgr();
            OperatingMgr.InitMgr();
        }

        public void StartMgr()
        {
            GameBoradMgr.StartMgr();
            OperatingMgr.StartMgr();
        }

        public void UpdateMgr()
        {

        }

        public void EndMgr()
        {

        }
    }
}


4.BlockMgr主要提供可供全局访问的方块数组,是静态类

这个类里面的元素在GameBoradMgr管理类里面初始化,方便在游戏存储的时候访问

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

namespace DLAM
{
    public static class BlockMgr 
    {
        //游戏方块
        public static Block[,] Block;
        //游戏背景
        public static BlockBg[,] BlockBg;
        //当前剩余的可放置的方块
        public static int BlockIndex = 3;
    }
}

5.GameBoradMgr 游戏区管理类

这个类主要用来管理游戏填充区域,主要用来生成游戏背景和游戏方块
在这里插入图片描述

Block方块类

基础类,主要是修改方块的基础类型,包括类型,颜色,等等

namespace DLAM
{
    public class Block : GameBase
    {
        public SpriteRenderer m_Sprite;
        private Vector2 m_Pos;

        public void InitBlock(int type,Vector2 pos)
        {

        }

        public void SetArrayPos(Vector2 pos)
        {
            m_Pos = pos;
        }

        public Vector2 GetArrayPos()
        {
            return m_Pos;
        }

        public void UpLayer()
        {
            m_Sprite.sortingOrder = 100;
        }

        public void DownLayer()
        {
            m_Sprite.sortingOrder = 10;
        }
    }
}

BlockBg方块背景类

方块背景类,主要修改方块背景的虚线框,是否填充,数组位置等等

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using DLBASE;

namespace DLAM
{
    public class BlockBg : GameBase
    {
        public GameObject m_Bg;
        public GameObject m_White;
        private Vector2 m_Pos;
        private bool m_Isfill;

        public void SetArrayPos(Vector2 pos)
        {
            m_Pos = pos;
        }

        public Vector2 GetArrayPos()
        {
            return m_Pos;
        }

        public void ShowHightBox()
        {
            m_White.SetActive(true);
        }

        public void CloseHightBox()
        {
            m_White.SetActive(false);
        }

        public bool GetFill()
        {
            return m_Isfill;
        }

        public void SetFill(bool isfill)
        {
            m_Isfill = isfill;
        }
    }
}

区域管理类

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

namespace DLAM
{
    /// <summary>
    /// 游戏区域管理类
    /// </summary>
    public class GameBoradMgr : IMgr
    {
        public void InitMgr()
        {
            BlockMgr.Block = new Block[GameConfig.Row,GameConfig.Col];
            BlockMgr.BlockBg = new BlockBg[GameConfig.Row, GameConfig.Col];
        }
        public void StartMgr()
        {
            for (int row = 0; row < BlockMgr.BlockBg.GetLength(0); row++)
            {
                for (int col = 0; col < BlockMgr.BlockBg.GetLength(1); col++)
                {
                    float start = -(BlockMgr.BlockBg.GetLength(0) - 1) * GameConfig.Distance / 2;
                    float end = -(BlockMgr.BlockBg.GetLength(1) - 1) * GameConfig.Distance / 2;
                    GameObject go = Object.Instantiate(GameRoot.Ins.BlockBG);
                    go.transform.SetParent(GameRoot.Ins.BlockParent, false);
                    go.transform.localPosition = new Vector3(col * GameConfig.Distance + start, row * GameConfig.Distance + end, 0);
                    go.transform.localScale = new Vector3(GameConfig.BGScale, GameConfig.BGScale, GameConfig.BGScale);
                    Vector2 pos = new Vector2(row, col);
                    BlockBg blockBg = go.GetComponent<BlockBg>();
                    blockBg.SetArrayPos(pos);
                    BlockMgr.BlockBg[row, col] = blockBg;
                }
            }
        }
        public void UpdateMgr()
        {

        }
        public void EndMgr()
        {

        }       
    }
}

BlockDrag 方块拖动检测

在这里插入图片描述

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using DLBASE;
using System;

namespace DLAM
{
    public class BlockDrag : GameBase
    {
        public List<Block> Blocks;
        private int[,] m_Block;
        private int m_Id;
        private int m_State;
        private int m_Dir;
        private Vector3 m_OldPos;
        private Action<Transform, List<Block>> m_DragBlock;
        private Action<Transform, List<Block>> m_DragBlockEnd;

        public override void _Init()
        {
            m_OldPos = transform.localPosition;
        }

        public void InitBlock(int[,] blockconfig,int id,int state,int dir)
        {
            m_Block = blockconfig;
            m_Id = id;
            m_State = state;
            m_Dir = dir;
        }

        public override void _OnMouseDown()
        {

        }

        public void UpLayer()
        {
            for (int i = 0; i < Blocks.Count; i++)
            {
                Blocks[i].UpLayer();
            }
        }

        public void DownLayer()
        {
            for (int i = 0; i < Blocks.Count; i++)
            {
                Blocks[i].DownLayer();
            }
        }

        public override void _OnMouseDrag()
        {
            UpLayer();
            Vector3 pos = Camera.main.ScreenToWorldPoint(Input.mousePosition);
            pos = new Vector3(pos.x, pos.y, transform.position.z);
            transform.localPosition = pos;
            transform.localScale = Vector3.one;
            m_DragBlock?.Invoke(transform, Blocks);
        }
        public override void _OnMouseUp()
        {
            DownLayer();
            ResetBlock();
            m_DragBlockEnd?.Invoke(transform, Blocks);
        }

        public void ResetBlock()
        {
            transform.localPosition = m_OldPos;
            transform.localScale = new Vector3(0.7f, 0.7f, 0.7f);
        }

        public void DragBlock(Action<Transform, List<Block>> drag)
        {
            m_DragBlock += drag;
        }

        public void DragBlockEnd(Action<Transform, List<Block>> dragend)
        {
            m_DragBlockEnd += dragend;
        }
    }
}

6.OperatingMgr 操控区域管理类

这个类主要用来管理游戏操作区域
在这里插入图片描述

拖动 (DragBlockHundler)

拖动方块检测,根据当前拖动的方块与界面背景的方块位置,判断当前是否显示可以填充

 for (int row = 0; row < BlockMgr.BlockBg.GetLength(0); row++)
            {
                for (int col = 0; col < BlockMgr.BlockBg.GetLength(1); col++)
                {
                    for (int index = 0; index < blocks.Count; index++)
                    {
                        float x = t.position.x + blocks[index].transform.localPosition.x;
                        float y = t.position.y + blocks[index].transform.localPosition.y;
                        float targetx = GameRoot.Ins.BlockParent.transform.position.x + BlockMgr.BlockBg[row, col].transform.localPosition.x;
                        float targety = GameRoot.Ins.BlockParent.transform.position.y + BlockMgr.BlockBg[row, col].transform.localPosition.y;
                        float xdis = Mathf.Abs(x - targetx);
                        float ydis = Mathf.Abs(y - targety);
                        if (xdis <= m_Offset && ydis <= m_Offset)
                        {
                            if (!BlockMgr.BlockBg[row, col].GetFill())
                            {
                                m_SearchBlockBG.Add(BlockMgr.BlockBg[row, col]);
                            }
                            else
                            {
                                BlockMgr.BlockBg[row, col].ShowHightBox();
                            }
                            break;
                        }
                        else
                        {
                            BlockMgr.BlockBg[row, col].CloseHightBox();
                        }
                    }
                }
显示虚线框(ShowHightBox)
        /// <summary>
        /// 显示虚线框
        /// </summary>
        private void ShowHightBox(List<Block> blocks)
        {
            //数量不对,不显示虚线框
            if (blocks.Count != m_SearchBlockBG.Count)
            {
                for (int i = 0; i < m_SearchBlockBG.Count; i++)
                {
                    m_SearchBlockBG[i].CloseHightBox();
                }
                return;
            };
            //显示虚线框
            for (int i = 0; i < m_SearchBlockBG.Count; i++)
            {
                m_SearchBlockBG[i].ShowHightBox();
            }
        }

拖动完成(DragBlockEndHundler)

    private void DragBlockEndHundler(Transform t, List<Block> blocks)
    {
        FillBlock(blocks);
        CloseAllBgHightBox();
    }
填充方块(FillBlock)
        /// <summary>
        /// 填充方块
        /// </summary>
        private void FillBlock(List<Block> blocks)
        {
            //判断找到的格子是否和当前选择的数量一样,一样填充,不一样,则不填充
            if (blocks.Count != m_SearchBlockBG.Count) return;
            for (int i = 0; i < m_SearchBlockBG.Count; i++)
            {
                blocks[i].transform.SetParent(GameRoot.Ins.BlockParent);
                blocks[i].transform.position = m_SearchBlockBG[i].transform.position;
                blocks[i].SetArrayPos(m_SearchBlockBG[i].GetArrayPos());
                blocks[i].transform.localScale = new Vector3(GameConfig.BlockScale, GameConfig.BlockScale, GameConfig.BlockScale);
                m_SearchBlockBG[i].SetFill(true);
                int row = (int)m_SearchBlockBG[i].GetArrayPos().x;
                int col = (int)m_SearchBlockBG[i].GetArrayPos().y;
                BlockMgr.Block[row, col] = blocks[i];
            }
            SearchEliminateBlock();
            SysManager.ObjectBase.StartCortinueGO(EliminateBlock());
            //填充成功,则计数器减
            BlockMgr.BlockIndex--;        
            if (BlockMgr.BlockIndex == 0)
            {
                BlockMgr.BlockIndex = 3;
            }
            ReBuildNewBlock();            
        }
找到可消除的方块(SearchEliminateBlock)
        /// <summary>
        /// 找到可消除行和列
        /// </summary>
        private void SearchEliminateBlock()
        {
            m_ClearRowBlockList.Clear();
            m_ClearColBlockList.Clear();
            for (int row = 0; row < BlockMgr.Block.GetLength(0); row++)
            {
                for (int col = 0; col < BlockMgr.Block.GetLength(1); col++)
                {
                    if (BlockMgr.Block[row, col] == null) break;
                    if (col == BlockMgr.Block.GetLength(1) - 1)
                    {
                        m_ClearRowBlockList.Add(row);
                    }
                }
            }
            for (int col = 0; col < BlockMgr.Block.GetLength(1); col++)
            {
                for (int row = 0; row < BlockMgr.Block.GetLength(0); row++)
                {
                    if (BlockMgr.Block[row, col] == null) break;
                    if (row == BlockMgr.Block.GetLength(0) - 1)
                    {
                        m_ClearColBlockList.Add(col);
                    }
                }
            }
        }
消除方块(EliminateBlock)
        /// <summary>
        /// 直接消除
        /// </summary>
        private IEnumerator EliminateBlock()
        {
            for (int row = 0; row < m_ClearRowBlockList.Count; row++)
            {
                for (int col = 0; col < BlockMgr.Block.GetLength(1); col++)
                {
                    int currentrow = m_ClearRowBlockList[row];
                    GameObject go = BlockMgr.Block[m_ClearRowBlockList[row], col].gameObject;
                    SysManager.ObjectBase.DestoryGO(go);
                    BlockMgr.BlockBg[m_ClearRowBlockList[row], col].SetFill(false);
                    yield return new WaitForSeconds(0.02f);
                }
            }
            for (int row = 0; row < BlockMgr.Block.GetLength(0); row++)
            {
                for (int col = 0; col < m_ClearColBlockList.Count; col++)
                {
                    int currentcol = m_ClearColBlockList[col];
                    if (BlockMgr.Block[row, m_ClearColBlockList[col]] != null)
                    {
                        GameObject go = BlockMgr.Block[row, m_ClearColBlockList[col]].gameObject;
                        SysManager.ObjectBase.DestoryGO(go);
                        BlockMgr.BlockBg[row, m_ClearColBlockList[col]].SetFill(false);
                    }
                    yield return new WaitForSeconds(0.02f);
                }
            }

        }
重新构建三个新的方块(ReBuildNewBlock)
    /// <summary>
    /// 重新构建新的方块
    /// </summary>
    private void ReBuildNewBlock()
    {
        //当前还未消除完成
        if (BlockMgr.BlockIndex != 3) return;
        int type = Random.Range(0, BlockConfig.Block.Length);
        int state = Random.Range(0, 5);
        int dir = Random.Range(0, 4);
        BuildBlock(m_Left, type, state, dir);
        type = Random.Range(0, BlockConfig.Block.Length);
        state = Random.Range(0, 5);
        dir = Random.Range(0, 4);
        BuildBlock(m_Mid, type, state, dir);
        type = Random.Range(0, BlockConfig.Block.Length);
        state = Random.Range(0, 5);
        dir = Random.Range(0, 4);
        BuildBlock(m_Right, type, state, dir);
    }
构建方块(BuildBlock)

构建方块需要传入:方块类型,方块颜色类型,方块方向 后续做刷新道具和旋转道具的时候可以使用这个方法

        /// <summary>
        /// 生成方块
        /// </summary>
        /// <param name="id">方块配置id</param>
        /// <param name="state">方块颜色类型</param>
        /// <param name="dir">方块方向</param>
        private void BuildBlock(BlockDrag blockDrag, int id, int state, int dir)
        {
            blockDrag.Blocks.Clear();
            int[,] blockArray = GameUtlis.SetMtrixDir(BlockConfig.Block[id], dir);
            blockDrag.InitBlock(blockArray, id, state, dir);
            for (int row = 0; row < blockArray.GetLength(0); row++)
            {
                for (int col = 0; col < blockArray.GetLength(1); col++)
                {
                    if (blockArray[row, col] == 1)
                    {
                        GameObject go = Object.Instantiate(GameRoot.Ins.Block);
                        go.transform.SetParent(blockDrag.transform, false);
                        float start = -(blockArray.GetLength(0) - 1) * GameConfig.Distance / 2;
                        float end = -(blockArray.GetLength(1) - 1) * GameConfig.Distance / 2;
                        go.transform.localPosition = new Vector3(row * GameConfig.Distance + start, col * GameConfig.Distance + end, 0);
                        go.transform.localScale = new Vector3(GameConfig.BlockScale, GameConfig.BlockScale, GameConfig.BlockScale);
                        Block block = go.GetComponent<Block>();
                        Vector2 pos = new Vector2(col, row);
                        block.InitBlock(id, pos);
                        blockDrag.Blocks.Add(block);
                    }
                }
            }
        }
死亡判断(EndAllGames)

NoFillBoard函数用来判断单个物体是否可填充
主要思想:用方块的二维数组扫一下界面布局的二维数组,判断是否有可填充的位置,如果有则retrun!

在这里插入图片描述

        /// <summary>
        /// 所有对象都无法填充判断
        /// </summary>
        private void EndAllGames()
        {
            m_LeftOver = false;
            m_RightOver = false;
            m_MidOver = false;
            m_LeftOver = NoFillBoard(m_Left.Blocks);
            m_MidOver = NoFillBoard(m_Mid.Blocks);
            m_RightOver = NoFillBoard(m_Right.Blocks);
            if (m_LeftOver && m_MidOver && m_RightOver)
            {
                EndGame();
                return;
            }
        }

        /// <summary>
        /// 游戏结束
        /// </summary>
        private void EndGame()
        {
            Debug.Log("游戏结束!!!");
        }

        /// <summary>
        /// 是否可以填充判断
        /// </summary>
        private bool NoFillBoard(List<Block> blocks)
        {
            if (blocks == null) return false;
            if (blocks.Count == 0) return true;
            for (int row = 0; row < BlockMgr.BlockBg.GetLength(0); row++)
            {
                for (int col = 0; col < BlockMgr.BlockBg.GetLength(1); col++)
                {
                    for (int i = 0; i < blocks.Count; i++)
                    {
                        int blockrow = (int)blocks[i].GetArrayPos().x + row;
                        int blockcol = (int)blocks[i].GetArrayPos().y + col;
                        if (blockrow > BlockMgr.BlockBg.GetLength(0) - 1 || blockcol > BlockMgr.BlockBg.GetLength(1) - 1) break;
                        if (BlockMgr.BlockBg[blockrow, blockcol].GetFill())
                        {
                            break;
                        }
                        if (i == blocks.Count - 1)
                        {
                            //还可以消除
                            return false;
                        }
                    }
                    if (row == BlockMgr.BlockBg.GetLength(0) - 1 && col == BlockMgr.BlockBg.GetLength(1) - 1)
                    {
                        //无法消除
                        return true;
                    }
                }
            }
            return false;
        }
重新开始游戏(ResetGame)
        /// <summary>
        /// 重新开始游戏
        /// </summary>
        private void ResetGame()
        {
            //这里简单的方式留给你们,删除或者回收界面上的方块和可操作的方块,重置背景填充
        }
完整代码
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using DLBASE;

namespace DLAM
{
    /// <summary>
    /// 游戏操作区域管理类
    /// </summary>
    public class OperatingMgr : IMgr
    {
        private BlockDrag m_Left;
        private BlockDrag m_Mid;
        private BlockDrag m_Right;
        private List<BlockBg> m_SearchBlockBG;
        private float m_Offset = 3;
        private List<int> m_ClearRowBlockList;
        private List<int> m_ClearColBlockList;
        private bool m_LeftOver;
        private bool m_MidOver;
        private bool m_RightOver;

        public void InitMgr()
        {
            m_Left = GameRoot.Ins.Left.GetComponent<BlockDrag>();
            m_Mid = GameRoot.Ins.Mid.GetComponent<BlockDrag>();
            m_Right = GameRoot.Ins.Right.GetComponent<BlockDrag>();
            m_Left.DragBlock(DragBlockHundler);
            m_Mid.DragBlock(DragBlockHundler);
            m_Right.DragBlock(DragBlockHundler);
            m_Left.DragBlockEnd(DragBlockEndHundler);
            m_Mid.DragBlockEnd(DragBlockEndHundler);
            m_Right.DragBlockEnd(DragBlockEndHundler);
            m_SearchBlockBG = new List<BlockBg>();
            m_ClearRowBlockList = new List<int>();
            m_ClearColBlockList = new List<int>();
        }

        public void StartMgr()
        {
            ReBuildNewBlock();
        }

        private void DragBlockHundler(Transform t, List<Block> blocks)
        {
            m_SearchBlockBG.Clear();
            for (int row = 0; row < BlockMgr.BlockBg.GetLength(0); row++)
            {
                for (int col = 0; col < BlockMgr.BlockBg.GetLength(1); col++)
                {
                    for (int index = 0; index < blocks.Count; index++)
                    {
                        float x = t.position.x + blocks[index].transform.localPosition.x;
                        float y = t.position.y + blocks[index].transform.localPosition.y;
                        float targetx = GameRoot.Ins.BlockParent.transform.position.x + BlockMgr.BlockBg[row, col].transform.localPosition.x;
                        float targety = GameRoot.Ins.BlockParent.transform.position.y + BlockMgr.BlockBg[row, col].transform.localPosition.y;
                        float xdis = Mathf.Abs(x - targetx);
                        float ydis = Mathf.Abs(y - targety);
                        if (xdis <= m_Offset && ydis <= m_Offset)
                        {
                            if (!BlockMgr.BlockBg[row, col].GetFill())
                            {
                                m_SearchBlockBG.Add(BlockMgr.BlockBg[row, col]);
                            }
                            break;
                        }
                        else
                        {
                            BlockMgr.BlockBg[row, col].CloseHightBox();
                        }
                    }
                }
            }
            ShowHightBox(blocks);
        }

        /// <summary>
        /// 显示虚线框
        /// </summary>
        private void ShowHightBox(List<Block> blocks)
        {
            //数量不对,不显示虚线框
            if (blocks.Count != m_SearchBlockBG.Count)
            {
                for (int i = 0; i < m_SearchBlockBG.Count; i++)
                {
                    m_SearchBlockBG[i].CloseHightBox();
                }
                return;
            };
            //显示虚线框
            for (int i = 0; i < m_SearchBlockBG.Count; i++)
            {
                m_SearchBlockBG[i].ShowHightBox();
            }
        }

        private void DragBlockEndHundler(Transform t, List<Block> blocks)
        {
            FillBlock(blocks);
            CloseAllBgHightBox();
        }

        /// <summary>
        /// 填充方块
        /// </summary>
        private void FillBlock(List<Block> blocks)
        {
            //判断找到的格子是否和当前选择的数量一样,一样填充,不一样,则不填充
            if (blocks.Count != m_SearchBlockBG.Count) return;
            for (int i = 0; i < m_SearchBlockBG.Count; i++)
            {
                blocks[i].transform.SetParent(GameRoot.Ins.BlockParent);
                blocks[i].transform.position = m_SearchBlockBG[i].transform.position;
                blocks[i].SetArrayPos(m_SearchBlockBG[i].GetArrayPos());
                blocks[i].transform.localScale = new Vector3(GameConfig.BlockScale, GameConfig.BlockScale, GameConfig.BlockScale);
                m_SearchBlockBG[i].SetFill(true);
                int row = (int)m_SearchBlockBG[i].GetArrayPos().x;
                int col = (int)m_SearchBlockBG[i].GetArrayPos().y;
                BlockMgr.Block[row, col] = blocks[i];
            }
            blocks.Clear();
            SearchEliminateBlock();
            SysManager.ObjectBase.StartCortinueGO(EliminateBlock());
            //填充成功,则计数器减
            BlockMgr.BlockIndex--;        
            if (BlockMgr.BlockIndex == 0)
            {
                BlockMgr.BlockIndex = 3;
            }
            ReBuildNewBlock();
            EndAllGames();
        }

        /// <summary>
        /// 找到可消除行和列
        /// </summary>
        private void SearchEliminateBlock()
        {
            m_ClearRowBlockList.Clear();
            m_ClearColBlockList.Clear();
            for (int row = 0; row < BlockMgr.Block.GetLength(0); row++)
            {
                for (int col = 0; col < BlockMgr.Block.GetLength(1); col++)
                {
                    if (BlockMgr.Block[row, col] == null) break;
                    if (col == BlockMgr.Block.GetLength(1) - 1)
                    {
                        m_ClearRowBlockList.Add(row);
                    }
                }
            }
            for (int col = 0; col < BlockMgr.Block.GetLength(1); col++)
            {
                for (int row = 0; row < BlockMgr.Block.GetLength(0); row++)
                {
                    if (BlockMgr.Block[row, col] == null) break;
                    if (row == BlockMgr.Block.GetLength(0) - 1)
                    {
                        m_ClearColBlockList.Add(col);
                    }
                }
            }
        }

        /// <summary>
        /// 直接消除
        /// </summary>
        private IEnumerator EliminateBlock()
        {
            for (int row = 0; row < m_ClearRowBlockList.Count; row++)
            {
                for (int col = 0; col < BlockMgr.Block.GetLength(1); col++)
                {
                    int currentrow = m_ClearRowBlockList[row];
                    GameObject go = BlockMgr.Block[m_ClearRowBlockList[row], col].gameObject;
                    SysManager.ObjectBase.DestoryGO(go);
                    BlockMgr.BlockBg[m_ClearRowBlockList[row], col].SetFill(false);
                    yield return new WaitForSeconds(0.02f);
                }
            }
            for (int row = 0; row < BlockMgr.Block.GetLength(0); row++)
            {
                for (int col = 0; col < m_ClearColBlockList.Count; col++)
                {
                    int currentcol = m_ClearColBlockList[col];
                    if (BlockMgr.Block[row, m_ClearColBlockList[col]] != null)
                    {
                        GameObject go = BlockMgr.Block[row, m_ClearColBlockList[col]].gameObject;
                        SysManager.ObjectBase.DestoryGO(go);
                        BlockMgr.BlockBg[row, m_ClearColBlockList[col]].SetFill(false);
                    }
                    yield return new WaitForSeconds(0.02f);
                }
            }

        }

        /// <summary>
        /// 生成方块
        /// </summary>
        /// <param name="id">方块配置id</param>
        /// <param name="state">方块颜色类型</param>
        /// <param name="dir">方块方向</param>
        private void BuildBlock(BlockDrag blockDrag, int id, int state, int dir)
        {
            blockDrag.Blocks.Clear();
            int[,] blockArray = GameUtlis.SetMtrixDir(BlockConfig.Block[id], dir);
            blockDrag.InitBlock(blockArray, id, state, dir);
            for (int row = 0; row < blockArray.GetLength(0); row++)
            {
                for (int col = 0; col < blockArray.GetLength(1); col++)
                {
                    if (blockArray[row, col] == 1)
                    {
                        GameObject go = Object.Instantiate(GameRoot.Ins.Block);
                        go.transform.SetParent(blockDrag.transform, false);
                        float start = -(blockArray.GetLength(0) - 1) * GameConfig.Distance / 2;
                        float end = -(blockArray.GetLength(1) - 1) * GameConfig.Distance / 2;
                        go.transform.localPosition = new Vector3(row * GameConfig.Distance + start, col * GameConfig.Distance + end, 0);
                        go.transform.localScale = new Vector3(GameConfig.BlockScale, GameConfig.BlockScale, GameConfig.BlockScale);
                        Block block = go.GetComponent<Block>();
                        Vector2 pos = new Vector2(col, row);
                        block.InitBlock(id, pos);
                        blockDrag.Blocks.Add(block);
                    }
                }
            }
        }

        /// <summary>
        /// 重新构建新的方块
        /// </summary>
        private void ReBuildNewBlock()
        {
            //当前还未消除完成
            if (BlockMgr.BlockIndex != 3) return;
            int type = Random.Range(0, BlockConfig.Block.Length);
            int state = Random.Range(0, 5);
            int dir = Random.Range(0, 4);
            BuildBlock(m_Left, type, state, dir);
            type = Random.Range(0, BlockConfig.Block.Length);
            state = Random.Range(0, 5);
            dir = Random.Range(0, 4);
            BuildBlock(m_Mid, type, state, dir);
            type = Random.Range(0, BlockConfig.Block.Length);
            state = Random.Range(0, 5);
            dir = Random.Range(0, 4);
            BuildBlock(m_Right, type, state, dir);
        }

        /// <summary>
        /// 关闭所有虚线框
        /// </summary>
        private void CloseAllBgHightBox()
        {
            for (int i = 0; i < BlockMgr.BlockBg.GetLength(0); i++)
            {
                for (int j = 0; j < BlockMgr.BlockBg.GetLength(0); j++)
                {
                    BlockMgr.BlockBg[i, j].CloseHightBox();
                }
            }
        }

        /// <summary>
        /// 所有对象都无法填充判断
        /// </summary>
        private void EndAllGames()
        {
            m_LeftOver = false;
            m_RightOver = false;
            m_MidOver = false;
            m_LeftOver = NoFillBoard(m_Left.Blocks);
            m_MidOver = NoFillBoard(m_Mid.Blocks);
            m_RightOver = NoFillBoard(m_Right.Blocks);
            if (m_LeftOver && m_MidOver && m_RightOver)
            {
                EndGame();
                return;
            }
        }

        /// <summary>
        /// 游戏结束
        /// </summary>
        private void EndGame()
        {
            Debug.Log("游戏结束!!!");
        }

        /// <summary>
        /// 是否可以填充判断
        /// </summary>
        private bool NoFillBoard(List<Block> blocks)
        {
            if (blocks == null) return false;
            if (blocks.Count == 0) return true;
            for (int row = 0; row < BlockMgr.BlockBg.GetLength(0); row++)
            {
                for (int col = 0; col < BlockMgr.BlockBg.GetLength(1); col++)
                {
                    for (int i = 0; i < blocks.Count; i++)
                    {
                        int blockrow = (int)blocks[i].GetArrayPos().x + row;
                        int blockcol = (int)blocks[i].GetArrayPos().y + col;
                        if (blockrow > BlockMgr.BlockBg.GetLength(0) - 1 || blockcol > BlockMgr.BlockBg.GetLength(1) - 1) break;
                        if (BlockMgr.BlockBg[blockrow, blockcol].GetFill())
                        {
                            break;
                        }
                        if (i == blocks.Count - 1)
                        {
                            //还可以消除
                            return false;
                        }
                    }
                    if (row == BlockMgr.BlockBg.GetLength(0) - 1 && col == BlockMgr.BlockBg.GetLength(1) - 1)
                    {
                        //无法消除
                        return true;
                    }
                }
            }
            return false;
        }

        public void UpdateMgr()
        {

        }

        public void EndMgr()
        {

        }
    }
}


7.EffectMgr 特效管理类

这个类主要用来管理游戏特效,消除方块的时候调用
在这里插入图片描述

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

namespace DLAM
{
    /// <summary>
    /// 特效管理类
    /// </summary>
    public class EffectMgr : IMgr
    {
        public void ShowBlockEffect()
        {
            Debug.Log("展示特效!!!");
        }

        public void EndMgr()
        {

        }

        public void InitMgr()
        {

        }

        public void StartMgr()
        {

        }

        public void UpdateMgr()
        {

        }
    }
}

8.GameConfig和BlockConfig配置类

GameConfig游戏基础配置类

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

namespace DLAM
{
    public static class GameConfig
    {
        public static int Col = 10;
        public static int Row = 10;
        public static float Distance = 6;
        public static float BGScale = 6;

        public static float BlockScale = 12;
    }
}


BlockConfig方块配置类
主要是用二维数组代表方块的样式,根据二维数组来生成方块,可以想象一下,一个个方块其实就是一个个的数组!

namespace DLAM
{
    public class BlockConfig 
    {
        //单格子方块
        public static int[,] OBlock = new int[1, 1] { { 1 } };
        //两个格子
        public static int[,] OTBlock = new int[2, 1] { { 1 }, { 1 } };

        public static int[,] OCBlock = new int[3, 1] { { 1 }, { 1 }, { 1 } };

        public static int[,] ODBlock = new int[4, 1] { { 1 }, { 1 }, { 1 }, { 1 } };

        public static int[,] OEBlock = new int[5, 1] { { 1 }, { 1 }, { 1 }, { 1 }, { 1 } };

        public static int[,] MTBlock = new int[2, 2] { { 1, 1 }, { 1, 1 } };

        public static int[,] MTTBlock = new int[2, 3] { { 1, 1, 1 }, { 1, 1, 1 } };

        public static int[,] ZLBlock = new int[2, 2] { { 1, 1 }, { 1, 0 } };
        //Z形状
        public static int[,] ZBlock = new int[2, 3] { { 1, 1, 0 }, { 0, 1, 1 } };
        //反Z形状
        public static int[,] RZBlock = new int[2, 3] { { 0, 1, 1 }, { 1, 1, 0 } };
        //T形状
        public static int[,] TBlock = new int[2, 3] { { 0, 1, 0 }, { 1, 1, 1 } };
        //7形状
        public static int[,] LBlock = new int[3, 3] { { 1, 1, 1 }, { 1, 0, 0 }, { 1, 0, 0 } };
        //反7
        public static int[,] RLBlock = new int[3, 3] { { 1, 0, 0 }, { 1, 0, 0 }, { 1, 1, 1 } };

        public static int[,] DLBlock = new int[3, 2] { { 1, 1 }, { 1, 0 }, { 1, 0 } };

        public static int[,] DLRBlock = new int[3, 2] { { 1, 1 }, { 0, 1 }, { 0, 1 } };
        //田字
        public static int[,] MBlock = new int[3, 3] { { 1, 1, 1 }, { 1, 1, 1 }, { 1, 1, 1 } };
    }
}

9.GameUtlis工具类

这个类主要封装了旋转二维数组的函数,方便全局使用

using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

namespace DLAM
{
    public static class GameUtlis 
    {
        /// <summary>
        /// 转置矩阵
        /// </summary>
        /// <returns></returns>
        public static int[,] TransposeMtrix(int[,] matrix)
        {
            int[,] array = new int[matrix.GetLength(1), matrix.GetLength(0)];

            for (int i = 0; i < matrix.GetLength(0); i++)
            {
                for (int j = 0; j < matrix.GetLength(1); j++)
                {
                    array[matrix.GetLength(1) - 1 - j,i] = matrix[i, j];
                }
            }
            return array;
        }

        public static int[,] TurnMtrix(int[,] matrix)
        {
            int[,] array = new int[matrix.GetLength(0), matrix.GetLength(1)];
            if(matrix.GetLength(0)==1|| matrix.GetLength(1) == 1)
            {
                return matrix;
            }
            for (int i = 0; i < matrix.GetLength(0); i++)
            {
                for (int j = 0; j < matrix.GetLength(1); j++)
                {
                    array[i, j] = matrix[matrix.GetLength(0) - 1 - i, matrix.GetLength(1) - 1 - j];
                }
            }
            return array;
        }

        public static int[,] ChangeMtrixDir(int[,] matrix, int dir)
        {
            int[,] blocks = new int[0, 0];
            switch (dir)
            {
                case 0:
                    blocks = GameUtlis.TransposeMtrix(matrix);
                    blocks = TurnMtrix(blocks);
                    break;
                case 1:
                    blocks = GameUtlis.TransposeMtrix(matrix);
                    blocks = TurnMtrix(blocks);
                    break;
                case 2:
                    blocks = GameUtlis.TransposeMtrix(matrix);
                    blocks = TurnMtrix(blocks);
                    break;
                case 3:
                    blocks = GameUtlis.TransposeMtrix(matrix);
                    blocks = TurnMtrix(blocks);
                    break;
            }
            return blocks;
        }
        public static int[,] SetMtrixDir(int[,] matrix, int dir)
        {
            int[,] blocks = new int[0, 0];
            switch (dir)
            {
                case 0:
                    blocks = matrix;
                    break;
                case 1:
                    blocks = GameUtlis.TransposeMtrix(matrix);
                    blocks = TurnMtrix(blocks);
                    break;
                case 2:
                    blocks = GameUtlis.TransposeMtrix(matrix);
                    blocks = TurnMtrix(blocks);
                    blocks = GameUtlis.TransposeMtrix(blocks);
                    blocks = TurnMtrix(blocks);
                    break;
                case 3:
                    blocks = GameUtlis.TransposeMtrix(matrix);
                    blocks = TurnMtrix(blocks);
                    blocks = GameUtlis.TransposeMtrix(blocks);
                    blocks = TurnMtrix(blocks);
                    blocks = GameUtlis.TransposeMtrix(blocks);
                    blocks = TurnMtrix(blocks);
                    break;
                case 4:
                    blocks = matrix;
                    break;
            }
            return blocks;
        }

        public static IEnumerator Wait(float time,Action callback)
        {
            yield return new WaitForSeconds(time);
            callback?.Invoke();
        }

        public static void RandomNumber(float prcent,Action sucess,Action fail)
        {
            float num = UnityEngine.Random.Range(0, 100);
            if (num > prcent)
            {
                fail?.Invoke();
            }
            else
            {
                sucess?.Invoke();
            }
        }

    }
}

11.项目结构

在这里插入图片描述

10.最终效果

在这里插入图片描述
DLAM是哆啦A梦的意思!!哈哈因为生活中朋友都叫我大雄!

工程地址:

工程地址BlockJewel

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 8
    评论
在五花八门的游戏分类中,益智游戏是不可或缺的一大板块;而在益智游戏这个分类中,消除合成类游戏又是当之无愧的No.1。从考古级别的《俄罗斯方块》到现在风靡全国的《开心消消乐》,消除合成类游戏经久不衰,并且不断地涌现出新的经典作品,带给我们新的启发和乐趣。作为Unity3D的初级开发者,从头到尾独立完成一款简单的2D棋盘消除合成小游戏是你初级实战的最好选择。既能全面而详细的检验你的基础框架能力、C#编程能力、UGUI适配技巧,又可以在此基础上,较为深入的学习协程方法、DoTween插件和消除合成类的核心算法,一举数得。一言以蔽之,消除合成类游戏不难,但要写好却并不容易。它琐碎的功能逻辑、层出不穷的延时操作以及复杂的状态控制很容易让人顾此失彼,手忙脚乱,最后的结果往往是,费劲九牛二虎之力把功能实现好了,但代码已经乱成一团糟,定位Bug难、扩展新功能难,甚至自己读起来也难。本课程的最大目的,就是帮初级开发者梳理逻辑,写出规范而有条理的代码,避免陷入以上尴尬境地。条理捋清楚了,你就会觉得一切似乎变得简单了,很多地方都会顺理成章。本课程没有什么高深的编程技巧,更没有炫酷的视觉效果,只是一步一步教你如何踏踏实实、稳稳当当的完成一款《简单消消乐》。因此,资深大牛你就别进了,想学高深知识的你就别点了,自认为消除小case、分分钟搞定的高手你也趁早走人。在这门课程里,你能够学到的,只有以下几点:1、如何使用UGUI搭建棋盘游戏的基础阵列;2、如何快速的实现通用的三消逻辑;3、如何使用Dotween插件实现物体的位移、缩放、旋转动画;4、如何熟练的使用协程方法完成延时操作逻辑;5、数组、集合、引用类型、Prefab等基础知识的巩固;6、如何写出规范而有条理的代码;7、益智小游戏的通用模板。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 8
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值