Pull to refresh

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

Reading time4 min
Views9.1K
Продолжаем разговор от 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
}


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



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

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

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

Articles