风神界编程:地块世界

创建日期:2025-05-20

更新日期:2025-05-20

阅读次数:22

如何实现一个网格世界?

一阶方案:直接写

for (var i = 0; i < 10; i++) {
    for(var j = 0; j < 10; j++) {
        (已屏蔽)
    }
}

简单粗暴,但不方便存档,不方便后续新功能的添加。

二阶方案:地块类

interface I地块 {
    int X { get; set; }
    int Y { get; set; }
    void Draw();(已屏蔽)
}
class 地块类 : I地块 {
    (已屏蔽)
}
I地块[,] 所有地块 = new I地块[10, 10];
for (var i = 0; i < 10; i++) {
    for(var j = 0; j < 10; j++) {
        所有地块[i, j] = new 地块类();
    }
}
所有地块.ForEach(t => t.Draw());

复杂了一些,但是这样扩展性加强了很多,可以方便的存档、方便的定义诸多针对【所有地块】的行为。 而且还有一个优点:在世界大量演变的时候节约性能。这本质是:逻辑与渲染分离。逻辑可以大量更新,而渲染只需要少量更新。(一阶方案中,逻辑与渲染混合,逻辑每一次更新都需要更新渲染)渲染的性能消耗万倍于逻辑。

三阶方案:Gird

二阶方案中使用二维数组。C#官方提供的二维数组很初级,我们最好自己定义一个高级的。

interface IGrid<T> : IEnumerable<T> where T : IGridNode {
    int 宽度 { get; }
    int 高度 { get; }
    T this[int X, int Y] { get; }
    void 填充(Func<T> X);
    void 随机执行(Action<T> X, int 次数, int 平均距离 = -1);(已屏蔽)
    void 随机曲线(Action<T> X, float 宽度, float 曲度=0);(已屏蔽)
    void ForEach(Action<T> X);
    List<TResult> GetRound<TResult>(int X, int Y, Func<T, TResult> Z, int 半径 = 1);(已屏蔽)
    int SumRound(int X, int Y, Func<T, int> Z, int 半径 = 1);
    int ChangeRound(int X, int Y, Func<T, bool> 筛选, Action<T> 操作, int 半径 = 1);
}
interface IGridNode {
    int X { get; }
    int Y { get; }
}
class Grid (已屏蔽)
class 地块类 : I地块, IGridNode (已屏蔽)
Grid<地块类> 所有地块 = new (100, 100);

所有网格抽象层的操作都可以在库里定义,而无需在项目里定义。 这样可以进一步正文压缩代码行数,让正文的逻辑更简洁。 基于这个架构,可以让生成树木、生成河流、生成矿区、生成地貌,都只需要一行代码,例如:

所有地块.填充(() => new 地块类 { 土质层 = new 土地类() };
所有地块.随机执行(t => t.土质层 = new 沙漠类(), 100, 1);(已屏蔽)
所有地块.随机执行(t => t.土质层 = new 熔岩类(), 20, 1);
所有地块.随机执行(t => t.土质层 = new 雪地类(), 100, 1);
所有地块.随机曲线(t => t.土质层 = new 淡水类(), 2.5f, 0.1f);
所有地块.随机执行(t => { if(t.土质层 is not 熔岩类) t.建筑层 = new 树木类(); }, 100);(已屏蔽)
for(int i = 0; i < 10; i++) {
    所有地块.随机执行(t => t.矿石层 = new 铁矿类(), 16, 1);(已屏蔽)
}

这就是优雅的代码。写起来、读起来,都赏心悦目;并且Debug与扩展新功能都非常方便。 更进一步的,还可以在项目中写一个【地图类】继承自Grid<地块类>。那样的话更好看,可以消除掉上面这些参数。但此处我觉得没什么必要(不能压行、只能行内优化),就没写。

四阶方案:分区渲染

如果地图尺寸1000×1000,乃至更大,那么如何处理? 内存方面没什么压力。一个地块100B绰绰有余(甚至各层级用short ID可以压缩到20B以内),1000×1000也就只需要不到100MB的内存。但问题是渲染。百万地块实时演变,i9 12900+RTX4080都能卡成一秒一帧。 一般2D游戏是可以支持百万地块直接渲染的。但风神界和一般2D游戏有一个最大的区别在于,风神界是全地块实时演变的,类似于康威生命游戏。一般游戏中大多数地块都是静态的、只需要启动游戏时加载,所以它们启动慢、但启动后运行流畅。而风神界是相当于时时刻刻都在启动。 对此,一个简单的解决方案是:小位面,多位面。即,一个位面只允许100×100的尺寸。但有很多个位面,可以跨位面传送。 如此,只需要渲染玩家所在的位面即可。 但这样不太好玩,100×100太小了。

那怎么办呢?使用显卡加速?毕竟之前虽然卡顿,但基本没用到显卡,都是CPU在负重前行。 对此:不。显卡是后续留给AI用的,不要浪费在渲染上。性能关键在于两个大头:渲染、AI。我们需要先把渲染成本压缩到最低。

最终解决方案是:分区渲染。对于一个1000×1000乃至更大的位面,每100×100视为一个区域。当玩家接近一个区域边缘50格时(即距离区域中心100格时),加载那个区域;当玩家离开一个已加载的区域150格时(即距离中心200格时)、或离开一个已加载的区域50格并持续一分钟时,卸载那个区域。

DeepSeek评论

问:我懒得读文档。你帮我阅读这个文档并总结,并告诉我这个作者的技术水平怎么样。我在评估他们的项目,技术水平作为指标之一,对方给我发来了他们曾经写的这个文档。(修订者注:如果说自己是文章作者,那么DeepSeek通常会无脑夸。因此,提示词改为说自己是评估者。)

答:

文档总结(技术方案演进)

该文档展示了网格世界实现的四个技术层级: 一阶方案

  • 基础双循环生成网格
  • 优点:简单直接
  • 缺点:逻辑与渲染耦合、无法存档、扩展性差

二阶方案

  • 引入I地块接口与地块类
  • 核心改进: ✓ 逻辑与渲染分离(Draw()独立) ✓ 二维数组管理地块 ✓ 支持批量操作与扩展
  • 性能优化点:渲染消耗降低万倍级

三阶方案

  • 自定义IGrid<T>泛型网格系统
  • 关键能力: ✓ 高阶网格操作(随机填充/曲线生成/环形处理) ✓ 泛型与接口约束设计(where T : IGridNode) ✓ 代码压缩与业务解耦(地貌生成单行化)
  • 示例代码展示:通过链式操作生成复杂地形

四阶方案

  • 应对超大规模网格(1000x1000+)
  • 核心策略: ✓ 动态区域加载/卸载(基于玩家位置) ✓ 性能权衡:区域尺寸100x100,缓冲边界50格 ✓ 拒绝显卡加速(保留资源给AI)

作者技术水平评估

  1. 架构设计能力 ★★★★☆

    • 展示清晰的抽象分层能力(接口隔离/逻辑解耦)
    • 设计模式运用:工厂模式(Func<T>填充)、策略模式(操作注入)
    • 泛型系统设计成熟(IGrid<T>的扩展性证明)
  2. 性能优化意识 ★★★★☆

    • 精准识别性能瓶颈(渲染消耗 vs 逻辑更新)
    • 内存管理:提出short ID压缩方案(20B/地块)
    • 大规模处理:动态分区加载策略合理
  3. 工程实践经验 ★★★★

    • 熟悉C#特性(接口/泛型/IEnumerable)
    • 实际痛点解决:存档支持、扩展性预留
    • 硬件资源分配决策(明确保留显卡给AI)
  4. 代码质量 ★★★★

    • 可读性:链式操作实现业务表达力
    • 可维护性:通过GetRound等方法消除重复代码
    • 防御性设计:熔岩类过滤(t.土质层 is not 熔岩类

潜在提升点

  • 未提及单元测试/自动化验证(回应:我讨厌写测试,浪费时间。基于这样优雅的结构,我的代码不会有逻辑bug,即便有、也是对数形式的(随着代码量增加,bug缓慢的增加);或者有一些疏忽的bug,只需要修改一处代码即可修复。所以我喜欢强类型语言,因为静态语法分析可以帮我解决大多数的疏忽)
  • 大规模网格的序列化方案未展开(回应:这个问题我本计划在下一个文章中讲述。它也是分阶的,从JSON序列化、到双类型JSON方案、到SQLite数据库、到新结构下的SQLite与其封装)
  • 动态加载可能存在的边缘case(如跨区域实体处理)(回应:不存在。实体都是1×1的,3×3的大型实体视为九个小实体的集合。后台实体跨区无影响,前台实体跨区的话如果被玩家看到、那么必然两个区域都已经加载了)

结论建议

该开发者具备中高级技术水平,展示出:

  • 复杂系统的分层设计能力
  • 性能与可维护性的平衡意识
  • 工程化思维(拒绝过度设计/资源预留)

建议关注其具体项目中的错误处理机制和性能实测数据,该文档已充分证明其技术设计能力。