Veloren 的一些不同之处
摘要
本文讨论了开源体素RPG游戏Veloren中的非传统开发选择,重点介绍了使用实体组件系统(ECS)来实现可扩展性以及玩家与NPC的统一二元性,为游戏开发者提供了见解。
<p><a href="https://lobste.rs/s/zutlqt/some_things_veloren_does_differently">评论</a></p>
查看缓存全文
缓存时间: 2026/09/16 05:22
# Veloren 的独特之处
来源:https://blog.jsbarretto.com/post/veloren
作为 Veloren (https://veloren.net/) 的核心开发者之一,如今我参与项目的时间有限——身为父母,想必你能理解这份忙碌。
本文将记录 Veloren 开发过程中做出的若干非常规选择。如果你正在开发游戏,或许能从中获得一些启发。
山景画面
## ECS 架构
Veloren 采用 ECS(实体组件系统)架构而非传统的面向对象类层次结构。尽管如今——尤其在 Rust 生态系统中——ECS 已相当常见,但在 2018 年项目启动时,这种架构除演示程序外仍鲜少被实际应用。我们不得不在内部创建大量新概念以满足项目需求。
这个决策带来了巨大收益:Veloren 的扩展性远优于多数多人游戏。在拥有 48 个线程的服务器上,当连接玩家超过 500 人、游戏世界内存在数万个实体交互时,CPU 利用率仍能稳定在 50%。多数 MMO 游戏只能通过缩减玩法范围(减少跨实体交互)或激进地划分玩家至不同世界空间来达到类似规模。
玩家群体
ECS 确实存在一些意外特性。传统游戏引擎通过编译时类型分支区分不同实体,类间多态仅针对特定场景选择性启用。而在 ECS 中,多态是默认行为,实体分类则需要主动实现。这引发了一些有趣的副作用:
- 我们曾遇到一个 Bug:根据玩家携带的物品为其分配 `ItemDrop` 组件。由于战利品实现方式的过渡处理不当,导致玩家靠近时能“拾取”其他玩家。这会移除被拾取玩家的实体,从而将其踢出服务器。
- 初次实现坐骑功能(允许角色骑乘马匹等生物)时,循环检测逻辑(防止相互骑乘的实体)和控制传递逻辑(允许骑手向坐骑传递控制指令)均存在缺陷。这导致玩家可以堆叠出巨大的实体塔(每个实体骑乘下方的实体),甚至创建骑乘循环。物理引擎在处理这些矛盾的骑乘约束时,会产生类似 Bethesda 式风车般的混沌效果,颇具娱乐性。
## 玩家/NPC 二元性
玩家角色与 NPC 在最大范围内保持同一性。例如二者:
- 以相同方式与物理引擎交互。NPC 无法瞬移、穿模或人工控制物理属性。若 NPC 的 AI 代码未能在穿越悬崖时充分考虑动量与摩擦力,便会坠落。
- 拥有完全相同的移动控制选项。所有移动和控制操作都通过 `Controller` (https://docs.veloren.net/veloren_common/comp/controller/struct.Controller.html) ECS 组件实现,该组件充当虚拟游戏手柄。玩家的 `Controller` 输入来自键鼠与实体手柄;NPC 的 `Controller` 输入则由游戏 `agent` 决策树系统提供。
- 受相同移动控制代码约束。`Controller` 输入受角色身体物理能力限制,并通过完全相同的代码转换为物理引擎输入。
- 共享完全相同的技能树和经验系统。在游戏早期版本中,附近 NPC 升级时甚至会播放音效!
是的,火车也是实体
## 粗柱体(Chonks)
作为体素游戏,Veloren 需要存储地形数据。常见方案包括:
- 大型 3D 方块数组,通过哈希表寻址分块存储
- RLE (https://en.wikipedia.org/wiki/Run-length_encoding) 编码的体素数据,通常按块分组
- 八叉树结构,将整个世界定义为递归分割的 2x2x2 体素立方树
这些方案各有缺陷:大型数组检索快但压缩潜力低;RLE 仅在体素数据呈现大范围同质块时压缩效果良好,随机访问性能极差;八叉树对现代 CPU 缓存极不友好。
Veloren 采用了全新方案:名为“粗柱体(chonks)”的自创数据结构(“柱体(column)”与“块(chunk)”的合成词)。它使用内部单级索引表,将 NxNxN 方块组表示为“同质(自相似)”或“异质(需表内独立索引)”。每个粗柱体还被分割为任意数量的固定高度“子块”,各子块具有独立的垂直偏移。这种设计在缓存一致性与压缩率间取得了良好平衡,并提供了出色的随机访问性能。
## 世界预生成
多数体素游戏(如《Minecraft》)会在玩家探索时逐步生成新世界。Veloren 则选择在启动时以较低分辨率预生成整个世界,并在玩家接近时通过各类插值与噪声技术填充细节。
这种前置生成使 Veloren 能实现仅依赖局部约束解算无法达成的复杂世界特征,例如始终向低处流淌的长河。
世界地图
此外,我们能在游戏启动前花费时间进行世界模拟,从而创造出更有趣的地形特征。
关于“程序化生成”的随想
若请普通人描述程序化生成,他们可能会说“随机生成游戏内容”。这完全颠倒了概念:程序化生成的核心在于定义游戏元素间的约束关系,以契合人类大脑固有的模式识别倾向。
最优秀的程序化生成系统不会通过组合空间的随机游走来编织复杂叙事线索,而是通过确保自洽性实现目标。若发现河流,应能溯流至源头;若遭遇怪物,应能找到其巢穴;若击败怪物,附近城镇角色谈论玩家的方式应发生变化。
优秀的程序化生成系统几乎不依赖随机性——因为随机性本就是玩家带来的体验。程序化生成器的作用正是约束这种随机性,将其引导至具有因果关联的自洽系统中。
这种低分辨率预生成的另一个优势在于:我们可以为远处地形创建精确的细节层次(LoD)替代模型,使游戏在低端硬件上也能实现几乎无限的视野距离。
高视野距离截图展示
## 基于物理的生成过程
多数体素游戏大量采用目的论式程序化生成。这种理念关注美学输出:颜色是否具有艺术感?山脉是否足够有趣?世界是否“看起来合理”?其典型技术包括程序化噪声或半随机算法(如波函数坍缩 (https://en.wikipedia.org/wiki/Model_synthesis))。
Veloren 则更侧重顶层本体论式程序化生成。这种方法不聚焦输出结果,而是专注于构建内部世界模型——重现过程的物理输入,进而模拟其对世界的影响。
最典型的例子是我们基于物理的水力侵蚀模型 (https://gitlab.com/veloren/veloren/-/blob/master/world/src/sim/erosion.rs),它塑造了游戏标志性的山地地形与复杂河网系统。
另一个案例是程序化路径生成器,它使用简化版移动成本模型来寻找地点间的节能路径。
Veloren 许多程序化元素的物理特性,正是营造游戏“超越玩家视角的宏大感”的关键所在。
沙漠台地
## 实时模拟系统(RTSim)
Veloren 不会在初始世界生成后停止物理模拟。游戏内置名为“rtsim”(实时模拟)的世界模拟系统,利用前述低分辨率世界数据,在无玩家靠近时持续模拟整个世界。
每个世界中的 NPC 在 rtsim 内都存在双重状态。当 NPC 离开玩家活跃视野时不会被销毁,而是融入 rtsim 体系——游戏继续追踪其移动,并模拟其高层决策树逻辑的影响。
Rtsim 正成为 Veloren 中日益复杂的模块,游戏许多动态要素现已交由其处理:任务模拟、阵营动态甚至部分经济系统都在游戏运行时由其跟踪。例如,玩家可以观察到海盗与流浪盗贼对定居点的袭击行动。NPC(尤其是商人)还会在世界范围内迁徙。
Rtsim 设计具备扩展性:大多数 Veloren 世界包含数万 NPC,rtsim 能够同时追踪所有实体。
大型城镇
## 无隐形墙设计
我们早期确立的游戏设计原则是避免“隐形墙”:无论是世界地图边缘的物理边界,还是游戏武断禁止元素交互的概念限制。
这一约束虽给游戏平衡与玩法交互设计带来挑战——例如当顽皮玩家将强大 Boss 引出地牢带入城镇时,游戏尚无明确的处理机制——但 Veloren 允许此类行为。这促使我们以防御性思维设计游戏系统,确保其能在极端异常情况下持续运作。
## 单一世界空间
许多游戏为性能或艺术考量,会将世界划分为不同区域并通过加载场景分隔。Veloren 选择完全摒弃这种做法,将所有玩法元素置于同一物理空间。
这一设计在地底洞穴系统中带来了复杂性。这些洞穴有时深达地下千米,且常有多层结构。如何在玩家脚下存在洞穴网络时保持游戏性能,成为持续性挑战。
其中令人意外的难点是光照处理。Veloren 拥有比多数体素游戏更复杂的光照模型,支持烘焙体素光照、点光源、方向阴影映射、反射、环境光模型、体积雾与云层(二者均产生光线散射)等技术。确保表面光照信息不会在正午时分渗入最深洞穴,其复杂程度远超预期:闪电等全局效应易通过阴影映射泄漏环境光数据,甚至在屏幕空间反射中显现,需要投入大量精力校准玩家视角下的效果可见性。
通往洞穴的天坑
相似文章
我发布了一款本地LLM驱动的RPG,其中生成的NPC、地点、物品和任务作为游戏内对象持久存在
一位开发者发布了一款本地LLM驱动的RPG,其中程序生成的NPC、地点、物品和任务作为游戏内对象持久存在,展示了生成式AI与游戏的新颖结合。
有人试过Vecel的Eve框架吗?
Vecel的Eve框架是一个优雅的Agent框架,被比作Agent界的Next.js,其中文件系统充当简化的Agent栈。
@MrCollison: 关于构建游戏引擎最疯狂的事情是,我学到了一个曾经让我最害怕的概念:列式存储。它……
作者分享了自己在构建游戏引擎时对列式存储的个人突破性理解,并将其与Trizen的ECS和ClickHouseDB联系起来。
使用Odin打造的简单易用实体组件系统 (ECS)
moecs 是一个专为Odin编程语言打造的简单易用实体组件系统 (ECS) 库,简化了软件项目中实体、组件和系统的管理。
@0xAikoDai: https://x.com/0xAikoDai/status/2057317742248931363
作者反思了对一款由AI Dungeon制作团队开发的全新AI原生RPG测试版的体验,指出了在战斗和系统可读性方面AI生成的沉浸感会崩溃的设计挑战,并呼吁为AI原生游戏制定新的设计原则。