转载请注明出处:http://www.cnblogs.com/shamoyuu/p/unity_minecraft_04.html

一、新建Block类

我们的Block类用来存储跟Block相关的信息,例如name,id,贴图坐标等等

using UnityEngine;

/// <summary>
/// 方块的方向
/// </summary>
public enum BlockDirection : byte
{
Front = ,
Back = ,
Left = ,
Right = ,
Top = ,
Bottom =
} /// <summary>
/// 方块对象,存储方块的所有信息
/// </summary>
public class Block
{
//方块的ID
public byte id; //方块的名字
public string name; //方块的图标,并不会采用在游戏中动态生成的做法
public Texture icon; //方向(指的是前面所面朝的方向)
public BlockDirection direction = BlockDirection.Front; //前面贴图的坐标
public byte textureFrontX;
public byte textureFrontY; //后面贴图的坐标
public byte textureBackX;
public byte textureBackY; //右面贴图的坐标
public byte textureRightX;
public byte textureRightY; //左面贴图的坐标
public byte textureLeftX;
public byte textureLeftY; //上面贴图的坐标
public byte textureTopX;
public byte textureTopY; //下面贴图的坐标
public byte textureBottomX;
public byte textureBottomY; //都是A面的方块
public Block(byte id, string name, byte textureX, byte textureY)
: this(id, name, textureX, textureY, textureX, textureY, textureX, textureY, textureX, textureY)
{
} //上面是A,其他面是B的方块
public Block(byte id, string name, byte textureX, byte textureY, byte textureTopX, byte textureTopY)
: this(id, name, textureX, textureY, textureX, textureY, textureX, textureY, textureX, textureY, textureTopX, textureTopY, textureX, textureY)
{
} //上面是A,下面是B,其他面是C的方块
public Block(byte id, string name, byte textureX, byte textureY, byte textureTopX, byte textureTopY, byte textureBottomX, byte textureBottomY)
: this(id, name, textureX, textureY, textureX, textureY, textureX, textureY, textureX, textureY, textureTopX, textureTopY, textureBottomX, textureBottomY)
{
} //上面是A,下面是B,前面是C,其他面是D的方块
public Block(byte id, string name, byte textureFrontX, byte textureFrontY, byte textureX, byte textureY, byte textureTopX, byte textureTopY, byte textureBottomX, byte textureBottomY)
: this(id, name, textureFrontX, textureFrontY, textureX, textureY, textureX, textureY, textureX, textureY, textureTopX, textureTopY, textureBottomX, textureBottomY)
{
} //上下左右前后面都不一样的方块
public Block(byte id, string name, byte textureFrontX, byte textureFrontY, byte textureBackX, byte textureBackY, byte textureRightX, byte textureRightY,
byte textureLeftX, byte textureLeftY, byte textureTopX, byte textureTopY, byte textureBottomX, byte textureBottomY)
{
this.id = id;
this.name = name; this.textureFrontX = textureFrontX;
this.textureFrontY = textureFrontY; this.textureBackX = textureBackX;
this.textureBackY = textureBackY; this.textureRightX = textureRightX;
this.textureRightY = textureRightY; this.textureLeftX = textureLeftX;
this.textureLeftY = textureLeftY; this.textureTopX = textureTopX;
this.textureTopY = textureTopY; this.textureBottomX = textureBottomX;
this.textureBottomY = textureBottomY;
}
}

最上面我们定义了方块方向,不过我们暂时不会用到,先放着。

然后我们定义了方块的基础信息,还有它各个面上的贴图。

重载了多个构造函数来生成方块,都是A面的那个应该比较常用。

贴图的坐标是0~1的float,我们把一张贴图划分成了32×32的(如下图),每一个瓦片宽高都是1/32,Block的贴图坐标就是这么算出来的。

图是高清图,右键保存下来,拖给Chunk的预制体

二、新建BlockList类

BlockList类,用来管理我们所有的Block,我们先简单地用它生成一个土块。

using System.Collections.Generic;
using UnityEngine; /// <summary>
/// 存储所有的Block对象的信息
/// </summary>
public class BlockList : MonoBehaviour
{
public static Dictionary<byte, Block> blocks = new Dictionary<byte, Block>(); void Awake()
{
Block dirt = new Block(, "Dirt", , );
blocks.Add(dirt.id, dirt);
} public static Block GetBlock(byte id)
{
return blocks[id];
}
}

这里Block dirt = new Block(1, "Dirt", 2, 31)中的2,31是以左下角为起点开始数的,左下角的贴图是0,0,所以2,31是我们最顶部第3个瓦片

三、修改Chunk,为Block添加UV坐标

我们新建一个private List<Vector2> uv = new List<Vector2>(),用来存储uv点的信息,它和vertices的用法是一样的,我们也是从左下角开始,逆时针循环。

我们按照这个顺序添加点就可以了

using Soultia.Util;
using System.Collections;
using System.Collections.Generic;
using UnityEngine; namespace Soultia.Voxel
{
[RequireComponent(typeof(MeshFilter))]
[RequireComponent(typeof(MeshRenderer))]
[RequireComponent(typeof(MeshCollider))]
public class Chunk : MonoBehaviour
{
public static int width = ;
public static int height = ; public byte[,,] blocks;
public Vector3i position; private Mesh mesh; //面需要的点
private List<Vector3> vertices = new List<Vector3>();
//生成三边面时用到的vertices的index
private List<int> triangles = new List<int>();
//所有的uv信息
private List<Vector2> uv = new List<Vector2>();
//uv贴图每行每列的宽度(0~1),这里我的贴图是32×32的,所以是1/32
public static float textureOffset = / 32f;
//让UV稍微缩小一点,避免出现它旁边的贴图
public static float shrinkSize = 0.001f; //当前Chunk是否正在生成中
private bool isWorking = false; void Start()
{
position = new Vector3i(this.transform.position);
if (Map.instance.chunks.ContainsKey(position))
{
Destroy(this);
}
else
{
this.name = "(" + position.x + "," + position.y + "," + position.z + ")";
StartFunction();
}
} void StartFunction()
{
mesh = new Mesh();
mesh.name = "Chunk"; StartCoroutine(CreateMap());
} IEnumerator CreateMap()
{
while (isWorking)
{
yield return null;
}
isWorking = true;
blocks = new byte[width, height, width];
for (int x = ; x < Chunk.width; x++)
{
for (int y = ; y < Chunk.height; y++)
{
for (int z = ; z < Chunk.width; z++)
{
blocks[x, y, z] = ;
}
}
} StartCoroutine(CreateMesh());
} IEnumerator CreateMesh()
{
vertices.Clear();
triangles.Clear(); //把所有面的点和面的索引添加进去
for (int x = ; x < Chunk.width; x++)
{
for (int y = ; y < Chunk.height; y++)
{
for (int z = ; z < Chunk.width; z++)
{
//获取当前坐标的Block对象
Block block = BlockList.GetBlock(this.blocks[x, y, z]);
if (block == null) continue; if (IsBlockTransparent(x + , y, z))
{
AddFrontFace(x, y, z, block);
}
if (IsBlockTransparent(x - , y, z))
{
AddBackFace(x, y, z, block);
}
if (IsBlockTransparent(x, y, z + ))
{
AddRightFace(x, y, z, block);
}
if (IsBlockTransparent(x, y, z - ))
{
AddLeftFace(x, y, z, block);
}
if (IsBlockTransparent(x, y + , z))
{
AddTopFace(x, y, z, block);
}
if (IsBlockTransparent(x, y - , z))
{
AddBottomFace(x, y, z, block);
}
}
}
} //为点和index赋值
mesh.vertices = vertices.ToArray();
mesh.triangles = triangles.ToArray();
mesh.uv = uv.ToArray(); //重新计算顶点和法线
mesh.RecalculateBounds();
mesh.RecalculateNormals(); //将生成好的面赋值给组件
this.GetComponent<MeshFilter>().mesh = mesh;
this.GetComponent<MeshCollider>().sharedMesh = mesh; yield return null;
isWorking = false;
} public static bool IsBlockTransparent(int x, int y, int z)
{
if (x >= width || y >= height || z >= width || x < || y < || z < )
{
return true;
}
return false;
} //前面
void AddFrontFace(int x, int y, int z, Block block)
{
//第一个三角面
triangles.Add( + vertices.Count);
triangles.Add( + vertices.Count);
triangles.Add( + vertices.Count); //第二个三角面
triangles.Add( + vertices.Count);
triangles.Add( + vertices.Count);
triangles.Add( + vertices.Count); //添加4个点
vertices.Add(new Vector3( + x, + y, + z));
vertices.Add(new Vector3( + x, + y, + z));
vertices.Add(new Vector3( + x, + y, + z));
vertices.Add(new Vector3( + x, + y, + z)); //添加UV坐标点,跟上面4个点循环的顺序一致
uv.Add(new Vector2(block.textureFrontX * textureOffset, block.textureFrontY * textureOffset) + new Vector2(shrinkSize, shrinkSize));
uv.Add(new Vector2(block.textureFrontX * textureOffset + textureOffset, block.textureFrontY * textureOffset) + new Vector2(-shrinkSize, shrinkSize));
uv.Add(new Vector2(block.textureFrontX * textureOffset + textureOffset, block.textureFrontY * textureOffset + textureOffset) + new Vector2(-shrinkSize, -shrinkSize));
uv.Add(new Vector2(block.textureFrontX * textureOffset, block.textureFrontY * textureOffset + textureOffset) + new Vector2(shrinkSize, -shrinkSize));
} //背面
void AddBackFace(int x, int y, int z, Block block)
{
//第一个三角面
triangles.Add( + vertices.Count);
triangles.Add( + vertices.Count);
triangles.Add( + vertices.Count); //第二个三角面
triangles.Add( + vertices.Count);
triangles.Add( + vertices.Count);
triangles.Add( + vertices.Count); //添加4个点
vertices.Add(new Vector3(- + x, + y, + z));
vertices.Add(new Vector3(- + x, + y, + z));
vertices.Add(new Vector3(- + x, + y, + z));
vertices.Add(new Vector3(- + x, + y, + z)); //添加UV坐标点,跟上面4个点循环的顺序一致
uv.Add(new Vector2(block.textureBackX * textureOffset, block.textureBackY * textureOffset) + new Vector2(shrinkSize, shrinkSize));
uv.Add(new Vector2(block.textureBackX * textureOffset + textureOffset, block.textureBackY * textureOffset) + new Vector2(-shrinkSize, shrinkSize));
uv.Add(new Vector2(block.textureBackX * textureOffset + textureOffset, block.textureBackY * textureOffset + textureOffset) + new Vector2(-shrinkSize, -shrinkSize));
uv.Add(new Vector2(block.textureBackX * textureOffset, block.textureBackY * textureOffset + textureOffset) + new Vector2(shrinkSize, -shrinkSize));
} //右面
void AddRightFace(int x, int y, int z, Block block)
{
//第一个三角面
triangles.Add( + vertices.Count);
triangles.Add( + vertices.Count);
triangles.Add( + vertices.Count); //第二个三角面
triangles.Add( + vertices.Count);
triangles.Add( + vertices.Count);
triangles.Add( + vertices.Count); //添加4个点
vertices.Add(new Vector3( + x, + y, + z));
vertices.Add(new Vector3(- + x, + y, + z));
vertices.Add(new Vector3(- + x, + y, + z));
vertices.Add(new Vector3( + x, + y, + z)); //添加UV坐标点,跟上面4个点循环的顺序一致
uv.Add(new Vector2(block.textureRightX * textureOffset, block.textureRightY * textureOffset) + new Vector2(shrinkSize, shrinkSize));
uv.Add(new Vector2(block.textureRightX * textureOffset + textureOffset, block.textureRightY * textureOffset) + new Vector2(-shrinkSize, shrinkSize));
uv.Add(new Vector2(block.textureRightX * textureOffset + textureOffset, block.textureRightY * textureOffset + textureOffset) + new Vector2(-shrinkSize, -shrinkSize));
uv.Add(new Vector2(block.textureRightX * textureOffset, block.textureRightY * textureOffset + textureOffset) + new Vector2(shrinkSize, -shrinkSize));
} //左面
void AddLeftFace(int x, int y, int z, Block block)
{
//第一个三角面
triangles.Add( + vertices.Count);
triangles.Add( + vertices.Count);
triangles.Add( + vertices.Count); //第二个三角面
triangles.Add( + vertices.Count);
triangles.Add( + vertices.Count);
triangles.Add( + vertices.Count); //添加4个点
vertices.Add(new Vector3(- + x, + y, + z));
vertices.Add(new Vector3( + x, + y, + z));
vertices.Add(new Vector3( + x, + y, + z));
vertices.Add(new Vector3(- + x, + y, + z)); //添加UV坐标点,跟上面4个点循环的顺序一致
uv.Add(new Vector2(block.textureLeftX * textureOffset, block.textureLeftY * textureOffset) + new Vector2(shrinkSize, shrinkSize));
uv.Add(new Vector2(block.textureLeftX * textureOffset + textureOffset, block.textureLeftY * textureOffset) + new Vector2(-shrinkSize, shrinkSize));
uv.Add(new Vector2(block.textureLeftX * textureOffset + textureOffset, block.textureLeftY * textureOffset + textureOffset) + new Vector2(-shrinkSize, -shrinkSize));
uv.Add(new Vector2(block.textureLeftX * textureOffset, block.textureLeftY * textureOffset + textureOffset) + new Vector2(shrinkSize, -shrinkSize));
} //上面
void AddTopFace(int x, int y, int z, Block block)
{
//第一个三角面
triangles.Add( + vertices.Count);
triangles.Add( + vertices.Count);
triangles.Add( + vertices.Count); //第二个三角面
triangles.Add( + vertices.Count);
triangles.Add( + vertices.Count);
triangles.Add( + vertices.Count); //添加4个点
vertices.Add(new Vector3( + x, + y, + z));
vertices.Add(new Vector3( + x, + y, + z));
vertices.Add(new Vector3(- + x, + y, + z));
vertices.Add(new Vector3(- + x, + y, + z)); //添加UV坐标点,跟上面4个点循环的顺序一致
uv.Add(new Vector2(block.textureTopX * textureOffset, block.textureTopY * textureOffset) + new Vector2(shrinkSize, shrinkSize));
uv.Add(new Vector2(block.textureTopX * textureOffset + textureOffset, block.textureTopY * textureOffset) + new Vector2(-shrinkSize, shrinkSize));
uv.Add(new Vector2(block.textureTopX * textureOffset + textureOffset, block.textureTopY * textureOffset + textureOffset) + new Vector2(-shrinkSize, -shrinkSize));
uv.Add(new Vector2(block.textureTopX * textureOffset, block.textureTopY * textureOffset + textureOffset) + new Vector2(shrinkSize, -shrinkSize));
} //下面
void AddBottomFace(int x, int y, int z, Block block)
{
//第一个三角面
triangles.Add( + vertices.Count);
triangles.Add( + vertices.Count);
triangles.Add( + vertices.Count); //第二个三角面
triangles.Add( + vertices.Count);
triangles.Add( + vertices.Count);
triangles.Add( + vertices.Count); //添加4个点
vertices.Add(new Vector3(- + x, + y, + z));
vertices.Add(new Vector3(- + x, + y, + z));
vertices.Add(new Vector3( + x, + y, + z));
vertices.Add(new Vector3( + x, + y, + z)); //添加UV坐标点,跟上面4个点循环的顺序一致
uv.Add(new Vector2(block.textureBottomX * textureOffset, block.textureBottomY * textureOffset) + new Vector2(shrinkSize, shrinkSize));
uv.Add(new Vector2(block.textureBottomX * textureOffset + textureOffset, block.textureBottomY * textureOffset) + new Vector2(-shrinkSize, shrinkSize));
uv.Add(new Vector2(block.textureBottomX * textureOffset + textureOffset, block.textureBottomY * textureOffset + textureOffset) + new Vector2(-shrinkSize, -shrinkSize));
uv.Add(new Vector2(block.textureBottomX * textureOffset, block.textureBottomY * textureOffset + textureOffset) + new Vector2(shrinkSize, -shrinkSize));
}
}
}

在CreateMesh方法中我们获取到了当前的Block对象,然后在绘制面的时候,根据Block的信息绘制了它对应的贴图。

需要注意的是,每一个uv点,我们都加了一个shrinkSize的偏差值,这是因为如果紧贴着边缘获取瓦片的话,当前的瓦片可能多取到旁边瓦片的1像素,形成锯齿

我们添加了这个偏差值以后就好了

我们加了偏差值以后,是少取了这个瓦片外面的一圈,这样即使某些情况下多取一像素也没事。

【Unity3D】Unity3D开发《我的世界》之四、创建一个Block的更多相关文章

  1. unity3d游戏开发学习之使用3dmax创建导弹模型

    在着手研究Unity3D的游戏开发时,3D模型能够考虑从unity的assets store去获取,也能够从网上搜索下载,同一时候咱们也能够尝试下自己动手去做一些简单的模型. 这里就依据unity3d ...

  2. C#程序员的春天之从零开始学习unity3D游戏开发入门教程二(创建项目及基本面板介绍)

    一项目创建: 创建项目是开发的第一步. 运行untiy之后如果是第一次运行会弹出 我们这里随便创建一个项目. 二Untiy面板介绍: 三代码编辑器的切换: 这里我安装了vs2012. 到这里开发环境基 ...

  3. Unity3D游戏开发从零单排(四) - 制作一个iOS游戏

    提要 此篇是一个国外教程的翻译,尽管有点老,可是适合新手入门. 自己去写代码.debug,布置场景,能够收获到非常多.游戏邦上已经有前面两部分的译文,这里翻译的是游戏的最后一个部分. 欢迎回来 在第一 ...

  4. three.js-走进3d的奇妙世界一创建一个三维场景

      一.git代码仓库地址 git clone https://github.com/josdirksen/learning-threejs-third  下载并解压 二.创建一个三维场景 如下图所示 ...

  5. 【Xamarin开发 Android 系列 8】 创建一个Json读取数据应用(上)

    后续将内容贴上来...........

  6. Unity3D游戏开发之粒子系统实现具体解释

     今天为大家分享的是Unity3D中的粒子系统.粒子系统通经常使用来表现烟雾.云等高级效果.是一个十分注重制作技巧的部分.今天我们将以一个气泡的演示实例来一起学习怎样在Unity3D中使用粒子系统 ...

  7. cocos2d-x游戏开发(二)之创建第一个项目

    配置好开发环境之后,尝试创建一个cocos项目 (1)打开cocos2d-x安装目录,如D:\DIY\cocos2d-x-3.3 看到目录下有可执行文件 download-deps 以及 setup ...

  8. Revit API创建一个拷贝房间内对象布局命令

    本课程演示创建一个拷贝房间内对象布局命令,完整演示步骤和代码.这个命令把选中房间内的对象复制到其它选中的一个或多个房间中,而且保持与源房间一致的相对位置.通过本讲座使听众知道创建一个二次开发程序很简单 ...

  9. Framework7 - 入门教程(安装、配置、创建一个H5应用)

    1,Framework7介绍 (1)Framework7 是一个开源免费的框架.可以用来开发混合移动应用(原生和 HTML 混合)或者开发 iOS & Android 风格的 WEB APP. ...

随机推荐

  1. unity getcomponentsinchildren 翻船

    今天使用GetComponentsInChildren, 老司机翻船.因为一直以来我使用这个函数,下意识的从来所有的相同component都是放在子节点下,本身节点肯定不会放一个相同的componen ...

  2. Mysql Innodb 锁机制

    latch与lock latch 可以认为是应用程序中的锁,可以称为闩锁(轻量级的锁) 因为其要求锁定的时间必须要非常短,若持续时间长,则会导致应用性能非常差,在InnoDB存储引擎中,latch又可 ...

  3. C#中的out参数/ref参数/params可变参数

    out参数: out关键字 通过引用来传递参数,在定义方法和调用方法的时候都必须使用out关键字 简单来讲out可以用来返回多个参数类型. static void Main(string[] args ...

  4. Effective Java 之-----精确的答案与double&float

    题目: 假设你口袋里有1$,看到货架上有一排美味的糖果,标价分别为0.10$,0.20$,0.30$...1$,你打算从标价为0.10$的糖果开始买起,每种买一颗,一直到不能支付货架上下一种价格的糖果 ...

  5. Jmockit之mock特性详解

    本文是Jmockit学习过程中,根据官网所列的工具特性进行解读. 1.调用次数约束(Invocation count constraints) 可以通过调用计数约束来指定预期和/或允许匹配给定期望的调 ...

  6. JUnit5 技术前瞻

    更多原创测试技术文章同步更新到微信公众号 :三国测,敬请扫码关注个人的微信号,感谢! 原文链接:http://www.cnblogs.com/zishi/p/6868495.html   JUnit ...

  7. spring jdbc踩坑日记,new JdbcTemplate 为null导致UserDao一直为null

    private DataSource datasource; private JdbcTemplate jdbcTemplateObject; //设置注入 public void setdataso ...

  8. bash启动加载过程

  9. SAS SATA SSD基本介绍

    SATA硬盘采用新的设计结构,数据传输快,节省空间,相对于IDE硬盘具有很多优势: 1 .SATA硬盘比IDE硬盘传输速度高.目前SATA可以提供150MB/s的高峰传输速率.今后将达到300 MB/ ...

  10. bzoj 1975: [Sdoi2010]魔法猪学院 [k短路]

    1975: [Sdoi2010]魔法猪学院 裸题... 被double坑死了 #include <iostream> #include <cstdio> #include &l ...