GameMaker Knockback for Isometric/Zelda Type RPG

T2008

Member
I'm trying to add a knock back for when player hits enemy wall (and for enemies eventually also). I've watched a few tutorials but none of them really work with my code. Below is the script for my player movement. It is 8 directional. Any ideas as to how to add a knockback into this?

Edit: I actually want to limit the knockback to collisions with enemies. Any ideas?

Code:
/// @description player_movement
//-----Input Keys
//Move
move_east        = (keyboard_check(vk_right)) && !(keyboard_check(vk_up)) && !(keyboard_check(vk_down));
move_north        = (keyboard_check(vk_up)) && !(keyboard_check(vk_left)) && !(keyboard_check(vk_right))
move_northeast    = (keyboard_check(vk_right)) && (keyboard_check(vk_up));
move_northwest    = (keyboard_check(vk_left)) && (keyboard_check(vk_up));
move_south        = (keyboard_check(vk_down)) && !(keyboard_check(vk_left)) && !(keyboard_check(vk_right));
move_southeast    = (keyboard_check(vk_right)) && (keyboard_check(vk_down));
move_southwest    = (keyboard_check(vk_left)) && (keyboard_check(vk_down));
move_west        = (keyboard_check(vk_left)) && !(keyboard_check(vk_up)) && !(keyboard_check(vk_down));
//Stop
stop_east        = (keyboard_check_released(vk_right));
stop_north        = (keyboard_check_released(vk_up));
stop_northeast    = (keyboard_check_released(vk_right)) && (keyboard_check_released(vk_up));
stop_northwest    = (keyboard_check_released(vk_left)) && (keyboard_check_released(vk_up));
stop_south        = (keyboard_check_released(vk_down));
stop_southeast    = (keyboard_check_released(vk_right)) && (keyboard_check_released(vk_down));
stop_southwest    = (keyboard_check_released(vk_left)) && (keyboard_check_released(vk_down));
stop_west        = (keyboard_check_released(vk_left));
//-----Apply Movement
//Move East
if (move_east) {
    //Define Direction
    Direction = "Right";
    //Set Sprite
    player_direction_sprite_walk();
    //Move Player
    if (place_meeting(x+global.walking_speed,y,obj_all_solid_parent)) {
        while(!place_meeting(x+sign(global.walking_speed),y,obj_all_solid_parent)) {
            x+=sign(global.walking_speed); 
        }
        global.walking_speed = 0;
    }
    x += global.walking_speed;
}
//Stop East
if (stop_east) {
    player_direction_sprite_stopped();
}
//Move North
if (move_north) {
    //Define Direction
    Direction = "Up";
    //Set Sprite
    player_direction_sprite_walk();
    //Move Player
    if (place_meeting(x,y-global.walking_speed,obj_all_solid_parent)) {
        while(!place_meeting(x,y-sign(global.walking_speed),obj_all_solid_parent)) {
            y-=sign(global.walking_speed); 
        }
        global.walking_speed = 0;
    }
    y -= global.walking_speed; 
}
//Stop North
if (stop_north) {
    player_direction_sprite_stopped();
}
 
Last edited:
I would do it like this.

In the create event, set up some variables for knockback direction, speed, max speed, and decrement amount (to smoothly stop).
Create Event:
Code:
kb_dir = 0;
kb_spd = 0;
kb_max_spd = 4;
kb_dec = .2;
In the step event, check if knockback speed is greater than 0, and if so, move in the knockback direction and decrease knockback speed.
Step Event (added to beginning or end):
Code:
if(kb_spd>0){
    kb_spd-=kb_dec;
    x+=lengthdir_x(kb_spd,kb_dir);
    y+=lengthdir_y(kb_spd,kb_dir);
    //You may need to handle some collision stuff here to prevent going into other objects or walls.
}
In the collision with enemy event, if you aren't being knocked back, set the knockback direction to the direction from enemy to player, and set the knockback speed to its max speed.
Collision Event:
Code:
if(kb_spd<=0){
    kb_dir = round(point_direction(other.x,other.y,x,y)/45)*45; //This ensures the direction chosen is one of you 8 directions
    kb_spd = kb_max_spd;
}
Let me know if anything is unclear.
 

T2008

Member
Thanks so much for this response! I haven't had the chance to implement yet. Also, do you have any idea re: collision code. They way I have it set up, I'm not sure how I would handle the collisions from the knockback. I tried other knockback code that worked except for the collision part (player got stuck in something).

Edit: I tried your code out and it sees to work but for the collision. Thanks so much!!! Any ideas on how to add collisions to my code?
 
Last edited:

T2008

Member
I tried editing code to include the below collision, but it didn't work. I can't figure out how to not get stuck in wall, etc with your knockback code (which works perfectly otherwise). I know it was a shot in the dark but any insights on how I can change to make work with collisions? (I don't want to have to redo my collision code; prefer to have it fit in with mine)

In Movement Script:
Code:
//-----Knockback
if(kb_spd > 0) {
    if (place_meeting(x+lengthdir_x(kb_spd,kb_dir),y+lengthdir_y(kb_spd,kb_dir),obj_all_solid_parent)) {
        while(!place_meeting(x+sign(lengthdir_x(kb_spd,kb_dir)),y+sign(lengthdir_y(kb_spd,kb_dir)),obj_all_solid_parent)) {
            x+=sign(lengthdir_x(kb_spd,kb_dir));
            y+=sign(lengthdir_y(kb_spd,kb_dir));
        }
        kb_spd = 0;
        kb_max_spd = 0;
    }
    kb_spd-=kb_dec;
    x+=lengthdir_x(kb_spd,kb_dir);
    y+=lengthdir_y(kb_spd,kb_dir);
}
Edit:
I also tried the below which seems to work but not sure if it will eventually get stuck. Do you see any problems with this?

Code:
//-----Knockback
if(kb_spd > 0) {
    if (!place_meeting(x,y,obj_all_solid_parent)) {
    kb_spd-=kb_dec;
    x+=lengthdir_x(kb_spd,kb_dir);
    y+=lengthdir_y(kb_spd,kb_dir);
    }
}
 
Last edited:
I tried editing code to include the below collision, but it didn't work. I can't figure out how to not get stuck in wall, etc with your knockback code (which works perfectly otherwise). I know it was a shot in the dark but any insights on how I can change to make work with collisions? (I don't want to have to redo my collision code; prefer to have it fit in with mine)

In Movement Script:
Code:
//-----Knockback
if(kb_spd > 0) {
    if (place_meeting(x+lengthdir_x(kb_spd,kb_dir),y+lengthdir_y(kb_spd,kb_dir),obj_all_solid_parent)) {
        while(!place_meeting(x+sign(lengthdir_x(kb_spd,kb_dir)),y+sign(lengthdir_y(kb_spd,kb_dir)),obj_all_solid_parent)) {
            x+=sign(lengthdir_x(kb_spd,kb_dir));
            y+=sign(lengthdir_y(kb_spd,kb_dir));
        }
        kb_spd = 0;
        kb_max_spd = 0;
    }
    kb_spd-=kb_dec;
    x+=lengthdir_x(kb_spd,kb_dir);
    y+=lengthdir_y(kb_spd,kb_dir);
}
Edit:
I also tried the below which seems to work but not sure if it will eventually get stuck. Do you see any problems with this?

Code:
//-----Knockback
if(kb_spd > 0) {
    if (!place_meeting(x,y,obj_all_solid_parent)) {
    kb_spd-=kb_dec;
    x+=lengthdir_x(kb_spd,kb_dir);
    y+=lengthdir_y(kb_spd,kb_dir);
    }
}
Looks like your solutions are very close. I think the bottom one will have issues with subpixels but I'm not entirely sure. And the top one should check horizontal and vertical directions separately.

I made my own project and tested this out for the step event:
Code:
//Get input
var l, r, u, d;
l = keyboard_check(ord("A"));
r = keyboard_check(ord("D"));
u = keyboard_check(ord("W"));
d = keyboard_check(ord("S"));

//Only let the player move if they are not being knocked back
if(kb_spd<=0){
    hsp = (r-l);
    vsp = (d-u);
}else{
    kb_spd-=kb_dec;
    hsp = 0;
    vsp = 0;
}

//This lets you go in 8 directions
if(hsp!=0 || vsp!=0){
    dir = point_direction(0,0,hsp,vsp);
    spd = walk_spd;
}else{
    dir = 0;
    spd = 0;   
}

//Set horizontal and vertical speed based on input and knockback
hsp = lengthdir_x(spd,dir)+lengthdir_x(kb_spd,kb_dir);
vsp = lengthdir_y(spd,dir)+lengthdir_y(kb_spd,kb_dir);

//Handle horizontal collision
if(position_meeting(x+hsp,y,oBlock)){
    while(!position_meeting(x+sign(hsp),y,oBlock)) x+=sign(hsp);
    hsp = 0;
}
x+=hsp;

//Handle vertical collision
if(position_meeting(x,y+vsp,oBlock)){
    while(!position_meeting(x,y+sign(vsp),oBlock)) y+=sign(vsp);
    vsp = 0;
}
y+=vsp;
You would just need to add this to your create event:
Code:
walk_spd = 4; //Or whatever speed you want
How are you currently handling collisions with the player object? You can just slip that "+lengthdir_x(kb_spd...." into your horizontal check, and the y one to your vertical check.
 

Yal

🐧 *penguin noises*
GMC Elder
When I made Bushido Panda, which was essentially a jam game, I cheated a bit implementing knockback: I used hspeed/vspeed for it (or rather, speed/direction), had objects have friction, and had knockback be independent from normal movement (with some extra code to prevent enemies from moving into walls). So basically, when hit, you'd just do this to calculate knockback:
Code:
speed = 2
direction = point_direction(other.x,other.y,x,y)
 

T2008

Member
SnotWaffle,
I use to handle collisions with x = xprevious/y = yprevious. Then I changed recently to the code in my original post (which I copy a part below). The xprevious/yprevious is still in enemy code collision with player but I suppose I will add the below code to include enemies too. I'm not that advanced and it seems like collisions can be tricky.

When you say the one (which I tested and does seem to work) might have issues with subpixels, what does that mean? (sorry, I have no programming experience).

Yal, thanks for responding. How do you handle collisions with your knockback?

Collision Code
Code:
 //Move Player
   if (place_meeting(x,y-global.walking_speed,obj_all_solid_parent)) {
       while(!place_meeting(x,y-sign(global.walking_speed),obj_all_solid_parent)) {
           y-=sign(global.walking_speed);
       }
       global.walking_speed = 0;
   }
   y -= global.walking_speed
 

Yal

🐧 *penguin noises*
GMC Elder
Yal, thanks for responding. How do you handle collisions with your knockback?
I just used normal collision events and put the code there :p

(to prevent knocked-back stuff from getting stuck on walls and other out-of-bounds areas I ran code each step to set hspeed/vspeed to 0 if position x+hspeed,y or x,y+vspeed was invalid, respectively)
 
Top