• 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!

GameMaker Platformer: no gravity during melee jump attack

J

Johnjack

Guest
Hi!
I'm trying to develop a simple platformer on GMS2 (version 2.2.4.374) by following Shaun Spalding tutorials.
My problem is that during the jump attack animation, the player's "y" position is blocked, as if gravity were to disappear. At the end of the animation, gravity reappears.
I use a state machine.
If someone could help, i will be thankful. Here is my oPlayer code and state machine:

create event:
Code:
hsp = 0;
vsp = 0;
grv = 0.3;
jumpsp = 7;
walksp = 3;
hascontrol = true;

//for ledge assistance
grace_jump_time = 4; //number of grace period frames after leaving the ground you can still jump
grace_timer = grace_jump_time;
//for input buffering
jump_buffer = 4; //number of grace period frames between player pressing jump and hitting the ground when they will still jump
jump_buffer_timer = jump_buffer;

controller = 0;

state = PLAYERSTATE.FREE;
hitByAttack = ds_list_create();

enum PLAYERSTATE
{
   FREE,
   ATTACK_SLASH,
   ATTACK_SLASH_AIR,
   ATTACK_COMBO,
}
Step event:
Code:
#region //get player input

if (hascontrol)
{
   //Get the player's input
   key_right = keyboard_check(vk_right);
   //key_right = keyboard_check(ord("D"));
   key_left = -keyboard_check(vk_left);
   //original non-variable jumping
   key_jump = keyboard_check_pressed(vk_space);
   //for variable jumping
   key_jump_held = keyboard_check(vk_space);
   //for ledge assistance
   is_on_ground = false;
   //for jump input buffering
   jump_is_inside_buffer = false;
   //for attack
   key_attack = keyboard_check_pressed(ord("A"));

   if (key_left) || (key_right) || (key_jump)
   {
       controller = 0;
   }

   if (abs(gamepad_axis_value(0, gp_axislh)) > 0.2)
   {
       key_left = abs (min(gamepad_axis_value(0, gp_axislh),0))*-1;//j'ai juste rajouté le "*-1" parce qu'avec les modifications pour les ledge assistance et jump buffering, le perso allait à droite quand j'appuyais sur gauche à la manette.
       key_right = max (gamepad_axis_value(0, gp_axislh),0);
       controller = 1;
   }

   if (gamepad_button_check_pressed(0, gp_face1))
   {
       key_jump = 1;
       controller = 1;
   }


   if (gamepad_button_check_pressed(0, gp_face3))
   {
       key_attack = 1;
       controller = 1;
   }
}
else
{
   key_right =0;
   key_left =0;
   key_jump =0;
   key_attack =0;
}

#endregion

switch (state)
{
   case PLAYERSTATE.FREE: PlayerState_Free(); break;
   case PLAYERSTATE.ATTACK_SLASH: PlayerState_Attack_Slash(); break;
   case PLAYERSTATE.ATTACK_SLASH_AIR: PlayerState_Attack_Slash_Air(); break;
   case PLAYERSTATE.ATTACK_COMBO: PlayerState_Attack_Combo(); break;
}
PlayerState_Free
Code:
//React to inputs
move = key_left + key_right;
hsp = move * walksp;
if (vsp < 10) vsp+= grv;

//if you're on the ground, you can jump (base tutorial version)
if (place_meeting(x,y+1,oWall))
{
   vsp = key_jump * -jumpsp;
}

//For Ledge Assistance with input buffering
if (place_meeting(x,y+1,oWall))
{
    is_on_ground = true;
    grace_timer = grace_jump_time;
}
else{
    is_on_ground = false;
    grace_timer--;
}
PlayerState_Attack_Slash
Code:
hsp = 0;
vsp = 0;

//start of the attack
if (sprite_index != sAttack_Slash)
{
   sprite_index = sAttack_Slash;
   image_index = 0;
   ds_list_clear(hitByAttack);   
}

//Use attack hitbox & check for hits
mask_index = sAttack_SlashHB;
var hitByAttackNow = ds_list_create();
var hits = instance_place_list(x,y,oEnemy,hitByAttackNow,false);
if (hits > 0)
{
   for (var i = 0; i < hits; i++)
   {
       //if this instance has not yet been hit by this attack
       var hitID = hitByAttackNow[| i];
       if (ds_list_find_index(hitByAttack,hitID) == -1)
       {
           ds_list_add(hitByAttack, hitID);
           with (hitID)
           {
               EnemyHit(2);
           }
       }
   }
}

ds_list_destroy(hitByAttackNow);
mask_index = sPlayer;

if (animation_end())
{
   sprite_index = sPlayer;
   state = PLAYERSTATE.FREE;
}
PlayerState_Attack_Slash_Air (exactly the same as PlayerState_Attack_Slash)
Code:
hsp = 0;
vsp = 0;

//start of the attack
if (sprite_index != sAttack_Slash)
{
   sprite_index = sAttack_Slash;
   image_index = 0;
   ds_list_clear(hitByAttack);   
}

//Use attack hitbox & check for hits
mask_index = sAttack_SlashHB;
var hitByAttackNow = ds_list_create();
var hits = instance_place_list(x,y,oEnemy,hitByAttackNow,false);
if (hits > 0)
{
   for (var i = 0; i < hits; i++)
   {
       //if this instance has not yet been hit by this attack
       var hitID = hitByAttackNow[| i];
       if (ds_list_find_index(hitByAttack,hitID) == -1)
       {
           ds_list_add(hitByAttack, hitID);
           with (hitID)
           {
               EnemyHit(2);
           }
       }
   }
}

ds_list_destroy(hitByAttackNow);
mask_index = sPlayer;

if (animation_end())
{
   sprite_index = sPlayer;
   state = PLAYERSTATE.FREE;
}
I read that it would be necessary to create a separate script with the code concerning physics (gravity, collisions ...). Is that right?
 

Yal

🐧 *penguin noises*
GMC Elder
Put the gravity code in the attack state and you should experience gravity when attacking. This is a common mistake to make.

It's best to put code that needs to be in every state into a script, so you don't need to fix a bug in 1000 different places if you find a bug in the gravity code - you just need to fix the script.
I usually split this kind of thing up into very granular pieces - for instance, some states change your movement during special attacks, so I want the inertia code to be independent of the gravity and controls so I can just not have inertia in a state that overrides your movement. Here's an excerpt from the melee attack state of my SoulsVania engine:
upload_2019-12-14_23-20-0.png
 
J

Johnjack

Guest
Put the gravity code in the attack state and you should experience gravity when attacking. This is a common mistake to make.
Thanks for your reply. Maybe i'm blind, but I don't see what part of the gravity code I should put in the attack state? And where?
 

Yal

🐧 *penguin noises*
GMC Elder
This line:
if (vsp < 10) vsp+= grv;
Doesn't matter where you put it. It has no dependencies to any other physics code from what I can see (though if you put it after the jump code, you will jump slightly less high since gravity is applied after you jump, reducing the jump speed)

Also, I'd probably change it up like this:
Code:
if not(is_on_ground){
  if (vsp < 10){
    vsp+= grv;
  }
}
It's redundant to apply gravity when you ARE on ground, and you should always wrap if-statements in {curly brackets} so that you can add new statements below without accidentally breaking the logic.
 
J

Johnjack

Guest
Wow! Thank you so much! I feel so good!
I found a solution thanks to your advice and others!

Finally, I created a new script called "motion". Inside this script, I "cut & past" all the code concerning the gravity, motion and collisions from the "PlayerState_Free" script. Then,
in the beginning of the "PlayerState_Free" script, the "PlayerState_Attack_Slash" script and the "PlayerState_Attack_Slash_Air" script, I called the "motion" script by using:

Code:
motion();
And It works perfectly. I can breathe now.
 
Top