Windows Wall Jumping

D

DarthTenebris

Guest
Hello there my fellow programmers!
So I'm still working on my game, and I need help implementing a feature: wall jumping.
I followed a tutorial on youtube and put the code in, however, the code he (the tutorial) was using introduced a bug/glitch I ever experienced before, and clearly I didn't want it. So I decided to try to modify it and see if it works, but I can't get it to work. Here's some code:
Code:
if ((place_meeting(x,y + 1,obj_blockPar)) or ((place_meeting(x - 1,y,obj_blockPar)) && (keyboard_check_pressed(ord('D')))) or ((place_meeting(x + 1,y,obj_blockPar)) && (keyboard_check_pressed('A'))))
    {
    canJump = true;
    }
else
    {
    canJump = false;
    }
Link to the tutorial:
(4:18)

I understand what the code does, yet it doesn't work...
Can anyone help me fix it up?
 

jo-thijs

Member
I think the problem lies in this part not using ord:
keyboard_check_pressed('A')

Also, you can condense your code to:
Code:
canJump = (keyboard_check_pressed(ord('D')) && place_meeting(x - 1, y, obj_blockPar)) || (keyboard_check_pressed(ord('A')) && place_meeting(x + 1, y, obj_blockPar)) || place_meeting(x, y + 1, obj_blockPar);
 
D

DarthTenebris

Guest
@jo-thijs I fixed the ord() and it' still not working. And I need that canJump variable to be either true or false, not code
Jumping:
Code:
if keyboard_check_pressed(ord('W'))
        {
        if canJump = true
            {
            vspeed -= jumpHeight;
            }
        }
I'm afraid if I change/condense it, the whole thing will break. I don't think I want to risk that.
 

jo-thijs

Member
My code still leaves canJump with either the value true or false,
it is really equivalent to what you've used and it won't break anything.
If you feel like it is less readable though, go ahead and leave it the way it was.

Anyway, if there's still a glitch, you will need to specify what the glitch is that happens.
We don't know what happens that you don' want to happen.
 
D

DarthTenebris

Guest
@jo-thijs Nah, I feel it is less readable lol. So I'll leave it be. :)
As for the glitch, it only happens if I use the code from the tutorial. Since I modified it a bit, it doesn't happen anymore.
However, my fix was to OP... xD Now I can't wall jump, ever.

The glitch is that when I am near a wall, then I spam click the jump button but at the same time holding the proper button (to face the wall), I can fly... I'm proud that I can fly... Show you the best of mine... xD

Anyway, that is clearly unwanted.
It is sometimes possible to wall jump, although it is very rare and very hard.
I managed to get it in the first place, but with the glitch present.
 

jo-thijs

Member
Ok, I actually did not look at the tutorial before.
It's not really that great and it does not show what code is put in the collision event.

Anyway, I'm still not sure what the glitch is exactly.
What buttons do you press at what moments with what code to get what result?

I can see how the code you originally posted would make it difficult to wall jump,
as you need to be frame perfect.

You need to be directly next to the wall and press away from the wall at the exact frame you are jumping to wall jump,
which is nearly impossible to pull off.

I would advice not to force the player to press away from the wall to wall jump,
but rather to give the player some force away from the wall when he wall jumps
and allow a wall jump whenever the player is pushing towards the wall.
This results in much smoother controls in my opinion.

How to best implement that depends on how your movement system works though.
 
D

DarthTenebris

Guest
@jo-thijs
I would advice not to force the player to press away from the wall to wall jump,
but rather to give the player some force away from the wall when he wall jumps
and allow a wall jump whenever the player is pushing towards the wall.
This results in much smoother controls in my opinion.

How to best implement that depends on how your movement system works though.
Well, can you show me some code to do that?
My movement system is the standard [if keyboard_check() && place_free() x += spd] system.

Note: Do you know how to post project files (.gmx , .gmz , etc) to the forums?
 
T

TDSrock

Guest
Simply by adding your own vertical_speed and horizontal_speed values.
Then you can just change those as you find appropriate.
At the end of your script you would actually finalize the movement by saying :
Code:
x+= horizontal_speed;
y+= vertical_speed;
This makes it easy to implement momentum too if you were to ever want too.
 

jo-thijs

Member
I don't think you can post them directly to the forum, but what you can do is:
Export the project as a gmz file (File > export project), upload them somewhere (mediafire, onedrive, dropbox, google drive, box, ...)
and share the link to the gmz file.

I see you're using place_free, which meens you're using solid objects, which is bad practice.
I recommend getting rid of solids and using place_meeting instead of place_free.

Now, as to how to implement it, TDSrock gave the most elegant solution.
You don't let the player decide the speed, but the acceleration of the object.
This way, you just have to set the horizontal speed to a certain value when wall jumping.

However, if you insist on giving the player instantly spd as speed,
than you can also work with a timer variable that keeps pushing the player away from the wall for a certain amount of time.

Which of the options sounds better to you?
 
D

DarthTenebris

Guest
@TDSrock I don't really get what good would that do. All I know is that a x += spd variable is good enough for left-right movement, and vspeed -= jumpHeight variable is good enough for jumping. Hmm...

@jo-thijs
I see you're using place_free, which meens you're using solid objects, which is bad practice.
Umm, can you tell me why? It's been working quite well for me.

You don't let the player decide the speed, but the acceleration of the object.
This way, you just have to set the horizontal speed to a certain value when wall jumping.

However, if you insist on giving the player instantly spd as speed,
than you can also work with a timer variable that keeps pushing the player away from the wall for a certain amount of time.
I don't understand what you mean... :confused:

[EDIT]
Does this work?
https://drive.google.com/open?id=0B4upgMXZzv-7WlVrU29EWVlfTVE
 
Last edited by a moderator:

jo-thijs

Member
It's bad practice because solids do a lot of unwanted stuff people are often not aware of,
which causes issues later on in the project.

But even worse, they take away control over how things happen.
place_meeting in combination with parent objects will give you much more flexibility and control over your project.

And to my explenation, I guess I wasn't very clear.

You currently just add a constant to the x coordinate of the player for as long as the key for it is held down.
However, TDSrock and I were suggesting that you let spd change as well.

You could have something like:
Code:
var acc = 0.5;
var maxspd = 4;
spd = clamp(spd + (keyboard_check(vk_right) - keyboard_check(vk_left)) * acc, -maxspd, maxspd);

if place_meeting(x + spd, y, obj_wall) {
    while !place_meeting(x + sign(spd), y, obj_wall)
        x += sign(spd);
    spd = 0;
} else
    x += spd;
And if you don't like that,
you can set a variable walljumpTime to 10 when you wall jump
and every step that variable walljumpTime is not 0, you can decrease it by 10 and move the playeraway from the wall.
To know which direction this is, you store the direction in a variable as well.
 
D

DarthTenebris

Guest
It's bad practice because solids do a lot of unwanted stuff people are often not aware of,
which causes issues later on in the project.

But even worse, they take away control over how things happen.
place_meeting in combination with parent objects will give you much more flexibility and control over your project.

And to my explenation, I guess I wasn't very clear.

You currently just add a constant to the x coordinate of the player for as long as the key for it is held down.
However, TDSrock and I were suggesting that you let spd change as well.

You could have something like:
Code:
var acc = 0.5;
var maxspd = 4;
spd = clamp(spd + (keyboard_check(vk_right) - keyboard_check(vk_left)) * acc, -maxspd, maxspd);

if place_meeting(x + spd, y, obj_wall) {
    while !place_meeting(x + sign(spd), y, obj_wall)
        x += sign(spd);
    spd = 0;
} else
    x += spd;
And if you don't like that,
you can set a variable walljumpTime to 10 when you wall jump
and every step that variable walljumpTime is not 0, you can decrease it by 10 and move the playeraway from the wall.
To know which direction this is, you store the direction in a variable as well.
:confused::confused::confused:
I am well confused. I don't mess around with these kinds of codes. I'm somewhat a beginner-intermediate person, I still have a lot of stuff to learn...
The first thing I did to learn GML was to look at an example file, and try to find the GML equivalent of the DnD actions. Fact: I don't understand 2d arrays. Not ds_ functions either. The projects I make are usually platformers, or some-kind-of-game-that-does-not-need-physics games.

Back to the topic, mind explaining how the code works? Btw does the link work? https://drive.google.com/open?id=0B4upgMXZzv-7WlVrU29EWVlfTVE
 

jo-thijs

Member
In GameMaker, 2D arrays are just simply arrays of arrays.
If you do a[x, y], it will reference the yth element of the xth 1D array the 2D array a contains.

The ds functions are used for implementing specific common data structures.
They have certain things in common:
You create a new data structure by a ds_*_create(...) function.
This function returns an identifier, a unique number to reference this data structure.
Further operations on data structures are performed by ds_*_*(ds_id, ...) functions,
where ds_id is the identifier as returned by ds_*_create(...).
Then you destroy them by ds_*_destroy(ds_id).
If you don't do this, they will keep existing for the duration your game is active and it will create memory leaks.

The code I made first creates 2 temporary variables: acc(elerate) and maxspd.
It then updates spd, depending on user input.

keyboard_check(...) returns 1 if the given key is held down and it returns 0 otherwise.
This means that (keyboard_check(vk_right) - keyboard_check(vk_left))
will return 1 if the player is holding only the right arrow key,
-1 if he is only holding the left arrow key and 0 otherwise.
Multiplying this with acc will give a horizontal acceleration in the direction the player is inputting.

This is added to spd and clammed in the boundaries defined by maxspd.
clamp(x, lower, upper) is equivalent to min(max(x, lower), upper) (at least if lower <= upper).
This all is the new value of spd.

Then I check if the player would collide with obj_wall if he'd move spd amount horizontally.
If he wouldn't, then spd is added to x, otherwise some collision code is executed.
In this collision code, we move the player pixel by pixel towards the wall object,
until the next pixel would collide with the wall.
This gives a pixelperfect collision code (the error is less than 1 pixel).
spd is then set to 0 to take away momentum.

The link you provided works, but it is tedious to download every file individually.
It's nicer to upload the gmz file of your project (file > export project).
 
D

DarthTenebris

Guest
@jo-thijs
Thank you for the explanation on everything bro! :D

Updated the link (don't worry, it's a compressed .gmz now) :) : https://drive.google.com/open?id=0B4upgMXZzv-7NE1SZGY4MHo5UzA
I hate to admit it, I don't have the brain of the flash, and I'm not a smartty-pants either. I usually take a long time to understand/memorize something, but could you perhaps modify my project (as much comments as possible please :) ) and re-upload it somewhere (preferably mediafire or google drive), so I can take a look at the changes necessary?
 
T

tserek

Guest
How about this? Pretty simple platformer code with unlimited walljumps, similair to Super Meat Boy. This is something you can start work with. Works fine if your character and walls are 32x32 pixel sprites without precise check.

Player create:
Code:
vsp=0;
walljump=false;
Player step:
Code:
// variables
jump=15;
grav=0.9;
movespeed=4;

// inputs
key_right = keyboard_check(vk_right);
key_left = -keyboard_check(vk_left);
key_jump = keyboard_check_pressed(vk_space);

// react to inputs
if !walljump
{
move = key_left + key_right;
hsp = move * movespeed;
}

// walljump in process
if walljump
{
x+=hsp;
if key_right
or key_left
or !place_free(x+hsp,y)
{
  walljump=false;
}
}

// trigger jumps
if key_jump
{
// regular jump
if !walljump
{
  if vsp=0
  {
  if place_free(x,y-1)
  {
  vsp=-jump;
  }
  }
}
// begin walljump left
if !place_free(x+1,y)
&& place_free(x-1,y)
{
  hsp=-movespeed;
  walljump=true;
  vsp=-jump;
}

// begin walljump right
if !place_free(x-1,y)
&& place_free(x+1,y)
{
  hsp=movespeed;
  walljump=true;
  vsp=-jump;
}
}

// horizontal movement
if place_free(x+hsp,y) {x+=hsp;}

// vertical movement
vsp+=grav;
if vsp>0 {move_contact_solid(270, vsp);} // positive vsp, falling
if vsp<0 {move_contact_solid(90, vsp *-1);} // negative vsp, jumping

// reset values
if !place_free(x,y+1)
or !place_free(x,y-1)
{
vsp=0;
walljump=false;
}
 
Last edited by a moderator:
D

DarthTenebris

Guest
@jo-thijs Thanks for the "modding" on the project!
Looking at the gameplay, I can see that if you hug a wall (pressing the appropriate button, A or D) then spam the jump button, the player is launched off to the other direction. Clearly I don't want that, and therefore flipped my brain over finding a solution that won't do this. I managed to do it before, however, as you said, needs to be frame perfect.
You need to be directly next to the wall and press away from the wall at the exact frame you are jumping to wall jump,
which is nearly impossible to pull off.
Fact #1: Usually I insist on exactly something until I manage to give up. :p

I have an idea, what if I put a timer to when the player is next to a wall, and make it so that the player is able to re-jump if the alarm/timer is still active? Do you think it would work? Fact #2: I hate trying things. I'd do it only if I'm in the mood to try it, or if I'm sure it will succeed. :(

Thank you very much for the time and effort you put in helping me tho :D:D:D
 

jo-thijs

Member
Whether it would work?
Of course it will work, but it will feel quite different.
If it is the style you're going for, then do it!

The only thing that might be difficult with that, is to balance the timer.
If you'd give the player 10 steps to react, it will correspond to 1/3 of a second.
This is a decent react time, but in this time, the player will have moved 50 pixels away from the wall,
which is about one and a halve block, which would look awkward.

This could be solved by making the player stick to the wall for a couple of steps when he's not on the ground and is hugging the wall.

Anyway, I'm sure you'll get something with it!
 
D

DarthTenebris

Guest
Fact #1: Usually I insist on exactly something until I manage to give up. :p
I found a solution! The simplest way to fix it is...
Don't implement a wall jump feature. xD *facepalm*

I'm too drained to go about trying things.

Thank you for all you help and support throughout the process of me trying to add wall jump (even though it didn't end well). I really appreciate it.
I'll post if the project is playable! You guys are awesome! :cool:
 

WillB777

Member
I am experiencing the exact same troubles. I don't know how to make a wall jump code or where to put it.

This is the step event for the player:

if (hascontrol)
{
key_left = keyboard_check(vk_left) || keyboard_check(ord("A"));
key_right = keyboard_check(vk_right) || keyboard_check(ord("D"));
key_jump = keyboard_check_pressed(vk_up) || keyboard_check(ord("W"));
key_down = keyboard_check(vk_down) || keyboard_check(ord("S"));

var move = key_right - key_left;

hsp = move * walksp;

vsp = vsp + grv;

if (place_meeting(x,y+1,oWall)) && (key_jump)
{
vsp = -10;
}


if(place_meeting(x+hsp,y,oWall))
{
while (!place_meeting(x+sign(hsp),y,oWall))
{
x = x + sign(hsp);
}
hsp = 0;
}
}

x = x + hsp;

if(place_meeting(x,y+vsp,oWall))
{
while (!place_meeting(x,y+sign(vsp),oWall))
{
y = y + sign(vsp);
}
vsp = 0;
}


y = y + vsp;

if (!place_meeting(x,y+1,oWall))
{
sprite_index = sRaymondA;
image_speed = 0;
if (sign(vsp) > 0) image_index = 1; else image_index = 0;
}
else
{
image_speed = 1;
if (hsp == 0)
{
sprite_index = sRaymond;
}
else
{
sprite_index = sRaymondR;
}
}

if (hsp != 0) image_xscale = sign(hsp);


Create event for the player:

hsp = 0;
vsp = 0;
grv = 0.4;
walksp = 5;
hascontrol = true;
key_down = 0;
 
Top