Legacy GM Getting (x,y) of Collision event for sprite "tracing" effect

Silversea

Member
Hi guys.
In a game I'm working on I want a special effect that appears to "trace" the outline of a sprite. I have a solution in mind but its missing one crucial piece, which is finding the point of collision.

My solution is having 3 objects. Object 1 is an empty object with a mask that uses the outline of the sprite. Object 2 is a collision object. Object 3 is a custom particle. The aim is for object 2 to rotate around its axis, and, when it collides with the outline of object 1, creates object 3 (particles). This creates the effect of tracing the sprite outline.

An image demonstration:



This solution makes sense to me, but I can't create the particles on the outline of the sprite without finding the point of collision. Ideally I'd run a check in the Collision event to find the (x,y) of collision, and create an instance of the particle object at that spot. But how do I find the (x,y) in the Collision event?

Any thoughts, or, alternatively, another non-complicated solution that reproduces this effect? Note that the shape of the sprite is not always same, so it needs to be a dynamic solution that works for any sprite shape within the size range.

I think there could there be a (potentially slow) method of using lengthdir_x and lengthdir_y, along with several loops of position_meeting. But that's a bit awkward.

(Note that there is no issue with having to isolate the sprite outline from the sprite itself -- it already is an outline to begin with!).
 
Last edited:
R

Ryzzax

Guest
Well, I'm not a pro, and never done something like that before, but I have an idea, even though I don't really know how to code this...

So yeah, what you could do, instead of "drawing" the particles over the lines, you could make another sprite that the lines are already completly blue, and when that collision object rotates, it slowly creates the blue sprite over it, I don't know if this is possible, but it seems, the be more simple to do.

Hope it helps :)
 
have you considered just having a path that you have precomputed which represents the outline of the sprite, and having the effect follow that path?

You say the sprite already is an outline. Which makes me think maybe you don't need to do any of this work, and that you can just apply an effect using the sprite as a mask in some way. What is the ultimate goal of this exercise?
 

Silversea

Member
@Ryzzax
What you describe sounds just as tough as my solution to my ears, if not more so. You are removing the particle object sequence but then there is a need to implement code that is "cropping" the sprite and gradually revealing it. This is simple on a straight line (for instance a sprite "wiping" from left to right). But how would you code the "unfolding pie chart" cropping and revealing of the sprite in my instance? May not even be possible (although I'm sure someone could work it out, but it probably impacts the frame rates).

I expect I will probably use the particles for further effects too once the tracing is complete, so I think I might stick to having those around. Thanks for looking, though.

@flyingsaucerinvasion
There are too many sprites for this -- it would take hundreds of paths to match them all. It'll take some time to perfectly match the sprite outline in a path for even a few sprites let alone many. Otherwise yes, I would go this route.
 

ParodyKnaveBob

The Laughing Rogue
Howdy, Silversea,

There's probably some super awesome, simple way to accomplish this with a shader. But you know what? I've yet to even run a pass-through shader.

My first thoughts go to using a surface and a blend mode, colorizing via drawing a "mask" programmed as a triangle-fan primitive (letting you create a pie chart no problem). Another solution could be to draw a textured triangle-fan primitive pie-charting over your real sprite -- probably no surface nor blend-mode-changing required.

It can be complicated to just jump into the middle of it, yes, but once you get the basics of creating your own polygons, it's powerful (and even fun! heehee). I'd pore over the manual and play with stuff for awhile. I haven't checked if there's a good basic built-in tutorial on drawing primitives. The one on surfaces does touch on primitives, but we're talking loops of trigonometric functions and everything -- useful, yes, but perhaps overkill if you're just getting your feet wet. Go ahead and read and piddle around in a test project first, then ask for more if you need. $:^ ]

Regards,
Bob
 
I've got a shader solution for you. If you can think of a better way to get the angle from the center of a sprite to one of its pixels and to test if that angle is less than a certain value, then you might have improved the shader slightly...

So the fragment shader looks like this. The vertex shader is not changed from pass-through. What's happening here is an angle (in radians) is computed from the center of the sprite to each pixel. If that angle is less than the other angle (in radians), then the sprite texture color is drawn, otherwise the outline color is drawn.
Code:
varying vec2 v_vTexcoord;
varying vec4 v_vColour;
uniform vec4 uvs;
uniform float angle;
const vec3 outline_color = vec3(0.0,1.0,1.0);  //color of outline
void main()
{
    vec2 T = normalize(vec2((v_vTexcoord - uvs.xy) * uvs.zw));  //remap texcoord
    float dir = atan(T.y,T.x) + float(T.y < 0.0) * 6.2831853;  //angle from sprite center to this fragment
    vec4 tex_color = v_vColour * texture2D( gm_BaseTexture, v_vTexcoord );
    gl_FragColor = vec4(mix(tex_color.rgb,outline_color,float(dir <= angle)),tex_color.a);
}

Here's an example of using the shader.
Code:
//CREATE EVENT

//getting uvs for the sprite sub-image that I want to draw (needs to be done every time the sub image changes)
var _uv = sprite_get_uvs(sprite_index,0);
//and then compute some transformations that will be applied to the texture coordinates inside of the shader
uvs[0] = (_uv[0] + _uv[2])/2;
uvs[1] = (_uv[1] + _uv[3])/2;
uvs[2] = 1/(_uv[2] - _uv[0]);
uvs[3] = 1/(_uv[3] - _uv[1]);

//get shader uniforms
sh_uvs = shader_get_uniform(shader1,"uvs");
sh_angle = shader_get_uniform(shader1,"angle");

angle = 0;

//DRAW EVENT

shader_set(shader1);
shader_set_uniform_f(sh_uvs,uvs[0],uvs[1],uvs[2],uvs[3]);    //pass sprite uv transformations into shader
shader_set_uniform_f(sh_angle,angle);   //and the current angle

//I'm increasing the arc (measured in radians) around which the outline will be drawn.
angle += 0.02;
//here I'm starting over once the outline has fully encircled the sprite.
if (angle > (2 * pi)) { angle = 2 * pi - angle; }

draw_self();
shader_reset();

EDIT: I made a slight simplification to the shader by using the first overload for the atan function, which (I didn't know this before), already contains quadrant information.
 
Last edited:

Silversea

Member
Wow thanks guys for all of these suggestions.

I was surprised to find that my original solution actually works with lengthdir_x.

This was the working code I ended up with in Collision event of my "rotation" object. Cue badly syntaxed code:

Code:
//Collision event of OB_revealobj
dv = 0;

repeat(sprite_width/2)
  {if position_meeting(x+lengthdir_x(dv,image_angle),y+lengthdir_y(dv,image_angle),OB_spriteoutline)
  instance_create(x+lengthdir_x(dv,image_angle),y+lengthdir_y(dv,image_angle),EFF_particle)
  dv += 1;
  }
Hint: yes I hate "for" loops but it wasn't needed here anyway.

I'll have to try out that shader and surface method too and see what works best!
 
Top