Компоненты частиц описывают каждую отдельную частицу: как она появляется, как движется, как выглядит и когда исчезает. Они лежат в блоке components файла частиц, рядом с компонентами эмиттера, которые эти частицы создают.
Впервые работаешь с частицами? В гайде Твоя первая частица с нуля собирается рубиновая искра, и там используется большинство этих компонентов.
Что нужно каждой частице
На практике каждому эффекту нужен particle_lifetime_expression (иначе частицы никогда не исчезнут) и particle_appearance_billboard (иначе ничего не будет видно). Всё остальное необязательно и свободно комбинируется.
Числовые поля принимают обычное число или строку на Molang. Внутри можно использовать variable.particle_age, variable.particle_lifetime и от variable.particle_random_1 до _4, чтобы у каждой частицы был свой характер.
Начальное состояние
Эти компоненты задаются один раз, когда частица рождается.
| Компонент | Что делает | Главные поля |
|---|---|---|
minecraft:particle_initial_speed | С какой скоростью частица начинает двигаться | Число (блоков в секунду, в направлении формы эмиттера) или скорость [x, y, z] |
minecraft:particle_initial_spin | Начальный угол картинки и скорость её вращения | rotation: градусы (по умолчанию 0). rotation_rate: градусы в секунду (по умолчанию 0) |
minecraft:particle_initialization | Выполняет твой Molang для каждой частицы, чтобы задать переменные, которые читают другие поля | per_update_expression: выполняется при каждом обновлении. per_render_expression: выполняется каждый раз при отрисовке |
Скорость
"minecraft:particle_initial_speed": "math.random(1, 2)"С одним числом частица летит в направлении, которое задала форма эмиттера. С тремя числами ты сам задаёшь скорость, например [0, 2, 0] - прямо вверх. Если не добавлять компонент, частицы появляются неподвижными.
Вращение
"minecraft:particle_initial_spin": {
"rotation": "math.random(0, 360)",
"rotation_rate": "math.random(-90, 90)"
}Вращение поворачивает плоскую картинку вокруг её центра, как колесо. Случайный начальный угол - самый простой способ сделать так, чтобы толпа частиц не выглядела как копии.
Свои переменные
"minecraft:particle_initialization": {
"per_render_expression": "variable.twinkle = math.sin(variable.particle_age * 720) * 0.5 + 0.5;"
}Теперь variable.twinkle качается между 0 и 1 дважды в секунду, и её можно использовать для размера или цвета. Для значения, которое меняется по форме в течение всей жизни, часто проще использовать кривую.
Движение
Эти компоненты двигают частицу каждый кадр после её рождения.
| Компонент | Что делает | Главные поля |
|---|---|---|
minecraft:particle_motion_dynamic | Настоящее движение с силами: гравитация, ветер, сопротивление воздуха, ускорение вращения | linear_acceleration, linear_drag_coefficient, rotation_acceleration, rotation_drag_coefficient |
minecraft:particle_motion_parametric | Ты задаёшь точную позицию каждый кадр через Molang, силы не учитываются | relative_position, direction, rotation |
minecraft:particle_motion_collision | Позволяет частицам сталкиваться с блоками: отскакивать, скользить, останавливаться или исчезать | enabled, collision_radius, coefficient_of_restitution, collision_drag, expire_on_contact, events |
Динамическое
"minecraft:particle_motion_dynamic": {
"linear_acceleration": [0, -9.8, 0],
"linear_drag_coefficient": 0.5,
"rotation_acceleration": 0,
"rotation_drag_coefficient": 0
}| Поле | Что делает |
|---|---|
linear_acceleration | Толчок каждую секунду в виде [x, y, z] в блоках в секунду за секунду. [0, -9.8, 0] ощущается как падение. Положительный y поднимает вверх, как дым |
linear_drag_coefficient | Сопротивление воздуха. Чем быстрее летит частица, тем сильнее она замедляется. 0 значит без сопротивления |
rotation_acceleration | Ускоряет вращение (или замедляет при отрицательном значении), в градусах в секунду за секунду |
rotation_drag_coefficient | Замедляет вращение, чтобы крутящаяся частица успокаивалась |
Динамическое движение работает со скоростью частицы, поэтому сочетается с particle_initial_speed: стартуй быстро, а дальше пусть работают гравитация и сопротивление.
Параметрическое
"minecraft:particle_motion_parametric": {
"relative_position": [
"math.cos(variable.particle_age * 360) * 0.8",
"variable.particle_age",
"math.sin(variable.particle_age * 360) * 0.8"
]
}Здесь ты пропускаешь физику и просто говоришь, где находится частица относительно эмиттера. Этот пример делает круг раз в секунду и поднимается на один блок в секунду: получается рубиновая спираль. direction и rotation задаются так же.
Параметрическому движению нужен обычный эмиттер
Параметрическое движение не работает для частиц, созданных через emitter_rate_manual. Для эффектов, прикреплённых к мобу, оно работает, только если эмиттер использует локальное пространство для позиции.
Столкновения
"minecraft:particle_motion_collision": {
"collision_radius": 0.1,
"coefficient_of_restitution": 0.4,
"collision_drag": 2,
"events": { "event": "pop", "min_speed": 2 }
}Без этого компонента частицы пролетают сквозь блоки.
| Поле | Что делает |
|---|---|
enabled | Включает или выключает столкновения. Может быть Molang, проверяется каждый кадр. По умолчанию включено |
collision_radius | Размер частицы для столкновений с блоками. Не больше половины блока. Подбирай примерно под размер билборда |
coefficient_of_restitution | Упругость. 0 останавливает на месте, 1 отскакивает на ту же высоту, а значения между ними теряют часть высоты при каждом отскоке |
collision_drag | Замедляет частицу, пока она касается поверхности, в блоках в секунду. Она скользит и останавливается |
expire_on_contact | true удаляет частицу в момент касания блока. Подходит для капель дождя |
events | Вызывает одно из твоих событий при столкновении, например брызги. Один объект события или список. min_speed (минимум 2 блока в секунду) игнорирует лёгкие касания |
Столкновения снижают производительность
Проверять блоки для каждой частицы - работа для игры. Добавляй столкновения только там, где разница заметна, и держи max_particles у таких эффектов небольшим.
Внешний вид
Эти компоненты решают, как частица выглядит на экране.
| Компонент | Что делает | Главные поля |
|---|---|---|
minecraft:particle_appearance_billboard | Рисует частицу плоской картинкой и задаёт её размер, куда она повёрнута и какую часть текстуры показывает | size, facing_camera_mode, direction, uv |
minecraft:particle_appearance_tinting | Окрашивает картинку одним цветом или градиентом во времени | color |
minecraft:particle_appearance_lighting | Делает частицу темнее в тёмных местах и светлее на свету, как блоки | нет: пиши {} |
Билборд
"minecraft:particle_appearance_billboard": {
"size": [0.1, 0.1],
"facing_camera_mode": "lookat_xyz",
"uv": {
"texture_width": 32,
"texture_height": 8,
"uv": [0, 0],
"uv_size": [8, 8]
}
}size - это [ширина, высота], и он проверяется каждый кадр, так что Molang здесь может увеличивать или уменьшать частицу. Каждое значение отсчитывается от центра, поэтому 0.5 даёт квадрат шириной в один блок.
facing_camera_mode решает, куда повёрнута плоская картинка:
| Режим | Картинка |
|---|---|
lookat_xyz | Всегда смотрит на камеру, но остаётся вертикальной. Обычный выбор |
rotate_xyz | Лежит плоско на экране и поворачивается вместе с камерой |
lookat_y / rotate_y | Смотрит на камеру, но поворачивается только влево и вправо, как вырезанная фигурка на земле |
lookat_direction | Смотрит на камеру и выравнивается по направлению частицы. Подходит для полосок-следов |
direction_x / direction_y / direction_z | Направляет сторону x, сторону y или лицевую сторону картинки по направлению частицы |
emitter_transform_xy / _xz / _yz | Лежит плоско в одной из плоскостей эмиттера. _xz делает плоскую наклейку на земле |
Режимам направления нужно знать, куда направлена частица. Это задаётся через direction:
"direction": {
"mode": "derive_from_velocity",
"min_speed_threshold": 0.01
}derive_from_velocity берёт направление движения частицы, но только пока она движется быстрее min_speed_threshold. Используй "mode": "custom_direction" с "custom_direction": [x, y, z], чтобы задать его самому.
uv выбирает, какую часть текстуры показывать. texture_width и texture_height - размер твоего PNG в пикселях, uv - левый верхний угол, а uv_size - ширина и высота нужной части. Пример выше показывает первый кадр 8x8 из полоски 32x8.
Покадровая анимация
Положи несколько кадров рядом, и билборд сможет проигрывать их как мультфильм. Замени uv и uv_size на flipbook:
"uv": {
"texture_width": 32,
"texture_height": 8,
"flipbook": {
"base_UV": [0, 0],
"size_UV": [8, 8],
"step_UV": [8, 0],
"max_frame": 4,
"stretch_to_lifetime": true,
"loop": false
}
}| Поле | Что делает |
|---|---|
base_UV | Левый верхний угол первого кадра |
size_UV | Ширина и высота одного кадра |
step_UV | Насколько сдвигаться к следующему кадру. [8, 0] шагает вправо |
max_frame | Сколько всего кадров (первый - кадр 1) |
frames_per_second | Скорость воспроизведения |
stretch_to_lifetime | true игнорирует скорость и проигрывает все кадры ровно один раз за жизнь частицы |
loop | true начинает снова с первого кадра после последнего |
Рубиновая искра из 4 кадров, которая раскрывается, сияет и снова закрывается, выглядит гораздо живее одной картинки.
Окрашивание
"minecraft:particle_appearance_tinting": {
"color": [1, 0.15, 0.3, 1]
}Цвет умножается на текстуру, поэтому рисуй текстуры частиц белыми или серыми, а цвет пусть добавляет окрашивание. Цвет можно записать любым из этих способов:
| Форма | Пример |
|---|---|
[r, g, b] или [r, g, b, a], каждое от 0 до 1 | [1, 0.15, 0.3, 1] |
"#RRGGBB" | "#FF2650" |
"#AARRGGBB" (альфа первой) | "#80FF2650" - наполовину прозрачный |
| Molang в каждой ячейке | ["variable.tint.r", "variable.tint.g", "variable.tint.b", 1] |
Чтобы цвет менялся со временем, используй градиент. Цвета распределяются равномерно, а interpolant выбирает, в какой точке градиента частица находится прямо сейчас:
"minecraft:particle_appearance_tinting": {
"color": {
"gradient": {
"0.0": "#FFFFFFFF",
"0.3": "#FFFF2650",
"1.0": "#00600018"
},
"interpolant": "variable.particle_age / variable.particle_lifetime"
}
}Если записать градиент объектом, как здесь, каждый цвет стоит в той точке, которую ты указал. Обычный список, наоборот, распределяет их равномерно от 0 до 1. Эта искра вспыхивает белым, рано становится рубиново-красной, а потом медленно угасает.
Альфе нужен правильный материал
Полупрозрачные цвета видны только с материалом particles_blend или particles_add. С particles_alpha пиксель либо полностью виден, либо полностью скрыт.
Освещение
"minecraft:particle_appearance_lighting": {}С ним частицы выглядят темнее в пещерах и ночью и лучше вписываются в мир. Не добавляй его для того, что должно светиться в темноте: магии, огня, нашей рубиновой искры.
Время жизни
Эти компоненты решают, когда частица исчезает.
| Компонент | Что делает | Главные поля |
|---|---|---|
minecraft:particle_lifetime_expression | Основное время жизни: фиксированное время или проверка на Molang каждый кадр | max_lifetime, expiration_expression |
minecraft:particle_lifetime_events | Вызывает твои события в определённые моменты жизни каждой частицы | creation_event, expiration_event, timeline |
minecraft:particle_kill_plane | Удаляет частицы, которые пересекают невидимую плоскость | [A, B, C, D] |
minecraft:particle_expire_if_in_blocks | Удаляет частицы, которые оказались внутри любого из перечисленных блоков | Список названий блоков |
minecraft:particle_expire_if_not_in_blocks | Удаляет частицы, которые вышли из перечисленных блоков | Список названий блоков |
Выражение времени жизни
"minecraft:particle_lifetime_expression": {
"max_lifetime": "math.random(0.8, 1.5)"
}max_lifetime- время жизни в секундах, выбирается один раз при рождении частицы.expiration_expressionпроверяется каждый кадр. Когда оно не равно 0, частица исчезает. Например,"variable.particle_age > 1 && query.is_in_water"может завершить её раньше.
Можно использовать оба сразу: частица исчезнет по тому, что наступит раньше.
События жизни
"minecraft:particle_lifetime_events": {
"creation_event": "flash",
"expiration_event": "pop",
"timeline": {
"0.25": "twinkle"
}
}Названия указывают на блок events того же файла, и каждое поле принимает одно название или список. В отличие от версии для эмиттера, эти события срабатывают для каждой отдельной частицы, так что вспышка из 12 искр вызовет pop 12 раз. Что умеет событие, смотри в разделе про события.
Плоскость уничтожения
"minecraft:particle_kill_plane": [0, 1, 0, 0.5]Четыре числа описывают плоскость по-математически: все точки, где A*x + B*y + C*z + D = 0, отсчитанные от эмиттера, но выровненные по миру. Частицы, которые её пересекают, исчезают. [0, 1, 0, 0.5] - это пол на полблока ниже эмиттера. Это дешёвый способ остановить падающие частицы без столкновений.
В блоках и не в блоках
"minecraft:particle_expire_if_not_in_blocks": [
"minecraft:water",
"minecraft:flowing_water",
"minecraft:bubble_column"
]Так пузыри лопаются, когда добираются до поверхности: они живут, только пока находятся в воде. Для обратного используй particle_expire_if_in_blocks, например для пыли, которая исчезает, как только попадает в воду. Оба работают вместе с particle_lifetime_expression.
Частица целиком
Все четыре группы вместе. Это сторона частицы для падающего рубинового осколка, который отскакивает и угасает:
"minecraft:particle_initial_speed": "math.random(2, 3)",
"minecraft:particle_initial_spin": {
"rotation": "math.random(0, 360)",
"rotation_rate": 180
},
"minecraft:particle_motion_dynamic": {
"linear_acceleration": [0, -9.8, 0],
"rotation_drag_coefficient": 1
},
"minecraft:particle_motion_collision": {
"collision_radius": 0.05,
"coefficient_of_restitution": 0.3,
"collision_drag": 4
},
"minecraft:particle_appearance_billboard": {
"size": [0.06, 0.06],
"facing_camera_mode": "lookat_xyz",
"uv": {
"texture_width": 8,
"texture_height": 8,
"uv": [0, 0],
"uv_size": [8, 8]
}
},
"minecraft:particle_appearance_tinting": {
"color": "#FFE0204A"
},
"minecraft:particle_appearance_lighting": {},
"minecraft:particle_lifetime_expression": {
"max_lifetime": 2
}Дай ему эмиттер из раздела Компоненты эмиттера, например вспышку из 8 частиц из маленькой сферы, и получится отличный эффект разрушения блока.