Legacy GM Better way of coding oscillating movement

M

Matt93

Guest
I'm trying to code oscillating movement for my player. Basically, the player has a parachute, and is floating in the air. When he's idle (when there's no keyboard input) I want him to rotate slightly to the right, then back towards the left in an oscillating movement. I've written code that works, but I feel like there's a better way of doing it. I've had to use a variable which triggers to false when I want him to tilt in one direction, then to true when he tilts in the other. Here's my code:

Code:
//Tilt player
if (forth) //counter clockwise
{
    image_angle ++;
    if (image_angle >= 30)
    {
        forth = false; //this variable is set to false when player needs to tilt clockwise
    }
}

if (!forth) //clockwise
{
    image_angle --;
    if (image_angle <= -30)
    {
        forth = true; //true so player tilts counterclockwise
    }
}
Is there a less clunky way of doing this without needing an additional variable? Cheers!
 

Tsa05

Member
When the player starts to fall, time=0;

In the draw step:
Code:
rotation = 45*sin(.105*time)
draw_sprite_ext(sprite_index,-1,x,y,1,1,rotation,c_white,1)
time+=1;
This should draw the sprite, oscillating continuously between -45 and 45 degrees over a period of about 60 game steps. You can scale the degrees by changing the 45. You can change the period of swing by changing the .105.

This depends on the variable "time" to compute oscillation. If you want it totally variable-free, create a player sprite with rotating frames and just play it normally.
 
Yeah, that's a really "hard" oscillation. I have a script that I use for this.

Code:
///sin_oscillate(min,max,position)
return((argument[1]-argument[0])/2 * dsin(argument[2]) + (argument[1]+argument[0])/2);
So the way you would use this is like this:

Code:
image_angle = sin_oscillate(-30,30,timer)
timer+=1;
Adjust how the timer increments to increase or decrease the speed. (And of course declare timer as 0 in your create event).
 

dphsw

Member
You could also do this:
Code:
image_angle+=angle_change;
angle_change-=(0.005 * image_angle);
The number 0.005 will need some adjusting - there will be a way to work out the right amount to make it go up to 30 degrees, but it will probably be something to do with integration, which I was never very good at. (You could also put in a multiplier in the top equation.) The disadvantage of this is that you have to work out what number you need, and it will depend on frame rate. The advantage of this approach is that it's much more efficient than an approach using trigonometry (not important for a single sprite, but it would make a difference if it were being used for a particle system or something, especially on mobile) and more flexible - if you later wanted the parachute to be rotated by other factors like being blown around by wind or something, they would just be other factors to add to the equations.
 

csanyk

Member
I'm trying to code oscillating movement for my player. Basically, the player has a parachute, and is floating in the air. When he's idle (when there's no keyboard input) I want him to rotate slightly to the right, then back towards the left in an oscillating movement. I've written code that works, but I feel like there's a better way of doing it. I've had to use a variable which triggers to false when I want him to tilt in one direction, then to true when he tilts in the other. Here's my code:

Code:
//Tilt player
if (forth) //counter clockwise
{
    image_angle ++;
    if (image_angle >= 30)
    {
        forth = false; //this variable is set to false when player needs to tilt clockwise
    }
}

if (!forth) //clockwise
{
    image_angle --;
    if (image_angle <= -30)
    {
        forth = true; //true so player tilts counterclockwise
    }
}
Is there a less clunky way of doing this without needing an additional variable? Cheers!
This article I wrote may not answer your question directly, but it is good reading and may give you some insights into an approach I came up with to do wave-like motion, which you might adapt for your specific problem.

The solution you have is similar to my "cheap wave" solution, where you just increment a variable and then decrement it periodically on a timer. It's not a bad way to do it at all.
 
M

Matt93

Guest
Thank you so much for your replies everyone! I'm going to be trying out all of your methods to see what works best for what I'm wanting to do.
 
Thank you Pixelated_Pope, swift and elegant. Since it is tagged as legacy content, is there an even more elegant solution nowadays? Not sure if necro posting is the way to ask this .
 

TheouAegis

Member
Nearly anything you can do in Legacy GM (which now includes GMS1 in a lot of peoples' minds) can be done the same way in GMS2. The fact Pope used dsin() means the code is for Studio already, so that's about the best you're going to get. I mean, you can toss in unary operators.

A method of oscillating without dsin() is to set the speed at which you rotate based on how far away from the center.
Code:
image_angle += sway_speed;
sway_speed += sign(start_angle - image_angle) / 256;
However, Pope's method is the easiest to work with since it allows you to specify the limits. Furthermore, with Pope's method, you can set the limits to be higher than what you want to allow by using an additional variable, e.g., true_angle, and then setting your image_angle or whatever to that other variable clamped off within the limits you want so it lingers at the extremes.
Code:
true_angle = PopeScript(spawn_angle - 45, spawn_angle + 45, ++timer);
image_angle = clamp(true_angle,spawn_angle-30, spawn_angle+30);
 
Top