Skip to content

Snowstorm 粒子系统

Mojang Bedrock Edition 粒子的镜像实现,使用 JSON 定义粒子效果。

前置知识

需要了解 特效系统总览Bedrock 粒子格式。 推荐使用 Snowstorm Editor 可视化编辑粒子。

Behemiron的暴雪粒子1:1复刻了 WinterSky(JS) 的实现,支持 100% 的粒子语法,并修复了 WinterSky 中关于粒子物理计算的一些 Bug。粒子支持批量释放,支持绑定实体跟随。

Quick Start

kotlin
import com.behemiron.engine.forge.module.effect.snowstorm.SnowstormManager

// 在指定位置播放粒子
val runtime = SnowstormManager.play("snow.json", level, position)

// 绑定到实体
val runtime = SnowstormManager.play("aura.json", entity)

// 控制运行时
runtime.position = Vec3(x, y, z)   // 更新位置
runtime.active = false              // 暂停发射
runtime.bindToEntity(entity)        // 绑定实体

// 停止
runtime.stop()
SnowstormManager.stopAll()

资源放置在 Behemiron/particles/ 目录下:

Behemiron/particles/
├── snow.json
├── fire.json
└── effects/
    └── explosion.json

API Reference

SnowstormManager

SnowstormManager 是 Snowstorm 系统的入口单例,实现 EffectEngine<SnowstormFX, SnowstormFXRuntime>

方法返回值说明
play(path, level, position)SnowstormFXRuntime?在指定位置播放粒子
play(path, entity)SnowstormFXRuntime?播放并绑定到实体
stop(runtime)Unit停止指定运行时
stopAll()Unit停止所有运行时
preload(path, onComplete?)Unit异步预加载指定粒子
preloadAll(onComplete?)Unit异步预加载所有粒子
reload(path)Unit重载指定粒子定义
reloadAll()Unit重载所有粒子定义
getDefinition(path)SnowstormFX?获取粒子定义(懒加载)
registerDefinition(path, definition)Unit注册动态构建的粒子定义
unregisterDefinition(path)SnowstormFX?移除粒子定义
getActiveCount()Int活跃发射器数量
getActiveRuntimes()List<SnowstormFXRuntime>所有活跃运行时(只读)

路径格式:相对于 Behemiron/particles/ 目录,带 .json 后缀。

kotlin
// "fire.json"            -> Behemiron/particles/fire.json
// "effects/explosion.json" -> Behemiron/particles/effects/explosion.json

SnowstormFXRuntime

SnowstormFXRuntime 是粒子发射器的运行时实例。

属性/方法类型说明
pathString粒子标识符
positionVec3当前位置(可读写)
ageDouble发射器当前年龄(秒,只读)
lifetimeDouble发射器总生命周期(秒)
activeBoolean是否正在发射粒子
removedBoolean是否已移除(只读)
particlesMutableList<SnowstormParticle>所有活跃粒子
definitionSnowstormFX粒子定义数据
levelLevelMinecraft 世界
contextSnowstormContextMoLang 执行上下文
bindToEntity(entity)Unit绑定到实体(跟随位置)
unbindEntity()Unit解绑实体
stop() / remove()Unit移除发射器及所有粒子
spawn()SnowstormParticle手动生成一个粒子
spawn(position, velocity)SnowstormParticle在指定位置/速度生成粒子
isFinished()Boolean是否已完成
getParticleCount()Int活跃粒子数量
getEmitterCount()Int发射器数量(始终为 1)
setEntityScale(value)Unit设置实体缩放因子

SnowstormFX

粒子定义数据类。

属性类型说明
descriptionDescription标识符、纹理路径、材质类型
curvesMap<String, CurveData>曲线定义(用于参数动画)
eventsMap<String, EventData>事件定义(声音、子粒子等)
componentsJsonObject组件原始 JSON(延迟解析)

JSON 格式

Snowstorm 使用 Bedrock 粒子格式(版本 1.10.0):

json
{
  "format_version": "1.10.0",
  "particle_effect": {
    "description": {
      "identifier": "snowstorm:snow",
      "basic_render_parameters": {
        "material": "particles_alpha",
        "texture": "snow.png"
      }
    },
    "components": {
      "minecraft:emitter_rate_steady": {
        "spawn_rate": 80,
        "max_particles": 4000
      },
      "minecraft:emitter_lifetime_looping": {
        "active_time": 1
      },
      "minecraft:emitter_shape_box": {
        "offset": [0, 20, 0],
        "half_dimensions": [36, 0, 36],
        "direction": ["Math.random(-1, 1)", "-1.2", "Math.random(-1, 1)"]
      },
      "minecraft:particle_initial_speed": 1,
      "minecraft:particle_motion_dynamic": {
        "linear_acceleration": [0, -0.2, 0]
      },
      "minecraft:particle_appearance_billboard": {
        "size": [0.1, 0.1],
        "facing_camera_mode": "rotate_xyz",
        "uv": {
          "texture_width": 64,
          "texture_height": 64,
          "uv": [0, 0],
          "uv_size": [64, 64]
        }
      },
      "minecraft:particle_lifetime_expression": {
        "max_lifetime": 25
      }
    }
  }
}

组件参考

发射器生命周期

组件名说明主要参数
minecraft:emitter_lifetime_looping循环发射active_time, sleep_time
minecraft:emitter_lifetime_once单次发射active_time
minecraft:emitter_lifetime_expression表达式控制activation_expression, expiration_expression

发射速率

组件名说明主要参数
minecraft:emitter_rate_steady稳定速率spawn_rate, max_particles
minecraft:emitter_rate_instant瞬间发射num_particles

发射形状

组件名说明主要参数
minecraft:emitter_shape_point点发射offset, direction
minecraft:emitter_shape_box立方体区域offset, half_dimensions, direction
minecraft:emitter_shape_sphere球体区域offset, radius, direction
minecraft:emitter_shape_disc圆盘区域offset, radius, plane_normal, direction
minecraft:emitter_shape_entity_aabb实体包围盒direction

粒子初始状态

组件名说明主要参数
minecraft:particle_initial_speed初始速度数值或 MoLang 表达式
minecraft:particle_initial_spin初始旋转rotation, rotation_rate

粒子运动

组件名说明主要参数
minecraft:particle_motion_dynamic动态运动linear_acceleration, linear_drag_coefficient, rotation_acceleration, rotation_drag_coefficient
minecraft:particle_motion_parametric参数化运动relative_position, direction, rotation
minecraft:particle_motion_collision碰撞检测enabled, collision_radius, coefficient_of_restitution, collision_drag, expire_on_contact

粒子生命周期

组件名说明主要参数
minecraft:particle_lifetime_expression表达式生命周期max_lifetime, expiration_expression
minecraft:particle_lifetime_events生命周期事件creation_event, expiration_event, timeline
minecraft:particle_expire_if_in_blocks进入方块时消亡方块 ID 列表
minecraft:particle_expire_if_not_in_blocks离开方块时消亡方块 ID 列表
minecraft:particle_kill_plane平面边界平面方程 [A, B, C, D]

粒子外观

组件名说明主要参数
minecraft:particle_appearance_billboard公告板渲染size, facing_camera_mode, uv
minecraft:particle_appearance_tinting颜色着色color (渐变或表达式)
minecraft:particle_appearance_lighting光照无参数(启用即可)

其他发射器组件

组件名说明主要参数
minecraft:emitter_initialization发射器初始化creation_expression, per_update_expression
minecraft:emitter_local_space本地空间position, rotation, velocity

MoLang 集成

Snowstorm 使用独立的 MoLang 引擎(molang-snowstorm),包含以下命名空间:

命名空间别名说明
math-数学函数(math.sin, math.random, math.clamp 等)
variablev粒子/发射器/曲线变量
tempt临时变量

发射器变量

variable.emitter_lifetime    // 发射器生命周期
variable.emitter_age         // 发射器年龄
variable.emitter_random_1    // 随机数 1(创建时固定)
variable.emitter_random_2    // 随机数 2
variable.emitter_random_3    // 随机数 3
variable.emitter_random_4    // 随机数 4

粒子变量

variable.particle_lifetime   // 粒子生命周期
variable.particle_age        // 粒子年龄
variable.particle_random_1   // 随机数 1(每个粒子不同)
variable.particle_random_2   // 随机数 2
variable.particle_random_3   // 随机数 3
variable.particle_random_4   // 随机数 4

曲线变量

通过 curves 定义的曲线会自动注册为 variable.<curve_name>,在组件表达式中可直接引用。

支持的曲线类型:

类型说明
linear线性插值
bezier贝塞尔曲线
bezier_chain贝塞尔链(多段)
catmull_romCatmull-Rom 样条

事件系统

事件可以在粒子/发射器的生命周期关键点触发:

事件类型说明
sequence按顺序执行多个事件
randomize按权重随机选择一个事件
particle_effect生成子粒子
sound_effect播放声音
expression执行 MoLang 表达式
log输出日志

混合模式

材质名混合模式效果
particles_alphaAlpha 混合标准透明
particles_add加法混合发光效果
particles_blendAlpha 混合标准透明(同 alpha)
particles_opaque不透明完全覆盖
particles_multiply正片叠底阴影效果

完整示例

火焰粒子

json
{
  "format_version": "1.10.0",
  "particle_effect": {
    "description": {
      "identifier": "behemiron:flame",
      "basic_render_parameters": {
        "material": "particles_add",
        "texture": "flame.png"
      }
    },
    "curves": {
      "variable.flame_size": {
        "type": "bezier",
        "input": "variable.particle_age / variable.particle_lifetime",
        "horizontal_range": 1,
        "nodes": [0, 0.8, 0.5, 0]
      }
    },
    "components": {
      "minecraft:emitter_rate_steady": {
        "spawn_rate": 30,
        "max_particles": 200
      },
      "minecraft:emitter_lifetime_looping": {
        "active_time": 1
      },
      "minecraft:emitter_shape_point": {
        "offset": [0, 0, 0],
        "direction": ["Math.random(-0.3, 0.3)", 1, "Math.random(-0.3, 0.3)"]
      },
      "minecraft:particle_initial_speed": "Math.random(1, 3)",
      "minecraft:particle_lifetime_expression": {
        "max_lifetime": "Math.random(0.5, 1.5)"
      },
      "minecraft:particle_motion_dynamic": {
        "linear_acceleration": [0, 2, 0],
        "linear_drag_coefficient": 1
      },
      "minecraft:particle_appearance_billboard": {
        "size": ["variable.flame_size * 0.3", "variable.flame_size * 0.3"],
        "facing_camera_mode": "rotate_xyz",
        "uv": {
          "texture_width": 64,
          "texture_height": 64,
          "uv": [0, 0],
          "uv_size": [64, 64]
        }
      },
      "minecraft:particle_appearance_tinting": {
        "color": {
          "interpolant": "variable.particle_age / variable.particle_lifetime",
          "gradient": {
            "0.0": "#FFFFCC00",
            "0.5": "#FFFF6600",
            "1.0": "#00FF3300"
          }
        }
      }
    }
  }
}

Kotlin 运行时控制

kotlin
import com.behemiron.engine.forge.module.effect.snowstorm.SnowstormManager

// 预加载所有粒子
SnowstormManager.preloadAll { success, failed ->
    println("预加载完成: $success 成功, $failed 失败")
}

// 播放粒子
val runtime = SnowstormManager.play("flame.json", level, Vec3(100.0, 65.0, 200.0))
    ?: return

// 运行时控制
runtime.active = true
println("粒子数: ${runtime.getParticleCount()}")
println("年龄: ${runtime.age}s / ${runtime.lifetime}s")

// 绑定到实体并跟随
runtime.bindToEntity(player)

// 一段时间后停止
runtime.stop()

Ponder 场景中使用

kotlin
scene.effects.playSnowstormFx("flame.json", Vec3(2.0, 1.0, 2.0))