Unity 开发日记/教程 俄罗斯方块 (一) 定义方块

大名鼎鼎的俄罗斯方块 Tetris 的各种游戏乐趣和设计分析自然不需我赘述,仅在次分析其核心循环的工作机制.


系统随机产生方块 →  方块下落 同时玩家操作移动/旋转 → 方块落地,若某行被填满则消除,若超出上限则GAMEOVER


看上去好像很简单,我们只要把上述机制在UNITY中用计算机语言实现,可以说游戏的基本功能就都实现了.

按照序中所述,我们不使用瀑布开发流程,也就是在这一步里,我们只要能理解上述基本流程就可以了,甚至不需要去进一步分析整理,

就可以直接进入下一个制作阶段


① 系统随机产生方块

在这个功能描述里,我们可以看到,基本上分成1.系统 2.随机生成 3.方块 这个三个部分,其中系统应该是我们要做的整个游戏的当前要制作的部分的整体描述,

也可以说是我们要输出的结果,所以暂且不考虑,而随机生成的目标是方块,也就是说,我们首先要有方块才能进行随机生成.

分析需求之后,我们可以知道,要做的第一件事情就是 定义方块 

首先我们来看一下,经典俄罗斯方块:


分析以上七种方块,可知:俄罗斯方块是由4个一样大小的正方形结合而成的.

所以我们在定义方块之前应该先有正方形,在此处,因为我们在不同的方块中准备使用完全相同的正方形,所以可以将其视为一个整体,暂不继续追求正方形的定义.

而后就是正方的结合方式,当我们把正方形视为一个基本单位时,就可以建立基于正方形的坐标系,来描述上述几个图形,示例如下:

0,0 1,0 2,0 3,0

0,0    
0,1 1,1 2,1

    2,0
0,1 1,1 2,2

所以对于任意一个 方块来说,我们应该有用于描述坐标系边界的 方块尺寸,和记录正方形位置的 正方形坐标两个字段来描述该方块的基本信息.

在UNITY中建立BlockBase类(dm是我的脚本前缀,用于和其他脚本进行区分)

Unity 开发日记/教程 俄罗斯方块 (一) 定义方块_第1张图片

然后编辑内容

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

[CreateAssetMenu(fileName = "NewBlock",menuName = "TetrisDemo/BlockBase")]
public class dmBlockBase : ScriptableObject {
    public Vector2 blockSize;
    public List squareCoordList;
    public dmBlockBase()
    {
        squareCoordList = new List();
    }
}

这样我们做就好了用于存储方块数据的基本类.

Unity 开发日记/教程 俄罗斯方块 (一) 定义方块_第2张图片

在Project中要保存方块数据的文件夹单击鼠标右键,创建一个新方块,并填写方块数据

Unity 开发日记/教程 俄罗斯方块 (一) 定义方块_第3张图片

虽然这些数据已经可以满足我们将来用他们创建方块的实体,但是感觉在inspector窗口看这些坐标数据非常不直观.

下面我们来自定义unity的editor来优化这个问题.

创建BlockBaseEditor类,注意,unity中自定义Editor的代码必须放在Editor文件夹中,Unity会自动帮你把他放在非运行时工程,这样编译的exe中是不包含这些内容的,仅供我们(或者策划)在UNITY编辑器中使用

Unity 开发日记/教程 俄罗斯方块 (一) 定义方块_第4张图片

编辑内容

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEditor;
using UnityEditorInternal;


[CustomEditor(typeof(dmBlockBase))]
public class dmBlockBaseEditor : Editor {
    dmBlockBase targetBlock { get { return target as dmBlockBase; } }
    public override void OnInspectorGUI()
    {
        EditorGUI.BeginChangeCheck();
        Vector2 tempSize = targetBlock.blockSize;
        targetBlock.blockSize = EditorGUILayout.Vector2Field("方块尺寸:", targetBlock.blockSize);


        if(tempSize!= targetBlock.blockSize) //当方块尺寸变更时,删除超出方块尺寸范围的数据
        {
            List tempList = new List();
            tempList.AddRange(targetBlock.squareCoordList);
            foreach(Vector2 vec in tempList)
            {
                if(vec.x>=targetBlock.blockSize.x || vec.y >= targetBlock.blockSize.y)
                {
                    targetBlock.squareCoordList.Remove(vec);
                }
            }
        }


        GUILayout.Space(5);
        EditorGUILayout.LabelField("方块形状:");
        for(int y = 0; y < targetBlock.blockSize.y; y++)
        {
            EditorGUILayout.BeginHorizontal();
            for(int x = 0; x < targetBlock.blockSize.x; x++)
            {
                Vector2 nVec = new Vector2(x, y);
                GUI.backgroundColor = targetBlock.squareCoordList.Contains(nVec) ? Color.green : Color.gray;
                if (GUILayout.Button("", GUILayout.Width(EditorGUIUtility.singleLineHeight), GUILayout.Height(EditorGUIUtility.singleLineHeight)))
                {
                    if(targetBlock.squareCoordList.Contains(nVec))
                    {
                        targetBlock.squareCoordList.Remove(nVec);
                    }
                    else
                    {
                        targetBlock.squareCoordList.Add(nVec);
                    }
                    EditorUtility.SetDirty(target);
                }
                GUILayout.Space(2);
            }
            EditorGUILayout.EndHorizontal();
        }
        if (EditorGUI.EndChangeCheck())
        {
            EditorUtility.SetDirty(target);
        }
    }
}

得到新的编辑器,可以快读预览和设置方块的形状,我们将俄罗斯方块中经典的七个方块数据输入进来.

做到这一步,大家可以看到,用这种方式来固化方块的数据,任何人可以快速上手对方块的数据进行配置,以及根据项目需求添加新的方块.

Unity 开发日记/教程 俄罗斯方块 (一) 定义方块_第5张图片

下一步,我们就可以在 scene窗口根据这些数据实例化方块了!


目录


(一) 定义方块

(二) 搭建方块UI和生成方块.

(三) 搭建场地UI和游戏流程控制

(四) 方块下落和落地判定

(五) 方块平移和旋转

(六) 方块消除

你可能感兴趣的:(Unity,开发笔记)