Модуль Particles

Данный модуль позволяет создавать новые типы частиц и использовать их в мире.

Текстуры

Текстуры частиц должны находиться в директории ресурсов particle-atlas и иметь расширение png. Текстура должна быть квадратной или ее высота должна быть в целое число раз больше ее ширины (для анимированных текстур). 

Более оптимально, когда сторона не анимированной текстуры текстуры является степенью 2 и меньше 256, в таком случае она будет загружена как часть текстуры-атласа, собранной из других, удовлетворяющих этим условиям текстур, что является более оптимальным вариантом.

Именем текстуры, по которому ее можно будет идентифицировать, будет ее название без расширения, к примеру для файла "fire.png" именем текстуры будет "fire".

Регистрация типов

Для создания нового типа частиц используется метод Particles.registerParticleType(description), где description объект описания, содержащий все нужные параметры. Отдает данный метод уникальный id данной частицы, который далее можно будет использовать для ее спавна.

Все параметры в объекте description:

{
    // обязательные параметры 
    texture: "name", // name - имя текстуры частицы 
    size: [min, max], // минимальный и максимальный размер частицы 
    lifetime: [min, max],  // минимальное и максимальное время существования (в тиках)

    // необязательные параметры
    render: type, // тип рендера, где type число от 0 до 2, по умолчанию 1 (0 - аддитивный, 1 - без смешивания, 2 - со смешиванием), далее они будут описаны подробнее 
    color: [r, g, b, a], // 4х компонентный цвет, по умолчанию [1, 1, 1, 1]
    collision: enable, // если значение истинно, то частица не будет проходить сквозь блоки, однако это снижает производительность при большом кол-ве таких частиц, по умолчанию отключено
    velocity: [x, y, z], // начальная скорость частицы, в случае спавна без параметра начальной скорости, по умолчанию [0, 0, 0]
    acceleration: [x, y, z], // ускорение частицы, в случае спавна без параметра ускорения, по умолчанию [0, 0, 0]
    friction: {air: value, block: value}, // Множитель скорости частицы в воздухе (air) и при касании с блоком (block), обычно является числом от 0 до 1, близким к 1, но на практике может быть любым, по умолчанию оба значения равны 1. ВАЖНО ОТМЕТИТЬ: применяется перед добавлением ускорения к скорости частицы, значение block имеет смысл только если истинен параметр collision.
    keepVelocityAfterImpact: enabled, // если значение ложно, то частица будет обнулять скорость по данной координате после столкновения с блоком, иначе значение скорости сохранится, по умолчанию false, значение имеет смысл только если истинен параметр collision.
    addLifetimeAfterImpact: value, // после столкновения с блоком частица потеряет данное кол-во тиков от максимальной продолжительности жизни, по умолчанию 0 (потерь не будет), значение имеет смысл только если истинен параметр collision.
    isUsingBlockLight: enabled, // если значение истинно, то частица будет подвержена освещенности мира, в противном случае всегда иметь максимальную яркость, включение данного параметра может немного снизить производительность при большом кол-ве частиц, по умолчанию false

    /* Аниматоры позволяют изменять некоторые свойства конкретной частицы в зависимости от времени, каждый аниматор описывается объектом определенного формата и может быть не описан в случае ненадобности. Далее будет подробнее рассказано о них. */ 
    animators: {
        size: animatorDescription, // описывает поведение размера частицы, за единичный размер взят размер, указанный в описании типа.
        alpha: animatorDescription, // описывает непрозрачность частицы, за единичное значение взято значение alpha, указанное в параметре color в описании типа.
        texture: animatorDescrtiption // описывает кадр анимации, если текстура ее поддерживает, должен принимать значения [0, 1)  
    },

    /* Микро-эмиттеры (не стоит путать с обычными эмиттерами) описывают то, как конкретная частица может выпускать другие частицы по каким-то событиям, происходящим с ней. Каждый микро-эмиттер описывается определенного формата и может быть не описан в случае ненадобности. Далее будет подробнее рассказано о них. */
    emitters: { 
        idle: subEmitterDescription, // вызывается каждый тик
        impact: subEmitterDescription, // вызывается при ударе о блок, актуален, только если параметр collision истинен  
        death: subEmitterDescription // вызывается при окончании существования частицы
    }
}

Аниматоры

Аниматоры имеют период (period), время появления (fadeIn) и время исчезновения (fadeOut), а также начальное и конечное значения (start и end). Периодом может быть время жизни конкретной частицы или заданное кол-во тиков, остальное время задается в долях от периода.

Когда время появления уже закончилось, а время исчезновения еще не началось, аниматор будет принимать значение 1. Значение аниматора для непрозрачности и размера будет умножаться на заданные в типе значения непрозрачности и размера соответственно.

Далее приведены примеры графиков значений аниматоров:

1)RTENOTITLE 2)RTENOTITLE
3)RTENOTITLE 4)RTENOTITLE

Пояснения (на примере размера)

  1. Быстрое увеличение из ничего до максимального размера, некоторое время без изменений, потом медленное уменьшение до нуля и конец существования. (fadeIn < fadeOut, start = end = 0)
  2. Увеличение из ничего до максимального размера с течением всего существования. (fadeIn = 1, fadeOut = 0, start = 0, end = 1). Сочетается с 3 аниматором, если применить его для непрозрачности (увеличение и постепенное исчезновение одновременно).
  3. Начало с максимума, некоторое время без изменений, далее уменьшение до нуля и конец существования. (fadeIn = 0, fadeOut = 0.5, start=end=0)
  4. Функция аниматора по умолчанию - всегда максимальное значение. (fadeIn=fadeOut=start=end=0)

Аниматор текстуры

Нумерация кадров в анимированной текстуре происходит сверху вниз, начинается с 0. Значения аниматора текстуры умножаются на кол-во кадров и округляются вниз для получения номера кадра (таким образом значение 0 - нулевой кадр, значение 1 - последний кадр.

Обычно аниматор текстуры должен иметь вид аниматора из примера 2 с периодом равным периоду полной анимации (обычно в 2-4 раза больше, чем кадров в анимации).

Объект описания аниматора

 

{
    // каждое из следующих значений не обязательно, аниматор со всеми значениями по умолчанию имеет мало смысла, т.к. его значение всегда равно 1.
    period: value, // период аниматора в тиках, если меньше 0 или не указан, то это время жизни частицы 
    fadeIn: value, // время появление в долях от периода, по умолчанию 0 
    fadeOut: value, // время исчезновения в долях от периода, по умолчанию 0 
    start: // начальное значение, по умолчанию 0 
    end: // конечное значение, по умолчанию 0
}

Микро-эмиттеры

Микро-эмиттеры испускают определенный тип частиц с определенным шансом, когда с частицей, на которую они зарегистрированы происходит какое-то событие, к примеру удар о блок.

Объект описания микро-эмиттера

 

{
    // обязательные значения 
    type: id, // тип испускаемой частицы 

    // необязательные значения 
    data: data, // доп. данные испускаемой частицы, по умолчанию 0 
    chance: value, // шанс срабатывания от 0 до 1, по умолчанию 1 
    count: value, // кол-во частиц за раз, по умолчанию 1
    keepVelocity: enabled, // если истинно, то новая частица будет иметь скорость частицы, вызывающей микро-эмиттер, на момент вызова, по умолчанию false
    keepEmitter: enabled, // если истинно, то новая частица унаследует эмиттер, использованный для ее создания, если он был (ВАЖНО! В данном случае речь идет об эмиттерах, а не о микро-эмиттерах частиц, которые задают систему отсчета частиц, о них далее)
    randomize: value, // если это значение указано, то испускаемые частицы будут получать случайную начальную скорость, по модулю не более value * sqrt(3)
}

Тип рендера (смешивания)

Тип рендера описывает то, как частицы будут накладываться друг на друга и задается параметром render в описании типа частицы. Далее приведены все типы с описанием и изображением (частицы на всех изображениях отличаются только типом рендера, в остальном их текстура и кол-во одинаковы).

Оригинальная текстура частицы: 

RTENOTITLE

Без смешивания (задается значением 1)

Это самый простой и быстрый в плане отрисовки тип, поддерживает альфа-канал только 2х значений: 0 (полная прозрачность) и 1 (полная непрозрачность). По принципу аналогичен отрисовки большинства предметов в игре.  

RTENOTITLE

Обычное смешивание (задается значением 2)

В отличии от первого, поддерживает полупрозрачность и смешивание, использует привычное нам наложение, когда полупрозрачный объект передает часть цвета того, что находится за ним. (функция смешивания OpenGL: (SRC_ALPHA, ONE_MINUS_SRC_ALPHA))

RTENOTITLE

Аддитивное смешивание (задается значением 0)

Также поддерживает смешивание и полупрозрачность, однако в отличии от прошлого типа, цвета объекта за частицей и самой частицей, складываются. Является самым эффектным типом из всех 3. (функция смешивания OpenGL: (SRC_ALPHA, ONE))  

RTENOTITLE

Эмиттер

Эмиттер частиц позволяет изменять их положение после спавна, представляя собой систему координат, в которой находятся созданные им частицы и которую можно перемещать как угодно.

Эмиттер можно создавать только находясь в мире, и работает он только для новых частиц (частицы из ванильного MCPE не будут подвержены перемещению системы координат).

Эмиттер описывает систему координат, в которой находятся созданные частицы, при перемещении начала этой системы координат на какой-то вектор, все частицы в этой системе сдвинутся на такой же вектор, при этом изменения скорости частиц не произойдет.

Для создания эмиттера используйте new Particles.ParticleEmitter(x, y, z), где x, y, z - начальные координаты. Полученный объект обладает следующими методами, стоит учесть, что все они асинхронны и могут корректно работать из любого потока.

var emitter = new Particles.ParticleEmitter(x, y, z); // создает эмиттер с системой координат с началом в x, y, z

/* Работа с системой координат */

emitter.move(x, y, z) // сдвигает систему координат на x, y, z, что вызовет перенос всех частиц.

emitter.moveTo(x, y, z) // переносит начало системы координат в точку x, y, z

emitter.setVelocity(x, y, z) // устанавливает скорость системы координат по каждой оси в блоках в тик, для остановки можно вызвать emitter.stop() или emitter.setVelocity(0, 0, 0)

emitter.attachTo(entity) // привязывает начало системы координат к координатам данного моба, сбрасывает скорость системы координат

emitter.attachTo(entity, x, y, z) // то же самое, что и прошлый метод, но к координатам моба добалвяется сдвиг x, y, z

emitter.detach() // отвязывает систему координат от моба и оставляет ее на текущей позиции 
emitter.stop() // прекращает любое движение системы координат

emitter.getPosition() // возвращает объект, содержащий текущие x, y и z начала системы координат

/* Спавн частиц */

emitter.setEmitRelatively(enable) // по умолчанию отключена, что означает, что координаты частиц для данного эмиттера будут заданы в абсолютной системе координат, если включить, то их надо будет задавать относительно текущей позиции эмиттера. Это бывает крайне удобно, если вам нужно сделать полностью обособленную от движения эмиттера систему частиц.

emitter.emit(type, data, x, y, z) // спавнит частицу с данным типом и данной метадатой на заданных координатах, скорость и ускорение не будут заданы.

emitter.emit(type, data, x, y, z, vx, vy, vz) // спавнит частицу с данным типом и данной метадатой на заданных координатах, задает скорость, ускорение не будет задано.

emitter.emit(type, data, x, y, z, vx, vy, vz, ax, ay, az) // спавнит частицу с данным типом и данной метадатой на заданных координатах, задает скорость и ускорение.