动态手电筒

动态手电筒

一个轻量级的玩家手电筒系统(指令,尚未制作模型),通过动态光源实体模拟向前照射的光束。

实用

手电筒

为 Hytale 制作的小型插件实验,用于在未来的项目中实现玩家手电筒效果。

目前手电筒并非渲染为真正的投射光束,而是通过追踪玩家视角方向、在世界中寻找撞击点,并在这些命中位置周围生成小型动态光源实体来模拟的。这就是为什么可以看到它表现为向前投射的光束。

我还需要为手电筒创建一个模型。

当前思路

目前我尚不清楚如何正确实现,因此当前实现采用了一种更实用的变通方法:

  • 读取玩家头部方向
  • 追踪一条中心射线加上一圈额外射线
  • 检测已加载世界区块中附近的命中点
  • 选取有代表性的命中位置
  • 在这些位置生成/更新动态光源实体

这样得到的结果更像是伪造的投射手电筒撞击效果,而非真正的渲染级手电筒。

工作原理

该插件分为几个简单的部分:

  • Main 注册命令和刻循环系统
  • FlashlightCommand 启用、禁用或切换手电筒
  • FlashlightTickSystem 每隔数刻更新活跃的手电筒玩家
  • FlashlightService 包含主要逻辑
  • FlashlightConeMath 包含用于光束采样的数学辅助函数

运行时流程

当玩家执行命令时:

  • 切换玩家手电筒状态
  • 插件在世界线程上同步该玩家
  • 手电筒激活期间,每隔数刻重新计算光束

光束近似

光束近似使用以下方式:

  • 一条中心射线
  • 围绕其周围的一圈射线

服务程序会将这些射线向前追踪,直到它们在已加载的区块中命中非空气方块。

从这些结果中:

  • 如果存在中心命中点,则保留该点
  • 将圆圈命中点合并为一个加权次要命中点
  • 在这些位置生成或更新一个或多个动态光源实体

为什么使用动态光源实体

我选择使用生成的实体 + DynamicLight,因为目前我还没有合适的方法来完全按照我想要的方式渲染手电筒。

主要问题在于,我真正想要的是更接近以下效果的东西:

  • 一个真正的表面投影
  • 或者一个可见的锥形/光束效果
  • 或者基于着色器的叠加/后期处理效果

配置

该插件支持一个 config.json 文件来设置手电筒的主要参数。

配置文件存储在插件数据目录中,首次加载时如果不存在则会自动创建。

它用于在不重新编译插件的情况下调整主要数值,例如:

  • 调试渲染标志
  • 撞击光源启用/禁用
  • 玩家附着光源数值
  • 光束范围和光束角度
  • 射线步长
  • 撞击背面偏移
  • 圆圈射线数量
  • 调试绘制设置

如果文件缺失,插件会自动写入一个默认文件。 如果文件已存在,插件则从中加载数值。

示例:

{
  "debugDrawBeam": false,
  "debugShowHitPoint": false,
  "enableImpactLight": true,
  "playerLightRadius": 0,
  "playerLightRed": 0,
  "playerLightGreen": 0,
  "playerLightBlue": 0,
  "minEffectiveHitDistance": 2.0,
  "centerLightRadius": 5,
  "sideLightRadius": 2,
  "maxImpactLights": 10,
  "beamRange": 50.0,
  "beamHalfAngleDeg": 10.0,
  "rayStep": 0.08,
  "impactBackOffset": 0.15,
  "beamRingRays": 10,
  "debugDrawDurationSeconds": 0.12,
  "debugLineWidth": 0.02,
  "debugFade": false
}

激活手电筒的命令

/flashlight
/flashlight on
/flashlight off