| 其实很早我就打算发出来分享给大家了_(:з」∠)_ 但一直苦于高三学习的紧张,没法码这篇长篇大论
 .JPG) 现在放寒假了,也有一点点空闲时间了
 .gif) 好了废话不多说,我们进入正题:
 
 在网上找了很多相关例子,用得最多的还属柏林噪声了(柏林是个人的名字,不是地名
 .JPG) ) 你知道吗?我的世界用的就是这个算法
  关于这个噪声的具体描述我就不贴了_(:з」∠)_我估计一下午是解释不完了
 .JPG) 本人还在念高三,没学高数,所以具体的一些术语我也不解释了,免得误导大家
 .JPG) 大概就是用正玄波和噪声波相结合的产物
 可以理解为一个普通的sin函数曲线在每个对应的f(x)上随机加或减一个数,得到一个随机函数曲线
 (sin图像大家能理解吧,要是不理解那我也没办法了
 .jpg) ) 和普通随机数相比,优势很明显:
 不会产生悬崖式的断带,看起来也不是那么的突兀
 
 概念解释完了,我们结合例子看一下。由于我用的是unity学习这个算法,所以今天用unity来举例子
 .jpg) 打字大家估计看的烦,我直接上代码吧
  结合代码学习应该快一点 
 using System.Collections;
 using System.Collections.Generic;
 using UnityEngine;
 
 public class PerlinNoiseGenerator : MonoBehaviour {
 /*
 为了让大家看得更直观,我们用盒子来生成地图,就像我的世界一样
 */
 public int width = 100;//地图的长
 public int depth = 100;//地图的宽
 public float maxHeight = 10;//地图的高
 public float relief = 15;//生成地图的坡度
 
 private float _seedX, _seedZ;//长和宽的种子,当然这两个可以为同一个
 
 void Awake () {
 float _seedX = Random.value * 100f;//我发现不乘100根本看不出来有变化_(:з」∠)_
 float _seedZ = Random.value * 100f;
 
 for(int x = 0;x<width;x++){
 for (int z = 0; z < depth; z++) {
 GameObject cube = GameObject.CreatePrimitive (PrimitiveType.Cube);//生成一个盒子,就是右键生成那种
 cube.transform.localPosition = new Vector3 (x, 0, z);
 cube.transform.SetParent (transform);
 SetY (cube);
 }
 }
 }
 
 void Start () {
 
 }
 
 // Update is called once per frame
 void Update () {
 
 }
 
 void SetY (GameObject Cube){
 float Y = 0;
 
 float xSample = (Cube.transform.localPosition.x + _seedX) / relief;
 float zSample = (Cube.transform.localPosition.z + _seedZ) / relief;
 float noise = Mathf.PerlinNoise (xSample, zSample);//这个就是核心代码了,unity自带的一个算法。当然网上也是有这个随机库的,下一个就好啦
 Y = maxHeight * noise;//给盒子设置高度
 
 Cube.transform.localPosition = new Vector3 (Cube.transform.localPosition.x, Y,Cube.transform.localPosition.z);//设置盒子的新的高度
 }
 
 }
 
 到这里应该差不多了,我们看看效果_
 .gif) 
 
   
 看起来还行,确实蛮舒服的
  简单吧?大家快去试试吧!
 .gif) 
 
 (以下为拓展)
 既然核心算法大家都明白了,那我们还可以往更高级的地方考虑
 .jpg) 比如这种:
 
   或者这种:
 
   不过我想重点介绍这种(高度图结合柏林噪声并根据相关坡度生成相应贴图):
 
   这个一共需要两个脚本,一个存储变量,一个提供算法
 还是老规矩,直接上代码:
 这是提供算法的
 using System.Collections;
 using System.Collections.Generic;
 using UnityEngine;
 
 public class MapGenerator : MonoBehaviour {
 
 private TerrainData Terr_data;
 public Terrain Terr;
 private GameController Game;
 private float _seedX, _seedZ;
 private float relief = 15;
 private float Maxheight = 15;
 private float Height = 15;
 void Awake () {
 Game = GameObject.FindGameObjectWithTag (Tags.Gamesetting).GetComponent<GameController>();//这里很重要!请适当修改
 relief = Game.relief;
 Maxheight = Game.Maxheight;
 Height = Game.Height;
 float _seedX = Random.value * 100;
 float _seedZ = Random.value * 100;
 }
 
 // Use this for initialization
 void Start () {
 Terr_data = new TerrainData ();
 Terr_data.heightmapResolution = Game.heightmapResolution;
 SetHeighMap ();
 }
 
 // Update is called once per frame
 void Update () {
 
 }
 
 
 
 void SetHeighMap () {
 var heightmap = GetHeightMap ();
 Terr_data.SetHeights (0, 0, heightmap);
 Terr_data.alphamapResolution = 32;
 ApplyTextrue (Terr_data);
 Terr_data.size = new Vector3 (Game.Depth, Game.Maxheight, Game.Width);
 
 Terr = Terrain.CreateTerrainGameObject (Terr_data).GetComponent<Terrain> ();
 Terr.Flush ();
 }
 
 void ApplyTextrue (TerrainData data) {
 var FlatSplat = new SplatPrototype ();
 var SteepSplat = new SplatPrototype ();
 
 FlatSplat.texture = Game.FlatTexture;
 SteepSplat.texture = Game.SteepTexture;
 
 data.splatPrototypes = new SplatPrototype[] {
 FlatSplat,
 SteepSplat
 };
 data.RefreshPrototypes ();
 
 var splatMap = new float[data.alphamapResolution, data.alphamapResolution, 2];
 
 for (var z = 0; z < data.alphamapHeight; z++) {
 for (var x = 0; x < data.alphamapWidth; x++) {
 var normalizedX = (float)x / (data.alphamapWidth - 1);
 var normalizedZ = (float)z / (data.alphamapHeight - 1);
 
 var steepness = data.GetSteepness(normalizedX, normalizedZ);
 var steepnessNormalized = Mathf.Clamp(steepness / 5.5f, 0, 1f);
 
 splatMap[z, x, 0] = 1f - steepnessNormalized;
 splatMap[z, x, 1] = steepnessNormalized;
 }
 }
 data.SetAlphamaps(0, 0, splatMap);
 }
 
 float[,] GetHeightMap () {
 var Heightmap = new float[Terr_data.heightmapResolution, Terr_data.heightmapResolution];
 for (var x = 0; x < Terr_data.heightmapResolution; x++) {
 for (var z = 0; z < Terr_data.heightmapResolution; z++) {
 var XC = ((float)x + _seedX) / relief;
 var ZC = ((float)z + _seedZ) / relief;
 
 float Y = Mathf.PerlinNoise (XC, ZC);
 //                                GameObject go = GameObject.CreatePrimitive (PrimitiveType.Cube)as GameObject;
 //                                go.transform.position = new Vector3 (x, Y, z);
 Heightmap[x,z] = Y;
 }
 }
 return Heightmap;
 }
 }
 
 这是提供变量的:
 using System.Collections;
 using System.Collections.Generic;
 using UnityEngine;
 
 public class GameController : MonoBehaviour {
 [Header("地图属性")]
 public float Width = 100;
 public float Depth = 100;
 public float Maxheight = 50;
 public float Height = 10;
 public float WaterHigh = 10;
 public float relief = 15;
 public int heightmapResolution = 16;
 public Texture2D FlatTexture;
 public Texture2D SteepTexture;
 
 // Use this for initialization
 void Start () {
 
 }
 
 // Update is called once per frame
 void Update () {
 
 }
 }
 
 这一块就有点上难度了
 .jpg) 大家如果有不懂的可以评论一下,我一定会鼎力相助的  当然,这篇文章只是起到抛转引玉的效果。如果大家有什么好的想法的话,请务必在评论里面分享一下你的建议
 .gif) 
 (题外话)
 有没有人对东方的辐射类型的RPG游戏感兴趣啊
  迫切希望找个同好一起完成,我的QQ:370683893 谢谢大家
 .JPG) 
 
 |