Unity无限地形生成(基于柏林噪声的简单生成)

要求:构建一个户外开放世界游戏,为该游戏添加天空,地形,植物,并支持场景里自由漫游。这里实现一个无限地形的产生;
实现漫游
漫游的功能由玩家移动和摄像机跟随组成:

  1. 玩家移动脚本:挂载在玩家物体上
    (1)核心思想:获得键盘按下,使用Translate()来移动,并由共有变量speed来控制移动的速度。
    (2)代码实现:
 if (Input.GetKey(KeyCode.W)){this.gameObject.transform.Translate(Vector3.forward *speed * Time.deltaTime);} if (Input.GetKey(KeyCode.S)){this.gameObject.transform.Translate(Vector3.back * speed*Time.deltaTime);}if (Input.GetKey(KeyCode.A)){this.gameObject.transform.Translate(Vector3.left *speed* Time.deltaTime);}if (Input.GetKey(KeyCode.D)){this.gameObject.transform.Translate(Vector3.right *speed* Time.deltaTime);}
  1. 摄像机跟随脚本,挂载在主摄像机上,并需要添加主摄像机的跟随目标的位置
    (1)核心思路:记录相机和目标物体的初始间距,随着目标物体的运动,相机保持这个间距跟踪目标物体。
    (2)代码实现:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;public class CameraFellow : MonoBehaviour
{private Vector3 offset;public Transform player;void Start(){offset = player.position - transform.position;}void Update(){transform.position = Vector3.Lerp(transform.position, player.position - offset, Time.deltaTime * 5);}
}

产生地形块
既然要产生无限地形,那么设定这个地形的单位地形是很关键;这里的地形块使用unity的plane来设计, 操作mesh来设计地形
(1) 核心思路:采用噪声来随机mesh的顶点的高度,然后再覆盖原来的mesh的顶点,这样可以使得plane有地形的起伏;使用柏林噪声可以保证每个地形块在拼接的时候可以比较光滑起伏,这是无限地形的关键就是怎么样使得地形随机的情况下保证拼接的光滑。然后就是使用random来产生随机的顶点索引,再该顶点上设置植物。
(2) 核心代码:
a.使用柏林噪声更新高度
相关参数:

  public int heightScale = 5;public float detailScale = 5.0f;

b.使用mathf.PerlinNoise函数对顶点高度进行设置,然后再覆盖:

  Mesh mesh = this.GetComponent<MeshFilter>().mesh;Vector3[] vertices = mesh.vertices;for (int v = 0; v < vertices.Length; v++){vertices[v].y = Mathf.PerlinNoise((vertices[v].x + this.transform.position.x) / detailScale,(vertices[v].z + this.transform.position.z) / detailScale) * heightScale;}mesh.vertices = vertices;

c.随机植被的位置:

  public GameObject gass;public GameObject tree1;public GameObject tree2;
  int a = Random.Range(0, vertices.Length - 1);//随机位置产生草gass.transform.position = transform.TransformPoint(vertices[a]);int b = Random.Range(0, vertices.Length - 1);//随机位置产生树tree1.transform.position = transform.TransformPoint(vertices[b]);int c = Random.Range(0, vertices.Length - 1);//随机位置产生树tree2.transform.position = transform.TransformPoint(vertices[c]);

效果:


使用地形块拼接更大的场景,并根据玩家的位置更新地形,达到无限地形的效果。使用hash来记录产生的地形块,通过玩家的位置变化来判断是否移动;
(1) 核心思路
初始化生成一个大的网格比如代码中是2020的,这里以33的来说明;中间的位置是玩家的初始位置;每一个地形方格的位置以及他们创建的时间(这是为了判断这个方格是不是新的方格)保留在一个hash表中;

假设玩家向上移动,到上面那个方格;则玩家当前的位置为新的玩家初始位置,在周围生成一圈33的网格(实际上只往前产生一排网格,原来的保留下来),这些33的网格更新创建时间为当前时间,现在我们有了一个3*4的网格了;然后是删除后面一排网格(这些网格不在player的周围),判断标准是这些网格的创建时间不是等于当前时间;这样使得玩家始终在地形的中央;

(2) 关键代码
初始化地图,在player的周围生成地形,注意要使用hash表记录这些网格,这里可以建设player为(0,0):

this.gameObject.transform.position = Vector3.zero;starPos = Vector3.zero;float updateTime = Time.realtimeSinceStartup;//拼接为一个全新的20*20的大地形for(int x=-halfTilesX;x<halfTilesX;x++)for(int z=-halfTilesZ;z<halfTilesZ;z++){Vector3 pos = new Vector3(x * planeSize + starPos.x, 0, z * planeSize + starPos.z);GameObject t = (GameObject)Instantiate(plane, pos, Quaternion.identity);//使用Tile类来记录这些产生的gameobjects存储于hash表中//以位置信息记录标签string tilename = "Tile_" + ((int)(pos.x)).ToString() + "_" + ((int)(pos.z)).ToString();//修改原来的地形的名字t.name = tilename;//实例化Tile对象Tile tile = new Tile(t, updateTime);//添加到hash表中tiles.Add(tilename,tile);}

随着玩家移动更新地形:

 int xMove = (int)(player.transform.position.x - starPos.x);int yMove = (int)(player.transform.position.z - starPos.z);if(Mathf.Abs(xMove)>=planeSize||Mathf.Abs(yMove)>=planeSize){float updateTime = Time.realtimeSinceStartup;//这个比较关键即计算玩家位置是否靠近下一个网格(这里是向下取整)int playerX = (int)(Mathf.Floor(player.transform.position.x / planeSize) * planeSize);int playerZ = (int)(Mathf.Floor(player.transform.position.z / planeSize) * planeSize);for (int x = -halfTilesX; x < halfTilesX; x++)for (int z = -halfTilesZ; z < halfTilesZ; z++){Vector3 pos = new Vector3(x * planeSize + playerX, 0, z * planeSize +playerZ);//以位置信息记录标签string tilename = "Tile_" + ((int)(pos.x)).ToString() + "_" + ((int)(pos.z)).ToString();//判断这是一个新的格子吗,即不存在于if(!tiles.ContainsKey(tilename)){GameObject t = (GameObject)Instantiate(plane, pos, Quaternion.identity);//地形的名字:坐标t.name = tilename;//实例化Tile对象Tile tile = new Tile(t, updateTime);//添加到hash表中tiles.Add(tilename, tile);}else{//更新时间(tiles[tilename] as Tile).creatoinTime = updateTime;}}

根据地形格子的创建时间来更新hash表:

  Hashtable newTerrain = new Hashtable();foreach(Tile tls in tiles.Values){//当前这个格子不在player周围,删除if(tls.creatoinTime!=updateTime){//销毁Destroy(tls.theTile);}else{newTerrain.Add(tls.theTile.name, tls);}}tiles = newTerrain;//更新初始位置starPos = player.transform.position

(3)效果(使得player始终在地图的中间):


最终的效果:


不足之处:
使用柏林噪声产生的地形虽然连接比较平滑,但是地形形成上比较重复,不够随机。然后每次更新都需要删除大量的object的做法好像也不是太好。学生实验作业,可能有些问题,望指正。
参考资料:https://www.youtube.com/watch?v=dycHQFEz8VI

Unity无限地形生成(基于柏林噪声的简单生成)相关推荐

  1. Unity 使用柏林噪声(Perlin Noise)生成网格地图

    前言 最近在尝试制作一个基于网格地图的RPG游戏,所以想着自己生成一个网格地图. 但是网格地图的生成有很多的方式,大多数的方式都达不到我的要求,我需要一个地图可以随机生成各种地形,也可以储存一些地形数 ...

  2. Unity程序化地形教程 第二期 噪声图的完善和更多细节添加

    Unity程序化地形教程 第二期 噪声图的完善和更多细节添加 前言:完整的程序化地形教程在我的主页相关专栏中,目前正在持续更新,可以添加收藏,方便日后查找 零.学完本期能够实现的效果 书接上期,学完之 ...

  3. Unity记录3.4-地图-柏林噪声生成 1D 地图及过渡地图

    文章首发及后续更新:https://mwhls.top/4489.html,无图/无目录/格式错误/更多相关请至首发页查看. 新的更新内容请到mwhls.top查看. 欢迎提出任何疑问及批评,非常感谢 ...

  4. Unity记录3.3-地图-柏林噪声生成 2D 地图

    文章首发及后续更新:https://mwhls.top/4486.html,无图/无目录/格式错误/更多相关请至首发页查看. 新的更新内容请到mwhls.top查看. 欢迎提出任何疑问及批评,非常感谢 ...

  5. python生成10个随机密码_Python简单生成8位随机密码的方法

    本文实例讲述了Python简单生成8位随机密码的方法.分享给大家供大家参考,具体如下: #!/usr/bin/env python # -*- coding: utf-8 -*- import ran ...

  6. 木木的Unity学习笔记(四)—— Unity中的柏林噪声(Perlin Noise)

    木木的Unity学习笔记(四)-- Unity中的柏林噪声 柏林噪声是一个非常强大算法,经常用于程序生成随机内容,在游戏和其他像电影等多媒体领域广泛应用.算法发明者Ken Perlin也因此算法获得奥 ...

  7. 【转载】柏林噪声算法

    转载自:https://www.cnblogs.com/leoin2012/p/7218033.html   原作者:立航 柏林噪声是一个非常强大算法,经常用于程序生成随机内容,在游戏和其他像电影等多 ...

  8. 一篇文章搞懂柏林噪声算法,附代码讲解

    本文目的是以一种通俗简单的方式介绍Ken Perlin的改进版柏林噪声算法,讲解代码采用c#编写,开源免费使用.如果你只是想看完整代码,点击这里. 柏林噪声是一个非常强大算法,经常用于程序生成随机内容 ...

  9. Unity中使用柏林噪声生成地图

    孙广东  2017.3.27 http://blog.csdn.NET/u010019717 主要是利用Unity的 Mathf.PerlinNoise   函数(柏林噪声)的不同寻常的功能. htt ...

最新文章

  1. postgresql 数据库远程访问
  2. 防止在多模块Maven中找到“未找到插件”
  3. 李国杰院士:国内开源社区的崛起需要一个过程
  4. python构造函数_Python构造函数
  5. pku 1325 Machine Schedule(匈牙利算法)
  6. wps 项目进度_如何用Excel做项目进度表
  7. php yar swoole 比较,Hprose 和 Yar 的性能比较
  8. 图像处理之底片效果、黑白效果、浮雕效果
  9. 学生机房虚拟化(十二)搭建Clonezilla SE
  10. aix 到 linux的网络,通过VIOS实现AIX系统的网络虚拟化
  11. 阅文的作者们,正在进行一场必输的抗争
  12. 怎么在node环境使用es6语法? bable有什么作用? 发布环境下移除console
  13. Java之下载word文档,linux视频监控
  14. 智慧医院新系统架构设计与建设
  15. android后台通过View生成分享图片
  16. 手动设置网页cookie的值
  17. 坚持开源软件的创新之路--陆首群
  18. NO.65——人工智能学习:python实现广度优先搜索
  19. 线性滤波和非线性滤波
  20. matlab负无穷大到正无穷大怎么打,matlab中怎么定义n从负无穷到正无?

热门文章

  1. 数据库(二)表的设计
  2. 【Redis】利用 Redis 实现分布式锁
  3. 1、RunLoop应用简介
  4. 甲骨文(oracle) 美国,甲骨文全球大会.美国
  5. Win10找回windowsz照片查看器
  6. 今天雨停了,昨日杨是7点多冒雨赶来住宿
  7. 李宏毅机器学习作业二(从参考答案中学到了什么)
  8. 用cocos2dx做一个简单的单机捕鱼达人游戏(1)
  9. 计算机网络技术的自我鉴定怎么写,计算机网络实习自我鉴定范文
  10. 记忆计算机课,记忆人脑就计算机课件.ppt