您当前的位置: 首页 > 

CloudHu1989

暂无认证

  • 5浏览

    0关注

    89博文

    0收益

  • 0浏览

    0点赞

    0打赏

    0留言

私信
关注
热门博文

用ECS做HexMap:河流

CloudHu1989 发布时间:2019-09-04 14:58:34 ,浏览量:5

基于Unity2019最新ECS架构开发MMO游戏笔记25
    • 准备工作
    • 前言
      • ECS专题目录
      • ECS更新计划
      • 作者的话

河流 最终效果

准备工作

如果大佬对ECS版的海克斯无限地图感兴趣,不妨参与进来,欢迎Star/Folk源码 0下载Unity编辑器(2019.1.12f1 or 更新的版本),if(已经下载了)continue; 1克隆:git clone https://github.com/cloudhu/HexMapMadeInUnity2019ECS.git --recurse 或下载Zip压缩包 2如果下载的是压缩包,需要先将压缩包解压。然后将HexMapMadeInUnity2019ECS添加到Unity Hub项目中; 3用Unity Hub打开的开源项目:HexMapMadeInUnity2019ECS,等待Unity进行编译工作; 4打开项目后,启动场景在Scenes目录下,打开AdvancedHexMap场景(优化重构的版本)。

前言

在CSDN偶然发现了Andrew翻译的ECS官方文档,很有参考价值,这里推荐一下!如果之前有看到的话,可以少走不少弯路! 这一篇的河流比较复杂,花了两天时间来做,主要是水平有限,很多东西不理解。最终还是选择先实现出来,效果还可以,原作者的知识点这里就不说了,可以看原文,这里只说下河流的随机算法。

在生成单元的时候,根据单元的海拔来获取源头,毕竟河流的源头一般都是高处,水往低处流嘛。所以我暂时设定一个常量来控制源头的产生,顺便设置河床海拔和水面海拔偏移量的常数,都写在HexMetrics脚本里:

    #region River河流
    /// 
    /// 河流源头的海拔值
    /// 
    public const int RiverSourceElevation = 5;

    /// 
    /// 河床海拔偏移量
    /// 
    public const float StreamBedElevationOffset = -1.75f;

    /// 
    /// 水面海拔偏移量
    /// 
    public const float RiverSurfaceElevationOffset = -0.5f;
    #endregion

接下来在单元生成系统CellSpawnSystem中计算河流的随机算法,先申请两个容器来保存参数:

            //河流的源头
            NativeList riverSources = new NativeList(totalCellCount/15,Allocator.Temp);
            //流入的河流索引
            NativeArray riverIn = new NativeArray(totalCellCount, Allocator.Temp);
            
//若干代码

            //释放内存
            riverSources.Dispose();
            riverIn.Dispose();

这里使用原生的容器,方便申请内存和释放,河流源头产生的几率大概是2/7,还有一些源头是需要闭源的。首先把第0个单元设置为源头,这样方便去观察生成的效果,0是比较好的参照:

            //使第0个单元成为河流的源头
            Colors[0] = Color.green;
            Elevations[0] = HexMetrics.RiverSourceElevation;
            riverSources.Add(0);

之后的每个单元都随机生成,我们只需要观察一个源头即可:

            //后面将从服务器获取这些数据,现在暂时随机生成
            for (int i = 1; i = HexMetrics.RiverSourceElevation) riverSources.Add(i);
            }

这里的i是从1开始的,因为0已经被占位了,如果随机海拔满足河源产生的海拔,就将其索引添加进列表。这样我们手里就有原始数据了,这些数据将成为地图生成的关键,从这里开始,后面的地图都带有一定的必然性。 这里涉及到河流相关的数据,我们保存在Data组件里面:

/// 
/// 河流数据
/// 
public struct River : IComponentData
{
    /// 
    /// 是否有河流进入
    /// 
    public bool HasIncomingRiver;

    /// 
    /// 是否有河流出
    /// 
    public bool HasOutgoingRiver;

    /// 
    /// 流入方向
    /// 
    public int IncomingRiver;

    /// 
    /// 流出方向
    /// 
    public int OutgoingRiver;
}

在计算的时候先初始化这些字段,再通过算法来赋值,下面是出版的算法:五种河流的配置

  • 大河向东流,所以我们尽量使河流的走向是由西向东,未来地图的东面会做成湖或海;
  • 水往低处走,所以流经的单元必然比河源的海拔低;
  • 一个单元最多通过一条河流,这是为了使简化算法;
  • 优先流向与自身海拔相近的单元,这是为了源远流长,避免过早流入低海拔的单元;
  • 如果没有出口,就此闭源,这是为了减少河源,避免河流过短;

基于这些算法,我们来写代码:

  //初始化河流数据
  bool hasRiver = false;
  bool hasOutgoingRiver = false;
  bool hasIncomingRiver = false;
  int incomingRiver = int.MinValue;
  int outgoingRiver = int.MinValue;
  //如果当前单元是河源
  if (riverSources.Contains(i))
  {
      hasRiver = true;//河源单元必然有河流
      //上一个单元海拔,用来做比较
      int lastElevation = int.MinValue;
      //从六个方向寻找河床
      for (int j = 0; j             
关注
打赏
1664096582
查看更多评论
0.1176s