GameMaker How to grow and shrink an object gradually

O

Obj_Neil

Guest
I am not sure if there is a bug or something but I cannot get shrinking to work. It works for making an object grow, but the same thing doesn't make the object shrink. I am changing the xscale every step by adding to it.

Also, the same logic but used on the radius of a circle drawn in the draw event only grows the circle and will not shrink it. Here is the code. Am I missing something?

Code:
if image_xscale >= 7
{
image_xscale -= 0.1;
image_yscale = image_xscale;
}


 
if image_xscale <= 7
{
image_xscale += 0.1;
image_yscale = image_xscale;
}
 
Imagine for a second that at the start of the code, image_xscale = 7.

If you read through the code line by line, and run the maths through your head (or use pencil and paper if necessary), what does image_xscale and image_yscale equal at the end of this piece of code?
 
O

Obj_Neil

Guest
It equals 7. The same as when I only write the following code.

Code:
image_xscale = 7;
image_yscale = 7;
If you know why it isn't working, please let me know. I have also tried drawing a circle in draw then starting its radius at 30, then if >= to 30 I reduced that number. It doesn't work. But the same code does grow it from 2 radius to 30.
 
O

Obj_Neil

Guest
HA, ha. OMG! Okay, nevermind. It is >= 7 so it does nothing. I need to put if >= 1 to reduce it to 1, or 3 to reduce it to 3. Got it. Now I just need to think about how to grow it and shrink it back and forth to make it look like it is breathing.

If anyone knows how to do that, please let me know. What I have been trying is not working.
 
Last edited by a moderator:
O

Obj_Neil

Guest
I got it to work, but this seems ridiculous. There must be an easier way. Anyhow, it works. It gives me a breathing shape. The default of full_size in the create event is false.

Code:
// grow the circle
if image_xscale < 7 and !full_size
{
image_xscale += 0.1;
image_yscale = image_xscale;
}

if image_xscale = 7
{
full_size = true; 
}

// shrink the circle
if image_xscale > 3 and full_size
{
image_xscale -= 0.1;
image_yscale = image_xscale;
}

if image_xscale = 3
{
full_size = false; 
}
This also works for the radius of a drawn circle, which is what I needed it for, to make a breathing looking light source. Just in case anyone else finds the code useful, here it is. If anyone knows how to make it better, please share.

Create
Code:
full_size = false;
radius = 10;
Step
Code:
// grow the circle
if radius < 30 and !full_size
{
radius += 0.1;
}

if radius = 30
{
full_size = true;
}

// shrink the circle
if radius > 10 and full_size
{
radius -= 0.1;
}

if radius = 10
{
full_size = false;
}
Draw
Code:
draw_circle(x, y, radius, false);
I will be using draw_circle_color, though, so I can alter the colors with variables to get different color lights that breath, and I will be using gpu_set_blendmode_ex
 
Last edited by a moderator:
O

Obj_Neil

Guest
Alexx, that does seem to give more flexibility. It makes it easier to change how fast it breaths. Although, getting the exact size to grow and shrink from is harder. I did it this way. I am not very studied in maths. I more think of coding in logical terms, but here it is.

I do wonder if this is more process-intensive, though. If anyone knows the answer, let me know. These math functions seem like they would take more processing, though.

Create
Code:
t = 0;
increment = 2; // How fast to breath, i.e. change the size of the radius number
amplitude = 10; // how hard to breath, i.e. how much larger and smaller to grow and shrink than radius, which
// here is 60.
 
// have yy = y and you can make your object bounce up and down.
yy = radius;
Step
Code:
t = (t + increment) mod 360;
shift = amplitude * dsin(t);

//clone the movement from the object's speed and direction
yy += vspeed;
radius = yy + shift; // change radius to y to move object up and down.
Draw
Code:
draw_circle(x, y, radius, false);
 
It equals 7. The same as when I only write the following code.

Code:
image_xscale = 7;
image_yscale = 7;
If you know why it isn't working, please let me know. I have also tried drawing a circle in draw then starting its radius at 30, then if >= to 30 I reduced that number. It doesn't work. But the same code does grow it from 2 radius to 30.
Debugging is a skill that only gets easier with practise, so I didn't want to feed you an answer initially, just point you in the right direction.

As you have worked out, you can use a boolean flag to set whether the object is growing or shrinking. Then you just need a couple of variables holding min_scale and max_scale, then lerp (or just add and subtract if desired ) towards the appropriate one based on the boolean flag.

Or as @Alexx said, sin() function can be used, but will be slightly more computationally expensive.
 

Yal

🐧 *penguin noises*
GMC Elder
Sine function is actually pretty fast to compute, you can use an expansion formula to turn it into a polynomial sum (that's related to how
upload_2019-11-12_21-55-56.png
, but I'm too sleepy to give you the full details atm. Haven't really done my complex algebra the last half-decade, sorry for being rusty). Also for small angles sin a roughly equals a.


For Game Maker, I recommend using lengthdir_x / lengthdir_y instead of sin/cos. You don't need to think about GM's inverted y-axis shenanigans, and the units are in degrees instead of radians, making them doubly convenient when you want to just code a simple undulating movement.

Code:
image_xscale = 4 + lengthdir_x(3,current_time*0.005)
image_yscale = image_xscale
 
O

Obj_Neil

Guest
Yal, thank you very much. I didn't think to use lengthdir like this. It uses less cpu than sin. It also looks smoother than my if statement version. In fact, it looks as smooth as the sin version. The downside is that it is hard to tell how large it will grow.

Create
Code:
radius = 0;
size = 40;
Step
Code:
radius = size + lengthdir_x(10,current_time*0.05);
Draw
draw_circle(x, y, radius, false);
 

Yal

🐧 *penguin noises*
GMC Elder
The highest value lengthdir_x will get is the first argument ("length"), and it alternates between PLUS that value and MINUS that value. So it will alternate between size+10 and size-10 in your example... i.e., 50 largest size, 30 smallest size.
 
O

Obj_Neil

Guest
Thank you everyone. It worked out nicely. Here it is in action. I added randomness to it so they do not all breath the same.
 
Last edited by a moderator:
Top