【Unity】MineCraft我的世界沙盒游戏开发流程

一、插件介绍(必看)

核心插件:Uniblocks Voxel Terrain v1.4.1

将插件导入工程后,Uniblocks文件夹是关键,在文件夹中有材质、贴图、预制体、核心脚本等等。

1.“Engine”预制体是游戏核心引擎,它必须放入场景中(存在一个)。

2.“Chunk”预制体是大方块,由许多个小方块组成,小方块是逻辑上理解的,物理上并不存在,可理解为由一个个小Mesh构成了大方块Mesh。

3."block_0","block_1",..."block_9","block_70"预制体是小方块,每种预制体上都有一个脚本为Voxel,每种方块的Voxel所保存的信息不一样,这些预制体以及身上Voxel脚本的生成是由插件来自动生成的,点击Window->Uniblocks: blocks editor,弹出弹窗,选中相应的预制体编辑即可(注意:场景上必须要有Engine预制体存在该窗口才会正常显示!),窗口说明:

Window -> Uniblocks: blocks editor

【Unity】MineCraft我的世界沙盒游戏开发流程_第1张图片

上图中,我选中了empty。

Name:随意起的,就是左边那个按钮显示的文本;

ID:识别每种小方块的,而预制体名称也是为block_ID,如该empty的ID是0,那么在工程里面就一定有一个叫block_0的预制体,对应着它,在这个Blocks Editor窗口显示的属性都是Voxel脚本的属性。

Custom mesh:不勾选时,小方块会以立方体Mesh来渲染,即使你给了Mesh,也不会使用你给的Mesh。

Mesh:自定义Mesh(你给的Mesh)。

Define side textures :只有Custom mesh不勾选时,也就是选用立方体Mesh渲染时,才会有该属性出现,不勾选时,下方有一个属性Texture 只有一个X,Y选项填写,而勾选后,会出现6个X,Y选项填写,如下图。

【Unity】MineCraft我的世界沙盒游戏开发流程_第2张图片

Texture:不勾选Define side textures时有它,表示整个立方体Mesh的贴图会使用由Material index指定的在Chunk预制体上的材质的贴图(X,Y)相对位置的小图。

Top、Bottom、Right、Left、Forward、Back:勾选Define side textures时出现,它们表示立方体Mesh的6个面的贴图,分别使用Chunk预制体上的Material index索引号的材质的贴图的(X,Y)相对位置的小图。

Material index:它是Chunk预制体的材质球索引号,默认Chunk预制体身上只有一个材质球texture sheet,当Material index为0时,就是指这个texture sheet材质球。

Transparency:Solid不透明、Semi Transparent半透明(叶子需要它)、Transparent(全透明)

Collider:None、Cube 、 Mesh ,小方块采用的碰撞器。

基本就以上属性,上面有说到一个比较复杂的地方就是小方块到底用哪个材质球的贴图哪个位置的小图进行渲染,经过我发现插件自带的只有一个材质球,那么Material index都是0,那这个材质球身上也只有一个贴图,贴图X,Y分配如下。

【Unity】MineCraft我的世界沙盒游戏开发流程_第3张图片

在配置好block 属性后就按一下 Apply才能应用到预制体身上。

增加一个block 点击New block即可,复制一个block 如复制empty的,只需将empty的ID修改为一个新的ID,点击Apply即可。

删除一个block,只需去到相应文件夹下删除预制体即可。

Windows -> Uniblocks: Engine Editor

这也是需要Engine预制体在场景中才正常显示的窗口。

【Unity】MineCraft我的世界沙盒游戏开发流程_第4张图片

属性World Name是世界名称,在根目录下有一个Worlds文件夹下会有世界名称文件,保存着一些游戏的数据,当加载该Word时候,会进行加载之前保存的方块数据,没有的话就加载新的方块!
属性Chunk Spawn Distance : 8,表示地图会以玩家为中心,半径为8个大块的方法生成大块(称为可视区域)。
属性Chunk despawn Distance: 3 ,表示大块方块与可视区域的距离大于3个大块后会被销毁!即与玩家的距离大于8+3个大块的大块就会销毁!
属性Chunk height range:3,表示以玩家为中心,其上方有3个大块,下方有3个大块,那么垂直的多余方块是如何销毁的呢?是大于3个大块距离就销毁么(待测试)?
属性Chunk size length:16 表示大块的宽、高、长,单位是小块,即一个大块由16*16*16个小块组成,当然有些小块是透明的!
当修改完Engine Settings的属性后,如果不修改World Name那么你必须删除其对应的世界文件保存的数据文件,在根目录的Worlds文件夹下找到该world name对应的文件,删除里面的所有信息,不然可能会出错!(尼玛为什么编辑器不做好这一步还要我手动去删除?)。如果你修改world name那么就会在Worlds文件夹下创建一个新的文件保存数据。

Texture unit:贴图单位,即贴图中的小图,如果一个贴图有8*8个小图,那么单位就是0.125 = 1/8,也可以理解为其小图的像素点(宽或高)与贴图(宽或高)的比例
Texture padding: 0,  贴图中小图的间隙为0,这个也是一个比例,如果贴图是500*500,那么0.1就是50像素的间隙了!

Generate meshes 生成Mesh
Generate collider 生成collider

Save load voxel data 当这个取消勾选后,每次加载地图时候都会新生成一次地图,而不是之前的地图!

下面的一些属性,是联网用的,目前还没研究过。

二、插件常用API说明(必看)

Engine类:

Engine.SaveWorldInstant()  保存地图数据

Engine.GetVoxelGameObject(ushort voxelId) 根据Voxel小方块ID实例化小方块block_ID,返回GameObject

Engine.VoxelRaycast( Vector3 origin, Vector3 direction, float range, bool ignoreTransparent ) 相当于unity的射线检测,但是它是特殊的,因为unity的射线检测的是一个Chunk大方块,而不是小方块,但是这个方法能返回射线指着的大方块上的小方块VoxelInfo,具体如何实现自行看代码。(VoxelInfo是一个小方块的位置信息类,代表一个小方块在大方块的哪个位置上,下方会详细说明。)

Engine.PositionToChunkIndex(Vector3 position) 返回Index类型数据,根据世界坐标点获取该坐标在Chunk大方块的相对位置.

Engine.PositionToVoxelInfo( Vector3 position )  返回VoxelInfo类型数据,根据世界坐标点获取该坐标所在的VoxelInfo(该坐标所在的小方块位置对象)

VoxelInfo类:(以下方法都是普通公共方法及属性说明)

插入介绍Index类:插件封装的一个类似Vector3的东西,只是它里面封装了一些方法。

Index index;//小方块所在大方块Chunk的相对位置,例如:(0,0,0)表示小方块在大方块的左下角,这个相对关系是插件自己弄好了的。

Index adjacentIndex://小方块临近位置(与鼠标指向点的最近的那一边位置!)比如:前方有一个小方块,我指着它的正前方,即我看着它的那一面,那么临近位置就是它的正前方。这个不好说,到时候自己测试吧。

Chunk chunk; //小方块所在的大方块对象

GetVoxel():获取小方块的ID

SetVoxel(ushort data, bool updateMesh):根据data(ID)改变该小方块的mesh,或不改变只是改变方块的voxel数据。

Voxel类:(即block预制体身上的类,主要的API是它的静态方法)

Voxel.DestroyBlock ( VoxelInfo voxelInfo ):根据voxelInfo(小方块位置数据)删除小方块,触发其身上VoxelEvents脚本的VoxelEvents方法。

Voxel.PlaceBlock ( VoxelInfo voxelInfo, ushort data):将新的小方块(data是ID)放置到voxelInfo位置,触发其身上VoxelEvents脚本的OnBlockPlace方法。

Voxel.ChangeBlock( VoxelInfo voxelInfo, ushort data):将新的小方块(data是ID)放置到voxelInfo位置,但是会触发小方块身上的VoxelEvents类的OnBlockChange方法。

这个VoxelEvents类就不再过多说明了,个人建议不要去挂这个VoxelEvents到block身上,因为这种触发方式很花费性能,因为小方块不是以物体存在于场景的,而是虚拟的,只是大方块Mesh的其中一个虚拟的Mesh!所以为了触发小方块预制体身上的VoxelEvents脚本的事件,他就必须要先实例化这个物体出来,进而调用这些事件,调用完后再销毁该小方块~ 实例化和销毁是耗费性能的。

如果的确是需要这种需求,例如:把小方块放上去后需要做点什么,根据不同方块而做不同的事情,可以写个静态类,去调用,多用写if判断 根据ID就可以区分不同的方块了。虽然看起来不好看 但是起码性能绝对比插件原本的强很多。

ChunkManager类:(它管理着所有Chunk大方块)

ChunkManager.SpawnChunks(Vector3 position); 以世界某个点来实例化地图(地图生成的形状如Engine Editor窗口描述所说)。

后期有待更新,实际使用流程,其实基本上面说完后就可以自己试着玩玩了,源码也是很容易理解的,不过最好还是画着思维导图去理解,因为还是有些许乱的,这个插件源码。

你可能感兴趣的:(Unity游戏分析,Unity3d,个人见解)