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

一、导入Unity3D自带的第一人称角色控制器

直接导入就行,我们用FPSController。

二、为Map添加创建Chunk和判断Chunk是否存在的方法

using Soultia.Util;
using System.Collections;
using System.Collections.Generic;
using UnityEngine; namespace Soultia.Voxel
{
public class Map : MonoBehaviour
{
public static Map instance; public static GameObject chunkPrefab; public Dictionary<Vector3i, GameObject> chunks = new Dictionary<Vector3i, GameObject>(); //当前是否正在生成Chunk
private bool spawningChunk = false; void Awake()
{
instance = this;
chunkPrefab = Resources.Load("Prefab/Chunk") as GameObject;
} //生成Chunk
public void CreateChunk(Vector3i pos)
{
if (spawningChunk) return; StartCoroutine(SpawnChunk(pos));
} private IEnumerator SpawnChunk(Vector3i pos)
{
spawningChunk = true;
Instantiate(chunkPrefab, pos, Quaternion.identity);
yield return null;
spawningChunk = false;
} //通过Chunk的坐标来判断它是否存在
public bool ChunkExists(Vector3i worldPosition)
{
return this.ChunkExists(worldPosition.x, worldPosition.y, worldPosition.z);
}
//通过Chunk的坐标来判断它是否存在
public bool ChunkExists(int x, int y, int z)
{
return chunks.ContainsKey(new Vector3i(x, y, z));
}
}
}

上上一章用来测试的Start方法也删掉了,我们下面会通过玩家的位置来生成

三、添加草方块

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); Block grass = new Block(, "Grass", , , , , , );
blocks.Add(grass.id, grass);
} public static Block GetBlock(byte id)
{
return blocks.ContainsKey(id) ? blocks[id] : null;
}
}

四、修改Chunk

using Soultia.Util;
using System.Collections;
using System.Collections.Generic;
using System.Runtime.CompilerServices;
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.ChunkExists(position))
{
Debug.Log("此方块已存在" + position);
Destroy(this);
}
else
{
Map.instance.chunks.Add(position, this.gameObject);
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++)
{
if (y == Chunk.height - )
{
if (Random.Range(, ) == )
{
blocks[x, y, z] = ;
}
}
else
{
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;
} //此坐标方块是否透明,Chunk中的局部坐标
public bool IsBlockTransparent(int x, int y, int z)
{
if (x >= width || y >= height || z >= width || x < || y < || z < )
{
return true;
}
else
{
//如果当前方块的id是0,那的确是透明的
return this.blocks[x, y, z] == ;
}
} //前面
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));
}
}
}

我们修改了Chunk的CreateMap方法,让它在最顶部有一定几率生成草方块,便于我们直观地看到无限地形的生成。

然后修改了Start方法,判断了它是否存在,如果不存在,就把它添加到Map的chunks里,如果已经存在了,就销毁它。

五、添加PlayerController

这个对象就是用来检测玩家周围一定范围内的Chunk是否已经生成,如果没有生成就会生成它。

using Soultia.Util;
using Soultia.Voxel;
using UnityEngine; public class PlayerController : MonoBehaviour
{
//视线范围
public int viewRange = ; void Update()
{
for (float x = transform.position.x - Chunk.width * ; x < transform.position.x + Chunk.width * ; x += Chunk.width)
{
for (float z = transform.position.z - Chunk.width * ; z < transform.position.z + Chunk.width * ; z += Chunk.width)
{
int xx = Chunk.width * Mathf.FloorToInt(x / Chunk.width);
int zz = Chunk.width * Mathf.FloorToInt(z / Chunk.width);
if (!Map.instance.ChunkExists(xx, , zz))
{
Map.instance.CreateChunk(new Vector3i(xx, , zz));
}
}
}
}
}

然后把它拖给玩家

到这里就已经可以生成无限地形了,按住Shift一直跑,已经可以当成小小的跑酷游戏玩了~

【Unity3D】Unity3D开发《我的世界》之五、创建无限地形(视频)的更多相关文章

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

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

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

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

  3. Unity3D游戏开发初探—1.跨平台的游戏引擎让.NET程序员新生

    一.Unity3D平台简介 Unity是由Unity Technologies开发的一个让轻松创建诸如三维视频游戏.建筑可视化.实时三维动画等类型互动内容的多平台的综合型游戏开发工具,是一个全面整合的 ...

  4. [Unity3D]Unity3D游戏开发《反对》说到游戏(上)——目标跟踪

    朋友,大家好.我是秦培,欢迎关注我的博客.我的博客地址blog.csdn.net/qinyuanpei. 首先博主要自我反省,过了这么久才来更新博客,这段时间主要是在忙着写期末的作业,所以博主基本上没 ...

  5. [Unity3D]Unity3D游戏开发之跑酷游戏项目解说

    大家好,我是秦元培.我參加了CSDN2014博客之星的评选,欢迎大家为我投票,同一时候希望在新的一年里大家能继续支持我的博客. 大家晚上好.我是秦元培,欢迎大家关注我的博客,我的博客地址是blog.c ...

  6. [Unity3D]Unity3D游戏开发之伤害数值显示

    大家好,我是秦元培,欢迎大家关注我的博客,我的博客地址是blog.csdn.net/qinyuanpei.众所周知,在RPG游戏策划中最为重要的一个环节是数值策划.数值策划是一个关于游戏平衡方面的概念 ...

  7. Unity3D游戏开发初探—2.初步了解3D模型基础

    一.什么是3D模型? 1.1 3D模型概述 简而言之,3D模型就是三维的.立体的模型,D是英文Dimensions的缩写. 3D模型也可以说是用3Ds MAX建造的立体模型,包括各种建筑.人物.植被. ...

  8. 从一点儿不会开始——Unity3D游戏开发学习(一)

    一些废话 我是一个windows phone.windows 8的忠实粉丝,也是一个开发者,开发数个windows phone应用和两个windows 8应用.对开发游戏一直抱有强烈兴趣和愿望,但奈何 ...

  9. Unity3D游戏开发之连续滚动背景

    Unity3D游戏开发之连续滚动背景 原文  http://blog.csdn.net/qinyuanpei/article/details/22983421 在诸如天天跑酷等2D游戏中,因为游戏须要 ...

随机推荐

  1. malloc,calloc,realloc,alloc

    三个函数的申明分别是: void* realloc(void* ptr, unsigned newsize); void* malloc(unsigned size); void* calloc(si ...

  2. Spring Boot 使用maven打包成jar

    1.application.properties加入如下配置 server.port= 2.修改pom.xml <?xml version="1.0" encoding=&q ...

  3. notify丢失、虚假唤醒

    notify丢失: 假设线程A因为某种条件在条件队列中等待,同时线程B因为另外一种条件在同一个条件队列中等待,也就是说线程A/B都被同一个Object.wait()挂起,但是等待的条件不同. 现在假设 ...

  4. Spring整合JMS(二)——三种消息监听器

    原文地址:http://haohaoxuexi.iteye.com/blog/1893676 1.3     消息监听器MessageListener 在Spring整合JMS的应用中我们在定义消息监 ...

  5. 三栏布局,div左右盒子是定宽,中间是自适应

    用弹性布局flex: 给父盒子加个display:flex; 给中间盒子设flex=1; /* 弹性盒子布局*/ .wrap{ width: 100%; height: 90px; display: ...

  6. 洛谷 [P1402] 酒店之王

    有两个约束条件的二分图匹配 我们回忆一下二分图匹配的匈牙利算法的具体流程,它是通过寻找增广路来判断最大匹配数的,我们再观察一下题目中的两个条件,只有两个条件都满足,才算找到一条增广路,所以我们可以分别 ...

  7. css模板

    最近好多人问我博客的css模板.... 现在是高三,没多少时间,趁放假赶紧更一下 主体就是把博客园的一个模板改动了一点 上面的图片特效,也是从别人那里得到的代码,大致就是下面那些,下面的三个图片换成自 ...

  8. BZOJ 1502: [NOI2005]月下柠檬树 [辛普森积分 解析几何 圆]

    1502: [NOI2005]月下柠檬树 Time Limit: 5 Sec  Memory Limit: 64 MBSubmit: 1070  Solved: 596[Submit][Status] ...

  9. 使用IntelliJ IDEA(PHPStorm)和xdebug在firefox、chrome中远程调试PHP

    很多PHP程序员都习惯于使用echo.var_dump和exit来中断和调试web应用程序,本文主要介绍结合xdebug.IntelliJ IDEA.Firefox/chrome/IE来远程调试PHP ...

  10. 像我这样优雅地进行Spring整合MongoDB

    本文重点是要将mongodb与spring整合到项目中去,在实践中发现问题,追踪问题,然后解决问题. 一.准备 Maven.Spring(spring-data-mongodb) spring Dat ...