跳至正文

9 月:维度!

· 9 分钟读完
Gabriel • SyedMuhammad
lead developer™

维度!

维度 🌌​

我自豪地宣布 nanos world 最受请求集成的功能之一已实现:维度! 🥳

备注

在这个初始版本中,可能会出现漏洞、不同步和奇怪的事情,请立即告诉我!

维度是客户端中分开的世界,玩家和 Actor 在其中是分开的。默认情况下,所有玩家和实体都在维度 1 中。将玩家移到另一个维度后,所有不属于该维度的实体对该玩家来说都会被销毁,而新维度中的所有实体都会为他生成。

API 非常简单:

actor:SetDimension(number)

通过发送一个实体,它们的“子级”也会移动,例如:

  • 发送一个 Actor 时,所有其他附加的 Actor 也会随之移动。
  • 发送 Player 时,Character 会随之移动。
  • 发送 Character 时,Player 不会一起移动。 Weapon 或 Prop(以及附加物)会移动。
  • 发送 Vehicle 时,所有乘客也会被发送。

我还添加了一个新方法以便于使用事件:

Events.BroadcastRemoteDimension(dimension, event_name, params...)

此事件将发送给该维度中的所有玩家。

如果通过远程事件发送与玩家不在同一维度的实体,则参数将被替换为 nil,并显示警告。

新的瞄准阻挡动画​

我重做了武器在面向障碍物时被阻挡的方式。之前它会将 AimMode 切换为未瞄准,导致非常糟糕的效果,甚至使准星稍微移动。

现在武器会程序化弯曲,且 AimMode 不会改变,大大改善了游戏体验!

服务器同步值​

现在可以使用 Server.SetValue() 方法在服务器和客户端之间拥有全局同步值,新增了一个 bool 参数 sync_on_clients。这些值将像往常一样通过 Client.GetValue() 存在于所有客户端上。

蓝图改进​

我们的蓝图功能得到了增强!

事件调度器​

现在可以从 Lua 绑定到蓝图事件调度器了!使从蓝图到 Lua 的通信成为可能!

-- 生成蓝图
local blueprint = Blueprint(Vector(), Rotator(), "my-asset-pack::BP_AwesomeBlueprint",)

-- 订阅蓝图事件调度器
blueprint:BindBlueprintEventDispatcher("GorgeousDispatcher", function(self, arg1, arg2)
-- arg1 是字符串,arg2 是整数
Console.Log("从蓝图调用!", arg1, arg2)
end)

你可以在我们的新文档页面找到更多示例:蓝图通信!

函数返回值​

现在也可以从蓝图函数在 Lua 中获取返回值了!

传递 Actor​

我们可以通过参数在蓝图调用中传入和传出 Actor,在从 Lua 接收或发送时它们将被正确解析为对应的实体!例如你可以创建一个接收 Character 或 Actor 作为参数的蓝图事件,并通过 Lua 传递它,它将被自动解析并编组为正确的蓝图变量类型!

脚本事件变量​

现在我们的内部变量使用 8 字节传递浮点数和整数,允许通过事件(包括网络事件)传递更大的值!

Tick 性能提升​

我成功大幅提升了生成数千个实体时的性能(大多数是由关卡 StaticMesh 引起的。我实现了智能算法,根据距离和实体的实际 tick 需求来改进某些实体的 Tick 计算执行时机。

在某些情况下,这将 CPU 使用率提升了近 10 倍!

客户端网络主控​

新增的一项实验性功能是,如果玩家是该实体的网络主控,则允许在客户端调用方法。

例如,现在可以从客户端调用 TranslateTo、RotateTo、SetForce、AddImpulse、SetWeaponAimMode 和 SetViewMode!例如,这可以大大改善 Sandbox 物理枪的行为!

WebUI 原生表​

现在你不再需要对表使用 JSON.stringify() 来传递给 WebUI 事件了!你可以直接将它们作为参数传递,它将被原生解析,这意味着传递大表时性能更高,而且你不再需要担心字符串化或解析它们,因为它们已经以原生表的形式作为参数传入!

File JSON 解析器​

我们的 File 实体获得了一个新方法,可以原生加载 JSON 文件并将其表获取到 Lua 中:

File.ReadJSONAsync()
File.ReadJSON()

与将其作为原始字符串读取并使用 Lua JSON 库相比,我们获得了巨大的性能提升:

加载一个大 JSON 文件(9.5 MB)的基准比较
使用 Lua JSON 库解析:耗时 9964ms。
使用原生 JSON 解析器解析:耗时 1057ms。

CEF 改进​

加载屏幕​

我完成了将 CEF 集成到加载屏幕的工作,现在 Ultralight 已完全从 nanos world 中移除。

我们还为加载屏幕添加了一项新功能:能够停止主菜单音乐!为此你需要从 JS 调用一个事件:

Events.Call("StopMenuMusic");

更好的错误处理​

错误处理也得到了改进,之前我们在加载无效文件时没有错误反馈,现在有了。

Character 混合空间​

现在可以将自定义运动混合空间导入到你的 Character 中。你可以覆盖站立、下蹲和卧倒动画。还可以设置它们之间的过渡动画!

我们为此添加了新的 API 方法:

Character.SetAnimationIdleWalkRunStanding(anim_path, enable_tip)
Character.SetAnimationIdleWalkRunCrouching(anim_path, enable_tip)
Character.SetAnimationIdleWalkRunProning(anim_path)

Character.SetAnimationsTransitionStandingCrouching(anim_standing_to_crouching, anim_crouching_to_standing)
Character.SetAnimationsTransitionCrouchingProning(anim_crouching_to_proning, anim_proning_to_crouching)

你可以在我们的新文档页面找到更多示例:Character 运动动画!

预缓存资产​

现在可以预缓存资产使其在加载屏幕中加载(避免游戏过程中的 FPS 峰值),为此你只需调用:

Assets.Precache(asset_path)
备注

所有资产在引用后都会自动预缓存,所以这个新方法在需要预缓存将来使用或动态加载的资产时很有用。

更好的穿墙射击​

我们的射击穿墙效果不能正常工作,我决定重做它。现在穿射水体的距离远达 10 倍,造成的伤害也更大(之前子弹无法穿透水体)。

我们还添加了一个新的调试设置来在世界中绘制武器的子弹轨迹,对调试非常有用:

帧率​

我们的主菜单得到了一些改进,FPS 限制被硬编码提升到 120(之前是 60),加载期间提升到 60(之前是 30),这仍然不够好,因为我想让它自动限制到显示器刷新率。

标签​

我们的标签页获得了新标签以改善用户体验,主要是在创建新游戏时。现在无需进入那些菜单就能知道你已经选择了多少依赖项:

新游戏​

此外,在新游戏菜单中,现在所有配置(包括依赖项)都从磁盘的 Config.toml 文件加载。所以我们不必每次启动服务器时都重新配置它!

调试设置​

我们获得了 3 个新的调试设置:

  • Visualize Bullet Traces
  • Visualize Vehicle Doors
  • Visualize Character Capsule

杂项改进​

本月我们还获得的其他一些改进和小型新功能:

  • 载具现在会接收 TakeDamage 事件!
  • 现在可以通过新的 SetShowFlags() 方法切换一系列 SceneCapture 渲染功能。
  • 我们的控制台在客户端侧获得了多项改进。
  • 现在可以将材质、WebUI 和 SceneCapture 绘制到 Canvas 中(实验性)!
  • 我在脚本 API 中实现了一种支持多个返回值的方式,因此一些方法将开始支持这一特性!
  • 现在如果发生任何失败,数据库将返回一个错误参数。
  • 所有角色交互(抓取道具、拾取武器、进入载具)都已重做,现在与大物体交互时的追踪是 100% 精确的。此外,我还移除了为此所需的额外组件,这将提升在生成过多可交互物体时的性能。

结语​

本月我们取得了许多重大进展!蓝图改进对我来说是一项巨大成就,因为我不得不对虚幻引擎进行庞大的逆向工程,并使用多种内存技巧来拦截事件。

维度的加入是一项呼声极高的功能,极大地扩展了游戏创作的限制!

性能改进总是非常受欢迎的,我也乐于进行这些改进,我们仍有很大的进一步提升空间!

此外,我投入了一些时间进行内部的大规模重构,部分代码开始变得臃肿混乱,并且没有使用最现代的 C++20 技术。有时候这些重构对于重新掌控我们自己的代码非常有帮助。 😄

在接下来的更新中,我计划重新组织 API(正如我们在上次 #poll 中讨论的那样),我们添加的方法开始在静态类中积累,而它们之间缺乏凝聚力。我打算将它们分开,并为每个创建新的静态类,使理解和搜索 API 中的方法变得更加容易。

我开始实现的另一项改进是实体支持多个构造函数。这将使我们能够以更精简的方式生成实体。例如,如果我们想生成 2D 或 3D 声音,这将非常有用(2D 声音不需要位置参数)。

这就是本月的全部内容,下个月我将带来更多改进和新闻!非常感谢! 💖