Explorar o código

Integrate #304 + extra (#447)

Integrated Direction emit mode;
Integrate emitDirectionAsAngle parameter;
Integrate and slightly rework Particles2D sample;
Add rebuildOnChange variable (ex movable).
Pavel Alexandrov %!s(int64=7) %!d(string=hai) anos
pai
achega
4829b766f7
Modificáronse 3 ficheiros con 292 adicións e 26 borrados
  1. 54 26
      h2d/Particles.hx
  2. 238 0
      samples/Particles2d.hx
  3. BIN=BIN
      samples/particles2d_res/arrow.png

+ 54 - 26
h2d/Particles.hx

@@ -24,6 +24,10 @@ enum PartEmitMode {
 		A box, parametrized with emitDist and emitDistY
 	**/
 	Box;
+	/**
+		A box, parametrized with emitAngle and emitDistance
+	**/
+	Direction;
 }
 
 private class ParticleShader extends hxsl.Shader {
@@ -162,7 +166,8 @@ class ParticleGroup {
 	public var emitStartDist(default, set) : Float = 0.;
 	public var emitDist(default, set) : Float	= 50.;
 	public var emitDistY(default, set) : Float	= 50.;
-	public var emitAngle(default,set) : Float 	= -0.5;
+	public var emitAngle(default, set) : Float 	= -0.5;
+	public var emitDirectionAsAngle(default, set) : Bool = false;
 	public var emitSync(default, set) : Float	= 0;
 	public var emitDelay(default, set) : Float	= 0;
 
@@ -201,42 +206,53 @@ class ParticleGroup {
 	
 	/** Should partcles follow the emitter or stay in place? **/
 	public var isRelative(default, set) : Bool = true;
+	/** Should group rebuild on parameters change.
+		Note that some parameters take immediate effect on the existing particles, and some would force rebuild reagrdless.
+		Parameters that take immediate effect:
+		speedIncr, gravity, gravityAngle, fadeIn, fadeOut, fadePower, rotAuto, rotInit, incrX, incrY, emitLoop, blendMode
+		Parameters that will always force rebuild:
+		enable, sortMode, isRelative, texture, frameCount, frameDivisionX, frameDivisionY, nparts
+		Parameters that newer cause rebuild:
+		blendMode, colorGradient, animationRepeat
+	**/
+	public var rebuildOnChange : Bool = true;
 
 	inline function set_enable(v) { enable = v; if( !v ) { batch.clear(); needRebuild = true; }; return v; }
 	inline function set_sortMode(v) { needRebuild = true; return sortMode = v; }
 	inline function set_blendMode(v) { batch.blendMode = v; return blendMode = v; }
-	inline function set_size(v) { needRebuild = true; return size = v; }
-	inline function set_sizeRand(v) { needRebuild = true; return sizeRand = v; }
-	inline function set_sizeIncr(v) { needRebuild = true; return sizeIncr = v; }
-	inline function set_incrX(v) { needRebuild = true; return incrX = v; }
-	inline function set_incrY(v) { needRebuild = true; return incrY = v; }
-	inline function set_speed(v) { needRebuild = true; return speed = v; }
-	inline function set_speedIncr(v) { needRebuild = true; return speedIncr = v; }
-	inline function set_gravity(v) { needRebuild = true; return gravity = v; }
+	inline function set_size(v) { if (rebuildOnChange) needRebuild = true; return size = v; }
+	inline function set_sizeRand(v) { if (rebuildOnChange) needRebuild = true; return sizeRand = v; }
+	inline function set_sizeIncr(v) { if (rebuildOnChange) needRebuild = true; return sizeIncr = v; }
+	inline function set_incrX(v) { if (rebuildOnChange) needRebuild = true; return incrX = v; }
+	inline function set_incrY(v) { if (rebuildOnChange) needRebuild = true; return incrY = v; }
+	inline function set_speed(v) { if (rebuildOnChange) needRebuild = true; return speed = v; }
+	inline function set_speedIncr(v) { if (rebuildOnChange) needRebuild = true; return speedIncr = v; }
+	inline function set_gravity(v) { if (rebuildOnChange) needRebuild = true; return gravity = v; }
 	inline function set_gravityAngle(v : Float) {
-		needRebuild = true;
+		if (rebuildOnChange) needRebuild = true;
 		cosGravityAngle = Math.cos(v * Math.PI * 0.5);
 		sinGravityAngle = Math.sin(v * Math.PI * 0.5);
 		return gravityAngle = v;
 	}
 
-	inline function set_speedRand(v) { needRebuild = true; return speedRand = v; }
-	inline function set_life(v) { needRebuild = true; return life = v; }
-	inline function set_lifeRand(v) { needRebuild = true; return lifeRand = v; }
+	inline function set_speedRand(v) { if (rebuildOnChange) needRebuild = true; return speedRand = v; }
+	inline function set_life(v) { if (rebuildOnChange) needRebuild = true; return life = v; }
+	inline function set_lifeRand(v) { if (rebuildOnChange) needRebuild = true; return lifeRand = v; }
 	inline function set_nparts(n) { needRebuild = true; return nparts = n; }
-	inline function set_dx(v) { needRebuild = true; return dx = v; }
-	inline function set_dy(v) { needRebuild = true; return dy = v; }
-	inline function set_emitLoop(v) { needRebuild = true; return emitLoop = v; }
-	inline function set_emitMode(v) { needRebuild = true; return emitMode = v; }
-	inline function set_emitStartDist(v) { needRebuild = true; return emitStartDist = v; }
-	inline function set_emitDist(v) { needRebuild = true; return emitDist = v; }
-	inline function set_emitDistY(v) { needRebuild = true; return emitDistY = v; }
-	inline function set_emitAngle(v) { needRebuild = true; return emitAngle = v; }
-	inline function set_emitSync(v) { needRebuild = true; return emitSync = v; }
-	inline function set_emitDelay(v) { needRebuild = true; return emitDelay = v; }
-	inline function set_rotInit(v) { needRebuild = true; return rotInit = v; }
-	inline function set_rotSpeed(v) { needRebuild = true; return rotSpeed = v; }
-	inline function set_rotSpeedRand(v) { needRebuild = true; return rotSpeedRand = v; }
+	inline function set_dx(v) { if (rebuildOnChange) needRebuild = true; return dx = v; }
+	inline function set_dy(v) { if (rebuildOnChange) needRebuild = true; return dy = v; }
+	inline function set_emitLoop(v) { if (rebuildOnChange) needRebuild = true; return emitLoop = v; }
+	inline function set_emitMode(v) { if (rebuildOnChange) needRebuild = true; return emitMode = v; }
+	inline function set_emitStartDist(v) { if (rebuildOnChange) needRebuild = true; return emitStartDist = v; }
+	inline function set_emitDist(v) { if (rebuildOnChange) needRebuild = true; return emitDist = v; }
+	inline function set_emitDistY(v) { if (rebuildOnChange) needRebuild = true; return emitDistY = v; }
+	inline function set_emitAngle(v) { if (rebuildOnChange) needRebuild = true; return emitAngle = v; }
+	inline function set_emitDirectionAsAngle(v) { if (rebuildOnChange) needRebuild = true; return emitDirectionAsAngle = v; }
+	inline function set_emitSync(v) { if (rebuildOnChange) needRebuild = true; return emitSync = v; }
+	inline function set_emitDelay(v) { if (rebuildOnChange) needRebuild = true; return emitDelay = v; }
+	inline function set_rotInit(v) { if (rebuildOnChange) needRebuild = true; return rotInit = v; }
+	inline function set_rotSpeed(v) { if (rebuildOnChange) needRebuild = true; return rotSpeed = v; }
+	inline function set_rotSpeedRand(v) { if (rebuildOnChange) needRebuild = true; return rotSpeedRand = v; }
 	inline function set_texture(t) { texture = t; makeTiles(); return t; }
 	inline function set_colorGradient(t) { colorGradient = t; return t; }
 	inline function set_frameCount(v) { frameCount = v; makeTiles(); return v; }
@@ -344,6 +360,15 @@ class ParticleGroup {
 				var yy = sinA * (p.x - dx) + cosA * (p.y - dy) + dy;
 				p.x = xx;
 				p.y = yy;
+
+			case Direction:
+				speed = Math.abs(speed);
+				p.vx = Math.cos(g.emitAngle);
+				p.vy = Math.sin(g.emitAngle);
+				
+				var r = g.emitStartDist + g.emitDist * rand();
+				p.x += r * Math.cos(g.emitAngle - Math.PI / 2);
+				p.y += r * Math.sin(g.emitAngle - Math.PI / 2);
 		}
 
 		p.scale = size;
@@ -357,6 +382,9 @@ class ParticleGroup {
 		p.life = 0;
 		p.maxLife = life;
 
+		var rot = emitDirectionAsAngle ? Math.atan2(p.vy, p.vx) : srand() * Math.PI * g.rotInit;
+		p.rotation = rot;
+
 		if ( !isRelative ) {
 			// Less this.parts access
 			var parts = this.parts;

+ 238 - 0
samples/Particles2d.hx

@@ -0,0 +1,238 @@
+import h3d.mat.Texture;
+import h2d.Graphics;
+import h2d.Particles;
+import hxd.Res;
+
+class Particles2d extends SampleApp {
+	var g : ParticleGroup;
+	var particles : Particles;
+	var movableParticleGroup : ParticleGroup;
+	var time : Float;
+	
+	var arrow : Texture;
+	var square : Texture;
+	var moving : Bool = false;
+
+	override function init() {
+		super.init();
+		
+		square = null;// h2d.Tile.fromColor(0xFFFFFF, 16, 16).getTexture();
+		arrow = Res.arrow.toTexture();
+		
+		particles = new Particles(s2d);
+		g = new ParticleGroup(particles);
+		particles.addGroup(g);
+		
+		addSlider("Amount", function() return g.nparts, function(v) g.nparts = Std.int(v), 1, 1000);
+		addCheck("Sort", function() return g.sortMode == Dynamic, function(v) g.sortMode = v ? Dynamic : None);
+		addCheck("Loop", function() return g.emitLoop, function(v) { g.emitLoop = v; });
+		addCheck("Move", function() return moving, function(v) moving = v);
+		addCheck("Relative", function() return g.isRelative, function(v) g.isRelative = v);
+		addCheck("Dir as Angle", function() return g.emitDirectionAsAngle, function(v) { g.emitDirectionAsAngle = v; g.texture = v ? arrow : square; });
+		addCheck("RebuildMode", function() return g.rebuildOnChange, function(v) { g.rebuildOnChange = v; });
+
+		addChoice("EmitMode", ["Point A", "Point B", "Cone", "Box", "Dir A", "Dir B"], function (v) {
+			switch(v) {
+				case 0: changeToPointDemo();
+				case 1: changeToPointAndDirectionAsAngleDemo();
+				case 2: changeToConeDemo();
+				case 3: changeToBoxDemo();
+				case 4: changeToDirectionDemo();
+				case 5: changeToDirectionAndDirectionAsAngleDemo();
+			}
+		});
+		// addButton("PartEmitMode.Point Demo", changeToPointDemo);
+		// addButton("PartEmitMode.Point + emitDirectionAsAngle Demo", changeToPointAndDirectionAsAngleDemo);
+		// addButton("PartEmitMode.Cone Demo", changeToConeDemo);
+		// addButton("PartEmitMode.Box Demo", changeToBoxDemo);
+		// addButton("PartEmitMode.Direction Demo", changeToDirectionDemo);
+		// addButton("PartEmitMode.Direction + emitDirectionAsAngle Demo", changeToDirectionAndDirectionAsAngleDemo);
+		
+		changeToPointDemo();
+	}
+	
+	function changeToPointDemo() {
+		// clear();
+		reset();
+		
+		// g = new ParticleGroup(particles);
+		g.sizeRand = .2;
+		g.life = 1;
+		g.speed = 100;
+		g.speedRand = 3;
+		g.rotSpeed = 2;
+		g.emitMode = PartEmitMode.Point;
+		g.emitDist = 0;
+		g.fadeIn = 0;
+		g.fadeOut = 0;
+		g.dx = cast s2d.width / 2;
+		g.dy = cast s2d.height / 2;
+		
+		// particles.addGroup(g);
+	}
+	
+	function changeToPointAndDirectionAsAngleDemo() {
+		// clear();
+		reset();
+		
+		// g = new ParticleGroup(particles);
+		g.size = .8;
+		g.sizeRand = .2;
+		g.life = .5;
+		g.speed = 100;
+		g.speedRand = 3;
+		g.emitMode = PartEmitMode.Point;
+		g.emitDist = 0;
+		g.fadeIn = 0;
+		g.fadeOut = 0;
+		g.dx = cast s2d.width / 2;
+		g.dy = cast s2d.height / 2;
+		
+		// particles.addGroup(g);
+	}
+	
+	function changeToConeDemo() {
+		// clear();
+		reset();
+		
+		// g = new ParticleGroup(particles);
+		g.size = .2;
+		g.gravity = 1;
+		g.life = 5;
+		g.speed = 100;
+		g.speedRand = 3;
+		g.emitMode = PartEmitMode.Cone;
+		g.emitAngle = Math.PI;
+		g.emitDist = 0;
+		g.emitDistY = 0;
+		g.fadeIn = 1;
+		g.fadeOut = 1;
+		g.dx = cast s2d.width / 2;
+		g.dy = cast s2d.height / 2;
+		
+		// particles.addGroup(g);
+	}
+	
+	function changeToBoxDemo() {
+		// clear();
+		reset();
+		
+		// g = new ParticleGroup(particles);
+		g.size = .2;
+		g.gravity = 1;
+		g.life = 5;
+		g.speed = 100;
+		g.speedRand = 3;
+		g.emitMode = PartEmitMode.Box;
+		g.emitAngle = Math.PI;
+		g.emitDist = s2d.width;
+		g.emitDistY = s2d.height;
+		g.dx = cast s2d.width / 2;
+		
+		// particles.addGroup(g);
+	}
+	
+	function changeToDirectionDemo() {
+		// clear();
+		reset();
+		
+		// g = new ParticleGroup(particles);
+		g.size = .2;
+		g.gravity = 1;
+		g.life = 5;
+		g.speed = 100;
+		g.speedRand = 3;
+		g.emitMode = PartEmitMode.Direction;
+		g.emitDist = s2d.width;
+		g.emitAngle = Math.PI / 2;
+		g.fadeOut = .5;
+		
+		// particles.addGroup(g);
+	}
+	
+	function changeToDirectionAndDirectionAsAngleDemo() {
+		// clear();
+		reset();
+		
+		// g = new ParticleGroup(particles);
+		g.size = .8;
+		g.sizeRand = .2;
+		g.life = 6;
+		g.speed = 200;
+		g.speedRand = 3;
+		g.emitMode = PartEmitMode.Direction;
+		g.emitDist = s2d.height;
+		g.emitAngle = Math.PI / 4;
+		g.fadeIn = 0;
+		g.fadeOut = 0;
+		
+		
+		// particles.addGroup(g);
+	}
+	
+	static function main() {
+		Res.initEmbed();
+		new Particles2d();
+	}
+	
+	function reset() {
+		g.dx = 0;
+		g.dy = 0;
+		g.emitDist = 50.;
+		g.emitDistY = 50.;
+		g.emitAngle = -.5;
+		g.emitSync = 0;
+		g.emitDelay = 0;
+		g.emitStartDist = 0.;
+		
+		g.life = 1;
+		g.lifeRand = 0;
+		
+		g.sizeIncr = 0;
+		g.incrX = true;
+		g.incrY = true;
+		g.size = 1;
+		g.sizeRand = 0;
+		
+		g.speed = 50.;
+		g.speedRand = 0;
+		g.speedIncr = 0;
+		g.gravity = 0;
+		g.gravityAngle = 0;
+		
+		g.rotInit = 0;
+		g.rotSpeed = 0;
+		g.rotSpeedRand = 0;
+		g.rotAuto = false;
+		
+		g.fadeIn = .2;
+		g.fadeOut = .8;
+		g.fadePower = 1;
+		
+		particles.x = 0;
+		particles.y = 0;
+	}
+	
+	function clear():Void {
+		time = 0;
+		if (movableParticleGroup != null) movableParticleGroup = null;
+		if (g != null) particles.removeGroup(g);
+	}
+	
+	override function update(dt:Float) {
+		super.update(dt);
+		
+		if( moving ) {
+			time += dt * 0.6;
+			particles.x = Math.cos(time) * (s2d.width / 4);
+			particles.y = Math.sin(time) * (s2d.height / 4);
+		}
+		
+		// if (movableParticleGroup != null)
+		// {
+		// 	time += dt * 0.01;
+		// 	movableParticleGroup.dx = cast s2d.width / 2 + Math.cos(time) * 200;
+		// 	movableParticleGroup.dy = cast s2d.height / 2 + Math.sin(time) * 200;
+		// }
+	}
+}

BIN=BIN
samples/particles2d_res/arrow.png