1. Wiki
  2. /粒子
  3. /你的第一个粒子

你的第一个粒子

一步步为 Minecraft Bedrock 制作红宝石闪光粒子:粒子文件、纹理、曲线、事件,以及如何在游戏中播放它。

粒子就是 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

创建粒子文件,先写上它的名称和外观:

RP/particles/ruby_sparkle.json
{
  "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 个闪光,分布在一个小球周围:

RP/particles/ruby_sparkle.json(在 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"
},

每个发射器都需要一个生命周期组件和一个速率组件。缺了它们,什么都不会生成。形状是可选的:不写的话,每个粒子都从正中心开始。

第 4 步:粒子

接下来告诉每个闪光如何移动和显示。把这些加在发射器组件后面:

RP/particles/ruby_sparkle.json(在 components 内)
"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 块:

RP/particles/ruby_sparkle.json(在 particle_effect 内)
"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 则让你自己设定每个点和斜率。

现在在公告板的大小中使用这个变量:

在 minecraft:particle_appearance_billboard 内
"size": ["0.12 * variable.ruby_size", "0.12 * variable.ruby_size"],

要做渐隐效果,染色也可以在粒子生命周期中改变颜色。gradient 列出颜色,interpolant 决定当前处于它们之间的哪个位置:

在 components 内
"minecraft:particle_appearance_tinting": {
  "color": {
    "gradient": ["#FFFF8FA8", "#FFFF2650", "#00A0002A"],
    "interpolant": "variable.particle_age / variable.particle_lifetime"
  }
}

这里的每种颜色都写成 #AARRGGBB,所以前两个字符是透明度。闪光从淡粉色开始,变成红宝石红,最后变暗并消失。使用 particles_add 时,深色会淡出直至消失,用在发光效果上非常漂亮。

第 6 步:用事件加一个“砰”

事件让某件事在特定时刻发生。我们在每个闪光消失的地方留下一小团尘埃。

先做尘埃。它是第二个更小的效果:

RP/particles/ruby_dust.json
{
  "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,给事件起个名字,并说明它要做什么:

RP/particles/ruby_sparkle.json(在 particle_effect 内)
"events": {
  "pop": {
    "particle_effect": {
      "effect": "wiki:ruby_dust",
      "type": "emitter"
    }
  }
},

最后,在每个闪光生命结束时触发这个事件:

RP/particles/ruby_sparkle.json(在 components 内)
"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,每个粒子都会生成更多粒子,无穷无尽。事件一定要指向另一个更小的效果。

完成的文件

这是完整的闪光效果,已经换上了发光材质:

RP/particles/ruby_sparkle.json
{
  "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 中:

RP/entity/ruby_golem.entity.json(在 description 内)
"particle_effects": {
  "sparkle": "wiki:ruby_sparkle"
}

2. 在动画的某个时间点播放它。 locator 是可选的:它是模型上一个带名字的点,效果会随生物移动而跟随它。不写的话,效果会在生物脚下播放。

RP/animations/ruby_golem.animation.json(在某个动画内)
"particle_effects": {
  "0.5": {
    "effect": "sparkle",
    "locator": "head"
  }
}

3. 或者从动画控制器状态中播放。 它会在生物进入该状态时开始:

RP/animation_controllers/ruby_golem.ac.json(在某个状态内)
"particle_effects": [
  { "effect": "sparkle" }
]

以上每种方式都可以带一个 pre_effect_script:在效果开始前运行的一小段 Molang。用它把值传进粒子文件,比如一个取决于生物的颜色。

循环效果留给生物

生物播放效果时,效果的发射器会附着在它身上。这正是 emitter_lifetime_looping 和 emitter_lifetime_expression 大显身手的地方:一条在生物行走时一直跟随的拖尾,或者在某个 Molang 值开启时持续的光芒。

从脚本中

脚本可以随时随地播放粒子。你的行为包需要在清单中声明脚本模块:项目搭建中有说明。

BP/scripts/main.js
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 把值传进粒子。这样一个粒子文件就能做出任意颜色的闪光:

BP/scripts/main.js
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 读取颜色的三个分量:

在 components 内
"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

更多帮助见故障排查。想了解更多?所有发射器设置都在发射器组件中,所有粒子设置都在粒子组件中。

We use cookies to improve your experience and analyse site traffic. Learn more