• 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 Precise Enemy Knockback

D

dsosa

Guest
Hello! This is my first post on this forum. I haven't done any programming in a long time so I'm very rusty, not that I was a professional before or anything. My code is very messy and disorganized but the game operates pretty well so far. But I've just been having trouble trying to get any sort of knockback system working adequately. I want the enemy to be sent in a specfic direction with a specific amount of force when it collides with the hitbox object, but for now after so many attempts I don't even really know where to start. Help would be very much appreciated.
 

TheouAegis

Member
For wanting so many specific things that happen, you haven't specified what exactly you want to happen and what specifics you want specifically.
 

samspade

Member
Hello! This is my first post on this forum. I haven't done any programming in a long time so I'm very rusty, not that I was a professional before or anything. My code is very messy and disorganized but the game operates pretty well so far. But I've just been having trouble trying to get any sort of knockback system working adequately. I want the enemy to be sent in a specfic direction with a specific amount of force when it collides with the hitbox object, but for now after so many attempts I don't even really know where to start. Help would be very much appreciated.
At a minimum you need to post your movement and collision code. Describing some general things about your game might be good as well (top down, side scroller, etc.) as well as describing how you're detecting collisions with this object and how you (ideally) want to determine the force and direction.
 
D

dsosa

Guest
Code:
/// @description Control player character

//Step Event

var k_left  = keyboard_check(ord("A"));
var k_leftr = keyboard_check_released(ord("A"));
var k_right = keyboard_check(ord("D"));
var k_rightr = keyboard_check_released(ord("D"));
var k_jump  = keyboard_check_pressed(vk_space);
var k_down = keyboard_check(ord("S"));
var k_downp = keyboard_check_pressed(ord("S"));
var k_downr = keyboard_check_released(ord("S"));
var k_dash = keyboard_check_pressed(vk_shift);
var k_punch = keyboard_check_pressed(ord("P"));
var k_knee = keyboard_check_pressed(ord("O"));
var k_kick = keyboard_check_pressed(ord("I"));

var spd_wanted = 0; //The wanted horizontal speed for this step
var haccl = 0 //Set horizontal acceleration

if(k_left && crouchstate == 0 && attackstate == 0 && dashstate == 0 && !k_down)
{
    image_xscale = 1;
    haccl -=0.25;
    spd_wanted -= 2;
    if (speed_x >= spd_wanted){
    haccl +=0.25;   
    }
    if (place_meeting(x,y+1,oWall) && !k_down){
    
    image_speed = abs(speed_x)*0.85;
    sprite_index = sJotaroWalk;   
    pstate = "walk";
    }
}

if(k_right && crouchstate == 0 && attackstate == 0 && dashstate == 0 && !k_down)
{   
    image_xscale = -1;
    haccl +=0.25;
    spd_wanted += 2;
    if (speed_x <= spd_wanted){
    haccl -=0.25;   
    }
    if (place_meeting(x,y+1,oWall) && !k_down){
    image_speed = abs(speed_x)*0.85;
    sprite_index = sJotaroWalk;   
    pstate = "walk";
    }
}

if (k_downp && place_meeting(x,y+1,oWall) && dashstate = 0 && attackstate = 0){
image_index = 0;

}

if (k_down && place_meeting(x,y+1,oWall) && dashstate = 0 && sprite_index != sJotaroCrouchBackhand && attackstate = 0){

sprite_index = sJotaroCrouch
image_speed = 0.9;
crouchstate = 1;
haccl = 0;
spd_wanted = 0;
pstate = "crouch";
if (stam < maxstam){
stam += 0.5   
}

}


if (k_downr && crouchstate == 1 && dashstate == 0 && attackstate == 0){
image_index = 0;
sprite_index = sJotaroStandUp;   
}


if(k_dash && speed_x != 0 && dashstate == 0 && pstate != "dash" && attackstate = 0){
dashstate = 1;
image_index = 0;
}
if (dashstate == 1){
pstate = "dash";
stam -=2;
if(place_meeting(x,y+1,oWall)){
sprite_index = sJotaroDash;
image_speed = 1.05;
}
if(!place_meeting(x,y+1,oWall)){
sprite_index = sJotaroAirdash
image_speed = 1.05;
}
if (image_xscale == -1){
haccl = 0.8;
}
if (image_xscale == 1){
haccl = -0.8;
}
}
if (dashstate == 0){
pstate = "idle";
haccl = 0;

}

if (!k_right && !k_left && place_meeting(x,y+1,oWall) && !k_jump && dashstate = 0 && !k_down && sprite_index != sJotaroStandUp && sprite_index != sJotaroPunch && sprite_index != sJotaroKnee && sprite_index != sJotaroKick && sprite_index != sJotaroCrouchBackhand){
image_speed = 1;
sprite_index = sJotaroIdle;
pstate = "idle";
crouchstate = 0;
attackstate = 0;
}

if (k_punch && dashstate == 0 && place_meeting(x,y+1,oWall) && attackstate == 0 && crouchstate == 0){
attackstate = 1;
image_index = 0;
image_speed = 1.05;
sprite_index = sJotaroPunch;
instance_create_depth(x,y,0,oPunchHitbox);
}
if (k_knee && dashstate == 0 && place_meeting(x,y+1,oWall) && attackstate == 0){
attackstate = 1;
image_index = 0;
image_speed = 1.05;
sprite_index = sJotaroKnee;
instance_create_depth(x,y,0,oKneeHitbox);
}
if (k_kick && dashstate == 0 && place_meeting(x,y+1,oWall) && attackstate == 0){
attackstate = 1;
image_index = 0;
image_speed = 1.05;
sprite_index = sJotaroKick;
instance_create_depth(x,y,0,oKickHitbox);
}
if (k_punch && dashstate == 0 && place_meeting(x,y+1,oWall) && attackstate == 0 && crouchstate == 1){
attackstate = 1;
image_index = 0;
image_speed = 1.05;
sprite_index = sJotaroCrouchBackhand;
instance_create_depth(x,y,0,oBackhandHitbox);
}


if (!place_meeting(x,y+1,oWall) && sprite_index != sJotaroJump && dashstate = 0){
if (speed_y > 0){
image_speed = 1.05;
sprite_index = sJotaroFall;
}
if (speed_y <= 0){
image_speed = 1.05;
sprite_index = sJotaroAirborne;
}
crouchstate = 0;
}

speed_x += haccl; //Set the horizontal speed based on the wanted speed

speed_y += grav; //Apply gravity

if (dashstate = 0 && stam < maxstam){
stam +=1;   
}

//Horizontal collision
if(place_meeting(x + speed_x, y, oWall))
{
    while(!place_meeting(x + sign(speed_x), y, oWall))
    {
    x+=sign(speed_x);
    }
    speed_x = 0;
}
x += speed_x;

//Vertical collision
if(place_meeting(x, y + speed_y, oWall))
{
    while(!place_meeting(x, y + sign(speed_y), oWall))
    {
    y+=sign(speed_y);
    }
    speed_y = 0;
}
y += speed_y;

/*var spd_wanted = 0; //The wanted horizontal speed for this step

*/
speed_x += (spd_wanted - speed_x) * 0.15; //Smoothly accelerate / decelerate to the wanted speed

var xsp = round(speed_x); //Turn the theoretical value into an integer for collision and movement

//Horizontal collision
if(place_meeting(x+xsp, y, oWall))
{
    while(!place_meeting(x+sign(xsp), y, oWall))
    {
    x += sign(xsp);
    }
    xsp     = 0;
    speed_x = 0; 
}
x += xsp;

speed_y += grav; //Apply gravity

if(k_jump && place_meeting(x, y + 1, oWall))
{
    if(dashstate = 0) {
    image_speed = 1.2/*speed_y*8*/;
    image_index = 0;
    sprite_index = sJotaroJump;
    }
    if (crouchstate = 1) {
    crouchstate = 0;
    speed_y = -8.5
    pstate = "jump";
    } else {
    speed_y = -7;
    pstate = "jump";   
  }
}

var ysp = round(speed_y); //Turn the theoretical value into an integer for collision and movement

//Vertical collision
if(place_meeting(x, y + ysp, oWall))
{
    while(!place_meeting(x, y+sign(ysp), oWall))
    {
        y+=sign(ysp);
    }
    ysp     = 0
    speed_y = 0; 
}
y += ysp;
Sorry about that, here's everything in my step event. I made another object that can be controlled with the arrow keys and that's what I'm trying to get to work with the hitboxes. I made sprites for the hitboxes that coincide with the animations, and I'm using those for the hitbox objects.

For specifics, I wanted to try and make the punch hitbox send the object diagonally downward with strong force, and knee hitbox diagonally upward with lighter force, the kick hitbox forward with strong force, and the backhand hitbox diagonally upward (angled more upward than the knee) with strong force.
 

samspade

Member
Admittedly, I'm not sure why you have speed_x and speed_y and xsp and ysp. And why you change your x/y position twice based on both of those values. It seems like that would add a lot of unnecessary speed to the character. I would remove one of these.

But otherwise, looking at this, it seems like you have a side scroller and that your movement is based on acceleration - or your new location equals your old location plus velocity, and your velocity equals your current velocity plus your current acceleration.

In pseudo code:

acceleration = 0;
//do things to add to acceleration
//probably add in friction
velocity += acceleration;
location += velocity; //after checking for collisions

This type of system is pretty easy to add knockback, or really just any movement, too. You should be able to simply add it directly to velocity (which in your case is either speed_x/y or x/ysp or both, see first comment).

So, here is an example script:

Code:
scr_add_movement_to_player(force, direction);
/// @description Add movement to Player
/// @param force
/// @param direction

//translate force and direction (which is a representation of a vector as angle and magnitude)
//into an x and a y (which is a representation of the same vector using grid space)
var x_force = lengthdir_x(argument0, argument1);
var y_force = legntdhir_y(argument0, argument1);

with (obj_player) {
    speed_x += x_force;
    speed_y += y_force;
}
Now you can call that script wherever you want to add force. Again, without fully understanding your system, no guarantees that this would work exactly but as long as you're not setting your velocity to zero each step this should work.

Edit: if the vector stuff doesn't make sense, I would recommend watching this video:
 

TheouAegis

Member
Wait, you just want each of the four separate hitboxes to affect enemies differently, right? I mean, you already have distinct hitbox objects, so give each hitbox its own code. If it collides with an enemy, reduce the enemy's hp and if that kills the enemy, set the hsp and vsp of the enemy as is appropriate, and put the enemy in a "knockback" state so it doesn't run its normal code while flying through the air.
 
Top