Skip to content

VVE 的心智模型

VVE 最容易被误解成“一组能让 display entity 运动的函数”。更准确的理解是:它是一套以共享临时计算区为核心、用代码模板生成业务模块、用碰撞点协议连接运动模型与环境模型的运行时。

四层结构

text
MOT 预设模板(构建期)
        ↓ 生成
业务模块(函数 + 字段 + 接口)
        ↓ 创建 / 调度
模块实例(实体上的持久状态)
        ↕ _get / _store
共享临时对象(score + storage 运算区)

模板:构建代码

memory_storage/vve_block_1.0 这类目录属于 MOT 预设。它们在开发期产生 _class_new_getmain_c 等业务模块文件。模板不是运行时“类”,也不会在游戏里自动继承。

模板可以叠加:骨架模板先生成主体,测试、声音、骰子等功能模板再添加或覆盖同路径文件。它更像图层合成,而不是 Kotlin/Java 的类继承。

模块:共享行为

函数前缀界定一个模块,例如:

text
data/vve_examples/function/dice_6/
↳ vve_examples:dice_6/

模块拥有初始化、数据结构转换、实例生命周期与主程序。一个模块可创建多个实例,它们共享函数代码但不共享实体上的持久状态。

实例:持久状态

一个 item_displaymarker 或其他根实体保存某个具体物体的中心、速度、姿态等字段。实例跨 tick 存在。VVE 通过 tag 选择一类实例,例如:

mcfunction
execute as @e[tag=dice_6] run function vve_examples:dice_6/main_c

临时对象:唯一计算工作台

VVE 把当前对象的字段读到一组共享假玩家与 storage,执行高频计算,最后写回。这样数学函数不必为每个实体反复读写 NBT,但代价是:

  • 同一套临时对象不能同时代表两个实例;
  • _get → 计算 → _store 必须连续完成;
  • 不能在保存前嵌套另一个会覆盖相同临时字段的模型;
  • 外部回调必须清楚自己会不会改写 vve:io 或公共假玩家。

两个正交分类维度

“质点、刚体、介质”不是三个互斥的类。

维度问题VVE 选择
运动职责对象怎样保存和推进状态?质点 / 刚体
环境职责别人的碰撞点在这里得到什么响应?方块介质 / 实体介质

因此 cublock 可以同时是刚体和实体介质:它自己用八个点探测世界,别人也能把它探测为盒体。block 只是刚体,仍会撞地,但其他刚体不会自动撞到它。

碰撞点是协议边界

运动模型不需要知道水、斜面或另一个盒体具体怎样计算;介质也不需要知道碰撞点来自骰子还是载具。双方只交换:

text
cpoint {
  center:   (c_x, c_y, c_z)
  velocity: (c_vx, c_vy, c_vz)
  c_mass
}

介质读取它并返回位移、冲量、摩擦、接触法向、附着层等响应。物体再决定如何把响应应用到自己的平动和转动。

公开接口如何识别

VVE 源码的约定是:

名称典型含义对外使用
init初始化模块
_class, _new, _get明确的 API/扩展点
main*一轮物理或其中一个阶段是,但要理解调度契约
tick*实例遍历或计划入口
其他无下划线辅助函数内部实现默认否

下划线在这里不是“私有”,恰好相反,通常标识外部接口。一个内部文件即使技术上能 function 调用,也不代表 VVE 对其输入输出和版本稳定性做了承诺。

建立正确问题意识

遇到异常时,按层询问:

  1. 调度层:这个对象今天到底执行了几次主程序?
  2. 数据层:临时对象来自哪个实例,计算后写回了吗?
  3. 运动层:位置/姿态预测是否合理?
  4. 探测层:碰撞点在哪里,使用了哪个介质入口?
  5. 响应层:位移、冲量、摩擦和规整是否重复应用?
  6. 显示层:物理状态正确,只是 transformation 或插值不正确吗?

这套顺序比直接盯着 display entity 猜原因可靠得多。

VVE 由小豆 8593 开发;本站是面向学习与查阅的增强文档。