Я уверен, что Stage3D не чужды большинству читателей; это новый API, который предоставляет программистам AS3 доступ к графическому процессору. Тем не менее, кодирование против кодов операций в Stage3D, возможно, не является предпочтительным выбором для всех, так что повезло, что есть ярлык: Starling, библиотека, разработанная для инкапсуляции этого низкоуровневого программирования, чтобы сделать его намного проще. И вместе со Starling идет расширение эффектов частиц. В этом уроке мы рассмотрим системы частиц этого фреймворка и увидим, как его приложения применяются к игре «стреляй в них».
Шаг 1: Базовая настройка
Пропустите этот шаг, если вы работали с FlashDevelop в течение некоторого времени. Для начинающих, вот как вы устанавливаете библиотечный пакет — в данном случае Starling и расширение его частиц. Обратите внимание, что эти два предмета не входят в одну упаковку, поэтому нам придется загружать их отдельно.
Сначала загрузите фреймворк Starling и расширение его частиц из своих репозиториев. Распакуйте после успешной загрузки. Сканируйте первый разархивированный каталог на наличие папки src
и вставьте библиотеку инфраструктуры Starling, выделенную на рисунке ниже, в исходную папку вашего проекта.
Сканирование второй папки для расширения частиц и объединить их вместе. Вы можете перетащить выделенную папку ниже в папку Starling
. Изображение ниже — это конечный результат, к которому вы должны прийти.
Для получения дополнительной информации о FlashDevelop и использовании внешних библиотек см. Эти учебные руководства:
- Руководство для начинающих по FlashDevelop
- Как использовать внешнюю библиотеку в ваших проектах Flash
Шаг 2: Основные классы
Если вы еще не знакомы со Starling и его расширением частиц, я настоятельно рекомендую посетить видеоуроки Lee Brimelow по Starling и частицам , а также руководство Matthew Chung по обработке состояний анимации в Starling .
Мы собираемся просто пройтись по основам в два этапа. Если вы уже знакомы со Starling и его расширением частиц, смело переходите к шагу 4.
На втором изображении предыдущего шага (нижняя часть) Main.as
что создаются два класса: Main.as
и Testing.as
. Первый действует как пусковая установка для последнего. Итак, большая часть нашего кода Starling живет в Testing.as
. Я выделил важный код в Main.as
здесь:
01
02
03
04
05
06
07
08
09
10
11
12
13
|
private function init(e:Event = null):void
{
removeEventListener(Event.ADDED_TO_STAGE, init);
// entry point
var myStarling:Starling = new Starling(Testing, stage);
myStarling.simulateMultitouch = true;
myStarling.start();
//initiate Starling onto stage
//allow mouse/ touch events to happen in Starling
//turn key and start the engine!
}
|
… и Testing.as
должен выглядеть так:
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
|
public class Testing extends Sprite
{
public function Testing() {
addEventListener(Event.ADDED_TO_STAGE, init);
}
private function init(e:Event):void {
removeEventListener(Event.ADDED_TO_STAGE, init);
// code goes here.
stage.color = 0;
//Draw a little quad on stage,
//just to make sure everything’s in place
//Note the top left corner of sprite is aligned to middle of stage
var q:Quad = new Quad(30, 30);
q.color = 0xEEEEEE;
qx = stage.stageWidth >> 1;
}
}
|
И если все настроено правильно, вы должны прийти к результату, как показано ниже. Ничего особенного, просто спрайт на сцене.
Примечание: Testing.as
расширяет Sprite от Starling.display.Sprite
, а не flash.display.Sprite
. Классы имеют одинаковые имена, но не совпадают.
Шаг 3: Наращивание частиц в скворечнике
Расширение частиц Starling содержит три важных класса. Их функциональные возможности приведены в таблице ниже.
Наименование класса | функциональность |
Particle.as |
Отдельная частица с уникальными атрибутами. |
ParticleSystem.as |
Контролирует поток частиц: генерация, анимация и утилизация. |
ParticleDesignerPS.as |
Расширение ParticleSystem.as позволяющее легко манипулировать системой частиц. |
Мы создадим экземпляр ParticleDesignerPS.as
. Это требует ввода следующих аргументов в конструктор класса:
- XML-файл, содержащий все значения инициализации для свойств частиц (их довольно много)
- изображение для образца для всех частиц
Не беспокойтесь, onebyonedesign.com поможет вам с этим. Посетите их страницу дизайнера частиц и подправьте все эти ценности инициации к своему сердцу. Затем экспортируйте все данные в формат ZIP. Этот ZIP-файл будет содержать XML-файл и изображение эффекта частиц, который вы только что создали на их веб-странице!
Разархивируйте и извлеките все это в исходную папку в FlashDevelop. Смотрите выделенные элементы на изображении ниже.
Создайте операторы импорта, чтобы получить эти два элемента в свой класс Testing
. Вам также нужно будет переписать метод init
в разделе « Testing
. Они все ниже.
1
2
3
4
5
|
[Embed(source=»particle.pex», mimeType=»application/octet-stream»)]
private var InitValues:Class
[Embed(source = «texture.png»)]
private var Sample:Class
|
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
|
private function init(e:Event):void {
removeEventListener(Event.ADDED_TO_STAGE, init);
// code goes here.
stage.color = 0;
var flow1:ParticleDesignerPS =
new ParticleDesignerPS(
XML(new InitValues()),
Texture.fromBitmap(new Sample())
);
addChild(flow1);
flow1.emitterX = stage.stageWidth >> 1;
flow1.start();
Starling.juggler.add(flow1);
}
|
Вот результат, к которому вы должны прийти. Довольно просто, правда?
Шаг 4: Понимание системы частиц
Наш следующий шаг — включить взаимодействие с системой частиц (этот маленький огонь) во время выполнения. Мы будем использовать мышь, чтобы контролировать свойства огня. Однако, прежде чем мы это сделаем, я хотел бы немного отвлечься, чтобы проинформировать вас о концепции систем частиц.
Частицы — это просто спрайты, которые излучаются по координате. После рождения они будут анимироваться по определенной схеме. Эта модель может быть уникальной для каждой частицы или общей для всех частиц. Но будьте уверены, их физические свойства со временем изменятся. Например:
- Расстояние от координаты рождения
- Направление и скорость
- Цвет и альфа-уровень
- Размер
Также их жизнь на сцене определяется при рождении. Если каждой частице будет позволено жить вечно на сцене, у нас будет перенаселение, и производительность приложения пострадает из-за большого количества графических ресурсов для обработки. В какой-то момент частица умирает, но она не смещается со сцены. Вместо этого он перерабатывается, поскольку перемещается в координату рождения и принимает на себя роль новой частицы. Это новая частица, потому что для нее будет определен новый набор свойств, прежде чем начнется ее анимация и продолжится другой цикл.
(Это пул объектов , и вы можете посмотреть, как применить его к своим собственным проектам, не относящимся к Starling Flash.)
Итак, как это связано с нашим огнем? Ну, мы можем использовать функции замедления, чтобы оживить свойства этого пожара с течением времени. В структуре Starling ParticleDesignerPS
располагается в конце этой иерархии:
ParticleDesignerPS
> ParticleSystem
> DisplayObject
> EventDispatcher
> Object
Чтобы соблюсти баланс, мы просто проследим унаследованные свойства от ParticleSystem
. Давайте посмотрим на это следующий шаг …
Шаг 5: Свойства ParticleSystem
и ParticleDesignerPS
Ниже приведены свойства ParticleSystem
.
Свойство | Описание |
capacity |
Максимум частиц, которые система может нести в любой момент. Увеличивается с шагом 500, как только количество частиц превышает его текущую емкость. Только для чтения. |
numParticles |
Количество частиц в системе в данный момент. Только для чтения. |
emissionRate |
Количество частиц, генерируемых при рождении, координируется каждую секунду. |
emitterX , emitterY |
Контрольная точка для контейнера, в котором живут все частицы. |
|
Определение Context3DBlendFactor для источника и назначения. Назначение относится к цвету пикселя из последнего рендеринга, а источник относится к новому цвету пикселя для рисования в месте назначения. |
texture |
Текущее изображение выбрано как текстура частиц. Только для чтения. |
Те из ParticleDesignerPS
сведены в таблицу в следующей таблице. Большинство из этих свойств могут быть точно настроены его начальным и конечным состоянием. Например, все генерируемые частицы будут начинаться с размера 1,0 и заканчиваться на 0,1. Тем не менее, поток частиц будет скучным, если все частицы инициируются и заканчиваются в таких похожих состояниях, поэтому ParticleDesignerPS
обеспечивает дисперсию начального значения, а иногда и дисперсию в значении завершения.
Цитируя их пример, если мы дадим дисперсию 0,2 от начального размера частицы, последовательные частицы, рожденные или рециркулирующие в систему, начнут свой размер где-то между 0,8 ~ 1,2 и заканчиваются на 0,1.
Свойство | Описание |
emitterXVariance , emitterYVariance |
Изменение координаты рождения. |
startSize , startSizeVariance |
Начальный размер и дисперсия |
endSize , endSizeVariance |
Размер завершения и дисперсия |
emitAngle , emitAngleVariance |
Начальное направление и дисперсия частицы |
speed , speedVariance |
Начальная скорость и дисперсия частиц |
gravityX |
Ускорение по оси x на начальной скорости всех частиц |
gravityY |
Ускорение вдоль оси y на начальной скорости всех частиц |
tangentialAcceleration , tangentialAccelerationVariation |
Скорость вращения на скорости частицы и дисперсия |
В ParticleDesignerPS
предусмотрены два типа потока ParticleDesignerPS
: гравитационный и радиальный. В таблице выше показаны свойства, которые можно настроить, если вы используете гравитационный поток. Для гравитации координата рождения частиц находится на emitterX
и emitterY
Для радиальной координаты рождения частиц расположены в некоторой точке от emitterX
и emitterY
, и они движутся к ней. В таблице ниже показаны свойства радиального потока.
Свойство | Описание |
maxRadius , maxRadiusVariance |
Максимальный радиус от центра и дисперсия |
minRadius |
Минимальный радиус от центра |
rotationPerSecond , rotationPerSecondVariance |
Скорость вращения на скорости частицы |
startColor , startColorVariance |
Начальный цвет и дисперсия |
endColor , endColorVariance |
Окончание цвета и дисперсии |
Шаг 6: Добавление интерактивности
Что ж, спасибо за то, что приняли этот маленький обход. Теперь немного о ActionScript. В методе init
мы добавим слушателя на сцену для сенсорных событий.
1
|
stage.addEventListener(TouchEvent.TOUCH, track);
|
И слушатель как ниже.
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
|
private function track(e:TouchEvent):void {
var touch:Touch = e.getTouch(stage);
//when user presses mouse and moves
if (touch.phase == TouchPhase.MOVED) {
//calculate the angle to point particle flow to
var distX:Number = touch.globalX — flow1.emitterX;
var distY:Number = touch.globalY — flow1.emitterY;
var angle:Number = Math.atan2(distY, distX);
t = new Tween(flow1, 1.5, Transitions.EASE_OUT_BACK);
t.animate(«emitAngle», angle);
Starling.juggler.add(t);
}
}
|
Для выполнения анимации определен экземпляр Tween
. Его манипуляции во многом похожи на популярные движки Tween
. Затем мы добавляем его в жонглер текущего экземпляра Starling. Этот объект жонглера поможет постепенно обновлять экземпляр Tween
течением времени.
Результат ниже. Нажмите и перетащите мышку по сцене.
Шаг 7: Настройка корабля
Давайте сейчас настроим наш корабль и проложим на нем след. Ресурсы с opengameart.org, и я включил их в пакет загрузки. Проверьте этот сайт для других бесплатных игр искусства.
Мы начнем заново с другого класса, TestingShip.as
. Сначала импортируйте изображение космического корабля «boss1.png».
1
2
|
[Embed(source = «boss1.png»)]
private var Ship:Class
|
… с небольшой настройкой для инициализации в методе init
:
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
|
//setup the graphical appearance
var shipBMP:Bitmap = new Ship() as Bitmap;
var shipTEX:Texture = Texture.fromBitmap(shipBMP);
var shipIMG:Image = new Image(shipTEX);
//setup ship’s orientation & position
shipIMG.rotation -= Math.PI*0.5;
shipIMG.x -= shipIMG.width >> 1;
shipIMG.y += shipIMG.height >> 1;
theShip = new Sprite();
theShip.addChild(shipIMG);
addChildAt(theShip, 0);
//navigational properties of ship
loc = new Vector2D(stage.stageWidth >> 1, stage.stageHeight >> 1);
lof = new Vector2D(0, 10);
updateShip();
|
Обновите его положение и ориентацию в соответствии с loc
(местоположение) и lof
(линия обзора).
1
2
3
4
5
|
private function updateShip():void {
theShip.x = loc.x;
theShip.y = loc.y;
theShip.rotation = lof.getAngle();
}
|
Снова нажмите и перетащите в пределах сцены, чтобы увидеть эффект:
Шаг 8: Настройка выхлопной трассы
Хорошо, выхлоп корабля находится сверху самого корабля, и космический корабль не реагирует на события мыши. Мы исправим это сейчас. Просто emitterX
и emitterY
потока частиц на некоторое расстояние от космического корабля и обновите вращение космического корабля, используя lof
.
(Обратите внимание, что lof
обновляется при событиях мыши. Вы увидите сценарий следующим шагом.)
01
02
03
04
05
06
07
08
09
10
11
|
private function updateShip():void {
theShip.x = loc.x;
theShip.y = loc.y;
theShip.rotation = lof.getAngle();
//update particle trail
offset = new Vector2D(60, 0);
offset.setAngle(lof.getAngle());
flow1.emitterX = loc.x — offset.x;
flow1.emitterY = loc.y — offset.y;
}
|
Шаг 9: навигация по кораблю
Давайте попробуем запрограммировать навигацию корабля сейчас, при отправке события мыши. Я только прокомментировал важные строки:
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
|
private function track(e:TouchEvent):void {
var touch:Touch = e.getTouch(stage);
if (touch.phase == TouchPhase.MOVED) {
var distX:Number = touch.globalX — flow1.emitterX;
var distY:Number = touch.globalY — flow1.emitterY;
angle = Math.atan2(distY, distX);
t = new Tween(flow1, 1.5, Transitions.EASE_OUT_BACK);
t.animate(«emitAngle», angle + Math.PI);
t2 = new Tween(theShip, 1.5, Transitions.EASE_OUT);
t2.moveTo(touch.globalX, touch.globalY);
t2.onUpdate = refresh //call upon this function whenever tween engine runs
Starling.juggler.add(t);
Starling.juggler.add(t2);
}
}
private function refresh():void {
loc.x = theShip.x;
loc.y = theShip.y;
lof.setAngle(angle);
updateShip();
}
|
И вот шоу конечного результата. Перетащите мышь вокруг сцены, и космический корабль отправится туда.
Шаг 10: Анимировать выхлоп
Давайте точно настроим наш выхлоп. Когда корабль движется, выхлоп будет дуть сильнее, верно? Мы можем повысить emissionRate
и speed
emissionRate
при перемещении корабля, а также уменьшить скорость при остановке корабля. Вот событие, выделенное:
1
2
3
4
5
|
t2 = new Tween(theShip, 1.5, Transitions.EASE_OUT);
t2.moveTo(touch.globalX, touch.globalY);
t2.onUpdate = refresh //call upon this function whenever tween engine runs
t2.onStart = beginState //when ship starts moving
t2.onComplete = endState //when ship animation stops
|
А вот и вызовы функций для этих событий.
1
2
3
4
5
6
7
8
9
|
private function beginState():void {
flow1.emissionRate = 250
flow1.speed = 100;
}
private function endState():void {
flow1.emissionRate = 50
flow1.speed = 10;
}
|
Нажмите и перетащите снова, и обратите внимание на длину выхлопа.
Шаг 11: Эффект параллакса
Частицы также могут выражать, насколько быстро корабль движется относительно окружающей среды. Проверьте вывод ниже. Нажмите и перетащите мышку вокруг. Обратите внимание на скорость, с которой движутся окружающие частицы. Они увеличиваются при взаимодействии с кораблем и замедляются, когда вы прекращаете взаимодействие. Они также соответственно ориентируют свое вращение.
Настройка этого эффекта относительно проста в приложении, демонстрируемом onebyonedesign.com . Однако нам нужно будет написать код ActionScript, чтобы изменить его во время выполнения, и для этого понадобятся следующие несколько шагов.
Шаг 12: Один излучатель впереди
Инициирование частиц происходит в формате, аналогичном предыдущему примеру. Вы можете настроить свой эффект с помощью приложения onebyonedesign.com и импортировать его на свою сцену. Я просто пишу код прямо в ActionScript для простоты.
01
02
03
04
05
06
07
08
09
10
11
12
|
envr = new ParticleDesignerPS( XML(new InitValues()),
Texture.fromBitmap(new Sample())
);
addChildAt(envr,0);
envr.blendFactorSource = Context3DBlendFactor.ONE
envr.blendFactorDestination = Context3DBlendFactor.ONE
envr.speed = 10;
envr.startSize = 15;
envr.endSize = 20;
envr.lifespan = 5.0;
envr.emissionRate = 10
envr.start();
|
Нам также нужно будет поместить излучатель частиц на небольшое расстояние впереди корабля.
1
2
|
envrLoc = new Vector2D(100, 0);
envrLoc.setAngle(angle);
|
И обновите этот вектор во время выполнения.
1
2
3
4
5
|
//update the environment
envr.gravityX = -40*lof.x;
envr.gravityY = -40*lof.y;
envr.emitterX = loc.x + envrLoc.x;
envr.emitterY = loc.y + envrLoc.y;
|
Шаг 13: Распространение
Видите ли, emitterXVariance
и emitterYVariance
обрабатывают оси отдельно. Это означает, что если мы вращаем космический корабль, нам нужны некоторые средства определения длины разброса вдоль этих двух осей.
Теперь проверьте вектор для прямой видимости. Это всегда перпендикулярно линии спреда (тонкая темная линия). Мы можем соответственно масштабировать этот вектор и смешивать его x и y с дисперсией эмиттера в начальной точке. Проверьте демо ниже. Нажмите и перетащите мышку вокруг. Вы увидите поток частиц более ярким.
Наконец, масштабируйте величину распространения и поместите ее немного дальше впереди корабля, чтобы игроки не видели свою точку выброса.
1
2
|
envrLoc = new Vector2D(200, 0);
envrLoc.setAngle(angle);
|
1
2
3
4
5
|
//update the spread
spread = envrLoc.clone();
spread.scale(0.5);
envr.emitterXVariance = spread.y;
envr.emitterYVariance = spread.x;
|
Шаг 14: накачать ускорение
Наконец, когда корабль ускоряется, давайте увеличим соответственно значения силы gravityX
и gravityY
gravityX
gravityY
, а также gravityY
.
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
|
if (touch.phase == TouchPhase.MOVED) {
var distX:Number = touch.globalX — flow1.emitterX;
var distY:Number = touch.globalY — flow1.emitterY;
angle = Math.atan2(distY, distX);
//animate the exhaust
t = new Tween(flow1, 1.5, Transitions.EASE_OUT_BACK);
t.animate(«emitAngle», angle + Math.PI);
Starling.juggler.add(t);
//control the exhaust
flow1.speed = 350;
flow1.endSize = 70;
//orient the ship & parallax’s angle
lof.setAngle(angle);
lof.setMagnitude(10);
envrLoc.setAngle(angle);
}
if (touch.phase == TouchPhase.ENDED) {
//control the exhaust
flow1.speed = 100;
flow1.endSize = 10;
lof.setMagnitude(5);
}
|
Шаг 15: Корабль под атакой
По мере продвижения в игре вы обязательно будете получать удары и получать урон. Когда урон станет серьезным, ваш корабль сгорит. Такой эффект может быть создан здесь; мы можем использовать emissionXVariance
и emissionYVariance
чтобы определить область ожога. Я выделил их в коде ниже.
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
|
envr = new ParticleDesignerPS( XML(new InitValues()),
Texture.fromBitmap(new Sample())
);
addChildAt(envr,2);
envr.blendFactorSource = Context3DBlendFactor.ONE_MINUS_SOURCE_ALPHA
envr.blendFactorDestination = Context3DBlendFactor.ONE;
envr.emitterXVariance = theShip.width >> 2;
envr.emitterYVariance = theShip.height >> 2;
envr.emitAngle = 0;
envr.speed = 0;
envr.startSize = 40;
envr.endSize = 10;
envr.lifespan = 5.0;
envr.emissionRate = 10;
envr.start();
|
Тяжесть повреждения определяется площадью и интенсивностью ожога. Увеличьте и уменьшите emissionRate
чтобы смоделировать это. Я добавил элементы управления на клавиатуре «A» и «S», чтобы подражать этому.
01
02
03
04
05
06
07
08
09
10
|
private function controlBurn(e:KeyboardEvent):void {
if (e.keyCode == Keyboard.A) {
if(envr.emissionRate < 150) envr.emissionRate += 10;
if (envr.lifespan < 8) envr.lifespan += 0.5;
}
if (e.keyCode == Keyboard.S) {
if(envr.emissionRate > 10) envr.emissionRate -= 10;
if (envr.lifespan > 5) envr.lifespan -= 0.5;
}
}
|
Обратите внимание, что если вы увеличите продолжительность жизни частиц, огонь, похоже, будет гореть интенсивнее. Что ж, для интерполяции частиц от их начального размера до конечного размера требуется время, поэтому, если вы увеличите срок службы, потребуется больше времени для перехода от большего начального размера к меньшему конечному размеру. Поскольку более крупные частицы остаются в одном и том же месте дольше, они смешиваются вместе, создавая впечатление более интенсивного огня.
Шаг 16: Горящий Корабль
Нажмите клавишу «А», чтобы увидеть, как огонь горит интенсивнее, и клавишу «S», чтобы немного погасить его. Цвет выхлопа был изменен, чтобы отличать его от горения:
Шаг 17: Корабль взорвался
Все хорошие игры должны закончиться в какой-то момент. Независимо от того, кого устраняют, нельзя упускать хороший взрыв для финиша. Так как насчет ядерного грибного облака? Нажмите на демо ниже, чтобы увидеть его.
Теперь давайте закодируем это.
Шаг 18: Радиальный поток частиц
Этот поток частиц немного отличается от тех, которые мы видели. Ранее мы использовали тип потока частиц 0 (гравитация), а это тип 1 (радиальный). Частицы фактически движутся к середине с постоянной скоростью.
Я повернул дисперсию угла излучения к ее максимальному значению, чтобы вы могли видеть все сгенерированные частицы в форме круга Затем, анимируя максимальный радиус и минимальный радиус, в котором эти частицы должны жить с течением времени, используя Tween
, мы достигаем этого результата.
01
02
03
04
05
06
07
08
09
10
11
|
explosion = new ParticleDesignerPS(
XML(new InitValues()),
Texture.fromBitmap(new Sample())
);
addChild(explosion);
explosion.emitterX = stage.stageWidth >> 1;
explosion.emitterY = stage.stageHeight >> 1;
explosion.emitterType = 1;
explosion.emitAngle = 0;
explosion.maxRadius = 10;
explosion.minRadius = 0;
|
Вот код для выполнения анимации.
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
|
private function track(e:TouchEvent):void {
var touch:Touch = e.getTouch(stage);
if (touch.phase == TouchPhase.BEGAN) {
explosion.emitterX = touch.globalX;
explosion.emitterY = touch.globalY;
explosion.start();
t = new Tween(explosion, 1.0, Transitions.EASE_IN);
t.animate(«maxRadius», 150);
t.animate(«minRadius», 130);
t.onStart = freeze
t.onComplete = reset;
Starling.juggler.add(t);
}
}
private function freeze():void {
stage.removeEventListener(TouchEvent.TOUCH, track);
}
private function reset():void {
stage.addEventListener(TouchEvent.TOUCH, track);
explosion.stop();
explosion.maxRadius = 10;
explosion.minRadius = 0;
}
|
Шаг 19: Резюме
Так что это был длинный урок. Давайте сделаем небольшое резюме здесь. Мы прошли через:
- Настройка Starling и расширение его частиц
- Свойства системы частиц
- Примеры манипуляций с имуществом по сценарию шутера.
Вывод
Здесь мы немного рассмотрели. Тем не менее, один важный аспект, который я не прошел, это расширение ParticleSystem
. Это действительно даст вам возможность кодировать ваши собственные следы частиц вместо того, чтобы полагаться на ParticleDesignerPS
. Мне придется отложить это в другой учебник.
Спасибо за чтение и до встречи в следующем уроке. Оставляйте комментарии об ошибках и использовании этого движка частиц в вашем проекте, если вы решите его принять.