Graphics Cool effect using particles to display a picture

Pollux568

Member
GM Version: Studio 1.4 (should work with Studio 2)
Target Platform: Windows
Download: n/a, see code below
Links: n/a

Summary: Use particles to display picture

-- Greetings, fellow devs,

I'd like to share a cool effect I found with Game Maker Studio, which can be adapted for many other projects.


To give a little bit of context, I am currently developing Abyss Crew, a coop game taking place aboard a submarine, where each player has a specific role (pilot, sonar, gunner, engineer). In the game, the sonar player has to scan objects, and I wanted to make an image appear progressively on the screen.
I found it worked well by using particles!

The principle is to pick places randomly in a box around the shape we'd like to have, and to create particles only if the place is inside the shape.
1) First, you need to create the particles system you wish. I personally like the spheres, but there are many other possibilities.

global.particlesUI = part_system_create();
analyzerBlip=part_type_create();
part_type_shape(analyzerBlip,pt_shape_sphere);
part_type_size(analyzerBlip,.1,.1,0,0);
part_type_speed(analyzerBlip,0,0,0,0);
part_type_direction(analyzerBlip,0,0,0,0);
part_type_orientation(analyzerBlip,0,0,0,0,1);
part_type_color1(analyzerBlip,merge_colour(c_lime,c_white,0.25));
part_type_alpha2 (analyzerBlip,1,0);
part_type_scale(analyzerBlip,1,1);
part_type_blend(analyzerBlip,true);
part_type_life(analyzerBlip,60,60);

2) Then, draw the sprite you wish to use (in my case, an octopus silhouette). Tick "Use precise collision".


3) Create an object with this sprite. Remove the "visible" option.

4) In a step event, create the particles randomly around the object. If the place is inside the shape, create the particle, if not, do nothing.

for (var ii=0;ii<100;ii++){
var randX = 500+random(200);
var randY = 300+random(150);
if collision_point(randX,randY,obj_sonar_analyzer_drawing,true,true){
part_particles_create(global.particlesUI, randX, randY, analyzerBlip, 1);}
}
}


5) Test it!

Other ideas:
-making lines for a CRT screen.
-exploding object


Question: Which version of Game Maker to use?
I am using GMS 1.4 but code for GMS2 should be identical.

Question: Do I need one object per sprite?
You can use multiple sprites for the same object. Remember to put an image_speed = 0 in the Create event.
You could even make an animation, although I didn't test it.

Information: How to optimize the computation time (FrostyCat - 29/08/2019)
You can pre-calculate the "successful" collision instead of doing it 100 times every step.
You can either precalculate all the random locations and save their coordinates only when they match the sprite shape; or when a scan starts, store the matching locations as long as the scan continues, and reuse these locations next time we use the sprite.

Other questions? Answer here or send me an email at contact AT abysscrew.com , I'll update the questions list here to share it with the community :)
Hope it helped some of you!

Captain Pol, out --
 
Last edited by a moderator:

FrostyCat

Member
4) In a step event, create the particles randomly around the object. If the place is inside the shape, create the particle, if not, do nothing.

for (var ii=0;ii<100;ii++){
var randX = 500+random(200);
var randY = 300+random(150);
if collision_point(randX,randY,obj_sonar_analyzer_drawing,true,true){
part_particles_create(global.particlesUI, randX, randY, analyzerBlip, 1);}
}
}
If at all possible, this is something that should be pre-computed, not brute-forced a hundred times per frame at 60 FPS. One way is to do the iterated row-column scan once in an initialization room, recording the hit coordinates in a 2D array, then simply pulling random rows off that. An alternative is to store scan results on the first occurrence and reusing it when the same sprite needs the effect later.
 

Pollux568

Member
Good point.
I guess what takes a lot of computing is the "collision_point" part with high precision, not the 2x random function?
 

FrostyCat

Member
I guess what takes a lot of computing is the "collision_point" part with high precision, not the 2x random function?
Definitely. Collision checks are often the most expensive of all routine operations, especially when precise collisions are involved. You can and should check it with the profiler, as your 100-shots-per-step code looks heavy from a mile away.

Also, since you don't need the instance ID, position_meeting() is faster and does the same work.
 

Tsa05

Member
Wouldn't that produce too sharp an outline when particles spawn on the edge? The point is to look slightly blobby and noisy.
Yes! But maybe not. Would take some tweaking with the shape of the emitter, but imagine that the shape mask has edges with feathered opacity instead of the current solid-edged ones, and that the emitter or combination of emitters are within the stricter confines of the non-feathered shape.

I think that the effect of keeping the particles internal to a region with a somewhat steep opacity falloff curve would get the right effect, or at least quite similar. The edge particles might look less solid, and there'd be some partial circles fading rapidly, but if the particles aren't large, and are fading anyways, a similar effect should be gained without the collision checking needed. Particularly in the case of the sub, it's practically an oval emitter with a fade mask in its current state.

But yes, definitely would have to play with how much feathering, or else it would just be a hard-edged shape after all.
 
Top