粒子就是 Minecraft 里随处可见的那些扁平小图片:营火冒出的烟、开心的动物头上的爱心、水下的气泡。在本指南中,你将制作属于自己的粒子:红宝石闪光。它会迸发出一团红色的小光点,向上飘起、闪烁,然后渐渐消失。
你将学到粒子文件里要写什么、如何绘制它的纹理、如何让它随时间变化,以及如何通过命令、动画或脚本在游戏中显示它。
只需要资源包
粒子完全存在于资源包中。制作粒子不需要行为包,只有从生物或脚本中触发它时才需要。GodCraft 会帮你写好包文件和清单文件:见导出与安装。
文件一览
RP/
particles/
ruby_sparkle.json
ruby_dust.json
textures/
particle/
ruby_sparkle.png游戏会加载 particles 文件夹中的每个 .json 文件。文件名无所谓,但和粒子名保持一致会更容易查找。
发射器和粒子
动手之前,先了解每个效果都有的两个部分:
- 发射器是一个看不见的生成器。它决定出现多少粒子、粒子从哪里开始,以及它会持续生成多久。
- 粒子就是那些小图片。每个粒子决定自己如何移动、长什么样子,以及何时消失。
所以粒子组件分为两大类。以 minecraft:emitter_ 开头的设置生成器,以 minecraft:particle_ 开头的设置每张图片。它们可以按任意顺序书写。
| 文件的部分 | 内容 |
|---|---|
description | 粒子的名称,以及它的材质和纹理 |
curves | 可选。在粒子生命周期中变化的值 |
events | 可选。在特定时刻发生的事,比如生成更多粒子 |
components | 其他所有内容:发射器和粒子的设置 |
第 1 步:纹理
画一张 8x8 的 PNG,保存为 RP/textures/particle/ruby_sparkle.png。一颗小小的四角星效果就很好。
用白色和浅灰色来画,不要用红色。之后你会给它染色,而染色是把像素颜色相乘。白色可以变成任何你喜欢的颜色,但红色的图片染成蓝色几乎会变成黑色。
背景要完全透明。粒子永远是扁平的正方形,正是透明像素赋予了它们形状。
第 2 步:description
创建粒子文件,先写上它的名称和外观:
{
"format_version": "1.10.0",
"particle_effect": {
"description": {
"identifier": "wiki:ruby_sparkle",
"basic_render_parameters": {
"material": "particles_alpha",
"texture": "textures/particle/ruby_sparkle"
}
},
"components": {}
}
}identifier是你用来播放粒子的名称。一定要用你自己的命名空间(这里是wiki:),这样就永远不会和原版或其他附加包冲突。texture是从资源包根目录到你的 PNG 的路径,不带.png。material决定半透明像素如何绘制:
| 材质 | 像素效果 | 适用于 |
|---|---|---|
particles_alpha | 要么完全不透明,要么完全看不见 | 像素画,比如原版的爱心和暴击。最稳妥的选择。 |
particles_blend | 可以半透明 | 柔和的烟雾、薄雾、渐隐的尘埃 |
particles_add | 叠加在后方画面之上,所以会发光 | 魔法、火花、火焰、光 |
我们的闪光应该会发光,所以等它能正常显示后,把材质改成 particles_add。测试时先用 particles_alpha,因为它最容易看清。
格式版本
1.10.0 是大多数附加包粒子使用的版本,这些页面上的每个组件都支持它。较新的原版文件使用更高的版本,但本指南中的内容都用不到。
第 3 步:发射器
现在来填写 components。先是生成器。我们想要一次快速迸发出 12 个闪光,分布在一个小球周围:
"minecraft:emitter_lifetime_once": {
"active_time": 0.5
},
"minecraft:emitter_rate_instant": {
"num_particles": 12
},
"minecraft:emitter_shape_sphere": {
"radius": 0.4,
"direction": "outwards"
},emitter_lifetime_once让发射器运行一次,然后将其移除。emitter_rate_instant在同一瞬间生成全部 12 个粒子。emitter_shape_sphere把它们放在半径 0.4 格的球体内,每个都朝着远离中心的方向。
每个发射器都需要一个生命周期组件和一个速率组件。缺了它们,什么都不会生成。形状是可选的:不写的话,每个粒子都从正中心开始。
第 4 步:粒子
接下来告诉每个闪光如何移动和显示。把这些加在发射器组件后面:
"minecraft:particle_lifetime_expression": {
"max_lifetime": "math.random(0.6, 1.2)"
},
"minecraft:particle_initial_speed": 1.5,
"minecraft:particle_motion_dynamic": {
"linear_acceleration": [0, 1.2, 0],
"linear_drag_coefficient": 3
},
"minecraft:particle_appearance_billboard": {
"size": [0.12, 0.12],
"facing_camera_mode": "lookat_xyz",
"uv": {
"texture_width": 8,
"texture_height": 8,
"uv": [0, 0],
"uv_size": [8, 8]
}
},
"minecraft:particle_appearance_tinting": {
"color": [1, 0.15, 0.3, 1]
}每一项的作用如下:
- 生命周期。 每个闪光存在 0.6 到 1.2 秒。
math.random会为每个粒子选一个新数字,所以它们不会同时消失。这就是 Molang,Bedrock 使用的小型数学语言。 - 速度。 它们以每秒 1.5 格的速度沿球体给出的方向飞出。
- 运动。
linear_acceleration每秒把它们往上推一点,让它们像余烬一样飘起。linear_drag_coefficient是空气阻力:它会让最初的迸发迅速减速。 - 公告板。 每个粒子都是一个扁平的正方形。
size是它以格为单位的半宽和半高,所以0.12会做出一个大约四分之一格宽的正方形。lookat_xyz让它始终面向玩家。 - UV。 它选择显示纹理的哪一部分。我们的纹理只有一张 8x8 的图,所以全部使用:从
0, 0开始,取8, 8。 - 染色。 红、绿、蓝和透明度,每个取值 0 到 1。
[1, 0.15, 0.3, 1]是红宝石红。你也可以写成"#FF2650"。
保存,载入世界,然后输入:
/particle wiki:ruby_sparkle ~ ~1 ~你应该会看到一小团红色的光在你面前升起。如果什么都没看到,请查看本页末尾的表格。
第 5 步:用曲线让它闪烁
现在每个闪光都保持同样的大小,然后突然消失。曲线可以解决这个问题。它是一个按照你用几个数字画出的形状变化的值。
在 description 和 components 旁边添加一个 curves 块:
"curves": {
"variable.ruby_size": {
"type": "linear",
"input": "variable.particle_age / variable.particle_lifetime",
"nodes": [0.2, 1, 0.6, 0]
}
},- 名称必须以
variable.开头。游戏会在每一帧为每个粒子计算曲线,并把结果存进这个变量。 input表示当前处于曲线上的哪个位置。存活时间除以生命周期,会从0(刚出生)变到1(即将消失)。nodes是沿途的各个值,从开始到结束均匀分布。我们的闪光从小(0.2)开始,长到完整大小(1),再缩小(0.6),最后变成无(0)。type是曲线在节点之间如何变化。linear画直线。catmull_rom和bezier会画出平滑的弯曲,bezier_chain则让你自己设定每个点和斜率。
现在在公告板的大小中使用这个变量:
"size": ["0.12 * variable.ruby_size", "0.12 * variable.ruby_size"],要做渐隐效果,染色也可以在粒子生命周期中改变颜色。gradient 列出颜色,interpolant 决定当前处于它们之间的哪个位置:
"minecraft:particle_appearance_tinting": {
"color": {
"gradient": ["#FFFF8FA8", "#FFFF2650", "#00A0002A"],
"interpolant": "variable.particle_age / variable.particle_lifetime"
}
}这里的每种颜色都写成 #AARRGGBB,所以前两个字符是透明度。闪光从淡粉色开始,变成红宝石红,最后变暗并消失。使用 particles_add 时,深色会淡出直至消失,用在发光效果上非常漂亮。
第 6 步:用事件加一个“砰”
事件让某件事在特定时刻发生。我们在每个闪光消失的地方留下一小团尘埃。
先做尘埃。它是第二个更小的效果:
{
"format_version": "1.10.0",
"particle_effect": {
"description": {
"identifier": "wiki:ruby_dust",
"basic_render_parameters": {
"material": "particles_add",
"texture": "textures/particle/ruby_sparkle"
}
},
"components": {
"minecraft:emitter_lifetime_once": { "active_time": 0.2 },
"minecraft:emitter_rate_instant": { "num_particles": 3 },
"minecraft:emitter_shape_point": {},
"minecraft:particle_initial_speed": 0.4,
"minecraft:particle_lifetime_expression": { "max_lifetime": 0.3 },
"minecraft:particle_appearance_billboard": {
"size": [0.04, 0.04],
"facing_camera_mode": "lookat_xyz",
"uv": {
"texture_width": 8,
"texture_height": 8,
"uv": [0, 0],
"uv_size": [8, 8]
}
},
"minecraft:particle_appearance_tinting": { "color": "#FF7A0F2E" }
}
}
}然后回到 ruby_sparkle.json,给事件起个名字,并说明它要做什么:
"events": {
"pop": {
"particle_effect": {
"effect": "wiki:ruby_dust",
"type": "emitter"
}
}
},最后,在每个闪光生命结束时触发这个事件:
"minecraft:particle_lifetime_events": {
"expiration_event": "pop"
}事件能做的不只是生成粒子:
| 事件中的字段 | 作用 |
|---|---|
particle_effect | 启动另一个效果。type 可以是 emitter、emitter_bound、particle 或 particle_with_velocity |
sound_effect | 播放声音,在 event_name 中填写声音事件名 |
expression | 在发射器上运行一个 Molang 表达式 |
log | 向内容日志写一条消息,测试时很方便 |
sequence | 一个事件列表,依次全部运行 |
randomize | 一个事件列表,只按 weight 随机选一个运行 |
不要让效果生成它自己
如果 wiki:ruby_sparkle 在自己的事件中启动 wiki:ruby_sparkle,每个粒子都会生成更多粒子,无穷无尽。事件一定要指向另一个更小的效果。
完成的文件
这是完整的闪光效果,已经换上了发光材质:
{
"format_version": "1.10.0",
"particle_effect": {
"description": {
"identifier": "wiki:ruby_sparkle",
"basic_render_parameters": {
"material": "particles_add",
"texture": "textures/particle/ruby_sparkle"
}
},
"curves": {
"variable.ruby_size": {
"type": "linear",
"input": "variable.particle_age / variable.particle_lifetime",
"nodes": [0.2, 1, 0.6, 0]
}
},
"events": {
"pop": {
"particle_effect": {
"effect": "wiki:ruby_dust",
"type": "emitter"
}
}
},
"components": {
"minecraft:emitter_lifetime_once": {
"active_time": 0.5
},
"minecraft:emitter_rate_instant": {
"num_particles": 12
},
"minecraft:emitter_shape_sphere": {
"radius": 0.4,
"direction": "outwards"
},
"minecraft:particle_lifetime_expression": {
"max_lifetime": "math.random(0.6, 1.2)"
},
"minecraft:particle_lifetime_events": {
"expiration_event": "pop"
},
"minecraft:particle_initial_speed": 1.5,
"minecraft:particle_initial_spin": {
"rotation": "math.random(0, 360)",
"rotation_rate": 90
},
"minecraft:particle_motion_dynamic": {
"linear_acceleration": [0, 1.2, 0],
"linear_drag_coefficient": 3
},
"minecraft:particle_appearance_billboard": {
"size": ["0.12 * variable.ruby_size", "0.12 * variable.ruby_size"],
"facing_camera_mode": "lookat_xyz",
"uv": {
"texture_width": 8,
"texture_height": 8,
"uv": [0, 0],
"uv_size": [8, 8]
}
},
"minecraft:particle_appearance_tinting": {
"color": {
"gradient": ["#FFFF8FA8", "#FFFF2650", "#00A0002A"],
"interpolant": "variable.particle_age / variable.particle_lifetime"
}
}
}
}
}我们还悄悄加了 particle_initial_spin:每个闪光以随机角度开始并缓慢旋转,所以没有两个看起来一样。
播放粒子
用命令
/particle 在某个位置播放效果。需要开启作弊。
/particle wiki:ruby_sparkle ~ ~1 ~你也可以把它放进函数或命令方块中。用 execute 在某人身上播放:/execute as @a at @s run particle wiki:ruby_sparkle ~ ~2 ~ 会在每个玩家头顶显示闪光。
从生物的动画中
生物可以在动画中播放粒子。这是在资源包的客户端实体文件中完成的,所以如果你还没做过生物,请先看你的第一个自定义生物。
1. 给效果起个简称,写在客户端实体的 description 中:
"particle_effects": {
"sparkle": "wiki:ruby_sparkle"
}2. 在动画的某个时间点播放它。 locator 是可选的:它是模型上一个带名字的点,效果会随生物移动而跟随它。不写的话,效果会在生物脚下播放。
"particle_effects": {
"0.5": {
"effect": "sparkle",
"locator": "head"
}
}3. 或者从动画控制器状态中播放。 它会在生物进入该状态时开始:
"particle_effects": [
{ "effect": "sparkle" }
]以上每种方式都可以带一个 pre_effect_script:在效果开始前运行的一小段 Molang。用它把值传进粒子文件,比如一个取决于生物的颜色。
循环效果留给生物
生物播放效果时,效果的发射器会附着在它身上。这正是 emitter_lifetime_looping 和 emitter_lifetime_expression 大显身手的地方:一条在生物行走时一直跟随的拖尾,或者在某个 Molang 值开启时持续的光芒。
从脚本中
脚本可以随时随地播放粒子。你的行为包需要在清单中声明脚本模块:项目搭建中有说明。
import { world } from "@minecraft/server";
world.afterEvents.itemUse.subscribe(({ source, itemStack }) => {
if (itemStack.typeId !== "wiki:ruby_wand") return;
const { x, y, z } = source.location;
source.dimension.spawnParticle("wiki:ruby_sparkle", { x, y: y + 1.5, z });
});每当玩家使用 wiki:ruby_wand 物品时,就会在他头顶迸出闪光。dimension.spawnParticle 会向附近的所有人显示效果。player.spawnParticle 用法相同,但只有那个玩家能看到。
脚本还可以用 MolangVariableMap 把值传进粒子。这样一个粒子文件就能做出任意颜色的闪光:
import { MolangVariableMap } from "@minecraft/server";
// Inside the same itemUse handler as above:
const vars = new MolangVariableMap();
vars.setColorRGB("variable.tint", { red: 0.2, green: 0.6, blue: 1 });
source.dimension.spawnParticle("wiki:ruby_sparkle", { x, y: y + 1.5, z }, vars);在粒子文件中,用 variable.tint.r、variable.tint.g 和 variable.tint.b 读取颜色的三个分量:
"minecraft:particle_appearance_tinting": {
"color": ["variable.tint.r", "variable.tint.g", "variable.tint.b", 1]
}好用的 Molang 变量
这些值由游戏自动填好。可以在任何 Molang 字段中使用。
| 变量 | 值 |
|---|---|
variable.particle_age | 这个粒子已经存在了多久,单位为秒 |
variable.particle_lifetime | 这个粒子总共会存在多久 |
variable.particle_random_1 到 _4 | 四个 0 到 1 之间的随机数,每个粒子都不同 |
variable.emitter_age | 发射器已经运行了多久 |
variable.emitter_lifetime | 发射器总共运行多久 |
variable.emitter_random_1 到 _4 | 四个 0 到 1 之间的随机数,整个发射器共用 |
variable.entity_scale | 效果所附着的生物的大小 |
variable.particle_random_1 很适合增加变化。比如 "0.1 + variable.particle_random_1 * 0.05" 会让每个闪光的大小略有不同。
出问题时
| 你看到的现象 | 最可能的原因 |
|---|---|
| 什么都没有 | 发射器缺少生命周期或速率组件,或命令中的 identifier 和文件不一致 |
/particle 提示效果不存在 | JSON 中有拼写错误。打开内容日志找到出错的行 |
| 一个紫黑色方块 | texture 路径错误,或以 .png 结尾 |
| 整张纹理被挤进一个粒子里 | 缺少 uv 块,或 texture_width 和 texture_height 和 PNG 不一致 |
| 每个粒子周围有黑色方块 | PNG 背景不透明,或你对深色图片使用了 particles_add |
| 粒子颜色不对 | 染色会和纹理相乘。请用白色绘制纹理 |
| 它一直不停 | 它使用了 emitter_lifetime_looping。一次性迸发请用 emitter_lifetime_once |