GMS 2 Implement Parabolic Trayectory on a Top Down

GapingPixel

Member
Was wondering about the ways I can implement a Jumping behavior for an enemy on an Top Down game.

My initial idea was to just add a gravity variable and apply it while making the jump. But thing is I can't make it so it goes thro solids, because that would cause that the enemy would get out of the playable area at times. So I'm looking for a way of making it, so the enemy first sets a target for the landing(within the playable area) and then it would execute the leap, before calculating the direction/force needed to get there.


This is the kind of movement I want to add to my project.

 
Last edited:

CedSharp

Member
Simply have a way to "know" when it's not on the ground (a variable?) and then use that variable as a condition before checking for collision with solid objets.

Basically: "if you are not in the air AND there is a solid objet: do not move"
 

GapingPixel

Member
Simply have a way to "know" when it's not on the ground (a variable?) and then use that variable as a condition before checking for collision with solid objets.

Basically: "if you are not in the air AND there is a solid objet: do not move"
It has to know where's is jumping to, so it does not ends up out of the map. Colliding or not with solids isn't the deal.
 

GapingPixel

Member
My issue is that, z being add to y is not letting the obj to get close to the target.y

Code:
if animation_hit_frame(7) {
    onAir = true;
}

if onAir {

    var distanceTotal = point_distance(x,y,targetX,targetY);
    var spd = .8;
    var peakHeight = 30;

    x = approach(x, targetX, abs(lengthdir_x(spd,direction)));
    y = approach(y, targetY, abs(lengthdir_y(spd,direction)));
    var distanceRemaining = point_distance(x,y,targetX,targetY);
    var percent = (distanceTotal-distanceRemaining) / distanceTotal;
    var z = -peakHeight * sin(percent * pi);
    y += z;
}

if animation_hit_frame(16) {
    audio_play_sound(a_tankangel_attack, 5, false);
    //y = y-z
}

if animation_hit_frame(17) {
    onAir = false;
}



This is my current result
 

CedSharp

Member
instead of doing x,y = approach, you can do xdest = approach, and then use xdest as if you were moving normally with collisions.
something as simple as:
Code:
var xdest, ydest, moved, hdir, ydir;
// Get target position to move to
xdest = approach(x, targetX, abs(lengthdir_x(spd, direction)));
ydest = appearch(y, targetY, abs(lengthdir_y(spd, direction)));
// Prepare variables
hdir = sign(xdest - x);
vdir = sign(ydest - y);
xdest = abs(xdest);
ydest = abs(ydest);
moved = true;
// Move for real as long as can move
while((xdest > 0 || ydest > 0) && moved) {
  moved = false;
  if(xdest > 0 && !place_meeting(x + hdir, y, oWall)) {
    xdest--;
    x += hdir;
    moved = true;
  }
  if(ydest > 0 && !place_meeting(x, y + vdir, oWall)) {
    ydest--;
    y += vdir;
    moved = true;
  }
}
This code gets the position you are trying to move to;
It then calculates the distance for x and y that you have to move to;
And then loops that distance over a simple collision test.
My loop is a bit more complex because I want to loop both directions at the same time
to avoid "skipping past narrow spaces".

place_meeting is kinda expensive unless you have precise collision turned off.
You might want to replace it with the collision_* scripts instead :)
 

GapingPixel

Member
instead of doing x,y = approach, you can do xdest = approach, and then use xdest as if you were moving normally with collisions.
something as simple as:
Code:
var xdest, ydest, moved, hdir, ydir;
// Get target position to move to
xdest = approach(x, targetX, abs(lengthdir_x(spd, direction)));
ydest = appearch(y, targetY, abs(lengthdir_y(spd, direction)));
// Prepare variables
hdir = sign(xdest - x);
vdir = sign(ydest - y);
xdest = abs(xdest);
ydest = abs(ydest);
moved = true;
// Move for real as long as can move
while((xdest > 0 || ydest > 0) && moved) {
  moved = false;
  if(xdest > 0 && !place_meeting(x + hdir, y, oWall)) {
    xdest--;
    x += hdir;
    moved = true;
  }
  if(ydest > 0 && !place_meeting(x, y + vdir, oWall)) {
    ydest--;
    y += vdir;
    moved = true;
  }
}
This code gets the position you are trying to move to;
It then calculates the distance for x and y that you have to move to;
And then loops that distance over a simple collision test.
My loop is a bit more complex because I want to loop both directions at the same time
to avoid "skipping past narrow spaces".

place_meeting is kinda expensive unless you have precise collision turned off.
You might want to replace it with the collision_* scripts instead :)
That's nice for the collision checking!

But, on what I'm currently struggling is the curve, which is this part of the code, I think I shouldnt be using sin that way
Code:
var z = -peakHeight * sin(percent * pi);
    y = z+posy;
 

mar_cuz

Member
That's nice for the collision checking!

But, on what I'm currently struggling is the curve, which is this part of the code, I think I shouldnt be using sin that way
Code:
var z = -peakHeight * sin(percent * pi);
    y = z+posy;
z needs to be added to the y when drawing the sprite only in the draw event and not the actual y position in the room
 

CedSharp

Member
z needs to be added to the y when drawing the sprite only in the draw event and not the actual y position in the room
I agree. The position used for collision and everything is the position of your character when on the ground. (aka the area of the shadow)

If you set y to the jumping position, then when you do collision testing you will be testing... the position in the air, which will look extremely weird to the player.
You want to add something like this in the draw event to draw the sprite at a different location than your current position:

Code:
draw_sprite(sprite_index, image_index, x, y+z);
 

Yal

ūüźß *penguin noises*
GMC Elder
Here's an even better idea: have its ground X/Y position be its actual X/Y position, use that for collisions, and just draw it furher up when it's in midair. Makes collision checking with walls much easier, all you need to do is to add an extra "Z" variable for jump altitude and some logic in collisions with player attacks (and other stuff that can hurt it) to do nothing if it's too high up.
 

mar_cuz

Member
I agree. The position used for collision and everything is the position of your character when on the ground. (aka the area of the shadow)

If you set y to the jumping position, then when you do collision testing you will be testing... the position in the air, which will look extremely weird to the player.
You want to add something like this in the draw event to draw the sprite at a different location than your current position:

Code:
draw_sprite(sprite_index, image_index, x, y+z);
That is exactly how I do it. He also needs to account for how high in the air the enemy is so if the enemy is too high there is no collision. I have a way to do this but I'm at work and can't refer to my code
 
Hi, I code a super simple baseball game not so long ago, and I a used to define a Z variable with 3 or 4 values to the altitude, depending on it's distance_to_where it launch and where it's land. it working nicely, but maybe it's line consumming ^^ .

For the graphic part, i just use xscale and yscale with drawing_sprite_ext().
I declared var totale_distance from A to B. with the fonction distance_to_point.
for the ascending part ( distance_to_A < totale_distance/2) ; xscale = 1+distance_to_A/distance_to_B ; that way you get a value going from 1+0 to 1+1 =2;
which mean you can add a factor if you want your spite going bigger etc. For example in my game à add later an angle when batting the ball cos of the angle changing the totale_distance and sin(angle for the x and y scale) .
Assuming my game was pretty much wieved from air, you can add a second angle for the depth.
Hope it help.
 
I want also add that in hyper lightdrifter they might create and shadow object to the shadow with the linear trajectory… And they didn't take the time to make it growth. XD
 
Top