Show animation at touch location?

I’d like to show a simple animation at the point where the user touches the screen on their device. It’s a simple particle emitter based on this project.

My basic approach is to move the folder/group containing the particles to the desired location and then trigger the animation. It works fine when referencing an object’s position like so…

particle_emitter.position( another_object.position() );
particle_code.fireEmitter();

Using using the localPosition or screenPosition property of the pointerdown event, however, results in the animation occurring at the wrong location…

parent.on("pointerdown", (e) => {
   particle_emitter.position( e.localPosition );
   particle_code.fireEmitter();
});

I’m using a large plane that covers the screen to capture the pointerdown event. Where am I going wrong? Do I need to perform some kind of coordinate conversion?

Any help appreciated.

Yes if your particle group is relative to say your tracking image and your touch is relative to screen you are going to have to do a conversion.

If you look at the ZapBox Xylophone project ZapBox Xylophone Project File
There is conversion code in it they use for the controllers.

Steve

1 Like

Hi @shot,

As long as your plane with the pointer down event is relativeTo the same thing as your emitter, and there is no scale or rotation applied to the plane then no coordinate system conversion should be needed.

If on the other hand you’ve scaled the plane to make sure it covers the screen, then you’ll need to apply the inverse of that scaling - so if plane.scale([2, 2, 2]) you’ll need to multiply the “local coordinates” by 0.5 to get them back into the “parent coordinates”.

e.screenPosition will give coordinates that you can set as the position of any object that is relativeTo(Z.screen) to get it to align, regardless of the parent of the plane itself.

If there are more complicated relationships between the parent of the emitter and the parent of the plane then as Steve mentions things get a bit more complicated and you might need to get into using TriggerRegions to convert. It sounds like the effect you want can be achieved without that though.

Hope that helps!

2 Likes

Thanks, @stevesanerd and @simon. That really helped!

Super helpful!

I have it working now, but I have a quick follow-up question. Consider the following code which works…

parent.on("pointerdown", (e) => {

	// Instantiate particle emitter
	let emitter : any = Z.Symbol("Particle Emitter");
	
	// Add to hierarchy so it's visible
	symbol.nodes.Touch_Emitters.push( emitter );
	
	// Position at touch point
	emitter.position( e.localPosition );

	// Let 'er rip
	emitter.node('Particles Code').fireEmitter();
});

My question is, since the emitters must be added to the hierarchy in order to be visible, does that mean I need to explicitly remove them in order to keep resource utilization to a minimum? IOW, I don’t want emitters “accumulating” in that folder every time the user touches the screen. I just want them to appear and be disposed of after the particle animation.

What’s the best way to dispose of them once they’ve been triggered? Or do I need to bother?

For the benefit of anyone who comes across this thread, what wound up working is multiplying the local coordinates by the scaling factor (as opposed to the inverse of the scaling factor)…

const scale_factors = parent.scale();

parent.on("pointerdown", e => {

	// Instantiate particle emitter
	let emitter : any = Z.Symbol("Particle Emitter");
	
	// Add to hierarchy so it's visible
	symbol.nodes.Touch_Emitters.push( emitter );
	
	// Position at touch point
	emitter.position( scaleCoords( e.localPosition ));

	// Let 'er rip
	emitter.node('Particles Code').fireEmitter();
});

function scaleCoords( coords )
{
	return[
		coords[0] * scale_factors[0],
		coords[1] * scale_factors[1],
		coords[2] * scale_factors[2]
	];
}
1 Like