Particles System в моделировании толпы (3)

в 22:22, , рубрики: Без рубрики

Продолжаем разговор от 10.04.2014 (Particles System в моделировании толпы(2)).

В этой части:

  1. добавлю гибель стрелок (ведь взрывы убивают)
  2. поиграюсь с настройками эмиттеров — хочется эпичности

добавлю гибель стрелок (ведь взрывы убивают)

Для того, чтоб «убить стрелку», есть много разных способов. Я же выберу самый распространенный — уменьшить некое «количество здоровья» до нуля или меньше. Но для того, чтобы что-нибудь уменьшить, надо этим самым сначала снабдить — здоровьем (HealthInitializer).
Во время инициализации частицы, при помощи HealthInitializer, в свойства класса Particle.dictionary добавляется новая пользовательская переменная «health»

package waylines.initializers
{
	import org.flintparticles.common.particles.Particle;
	import org.flintparticles.common.emitters.Emitter;
	import org.flintparticles.common.initializers.InitializerBase;

	public class HealthInitializer extends InitializerBase
	{
		private var health:int;
		public function HealthInitializer(health:int=100)
		{
			this.health = health;
		}
		override public function initialize( emitter : Emitter, particle : Particle ) : void
		{
			particle.dictionary["health"] = health;
		}
	}
}

Частицы получили здоровье, и теперь можно его уменьшать.
Изменения в основной код:

  • инициализируем новое свойство
  • расширяем родительский метод MainWaylines_2.explosion

override protected function setup(e:Event=null):void
{
	super.setup(e);
	// добавляем "мелким стрелкам" новое свойство - здоровье 
	emitterWaylines.addInitializer( new HealthInitializer(100));
}

/*
 * логика проста (в одном пункте чуть ущербна - но я не укажу где)
 * 1. родительский метод explosion "выбивает" частицы из emitterWaylines и клонирует их в emitterExplosion
 * 2. расширенный метод перебирает в цикле частицы и уменьшает им здоровье. 
 * таким образом получается, что "повреждения" получают ВСЕ частицы 
 * - и только добавленные и те, что УЖЕ накрыло предыдущим взрывом 
 */
override protected function explosion(e:MouseEvent):void
{
	/*
	 * обязательный вызов родительского метода - для обработки частиц из emitterWaylines
	 */
	super.explosion(e);
	/*
	 * практически copy-paste родительского метода
	 * , нет только клонирования частиц из одного эмиттера в другой
	 */	
	...

	var particles:Array = emitterExplosion.particlesArray;
	var length:int = particles.length;
	for(var r:int=0; r<length; r++)
	{
		...

		if(Point.distance(explPoint, particlePoint) < explRadius)
		{
			particleClone = Particle2D(particles[r]);
			particleClone.angVelocity = -5 + Math.random() * 10;
			/*
			 * чуть "продлеваем жизнь" частицы во "взрывном эмиттере" - ей ведь добавляются повреждения...
			 */					
			particleClone.lifetime += 1;
			//particleClone.age = 0;
			/*
			 * уменьшаем здоровье у частиц внутри взрыва (от 10 до 40 единиц)
			 */
			particleClone.dictionary["health"] -= (10 + Math.random() * 30);
		}
	}			
}

Все работает. Непонятно только кого ранило, а кого и убило. Можно добавить цветовую дифференциацию штанов стрелок.
Вставляем пару строк в MainWaylines_3.explosion():

/*
 * если параметр здоровья меньше или равен нулю - частица удаляется из эмиттера, и запускается анимация
 */
if(particle.dictionary["health"] <= 0)
{	// стрелка "убита" - добавляем кляксу
	addBlot(particle);
	// удаляем частицу
	particle.isDead = true;
}
else
{ // стрелка "ранена" - изменим цвет
	Arrow(particle.image).color = getArrayColorByHealth(particle.dictionary["health"]);
}

поиграюсь с настройками эмиттеров — хочется эпичности

Библиотека частиц, взятая за основу для работы над приложением, оперирует физическими законами (масса, гравитация...) — тонкая материя, для меня во всяком случае (не технарь). Да и наверняка потребовалось бы писать собственные надстройки — что крайне нежелательно (хочется с программированием играться как с покупными детскими кубиками, а не самому точить на токарном станке).
Поэтому:

  • я просто ЗАМЕДЛИЛ эмиттеры на столько, насколько мне было нужно (в 100 раз)
  • увеличил параметр acceleration (в 10 раз) new MinimumDistance( 7, 6000 )
  • увеличил силу «анигравитации» (в 10 раз) new Antigravities(emitterWaylinesForMonsterArrows, -4000000)
override protected function setup(e:Event=null):void
{
	super.setup(e);
	// добавляем "мелким стрелкам" новое свойство - здоровье 
	emitterWaylines.addInitializer( new HealthInitializer(100));
	/*
	 * "замедлил время" для эмиттеров стрелок (больших и маленьких)
	 * по-умолчанию - .1
	 */
	emitterWaylines.maximumFrameTime = .001;
	emitterWaylinesForMonsterArrows.maximumFrameTime = .001;
	/*
	 * из-за замедления времени для эмиттеров движения стрелок, пришлось увеличить силы, действующие на частицы
	 * (ну, даже с житейской точки зрения это понятно - чтоб в маленьких промежутках времени были заметны изменения, силы нужно приложить побольше)
	 */
	emitterWaylines.addAction( new Antigravities(emitterWaylinesForMonsterArrows, -4000000) );// было 400000
	emitterWaylines.addAction( new MinimumDistance( 7, 6000 ) );// было 600
}

Потенциальный противник в результате стал двигаться значительно медленнее — пропорционально своим размерам относительно карты (если это гоблины или зомби, например). Саму карту можно масштабировать, координаты частиц экстраполировать на экраны большего (меньшего размеров).

Particles System в моделировании толпы (3)

Ну вот, собственно, это то, чем хотел поделиться — принципом моделирования толпы с помощью Системы Частиц. В результате получился почти готовый прототип Модели (MVC) для Tower Defence. 60 fps, при такой плотности частиц, добиться, конечно, не удастся… Но — оптимизировать есть куда (в предыдущих частях помянул), прикрутить бесплатный рендер (Starling, Away3d)

Код доступен на google code. Класс MainWaylines_3

P.S.: будет время, обязательно покажу прикрученный рендер

Автор: meiciuc

Источник


* - обязательные к заполнению поля


https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js