• Hey Guest! Ever feel like entering a Game Jam, but the time limit is always too much pressure? We get it... You lead a hectic life and dedicating 3 whole days to make a game just doesn't work for you! So, why not enter the GMC SLOW JAM? Take your time! Kick back and make your game over 4 months! Interested? Then just click here!

Action platformer commited jump arc attack and object issue.

Hi. I hope everyone is enjoying the holiday season.

I have been working on a platform game for some time now and I came across an issue. When jumping and attacking I noticed that the character would stop it's horizontal movement and just drop. I noticed this would also happen when my enemy character would get hit in mid air. Basically the instance_change command would stall horizontal speed.

I don't know if this is normal programming or typical of all builds of game maker but I found a way around it and actually used this fact to make an effective mechanic. I just want to see if anyone has found a more effective way of dealing with the issue than I have. If so or if there are problems or points of contention please let me know but with that said I think I have found something.


Ok so I have some scripts set up to catalog movement variables and such. Also to note I am not using a FMS for these player related items. I am going to use an Enum and FMS for the enemies if it the most effective way.

sc_constants

/// Initialize variables
grav = 1;
spd = 4;
hspd = 0;
vspd = 0;
jspd = -12;

I have standard issue vertical and horizontal collision, movement and inputs scripts and the like (see below). Then I did this for the attack script.

sc_plattack
______________________________________________________________________________
///Attack hitbox
#region

var key_attack = keyboard_check_pressed(vk_shift);




sprite_index = splayat;
image_speed = 4;

if (key_attack)
{
sprite_index = splayat;

if(sprite_index = splayat) && (image_index >= 1) || (image_index <= 3)
{
sc_athitbox()
}
}




if (vspd = 0) && (key_attack)

{
sc_obathitbox() see below
}


#endregion
______________________________________________________________________________
sc_athitbox()

///only changes to character attacking sprite

#region


if(sprite_index = splayat) && (image_index >= 1) || (image_index <= 3)
{
with (instance_create_layer(x,y,"Melee",par_playatbox))
{
image_speed = 4;
image_xscale = other.image_xscale;
hspeed = hspeed * image_xscale;

}


}

#endregion

______________________________________________________________________________

sc_obathitbox()

///creates character attacking object if on ground only

instance_change(par_playat,true)

______________________________________________________________________________

So what I did is I took advantage of the instance change to make my player stop when attacking on the ground, beautiful. While the player is attacking in the air it does not change instance but only the animation cycle through the sprite_index = whatever statement and as such the character has a committed jump arc just as I has hoped and attacks just fine in the air. No mid air stalling. He jumps in the pointed direction cannot change direction and he rises and falls with no interruptions.

Now for my player object I have scripts for constants in the create event, input/movement and collision in the step.

sc_constant() see above

______________________________________________________________________________

sc_colli

standard issue collision code

#region
// Vertical collisions
if (place_meeting(x, y+vspd, obj_solid))
{
while (!place_meeting(x, y+sign(vspd), obj_solid))
{
y += sign(vspd);
}
vspd = 0;
}
//Move vertically
y += vspd;


// Horizontal collisions
if (place_meeting(x+hspd, y, obj_solid))
{
while (!place_meeting(x+sign(hspd), y, obj_solid))
{
x += sign(hspd);
}
hspd = 0;
}
//Move horizontally
x += hspd;


#endregion

______________________________________________________________________________


sc_move()

///Inputs
#region
var key_right = keyboard_check(vk_right);
var key_left = keyboard_check(vk_left);
var key_jump = keyboard_check_pressed(vk_space);


var grounded = place_meeting(x,y+1,obj_solid);

//React to inputs
if(vspd < 12)
{
vspd += grav;

//Jump
if (grounded)
{
var move = key_right - key_left;
hspd = move*spd;
vspd = key_jump * jspd;

if key_right
{
image_xscale = 1;
}

if key_left
{
image_xscale = -1;
}
}
}

#endregion

Basically that's it. Constants go in the Create event, movement and input scripts in the step and the attack script is under the key pressed event. Everything seems to work.

The reason I am posting this is because trying to find mechanics for fixed arc jumping and attacking is hard to find on this site. I am not saying that this is a failing of the site because to even word this issue properly for a search is a pain. In the end it is just one of those unavoidable things I guess. I hope that someone else can benefit from these findings. Please feel free to debate or discuss the approach to this issue.

Thank you and have a happy new year. :)
 

MaxLos

Member
Is there some advantage to using instance_change instead of just having one variable called "state" and changing that? This just seems a bit messier to me. If you wanted to keep your momentum when attacking in the air it would be easy to just check if your in your attack state and say hsp = hsp
 
Last edited:
Is there some advantage to using instance_change instead of just having one variable called "state" and changing that? This just seems a bit messier to me. If you wanted to keep your momentum when attacking in the air it would be easy to just check if your in your attack state and say hsp = hsp
The thing is I have tried using states but the example I made can only work with enemies. The Enum and cases were made specifically for that as the error message said Enum has already been defined so I am a little bit perplexed as how to do this. Can you use Enum more than once. Suggestions? References?
 

MaxLos

Member
The thing is I have tried using states but the example I made can only work with enemies. The Enum and cases were made specifically for that as the error message said Enum has already been defined so I am a little bit perplexed as how to do this. Can you use Enum more than once. Suggestions? References?
Well I'm not very familiar with enums but it seems that you can't create two enums with the same name so that's why your getting that error message.

I dunno why states wouldn't work for you if you used them as I described.. Let me show you some pseudo code of how I usually handle state machines:

hsp = 0; //Horizontal speed
vsp = 0; //Vertical speed
grv = 0.3; //Gravity

movesp = 2; //Movement speed
jumpspeed = 5; //Jump speed

state = "Normal";
grounded = false;
key_left = keyboard_check(vk_left);
key_right = keyboard_check(vk_right);
key_jump = keyboard_check(vk_space);
key_attack = keyboard_check(vk_shift);
var move = key_right - key_left;

if (state = "Normal")
{
if !(move = 0) hsp = movesp;
else if (move = 0) hsp = 0;

//Jump
if (grounded) and (key_jump) vsp = -jumpspeed;
}
else if (state = "Attack")
{
hsp = hsp; //<-- This is what you should do to keep momentum when attacking
//If you only keep your momentum for specific attacks, just check for the sprite index rather
//than your attack state
}
//Gravity
if (vsp < 10) vsp += grv;
//Horizontal Collision
if (place_meeting(x+hsp,y,par_solid))
{
while (!place_meeting(x+sign(hsp),y,par_solid))
{
x = x + sign(hsp);
}
hsp = 0;
}

//Vertical Collision
if (place_meeting(x,y+vsp,par_solid))
{
while (!place_meeting(x,y+sign(vsp),par_solid))
{
y = y + sign(vsp);
}
vsp = 0;
}
//Image speed
switch (sprite_index)
{
case spr_player_idle = image_speed = 0.15; break;
case spr_player_walk = image_speed = 0.2; break;
case spr_player_airborn = image_speed = 0; break;
case spr_player_attack = image_speed = 0.25; break;
}


//Normal State Animation
if (state = "Normal")
{
//Grounded
if (grounded = true)
{
if (hsp = 0) sprite_index = spr_player_idle; //If we're not moving on the ground play idle animation
else if !(hsp = 0) sprite_index = spr_player_walk; //If we moving on the ground play walk animation
}

//Airborn
else if (grounded = false)
{
sprite_index = spr_player_airborn;
if (vsp < 0) //If we're moving up, play jump animation
else if (vsp > 0) //If we're moving down, play fall animation
}
if !(hsp = 0) image_index = sign(hsp); //Flip sprite to direction it's moving in
}
if (place_meeting(x,y+1,obj_floor)) grounded = true; else grounded = false; //Grounded
scr_inputs();
scr_animation();
scr_movement();
scr_collision();

if (key_attack) and (state = "Normal")
{
sprite_index = spr_player_attack;
state = "Attack";
}
if (state = "Attack") scr_attack_hitboxes(); //Create hitboxes when in attacks state

And of course you would add all that hitbox stuff from your original post and an animation end event or something to go back to your normal state when your attack finishes but you get the gist. Its a pretty identical setup to what you already have with your scripts but without the enums and instance_change. Hopefully I didn't forget anything

Edit: Rip my indentation
 
Last edited:
Well I'm not very familiar with enums but it seems that you can't create two enums with the same name so that's why your getting that error message.

I dunno why states wouldn't work for you if you used them as I described.. Let me show you some pseudo code of how I usually handle state machines:

hsp = 0; //Horizontal speed
vsp = 0; //Vertical speed
grv = 0.3; //Gravity

movesp = 2; //Movement speed
jumpspeed = 5; //Jump speed

state = "Normal";
grounded = false;
key_left = keyboard_check(vk_left);
key_right = keyboard_check(vk_right);
key_jump = keyboard_check(vk_space);
key_attack = keyboard_check(vk_shift);
var move = key_right - key_left;

if (state = "Normal")
{
if !(move = 0) hsp = movesp;
else if (move = 0) hsp = 0;

//Jump
if (grounded) and (key_jump) vsp = -jumpspeed;
}
else if (state = "Attack")
{
hsp = hsp; //<-- This is what you should do to keep momentum when attacking
//If you only keep your momentum for specific attacks, just check for the sprite index rather
//than your attack state
}
//Gravity
if (vsp < 10) vsp += grv;
//Horizontal Collision
if (place_meeting(x+hsp,y,par_solid))
{
while (!place_meeting(x+sign(hsp),y,par_solid))
{
x = x + sign(hsp);
}
hsp = 0;
}

//Vertical Collision
if (place_meeting(x,y+vsp,par_solid))
{
while (!place_meeting(x,y+sign(vsp),par_solid))
{
y = y + sign(vsp);
}
vsp = 0;
}
//Image speed
switch (sprite_index)
{
case spr_player_idle = image_speed = 0.15; break;
case spr_player_walk = image_speed = 0.2; break;
case spr_player_airborn = image_speed = 0; break;
case spr_player_attack = image_speed = 0.25; break;
}


//Normal State Animation
if (state = "Normal")
{
//Grounded
if (grounded = true)
{
if (hsp = 0) sprite_index = spr_player_idle; //If we're not moving on the ground play idle animation
else if !(hsp = 0) sprite_index = spr_player_walk; //If we moving on the ground play walk animation
}

//Airborn
else if (grounded = false)
{
sprite_index = spr_player_airborn;
if (vsp < 0) //If we're moving up, play jump animation
else if (vsp > 0) //If we're moving down, play fall animation
}
if !(hsp = 0) image_index = sign(hsp); //Flip sprite to direction it's moving in
}
if (place_meeting(x,y+1,obj_floor)) grounded = true; else grounded = false; //Grounded
scr_inputs();
scr_animation();
scr_movement();
scr_collision();

if (key_attack) and (state = "Normal")
{
sprite_index = spr_player_attack;
state = "Attack";
}
if (state = "Attack") scr_attack_hitboxes(); //Create hitboxes when in attacks state

And of course you would add all that hitbox stuff from your original post and an animation end event or something to go back to your normal state when your attack finishes but you get the gist. Its a pretty identical setup to what you already have with your scripts but without the enums and instance_change. Hopefully I didn't forget anything

Edit: Rip my indentation
Well I'm not very familiar with enums but it seems that you can't create two enums with the same name so that's why your getting that error message.

I dunno why states wouldn't work for you if you used them as I described.. Let me show you some pseudo code of how I usually handle state machines:

hsp = 0; //Horizontal speed
vsp = 0; //Vertical speed
grv = 0.3; //Gravity

movesp = 2; //Movement speed
jumpspeed = 5; //Jump speed

state = "Normal";
grounded = false;
key_left = keyboard_check(vk_left);
key_right = keyboard_check(vk_right);
key_jump = keyboard_check(vk_space);
key_attack = keyboard_check(vk_shift);
var move = key_right - key_left;

if (state = "Normal")
{
if !(move = 0) hsp = movesp;
else if (move = 0) hsp = 0;

//Jump
if (grounded) and (key_jump) vsp = -jumpspeed;
}
else if (state = "Attack")
{
hsp = hsp; //<-- This is what you should do to keep momentum when attacking
//If you only keep your momentum for specific attacks, just check for the sprite index rather
//than your attack state
}
//Gravity
if (vsp < 10) vsp += grv;
//Horizontal Collision
if (place_meeting(x+hsp,y,par_solid))
{
while (!place_meeting(x+sign(hsp),y,par_solid))
{
x = x + sign(hsp);
}
hsp = 0;
}

//Vertical Collision
if (place_meeting(x,y+vsp,par_solid))
{
while (!place_meeting(x,y+sign(vsp),par_solid))
{
y = y + sign(vsp);
}
vsp = 0;
}
//Image speed
switch (sprite_index)
{
case spr_player_idle = image_speed = 0.15; break;
case spr_player_walk = image_speed = 0.2; break;
case spr_player_airborn = image_speed = 0; break;
case spr_player_attack = image_speed = 0.25; break;
}


//Normal State Animation
if (state = "Normal")
{
//Grounded
if (grounded = true)
{
if (hsp = 0) sprite_index = spr_player_idle; //If we're not moving on the ground play idle animation
else if !(hsp = 0) sprite_index = spr_player_walk; //If we moving on the ground play walk animation
}

//Airborn
else if (grounded = false)
{
sprite_index = spr_player_airborn;
if (vsp < 0) //If we're moving up, play jump animation
else if (vsp > 0) //If we're moving down, play fall animation
}
if !(hsp = 0) image_index = sign(hsp); //Flip sprite to direction it's moving in
}
if (place_meeting(x,y+1,obj_floor)) grounded = true; else grounded = false; //Grounded
scr_inputs();
scr_animation();
scr_movement();
scr_collision();

if (key_attack) and (state = "Normal")
{
sprite_index = spr_player_attack;
state = "Attack";
}
if (state = "Attack") scr_attack_hitboxes(); //Create hitboxes when in attacks state

And of course you would add all that hitbox stuff from your original post and an animation end event or something to go back to your normal state when your attack finishes but you get the gist. Its a pretty identical setup to what you already have with your scripts but without the enums and instance_change. Hopefully I didn't forget anything

Edit: Rip my indentation

I ran your code but it displayed a few issues with the animation script. I renamed it but that is not the issue. The error message is as such:

Script: sc_anim at line 4 : got 'break' expected ':'
Script: sc_anim at line 5 : got 'case' expected '}'
Script: sc_anim at line 4 : Case argument should be a constant

scr_anim is just shortened. No issues there.
 

MaxLos

Member
I ran your code but it displayed a few issues with the animation script. I renamed it but that is not the issue. The error message is as such:

Script: sc_anim at line 4 : got 'break' expected ':'
Script: sc_anim at line 5 : got 'case' expected '}'
Script: sc_anim at line 4 : Case argument should be a constant

scr_anim is just shortened. No issues there.
oh whoops for the cases it should be :'s not ='s so for example
Code:
 case spr_player_idle: //Blah
not
Code:
 case spr_player_idle = //blah
 
Top