本篇教程由作者设定使用 CC BY-NC 协议。


看前提示:

本教程的一、二、三章改自ColorBlock模组的教程:https://www.mcbbs.net/thread-917845-1-1.html(已失效,懂得都懂),并扩展了亿些内容。

教程会不断更新迭代,添加更多的新内容和实例,更改纠正不合理处,随时都会更改,所以没有最终定稿版。后续或许会有稳定版。



一、命令和参数

所有命令均以 /particlex 为根,需要权限等级 2(OP)。命令采用树状结构,参数按顺序依次指定。

<> 为必选参数,[] 为可选参数。

紫色括号()内的为 参数的 数据类型、范围、默认值。


通用参数说明:

  • <粒子>:粒子类型。格式:粒子的命名空间IDParticleOptions

  • <坐标>:中心点坐标。格式:<x> <y> <z>,支持绝对、相对、局部坐标。Vec3

  • <颜色>:四分量颜色。格式:<红> <绿> <蓝> <透明度>。Vector4f,0.0~1.0)

  • <速度>:初始速度向量。格式:<vx> <vy> <vz>。Vec3

  • [寿命]:粒子生命周期。单位:游戏刻。特殊值:0 按原版进行处理,-1 表示无限。int,大于等于 -1,默认 0)

  • [速度表达式]:控制粒子生成后的运动的数学表达式。执行:每刻执行一次,次数等于粒子的 [寿命]。String,默认 null,即 不启用)

  • [速度步长]:<速度表达式>中 t 的每刻递增值double,默认 1.0)

  • [组]:将粒子加入指定组。可用 | 分隔多个组名。后续可通过 group 命令管理。String,默认 null)


1、普通粒子生成

最基础的粒子生成模式,用于在指定中心点周围随机生成一定数量的粒子。每个粒子的位置在给定范围内服从高斯(正态)分布,并可以设置颜色、速度、生命周期以及后续的运动表达式。

/particlex normal <粒子> <坐标> <颜色> <速度> <范围> <数量> [寿命] [速度表达式] [速度步长] [组]
  • <范围>:生成范围。格式:<dx> <dy> <dz>。粒子将在中心点加减此范围内随机分布(服从高斯分布/正态分布)。Vec3,大于等于 0.0)

  • [数量]:生成的粒子数量。int,大于等于 0 的 整数,默认 1)


2、条件粒子生成

一种基于数学表达式筛选粒子生成位置的功能。它允许你在一个三维空间范围内,按照指定步长采样每个点,只有当用户定义的布尔表达式在该点计算结果为真(非零)时,才会生成一个粒子。

/particlex conditional <粒子> <坐标> <颜色> <速度> <采样范围> <条件表达式> [采样步长] [寿命] [速度表达式] [速度步长] [组]
  • <采样范围>:遍历区域的范围。格式:<dx> <dy> <dz>。Vec3,大于等于 0.0)

  • <条件表达式>:返回非零值(真)时在该点生成粒子。执行:单刻执行多次,次数等于等于遍历区域内的候选点数量。String

  • [采样步长]:遍历区域的步长。粒子会在 -<范围> 到 +<范围> 范围内以该步长遍历,表达式为 真 时生成。double,大于 0.0,默认 0.1)


3、参数化粒子生成

参数化粒子生成是本模组最强大、最灵活的核心功能。它允许你通过数学表达式精确控制每个粒子的位置、颜色和运动轨迹。能够创建出各种复杂的图形和动画。

无 tick- 前缀的粒子 会在执行指令的同时全部生成,有 tick- 前缀的粒子 会逐刻生成(可做动画效果)

无 rgba- 前缀的粒子 颜色在指令的参数 <颜色> 中指定,有 rgba- 前缀的粒子 颜色在 <参数表达式> 中指定(可随"t"变化)

在直角坐标系(笛卡尔坐标系)中:

/particlex parameter <粒子> <坐标> <颜色> <速度> <起始> <结束> <参数表达式> [步长] [寿命] [速度表达式] [速度步长] [组]
/particlex tick-parameter <粒子> <坐标> <颜色> <速度> <起始> <结束> <参数表达式> [步长] [每刻迭代次数] [寿命] [速度表达式] [速度步长] [组]
/particlex rgba-parameter <粒子> <坐标> <速度> <起始> <结束> <参数表达式> [步长] [寿命] [速度表达式] [速度步长] [组]
/particlex rgba-tick-parameter <粒子> <坐标> <速度> <起始> <结束> <参数表达式> [步长] [每刻迭代次数] [寿命] [速度表达式] [速度步长] [组]

在极坐标系(球面坐标系)中:

/particlex polar-parameter <粒子> <坐标> <颜色> <速度> <起始> <结束> <参数表达式> [步长] [寿命] [速度表达式] [速度步长] [组]
/particlex tick-polar-parameter <粒子> <坐标> <颜色> <速度> <起始> <结束> <参数表达式> [步长] [每刻迭代次数] [寿命] [速度表达式] [速度步长] [组]
/particlex rgba-polar-parameter <粒子> <坐标> <速度> <起始> <结束> <参数表达式> [步长] [寿命] [速度表达式] [速度计算间隔] [组]
/particlex rgba-tick-polar-parameter <粒子> <坐标> <速度> <起始> <结束> <参数表达式> [步长] [每刻迭代次数] [寿命] [速度表达式] [速度步长] [组]
  • <起始>、<结束>:参数变量 t 的遍历范围double,<起始> 小于等于 <结束>)

  • <参数表达式>:每步计算的表达式。执行:无 tick- 前缀:单刻执行多次,次数等于从 <起始> 到 <结束> 以 <步长> 迭代的总步数;有 tick- 前缀: 每刻执行 [每刻迭代次数] 次。String

  • [步长]:每次执行<参数表达式>时 t 的递增值double,大于 0.0,默认 0.1)

  • [每刻迭代次数]:每游戏刻内执行<参数表达式>的次数int,大于 0,默认 10)


4、根据图片、视频生成粒子

将图片和视频转换为由粒子构成的动态视觉效果。

-matrix后缀 为矩阵变换模式。

若客户端缺少 JavaCV 库,视频功能将被禁用并提示下载。(存放在.javacv)

图像模式:将图片的每个像素转换为粒子。支持:.png、.jpg、.gif(只有第一帧)等。

/particlex image <粒子> <坐标> <图片路径> [缩放] [x旋转] [y旋转] [z旋转] [翻转] [粒子间距] [速度] [寿命] [速度表达式] [速度步长] [组]
/particlex image-matrix <粒子> <坐标> <path> [缩放] [矩阵] [粒子间距] [速度] [寿命] [速度表达式] [速度步长] [组]

视频模式:将视频逐帧转换为粒子动画(需 JavaCV 支持)。支持:.mp4、.mkv、.gif 等。

/particlex video <粒子> <坐标> <视频路径> [比例] [x旋转] [y旋转] [z旋转] [翻转] [粒子间距] [速度] [寿命] [速度表达式] [速度步长] [组]
/particlex video-matrix <粒子> <坐标> <视频路径> [比例] [矩阵] [粒子间距] [速度] [寿命] [速度表达式] [速度步长] [组]
  • <图片路径>:在 ./particleImages 目录下的文件String

  • <视频路径>:在 ./particleVideos 目录下的文件名String

  • [缩放]:缩放倍数double,大于等于 0.0。默认:0.1)

  • [X旋转]、[Y旋转]、[Z旋转]:绕 X、Y、Z 轴旋转的角度int,90 的整数倍,用 0, 90, 180, 270 表示,默认 0、0、0)

  • [翻转]:控制图像或视频的镜像翻转。可选:not(无翻转)、horizontally(水平翻转)、vertical(垂直翻转)enum,默认 not)

  • [矩阵]:4x4 变换矩阵。自定义矩阵格式:"(a11,a12,a13,a14,,a21,a22,a23,a24,,a31,a32,a33,a34,,a41,a42,a43,a44)"。预定义:E3(3x3单位矩阵)、E4(4x4单位矩阵)String,默认 E3)

  • [粒子间距]:每个像素对应粒子的密度。值越大,粒子间距越小。double,大于0.0,默认 10.0)


5、组管理

用于批量控制粒子的重要功能。通过为粒子指定组名,可以将大量粒子归入逻辑组,然后使用专门的组管理命令一次性移除或修改这些粒子的行为,而无需重新生成。在创建复杂特效、动画和交互时非常有用。

移除组内粒子:

/particlex group remove <组> [组移除条件表达式] [组坐标]

修改组内位置表达式的属性:

/particlex group change parameter <组> <组参数表达式> [组改变条件表达式] [组坐标]

修改组内速度表达式的属性:

/particlex group change speedexpression <组> <速度表达式> [组改变条件表达式] [组坐标]
  • [组移除条件表达式]:只有满足条件(返回非零值)的粒子会被移除。执行:单刻执行多次,次数为组内“所有”粒子数(包括寿命结束的粒子)String,默认 null)

  • <组参数表达式>:新的参数表达式。执行:单刻执行多次,次数为组内“所有”粒子数。String

  • <速度表达式>:新的速度表达式。执行:每刻执行一次,次数为组内粒子的剩余寿命。注:因和 [速度表达式] 一模一样,所以下文将两者统称为 [<速度表达式>]。String

  • [组改变条件表达式]:只有满足条件的粒子会被修改。执行:单刻执行多次,次数为组内“所有”粒子数。String,默认 null)

  • [组坐标]:指定参考点。格式:<x> <y> <z>,支持绝对、相对、局部坐标。用于 [组移除条件表达式]、[组改变条件表达式] 中的相对坐标计算。Vec3,默认 null)


6、辅助命令

不直接生成粒子,但提供工具和辅助功能的一组命令。它们主要用于信息查询、全局清理和性能优化。

列出可用数学函数:显示所有可在表达式中使用的数学函数

/particlex functions

清除所有粒子:立即清除当前维度所有生成的粒子,并清空所有粒子组。

/particlex clear-particle

清除图像缓存:清除图片缓存,释放内存。

/particlex clear-cache



二、表达式可用符号

书写位置:<条件表达式>、<参数表达式>、[<速度表达式>]、<组参数表达式>、[组改变条件表达式]、[组移除条件表达式]。


1、变量

用于控制粒子的位置、颜色、速度等属性。所有变量的值均为 double 类型。


(1)介绍:

变量名
描述补充默认值
t

参数模式下的迭代变量,或自定义运动的时间累积

<参数表达式>  中:<begin> 开始,<end> 结束,[步长] 每次递增值。

[速度表达式] 中:0.0 开始,清除粒子时 结束,[速度步长] 每次递增值

0.0
x、y、z

粒子相对于中心点的 笛卡尔偏移量

极坐标模式下由 s1、s2、dis 转换而来0.0
s1、s2、dis

粒子相对于中心点的 球坐标偏移量

方位角、俯仰角、距离,

其中 角 为 弧度制

0.0
vx、vy、vz速度分量
0.0

cr、cg、cb、

alpha

红、绿、蓝 颜色分量 和 透明度

范围 0.0~1.0,可超范围。

1.0
cx、cy、cz中心点坐标通常为命令中指定的 <坐标>0.0
dx、dy、dz粒子相对于中心点的 笛卡尔偏移量的 只读副本

每帧开始时,它们被设置为与 x, y, z 相同的值

0.0
ds1、ds2、ddis粒子相对于中心点的 球坐标偏移量的 只读副本每帧与 s1, s2, dis 同步0.0
age粒子年龄粒子已存在的 刻数0.0
destroy销毁粒子若设为 非零值(destory != 0.0),粒子将在 下一 tick 被移除0.0
PI圆周率 π
3.1415926535897930.0
E自然常数 e2.7182818284590450.0
自定义变量

通过赋值语句可以创建任意的自定义变量,

可为整数/浮点数变量、矩阵变量。

允许字符:字母(a-z、A-Z)、数字(0-9)、下划线(_)。

数字开头会被忽略。大小写敏感。


  • 内置变量:上表除了 自定义变量 外的变量,可以 跨刻读取和修改

  • 自定义变量:通过赋值引入,仅用于临时计算,每次表达式执行时都会重新初始化。

  • 定义变量后,可在后续表达式中直接引用变量。名:"radius=5;x=radius*cos(angle);y=radius*sin(angle)"。

  • 变量可以被重新赋值:"a=0; a=a+1"。


(2)内置变量分类:

位置因变量自变量无效变量常量

<条件表达式>


x, y, z

s1, s2, dis

t

vx, vy, vz

cx, cy, cz

dx, dy, dz

ds1, ds2, ddis

age, destroy

PI

E

<参数表达式>

直角坐标系:x, y, z

极坐标系:s1, s2, dis

rgba-命令:cr, cg, cb, alpha

t


vx, vy, vz

cx, cy, cz

dx, dy, dz

ds1, ds2, ddis

age, destroy

[<速度表达式>]

vx, vy, vz

cr, cg, cb, alpha

destroy

t

x, y, z

s1, s2, dis

cr, cg, cb, alpha

cx, cy, cz

dx, dy, dz

ds1, ds2, ddis

age

<组参数表达式>

x, y, z

vx, vy, vz

cr, cg, cb, alpha

cx, cy, cz

x, y, z

vx, vy, vz

cr, cg, cb, alpha

cx, cy, cz

t

s1, s2, dis

dx, dy, dz

ds1, ds2, ddis

age, destroy

[组改变条件表达式]


x, y, z

s1, s2, dis

t

vx, vy, vz

cx, cy, cz

dx, dy, dz

ds1, ds2, ddis

age, destroy

[组移除条件表达式]


x, y, z

s1, s2, dis

age

t

vx, vy, vz

cx, cy, cz

dx, dy, dz

ds1, ds2, ddis

destroy

  • 自变量:表达式执行前被赋予有意义的值,作为输入反映当前粒子状态;可读写。

  • 因变量:该变量的赋值会实际影响粒子的行为(生成、运动或筛选结果等);可读写。

  • 无效变量:其值 不反映当前粒子状态、不影响粒子的行为,可能为默认值;可读写。

  • 常量:固定值;只读。


2、运算符

类型符号
补充示例

加法+数值 或 矩阵 加法a + b
减法、取负-数值 或 矩阵 减法/取负a - b 或 -a
乘法*数值 或 矩阵 乘法a * b
除法/

数值 或 矩阵与标量 除法

a / b
幂运算^数值 或 矩阵与整数指数 幂a ^ b
取余%

数值 或 矩阵与标量 取余。

余数的符号与被除数相同

a % b

小于<返回 1(真)或 0(假)x < 1
小于等于<=返回 1(真)或 0(假)x <= 1
大于>返回 1(真)或 0(假)x > 4
大于等于>=返回 1(真)或 0(假)x >= 5
等于==返回 1(真)或 0(假)x == 1
不等于!=返回 1(真)或 0(假)x != 4

逻辑

运算符

逻辑与&

cond1 & cond2。短路求值。

两边都非零则返回 1(真),否则 0(假)

 1<t & t<4
逻辑或|

cond1 | cond2。短路求值。

至少一边非零则结果为 1(真),否则 0(假)

t<1 | 4<t
逻辑非!

!cond。

数值非零转为 0(真),零转为 1(假)

! t==1
赋值运算符赋值=将 右侧表达式的值 赋给 左侧变量

a=19、b=1.9、

c=(8,1,0,,5,2,0)

优先级从高到低:

  • “括号 ()、函数调用、矩阵字面量”→“一元运算符 -(取负)!”→“幂运算 ^(右结合)”→“乘除取余 * / %”→“加减 + -”→“比较 < <= > >= == !=”→“逻辑与 &”“逻辑或 |”→“赋值 =”。

算术运算符:支持数值(整数/浮点数)和矩阵运算。

  • 当两侧都是整数时,结果为整数(幂运算除外,幂运算返回浮点数)

  • 若一侧为浮点数,则结果为浮点数。

  • / 和 % 除数为 0 时:两侧都是整数 → 抛出异常;一侧为浮点数 → 特殊值。

  • 矩阵运算时,支持矩阵与标量、矩阵与矩阵的加、减、乘、除、取模、幂(仅整数幂)。矩阵乘法遵循线性代数规则。


3、其他语法、字符

类型字符用法描述例子

语句

分隔

;表达式1 ; 表达式2

分隔 多个独立的表达式语句,构成 一个表达式块。

整个块会按顺序执行,最后一个表达式的值作为整个块的返回值

a=1; b=2; c=a+b; d=sin(c)

列表

分隔

,元素1 , 元素2分隔 同一语句中的多个元素

多变量赋值:x, y, z = 1, 2, cos(t)

函数参数列表:pow(2, 3)

矩阵字面量中的列分隔:(1, 1, 4,, 5, 1, 4) 

矩阵

字面量

()(a1,a2,...,,b1,b2,...,,...)

用圆括号 () 包围,

行之间用 双逗号 ,, 分隔,

列之间用 单逗号 , 分隔

(1,2,3,,4,5,6) 或

(sin(t), cos(t),, t^2, log(t))

,,
,
括号()( 表达式/矩阵 )

改变 运算优先级,

也用于 矩阵字面量和解构

a*(114+b)、(x<=1|dis<1)&(s2>0)、

(1,1,4,,5,1,4)

函数

调用

函数标识符(参数1,参数2,...)

调用 数学函数。

参数可以是任意表达式或一个值,

参数数量需匹配函数定义

sin(t)
0-9数字用于 整数/浮点数、变量名

整数:11、4

浮点数:51.4

变量名:a1

.小数点用于 浮点数
空白字符 半角空格空白字符在解析时会被 忽略,仅用于 分隔语法元素。
x=t;     y=t^2


4、内置函数

表格中的“函数及数据类型”就是 /particlex functions 命令 输出的内容。

其中“double”之类的是数据类型,仅作提示,在命令中不能写出。在函数前面的是“输出/返回数据类型”,在括号里的是“输入数据类型”。


(1)常用数学函数:

来自Java标准库Math类中的函数,支持常见的数学运算。

概述函数解释补充函数及数据类型
基本三角函数正弦sin(a)计算角度 a 的正弦值输入 弧度double sin(double a)
余弦cos(a)计算角度 a 的余弦值输入 弧度double cos(double a)
正切tan(a)计算角度 a 的正切值输入 弧度double tan(double a)
反三角函数反正弦asin(a)计算数值 a 的反正弦值返回 弧度,范围[-π/2, π/2]double asin(double a)
反余弦acos(a)计算数值 a 的反余弦值返回 弧度,范围[0, π]double acos(double a)
反正切atan(a)计算数值 a 的反正切值返回 弧度,范围[-π/2, π/2]double atan(double a)
atan2(a, b)

计算 a÷b 的反正切值,

得出极坐标的相角theta。

返回 弧度,范围 [-π, π]double atan2(double a, double b)
角度转换
转 弧度toRadians(a)将 角度a 转换为 弧度
double toRadians(double a)
转 角度toDegrees(a)将 弧度a 转换为 角度
double toDegrees(double a)
指数与幂abpow(a, b)计算 a 的 b 次幂
double pow(double a, double b)
ea
exp(a)计算 e 的 a 次幂
double exp(double a)
ea−1expm1(a)计算 e 的 a 次幂减 1对接近 0 的输入,返回更精确double expm1(double a)
a×2b
scalb(a,b)计算 a 乘 2 的 b 次幂
double scalb(double a, int b)
无偏指数getExponent(a)计算 a 的无偏指数

int getExponent(double a)
对数ln(a)log(a)计算 a 的自然对数,即 ln(a)
底为 edouble log(double a)
lg(a)log10(a)计算 a 的常用对数,即 lg(a)底为 10double log10(double a)
ln(1+a)log1p(a)计算 1+a 的自然对数对接近 0 的输入,返回更精确double log1p(double a)
根号√asqrt(a)计算 a 的平方根
double sqrt(double a)
3√acbrt(a)计算 a 的立方根
double cbrt(double a)
√(x²+y²)hypot(a, b)计算 x²+y² 的平方根避免中间结果溢出double hypot(double a, double b)
双曲函数双曲正弦sinh(a)计算 a 的双曲正弦值
double sinh(double a)
双曲余弦cosh(a)计算 a 的双曲余弦值
double cosh(double a)
双曲正切tanh(a)计算 a 的双曲正切值返回 范围 (-1, 1)double tanh(double a)
极值较小值min(a, b)比较 a 和 b,返回较小值
double min(double a, double b)

long min(long a, long b)

int min(int a, int b)
较大值max(a, b)比较 a 和 b,返回较大值
double max(double a, double b)

long max(long a, long b)

int max(int a, int b)
取整向下取整floor(a)返回不大于 a 的最大整数
double floor(double a)
向上取整ceil(a)返回不小于 a 的最小整数
double ceil(double a)
四舍五入rint(a)返回最接近 a 的整数的 double 值
double rint(double a)
round(a)返回最接近 a 的 long 值
long round(double a)
绝对值abs(a)返回 a 的绝对值
double abs(double a)

long abs(long a)

int abs(int a)
absExact(a)溢出抛出异常(防止溢出)long absExact(long a)
int absExact(int a)
符号函数signum(a)返回 a 的符号
double signum(double a)
copySign(a, b)返回 a 的绝对值与 b 的符号结合后的值
double copySign(double a, double b)
随机数
random()生成 [0.0, 1.0) 范围内的随机数
double random()
数值范围限制clamp(a, b, c)

将 a 限制在 [b, c] 范围内

a 在区间内 返回 a,

超过 c 返回 c,小于 b 返回 b

double clamp(double a, double b, double c)
long clamp(long a, long b, long c)
int clamp(long a, int b, int c)

加法addExact(a, b)计算 a+b

溢出抛出异常(防止溢出)

long addExact(long a, long b)
int addExact(int a, int b)
递增incrementExact(a)返回 a+1long incrementExact(long a)
int incrementExact(int a)
减法subtractExact(a, b)计算 a−blong subtractExact(long a, long b)
int subtractExact(int a, int b)
递减decrementExact(a)返回 a−1long decrementExact(long a)
int decrementExact(int a)
乘法multiplyExact(a, b)计算 a×blong multiplyExact(long a, long b)
long multiplyExact(long a, int b)
int multiplyExact(int a, int b)
multiplyFull(a, b)
long multiplyFull(int a, int b)
multiplyHigh(a, b)返回 a×b 的 高位 64 位将 输入 视为 有符号数long multiplyHigh(long a, long b)
unsignedMultiplyHigh(a, b)将 输入 视为 无符号数long unsignedMultiplyHigh(long a, long b)
融合乘加运算fma(a, b, c)计算 a×b+c
double fma(double a, double b, double c)
除法divideExact(a, b)计算 a÷b溢出抛出异常(防止溢出)long divideExact(long a, long b)
int divideExact(int a, int b)
floorDiv(a, b)

计算 a÷b 的向下取整值,

即 整数商


long floorDiv(long a, long b)

long floorDiv(long a, int b)

int floorDiv(int a, int b)
floorDivExact(a, b)溢出抛出异常(防止溢出)long floorDivExact(long a, long b)
int floorDivExact(int a, int b)
ceilDiv(a, b)计算 a÷b 的向上取整值,

即 整数商加 1


long ceilDiv(long a, long b)

long ceilDiv(long a, int b)

int ceilDiv(int a, int b)
ceilDivExact(a, b)溢出抛出异常(防止溢出)long ceilDivExact(long a, long b)
int ceilDivExact(int a, int b)
取模floorMod(a, b)

计算 a÷b 的 余数,

向负无穷取整,符号与除数 b 一致


long floorMod(long a, long b)

int floorMod(long a, int b)

int floorMod(int a, int b)
ceilMod(a, b)

计算 a÷b 的 余数,

向正无穷取整,符号与除数 b 相反


long ceilMod(long a, long b)

int ceilMod(long a, int b)

int ceilMod(int a, int b)
IEEE标准余数IEEEremainder(a, b)

计算 a÷b 的 IEEE 754 标准余数。

结果满足 |r| ≤ |b|/2

a - b * n,其中 n 是最接近 a/b 的整数

(如果恰好有两个整数同样接近,则取偶数)

double IEEEremainder(double a, double b)
相反数negateExact(a)计算 a 的 相反数值溢出抛出异常(防止溢出)int negateExact(int a)
long negateExact(long a)
转 inttoIntExact(a)将 long 值安全转换为 int 值输入 超出 int 范围,抛出异常int toIntExact(long a)
最小精度单位ulp(a)返回 a 的 最小精度单位该浮点数在当前位置的最小增减量double ulp(double a)
邻近浮点数a 向 b 方向nextAfter(a, b)返回从 a 向 b 方向的下一个邻近浮点数
double nextAfter(double a, double b)
向上nextUp(a)返回比 a 大 的最小浮点数正方向的下一个值double nextUp(double a)
向下nextDown(a)返回比 a 小 的最大浮点数负方向的下一个值double nextDown(double a)


(2)扩展函数:

这些是本模组自定义的扩展函数,用于复杂粒子变换。

概述函数解释补充函数及数据类型
线性插值
lerp(delta, start, end)在 start 和 end 之间按比例 delta 线性插值公式“start+delta×(end-start)”double lerp(double delta, double start, double end)
lerpInt(delta, start, end)整数版本的线性插值,结果向下取整
int lerpInt(double delta, int start, int end)

矩阵变换

(4x4 齐次坐标)

(行向量)

平移矩阵translate(x, y, z)生成 3D 平移矩阵,沿 X、Y、Z 轴平移 x,y,z 个单位矩阵“(1,0,0,0,,0,1,0,0,,0,0,1,0,,x,y,z,1)”double[][] translate(double x, double y, double z)
缩放矩阵scale(x, y, z)生成 3D 缩放矩阵,沿 X、Y、Z 轴分别缩放 x,y,z 倍
矩阵“(x,0,0,0,,0,y,0,0,,0,0,z,0,,0,0,0,1)”double[][] scale(double x, double y, double z)
旋转矩阵rotate(pitch, yaw, roll)

生成绕 X(pitch)、Y(yaw)、Z(roll)轴

旋转的 3D 复合旋转矩阵

输入 弧度double[][] rotate(double pitch, double yaw, double roll)
rotateDeg(pitch, yaw, roll)输入 角度double[][] rotateDeg(double pitch, double yaw, double roll)
矩阵操作转置矩阵transpose(matrix)计算 矩阵matrix 的 转置矩阵行列互换double[][] transpose(double[][] matrix)
int[][] transpose(int[][] matrix)
逆矩阵invert(matrix)计算 矩阵matrix 的 逆矩阵
仅支持可逆方阵(使用高斯-约当消元法求方阵的逆矩阵)double[][] invert(double[][] matrix)



三、技巧


1、变换

想要搞懂本部分需了解“矩阵”的相关知识,特别是 矩阵的运算、3D 齐次坐标下的 线性变换矩阵。(当然你也可以直接从下面套用)


(1)静态变换

Ⅰ、直角坐标系:

书写位置:不带“polar-”前缀指令的 <参数表达式>、<组参数表达式> 。

<参数表达式> 格式:"...表达式部分变换部分..."。<组参数表达式> 格式:"...变换部分..."

变换部分矩阵格式:"(x,y,z)=(x,y,z,1)*变换矩阵"(单一换)、"(x,y,z)=(x,y,z,1)*变换矩阵1*变换矩阵2*..."(复合变换)

变换类型
变换矩阵(行向量)变换部分(分解格式)数值数值大小

平移

变换

translate(tx, ty, tz)x, y, z=x+tx, y+ty, z+tz

tx、ty、tz:

X 轴平移距离、Y 轴平移距离、Z 轴平移距离

0 为不平移;

大于 0 沿正向轴平移;

小于 0 沿负向轴平移

缩放

变换

scale(sx, sy, sz)x, y, z=x*sx, y*sy, z*sz

sx、sy、sz:

X 轴缩放大小、Y 轴缩放大小、Z 轴缩放大小

1 为不缩放;0 为二向箔;

大于 1 放大,小于 1 缩小;

小于 0 沿中心点镜像反转


X 轴

rotate(rx, ry, rz)

rotateDeg(rx, ry, rz)

y=y*cos(rx)-z*sin(rx);

z=y*sin(rx)+z*cos(rx)

rx:绕 X 轴旋转角度

大于 0 时,旋转方向为

+Z → +Y;0 为不旋转

Y 轴

x=x*cos(ry)+z*sin(ry);

z=-x*sin(ry)+z*cos(ry)

ry:绕 Y 轴旋转角度

大于 0 时,旋转方向为

+X → +Z;0 为不旋转

Z 轴

x=x*cos(rz)-y*sin(rz);

y=x*sin(rz)+y*cos(rz)

rz:绕 Z 轴旋转角度

大于 0 时,旋转方向为

+Y → +X;0 为不旋转

示例:

平移变换:

将 "x=t" 粒子图像 X轴平移-5格、Y轴平移2格,设定<参数表达式>为 "x=t(x,y,z)=(x,y,z,1)*translate(-5,2,0)",或 "x=tx,y=x-5,y+2"。

将组为 a 的粒子图像 沿X轴平移-5格、Y轴平移2格,设定<组参数表达式>为 "(x,y,z)=(x,y,z,1)*translate(-5,2,0)"。

缩放变换:

将 "x,y=t,t^2" 粒子图像 沿Y轴缩小到原来的0.5倍,设定<参数表达式>为 "x,y=t,t^2(x,y,z)=(x,y,z,1)*scale(1,0.5,1)"。

旋转变换:

将 "x,y=t,t^2" 粒子图像 沿X轴旋转45°,设定<参数表达式>为 "x,y,z=t,t^2,0(x,y,z)=(x,y,z,1)*rotateDeg(45,0,0)",或 "x,y,z=t,t^2,0(x,y,z)=(x,y,z,1)*rotate(PI/4,0,0)"。

复合变换:

将 "x,y=t,t^2" 粒子图像 沿X轴旋转−45°、Y轴放大到原来的5倍,设定<参数表达式>为 "x,y,z=t,t^2,0(x,y,z)=(x,y,z,1)*rotateDeg(-45,0,0)*scale(1,5,1)"。


Ⅱ、极坐标系:

书写位置:带“polar-”前缀指令的 <参数表达式>。

<表达式>格式:"...表达式部分变换部分...",或者两者结合。

变换类型变换部分数值数值大小
缩放变换dis=dis+sd

sd:

整体缩放大小

0 为不缩放;大于 0 放大,小于 0 缩小

dis=dis*sd

1 为不缩放;大于 1 放大,小于 1 缩小;

小于 0 沿原点镜像反转

旋转变换s1=s1+phiphi:水平旋转角度

大于 0 时,旋转方向为 左 → 右;0 为不旋转

s2=s2+theta

theta:垂直旋转角度大于 0 时,旋转方向为 下 → 上;0 为不旋转

示例:

以 "s2,dis=PI*2*t,2" 粒子图像为例。

缩放变换:

将粒子图像 放大2格,设定<参数表达式>为 "s2,dis=PI*2*t,2; dis=dis+2"。

将粒子图像 放大到原来的2倍,设定<参数表达式>为 "s2,dis=PI*2*t,2dis=dis*2"。

旋转变换:

将粒子图像 水平旋转45°,设定<参数表达式>为 "s1,s2,dis=0,PI*2*t,2; s1=s1+PI/4"。

将粒子图像 垂直旋转45°,设定<参数表达式>为 "s1,s2,dis=0,PI*2*t,2s2=s2+PI/4"。


(2)动态变换

书写位置:[<速度表达式>]。

格式:"...变换部分..."

变换部分矩阵格式

"(vx,vy,vz)=(x,y,z,1)*(变换矩阵-(1,0,0,0,,0,1,0,0,,0,0,1,0,,0,0,0,1))"(单一变换)

"(vx,vy,vz)=(x,y,z,1)*(变换矩阵1*变换矩阵2*...-(1,0,0,0,,0,1,0,0,,0,0,1,0,,0,0,0,1))"(复合变换)

变换类型变换矩阵(行向量)

变换部分(分解格式)

数值数值大小

平移变换

translate(tx, ty, tz)

vx, vy, vz=tx, ty, tz

tx、ty、tz:

X 轴平移速度、Y 轴平移速度、Z 轴平移速度

0 为不平移;

大于 0 沿正向轴移动;

小于 0 沿负向轴移动

缩放变换

scale(1+sx, 1+sy, 1+sz)

vx, vy, vz=

x*sx, y*sy, z*sz

sx、sy、sz:

X 轴缩放速度、Y 轴缩放速度、Z 轴缩放速度

0 为不缩放;

大于 0 放大,

小于 0 缩小

X 轴

rotate(rx, ry, rz)

rotateDeg(rx, ry, rz)

vy=y*cos(rx)-z*sin(rx) - y ;

vz=y*sin(rx)+z*cos(rx) - z

rx:绕 X 轴旋转速度

大于 0 时,旋转方向为

+Z → +Y;0 为不旋转

Y 轴

vx=x*cos(ry)+z*sin(ry) - x ;

vz=-x*sin(ry)+z*cos(ry) - z

ry:绕 Y 轴旋转速度

大于 0 时,旋转方向为

+X → +Z;0 为不旋转

Z 轴

vx=x*cos(rz)-y*sin(rz) - x ;

vy=x*sin(rz)+y*cos(rz) - y

rz:绕 Z 轴旋转速度

大于 0 时,旋转方向为

+Y → +X;0 为不旋转

原理:离散时间步长更新下(Δt=游戏刻=1),计算三维空间中一点经过变换后的速度分量,v = ( r' − r ) / Δt = r' − r = T • r − I4 • r =( T − I4 ) r

其中,变换后的速度分量 v=(vx​,vy​,vz​),变换前的坐标向量 r=(x,y,z),变换后的坐标向量 r'=(x',y',z'),

T 是作用于齐次坐标 (x,y,z,1) 的 4×4 变换矩阵,I4 是 4×4 单位矩阵。

示例:

平移变换:

将粒子图像 沿X轴平移0.2速度,设定 [<速度表达式>] 为 

"(vx,vy,vz)=(x,y,z,1)*(translate(0.2,0,0)-(1,0,0,0,,0,1,0,0,,0,0,1,0,,0,0,0,1))",或 "vx=0.2"。

缩放变换:

将粒子图像 沿Z轴缩小-0.1速度,设定 [<速度表达式>] 为 

"(vx,vy,vz)=(x,y,z,1)*(scale(1,1-0.1,1)-(1,0,0,0,,0,1,0,0,,0,0,1,0,,0,0,0,1))","vz=-0.1*z"。

将粒子图像 整体放大0.1速度,设定 [<速度表达式>] 为 

"(vx,vy,vz)=(x,y,z,1)*(scale(1+0.1,1+0.1,1+0.1)-(1,0,0,0,,0,1,0,0,,0,0,1,0,,0,0,0,1))",或 "(vx,vy,vz)=(x,y,z)*0.1"。

旋转变换:

将粒子图像 沿Y轴旋转PI/32速度,设定 [<速度表达式>] 为 

"(vx,vy,vz)=(x,y,z,1)*(rotate(0,PI/32,0)-(1,0,0,0,,0,1,0,0,,0,0,1,0,,0,0,0,1))",或 "(vx,vy,vz)=(x,y,z,1)*(rotateDeg(0,5.625,0)-(1,0,0,0,,0,1,0,0,,0,0,1,0,,0,0,0,1))"。

复合变换:

将粒子图像 沿X轴平移0.05速度、沿Y轴放大0.01速度、整体放大0.02速度、沿Y轴旋转PI/16速度,设定 [<速度表达式>] 为

"(vx,vy,vz)=(x,y,z,1)*(translate(0.05,0,0)*scale(1,1+0.01,1)*scale(1+0.02,1+0.02,1+0.02)*rotate(0,PI/16,0)-(1,0,0,0,,0,1,0,0,,0,0,1,0,,0,0,0,1))"。


2、分段表达式

在 表达式 中应用“逻辑运算符”“关系运算符”的方法,类似分段函数。

虽然 表达式 没有 三元运算符,但可以用下面的方法来实现相同的效果。

(1)利用关系运算符的返回值

原理:逻辑运算的结果(返回值)被规范化为整数:0 代表“假”,1 代表“真”。

格式:"temp=计算部分*(条件部分) 计算部分*(条件部分)+..."。(不分顺序。temp 为你想设的变量)

(2)利用逻辑运算符的短路特性(自定义变量 可能没用)

原理:

  • 对于 &,只有当左侧操作数为“真”(非零)时才会计算右侧操作数;若左侧为“假”时则右侧被跳过。

  • 对于 |,只有当左侧操作数为“假”时才计算右侧操作数;若左侧为“真”时则右侧被跳过。

格式:"(条件部分&表达式部分)|(条件部分&表达式部分)|…",或 "条件部分&表达式部分条件部分&表达式部分;…"。(先条件后表达式)

注意“表达式部分”内部不能包含 ; 。

示例:

例1:t<0 时粒子图像为 y=sin(x),t>=0 时粒子图像为 y=0.2*x^2,设定 <参数表达式> 为

  • 利用返回值:"x, y = t, sin(t)*(t<0) 0.2*t^2*(t>=0)"。

  • 利用短路特性: "( t<0&y=sin(t) )|( t>=0&y=0.2*t^2 )",或 "t<0&y=sin(t)t>=0&y=0.2*t^2"。

例2:将粒子图像在 t<20 时沿 +y 移动 2 格,在 20<=t<40 时沿 +x 移动 3 格,设定 [<速度表达式>] 为

  • 利用返回值:"vy=2/20.0*(t<20); vx=3/20.0*(20<=t&t<40)"。

  • 利用短路特性:( t<20&vy=2/20.0 )|( 20<=t&t<40&vx=3/20.0 )',或 't<20&vy=2/20.0; 20<=t&t<40&vx=3/20.0'。

例3:将粒子图像中 t>30、颜色值小于 (0.5,0.5,0.5) 的粒子 消失,设定 [<速度表达式>] 为

  • 利用返回值:"destroy = t>30 & cr%1<.5 & cg%1<.5 & cb%1<.5( *1 省略)

  • 利用短路特性:"t>30 & cr%1<.5 & cg%1<.5 & cb%1<.5 & destroy=1"。


3、缓动运动

书写位置:一般为 [<速度表达式>]。

本来想用 cubic-bezier(x1, y1, x2, y2) 的,结果想要实现很麻烦(或者压根不能实现),就不用了。

以下均在  [速度步长] 为 1.0 的情况下为准,若改变,则要让 T 里的 t 除以 [速度步长]。

首先归一化时间 t :

表达式:"t = t/Step ; t = (0<=t&t<Age)*(t/Age) + (t>=Age)*1"(需放在下面的表达式前面)

自定义变量:Age 为 缓动运动的时间(需填值)Step 为 [速度步长] 的值(需填值)

若 [速度步长] 的值为 1.0,则“ t = t/Step ; ”就不用写了。

常用缓动函数表达式:相对于位移而言。

缓动类型表达式补充
线性V=S/Age * 1

二次

缓入V=S/Age * 2*t
缓出V=S/Age * 2*(1-t)
缓入缓出V=S/Age * ((t<0.5)*(4*t) + (t>=0.5)*(4*(1-t)))

三次

缓入V=S/Age * 3*t^2
缓出V=S/Age * 3*(1-t)^2
缓入缓出V=S/Age * ((t<0.5)*(12*t^2) + (t>=0.5)*(12*(1-t)^2))

N次

缓入V=S/Age * N*t^N

N:阶次(需填值)

N1:临时变量。

缓出V=S/Age * N*(1-t)^N
缓入缓出

N=5 ;

N1=N*2^(N-1) ;

V=S/Age * ((t<0.5)*(N1*t^N) + (t>=0.5)*(N1*(1-t)^N))

指数

缓入V=S/Age * 10*log(2)*pow(2,10*(t-1))
缓出V=S/Age * 10*log(2)*pow(2,-10*t)
缓入缓出

V=S/Age * ((t<0.5)*(10*log(2)*pow(2,20*t-10)) + (t>=0.5)*(10*log(2)*pow(2,-20*t+10)))


正弦缓入V=S/Age * (PI/2)*sin(PI/2*t)
缓出V=S/Age * (PI/2)*cos(PI/2*t)
缓入缓出V=S/Age * (PI/2)*sin(PI*t)
圆形缓入V=S/Age * t/sqrt(1-t^2)
缓出

t=t+(t==0) ;

V=S/Age * (1-t)/sqrt(1-(1-t)^2)

回退

缓入

Bc=1.70158 ;

V=S/Age * (3*(Bc+1)*t^2-2*Bc*t)

Bc:过冲系数(典型值 1.70158)

V=S/Age * (3*t^2-(sin(PI*t)+PI*t*cos(PI*t)))

缓出

Bc=1.70158 ;

V=S/Age * (3*(Bc+1)*(1-t)^2-2*Bc*(1-t))

V=S/Age * (3*(1-t)^2-(sin(PI*(1-t))+PI*(1-t)*cos(PI*(1-t))))

缓入缓出

Bc=1.70158 ;

V=S/Age * ((t<0.5)*(12*(Bc+1)*t^2-4*Bc*t ) + (t>=0.5)*(12*(Bc+1)*(1-t)^2-4*Bc*(1-t)))


弹性

缓入

V=S/Age * (pow(2,-10*(1-t))*((-10*log(2))*sin(((1-t)-0.075)*2*PI/0.3 ) + (2*PI/0.3)*cos(((1-t)-0.075)*2*PI/0.3)))

基于 Penner 弹性缓动函数推导。

可以根据需要调整内部常数(如 0.075 和 0.3)

以获得不同的振荡效果

缓出

V=S/Age * (pow(2,-10*t)*(-10*log(2)*sin((t-0.075)*(2*PI)/0.3) + (2*PI/0.3)*cos((t-0.075)*(2*PI)/0.3)))

缓入缓出

V=S/Age * ((t<0.5)*(pow(2,-10*(2*t))*((-10*log(2))*sin(((2*t)-0.075)*2*PI/0.3)+(2*PI/0.3)*cos(((2*t)-0.075)*2*PI/0.3)))

 + (t>=0.5)*(pow(2,-10*(2*t-1))*((-10*log(2))*sin(((2*t-1)-0.075)*2*PI/0.3)+(2*PI/0.3)*cos(((2*t-1)-0.075)*2*PI/0.3))))

弹跳缓入

V=S/Age * (((1-t)<1/2.75)*(15.125*(1-t))+((1-t)>=1/2.75&(1-t)<2/2.75)*(15.125*((1-t)-1.5/2.75))

+((1-t)>=2/2.75&(1-t)<2.5/2.75)*(15.125*((1-t)-2.25/2.75))+((1-t)>=2.5/2.75)*(15.125*((1-t)-2.625/2.75)))


缓出

V=S/Age * ((t<1/2.75)*(15.125*t) + (t>=1/2.75&t<2/2.75)*(15.125*(t-1.5/2.75))

+(t>=2/2.75&t<2.5/2.75)*(15.125*(t-2.25/2.75)) + (t >= 2.5/2.75)*(15.125*(t-2.625/2.75)))


缓入缓出

V=S/Age * ((t<0.5)*(((1-2*t)<1/2.75)*(15.125*(1-2*t))+((1-2*t)>=1/2.75&(1-2*t)<2/2.75)*(15.125*((1-2*t)-1.5/2.75))

+((1-2*t)>=2/2.75&(1-2*t)<2.5/2.75)*(15.125*((1-2*t)-2.25/2.75))+((1-2*t)>=2.5/2.75)*(15.125*((1-2*t)-2.625/2.75)))

 + (t>=0.5)*(((2*t-1)<1/2.75)*(15.125*(2*t-1))+((2*t-1)>=1/2.75&(2*t-1)<2/2.75)*(15.125*((2*t-1)-1.5/2.75))

+((2*t-1)>=2/2.75&(2*t-1)<2.5/2.75)*(15.125*((2*t-1)-2.25/2.75))+((2*t-1)>=2.5/2.75)*(15.125*((2*t-1)-2.625/2.75))))


贝塞尔二次V=S/Age * (2*(1-t)*y1+2*t*(1-y1))

y1:控制点纵坐标(需填值)

起点 (0,0),终点 (1,1)。

三次V=S/Age * (3*(1-t)^2*y1+6*(1-t)*t*(y2-y1)+3*t^2*(1 - y2))

y1y2:贝塞尔曲线的控制点(需填值)

起点 (0,0),终点 (1,1)。

自定义变量:V 为 实际速度(可赋给 vx、vy、vz 等)S 为移动距离(需填值)

某些缓动后停不下来怎么办,可以限制 V,t>1 时让 V 为 0,例如:vy=V*(t<1)。

以上缓动方法并不是全部,你也可以用表达式设个想要的缓动运动。V 也并不一定只赋给 速度变量,其他变量也可赋。



四、小知识


1、客户端-服务端同步

命令在服务端执行,通过 NeoForge 的网络系统,将命令参数从服务端发送到所有在线的客户端,由客户端负责最终的粒子生成。


2、条件表达式生成粒子的大致原理

空间遍历:根据 <采样范围> 和 [采样步长],在三维空间中进行三重循环(从 -dx 到 +dx,以 [采样步长] 递增)。对每个候选点:

  • 将 <条件表达式> 中的 x, y, z 设置为当前点相对于中心的位置。

  • 自动计算球坐标 s1、s2 和 dis,以便表达式可以直接使用。

  • 执行 <条件表达式>。表达式的结果是一个整数值(0 表示假,非 0 表示真)

粒子生成:如果表达式返回值 非 0,则在该绝对位置(中心位置 + 偏移)生成一个粒子,并应用命令中指定的颜色、速度、生命周期等属性。


3、颜色

在 Minecraft 的渲染管线中,颜色值的处理过程如下:

  • 浮点数到整数的转换:将 浮点数 乘以 255 并强制转换为 int。(VertexConsumer)

  • 整数到字节的写入:直接将 int 强制转换为 byte,发生溢出截断(保留低 8 位)(BufferBuilder.setColor)

  • OpenGL 归一化:将内存中的 字节值 byte 当作 无符号整数(范围 0~255),然后除以 255.0 映射到 [0.0, 1.0]。(VertexFormatElement.Usage.COLOR)

最终效果:(cr, cg ,cb 都为这个数)

  • 2.0 → (int)(2.0*255) = 510 → (byte)510 = -2 → 254 / 255 ≈ 0.996(接近白色)

  • 3.5 → (int)(3.5*255) = 892 → (byte)892 = 124 → 124 / 255 ≈ 0.486(接近中等灰度)

  • -1.0 → (int)(-1.0*255) = -255 → (byte)-255 = 1 → 1 / 255 ≈ 0.004(接近黑色)

现象本质:整数溢出环绕,它解释了为什么超出 [0,1] 的值不会直接变成 1 或 0,而是循环到另一端的值。


4、特殊值

(1)介绍:

数学表达式中,浮点运算遵循 IEEE 754 浮点标准,因此可能产生两个特殊值:NaN(Not a Number)和 Infinity(无穷大)。这些值通常由非法或未定义的数学操作产生,并会影响粒子的行为和渲染。

  • NaN(Not a Number):表示未定义或不可表示的数值结果。NaN 具有传染性:任何包含 NaN 的算术运算结果仍为 NaN。NaN 与任何值(包括自身)的比较结果均为 假。

  • +Infinity(正无穷大):表示超出 double 上限的值。

  • -Infinity(负无穷大):表示超出 double 下限的值。

(2)产生

NaN:

  • 零除以零:0.0 / 0.0。

  • 取余中除数为零:1 % 0.0。

  • 负数开平方:sqrt(-1)。

  • 负数取对数:log(-1)。

  • 负数的小数次幂:pow(-2, 0.5)。

  • 反三角函数的参数超出定义域 [-1, 1]:asin(2)、acos(3)。

  • 其他:任何包含 NaN 的运算、Infinity - Infinity、Infinity / Infinity、0 × Infinity。

Infinity:

  • 正数除以零:1.0 / 0.0 → +Infinity。

  • 负数除以零:-1.0 / 0.0 → -Infinity。

  • 对零取对数:log(0) → -Infinity。

  • 零的负数次幂:pow(0, -2) → +Infinity。

  • 超出范围的指数:exp(1000) → +Infinity。

  • 其他:包含 Infinity 的部分运算。

无穷大参与比较运算时行为正常:+Infinity > 任何有限数 为 真,-Infinity < 任何有限数 为 真。但与 NaN 的比较的永远为 假。

(3)对粒子的影响

  • 速度变量(vx, vy, vz):NaN 将转换为 0.0。Infinity 等不会被转换,以“无穷大”速度移动,瞬间超出世界边界(通常会被移除或卡在边界)

  • 位置变量(x, y, z):NaN 可能无法渲染该粒子。Infinity 等粒子会被瞬间推到无限远处。

  • 颜色变量(cr, cg, cb, alpha):NaN 在渲染管道被视为未定义行为(可能导致不可见或显示为黑/白色)。Infinity 等渲染时可能被钳位到 1.0 或 0.0。

  • 销毁标志(destroy):销毁。


5、数据类型

参数、变量、函数等所用到的 数据类型 看下表。

数据类型说明占用空间取值范围

整数类型byte整数,禁用小数点1 字节-27 ~ 27−1
short2 字节-215 ~ 215−1
int4 字节-231 ~ 231−1
long8 字节-263 ~ 263−1
浮点类型float

即可表示 整数 又可表示 小数,建议加上小数点。

单精度 float,双精度 double

4 字节约-3.403E38 ~ 3.403E38
double8 字节约-1.798E308 ~ 1.798E308
字符类型char
2 字节'\u0000' ~ '\uFFFF'
布尔类型boolean表示逻辑上的 真(true)和 假(false)1 字节true、false

粒子类型ParticleOptions原版粒子类型 ID,包含可选参数

字符串String

无 引号 可用字符:“a~z、A~Z”、“0~9”、“-_.+”;

加 引号 可用字符:任意字符串,中文也可以,若字符串里有引号需用 \ 转译。

建议加上 引号(英文半角下的 单/双引号 " "、' ' )



向量Vec3三维向量,即 三个 double

Vector4f四分量,即 四个 float

数组double[][]二维 双精度 数组,用于表示 矩阵

int[][]二维 整型 数组,用于表示 矩阵

枚举enum为 常量 赋予 有意义的名称


6、配置文件

配置文件名为“exparticle.json”,存放在“.minecraft或 版本名称”下,而不是 config 里。

"maxParticleCount": 65536设置最大粒子数量上限,超出限制强制删除老的粒子int

"maxParticleTickMillis": 1000,设定每个粒子的单次更新操作耗时上限int

"ParallelParticleUpdate": false,控制是否启用多线程并行更新粒子boolean



五、出现的问题与解决方法


1、条件表达式无法正确生成粒子

问题:设<采样范围>: 0.5 0.5 0.5,<条件表达式>:"y==-0.1",[采样步长]:0.4 …"。结果粒子无法在其位置生成。把<条件表达式>改为"y<-0.0999&y>-0.1001",结果能生成。

原因:浮点数精度导致。

由于 -0.1、0.4 无法用二进制精确表示,实际存储的值与 -0.1 的精确值 不相等,导致 y == -0.1 为假。

解决方案:

  • 使用容差判断:例如 abs(y - (-0.1)) < 10^-6,这表示 y 接近 -0.1 的误差在 10^-6 以内。

  • 改用区间判断:例如 y > -0.1001 & y < -0.0999。

  • 调整步长使迭代值更准确:例如步长 0.125(1/8)在二进制中可以精确表示。但还是建议在编写条件表达式时,避免直接相等判断。


2、组坐标与执行位置

问题:在命令方块中输入组管理指令,若组坐标没有时,执行位置在玩家坐标而不是命令方块位置。

原因:

  • 网络包设计:当命令中未提供坐标时,服务端构造的网络包会将 hasPos 标记设为 false,并且不发送任何坐标数据。

  • 客户端处理:客户端收到网络包后,如果 hasPos 为 false,就会直接使用本地玩家(即当前客户端控制的玩家)的坐标作为默认参考点。

解决方案:

  • 手动指定坐标:在命令中显式添加 [组坐标] 参数,例如 ~ ~ ~(相对命令方块自身)或具体的绝对坐标。


3、与 /tick 指令

问题:/tick freeze、/tick unfreeze、/tick step 可以正常冻结解冻粒子。而 /tick rate 命令设置低于 20 时会减慢,但高于 20 时和 20 一样的效果。(单机)

原因:

  • 客户端 tick 速率硬上限:客户端的 tick 循环中,tick 间隔由 DeltaTracker.Timer 管理,会取「默认 20 TPS 对应的间隔」与「服务端同步的 tick 间隔」两者中的较大值。即使服务端要求更高的 tick 速率(间隔更短),客户端仍会采用 50ms 的最小间隔,导致实际速率无法超过 20 TPS。(Minecraft)

  • 粒子动画依赖客户端 tick:粒子的更新(包括自定义的 customTick 和 t 的递增)均在客户端主 tick 循环的 particleEngine.tick() 中执行。由于客户端 tick 速率被锁定在 ≤20 TPS,粒子动画自然无法获得高于 20 TPS 的更新频率。

  • 其他 tick 命令的机制:/tick freeze 通过冻结游戏逻辑让所有 tick 停止,粒子自然静止;/tick step 则在冻结状态下强制执行指定数量的 tick,从而逐帧推进动画。这些命令不改变 tick 速率,只控制 tick 的执行与否,因此能正常生效。(TickRateManager)

解决方案:

  • 若需加速粒子效果,可在自定义表达式中增大 t 的步长(如将 [速度步长] 设为更大的值),使单次 tick 内 t 的变化量增加,从而在相同 tick 数下达到更快的整体运动。



六、实用示例

工具、资源网站:MC 指令生成器 | OCEANParticlex 1.16.5(网站中使用的是 本模组前身 ColorBlock 中的指令,需自行替换对应指令)

再弄几个我自己做的小指令吧:

下面代码适用范围 以 数据包中的函数 为准,若想在 命令方块 中使用,需删除 反斜杠“\”。批量替换完 \ 直接粘贴到命令方块里就行,不用管换行。

“\”在数据包函数中的功能:单行命令的拆分和续接。


1、参数化粒子指令

(1)方块边框

particlex rgba-parameter minecraft:end_rod ~ ~2 ~ 0 0 0 0 12.0 \
"( t<1 & x,y,z=t-0.5,-0.5,-0.5 )| \
( 1<=t&t<2 & x,z=0.5,t-1.5 )| \
( 2<=t&t<3 & x,z=2.5-t,0.5 )| \
( 3<=t&t<4 & x,z=-0.5,3.5-t )| \
( 4<=t&t<5 & x,y,z=-0.5,t-4.5,-0.5 )| \
( 5<=t&t<6 & x,y,z=0.5,5.5-t,-0.5 )| \
( 6<=t&t<7 & x,y,z=0.5,t-6.5,0.5 )| \
( 7<=t&t<8 & x,y,z=-0.5,7.5-t,0.5 )| \
( 8<=t&t<9 & x,y,z=-0.5,0.5,t-8.5 )| \
( 9<=t&t<10 & x,z=t-9.5,0.5 )| \
( 10<=t&t<11 & x,z=0.5,10.5-t )| \
( 11<=t&t<12 & x,z=11.5-t,-0.5 ); \
cr,cg,cb,alpha=0,t,1,1.0" \
0.125 0

(2)沙漏形状

particlex tick-parameter minecraft:end_rod ~ ~10 ~ 0 1 1 1 0 0 0 0 200 \
's,a=5,PI/2; v,u=t*5,t*PI/100; \
(x,y,z)=(sin(v)*cos(u)^2,sin(u-a),cos(v)*cos(u)^2)*s' \
0.05 50 -1




 如有错误,欢迎指出。