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

Legacy GM [Solved] Accelerative movement seems to be tricky

X

XirmiX

Guest
I've followed some tutorials in the past and checked back on one in order to create a basic platformer, as it seems I had forgotten the basics of how to make it all work over time, since I'm basically redoing my entire game (reason being that everything's just bunched up, so I just created a new file and I'll be porting anything I need from the old file to the new). This is not about my tank game, btw, for those who are familiar with that out there.

Long and short of it is that I am adding acceleration and deceleration to my movement and because of that, collision checking becomes quite tricky. I guess I could enable physics, but it might bring in unwanted control into the game later on, so I'm trying to keep that out of here. The tutorial I checked back on was the following:


Here's some important code:
Movable object's Create event
Code:
///Initial variables
//Variables for movement
horizontal_speed = 0;
vertical_speed = 0;

//hspeed = horizontal_speed;
//vspeed = vertical_speed;


minimal_vertical_acceleration = 1;
minimal_horizontal_acceleration = 1;

accelerative_horizontal_speed = 1; //Pixels per frame
accelerative_vertical_speed = 16; //Pixels per frame

max_horizontal_speed = 4; //Pixels per frame
max_vertical_speed = 16; //Pixels per frame

//Variables for collision
collisionObjects = ds_list_create();
ds_list_add(collisionObjects, obj_collisionbox);
collisionCheck = ds_list_find_value(collisionObjects, 0);
[/I]

Movable object's Step event
Code:
///Setting movement keys


KeyRight = keyboard_check(vk_right);
KeyLeft = keyboard_check(vk_left);
KeyUp = keyboard_check_pressed(vk_up);
KeyDown = keyboard_check_pressed(vk_down);

//Up key//
//Up key not pressed
if !KeyUp
{
    if place_meeting(x,y+1,collisionCheck)
    {
        vertical_speed = 0;
    }
    else
    {
        if vertical_speed != max_vertical_speed
        {
            vertical_speed += accelerative_vertical_speed;
        }
    }
}

//Up key pressed
if KeyUp
{
    if place_meeting(x,y+1,collisionCheck)
    {
        //Start jumping only after 4 frames
        alarm[0] = 4;
    }
}

y += vertical_speed;

//Up key//
//Up key not pressed
if !KeyUp
{
    if place_meeting(x,y+1,collisionCheck)
    {
        vertical_speed = 0;
    }
    else
    {
        if vertical_speed != max_vertical_speed
        {
            vertical_speed += accelerative_vertical_speed;
        }
    }
}

//Up key pressed
if KeyUp
{
    if place_meeting(x,y+1,collisionCheck)
    {
        //Start jumping only after 4 frames
        alarm[0] = 4;
    }
}

y += vertical_speed;

//Right key//
//Right key press
if KeyRight
{
    if place_meeting(x+horizontal_speed,y,collisionCheck)
    {
        while(!place_meeting(x+sin(horizontal_speed),y,collisionCheck))
        {
            x += minimal_horizontal_acceleration;
        }
        horizontal_speed = 0;
    }
    else if !place_meeting(x+horizontal_speed,y,collisionCheck)
    {
        if (horizontal_speed != max_horizontal_speed) && place_meeting(x,y+1,collisionCheck)
        {
            horizontal_speed += accelerative_horizontal_speed;
        }
        else if place_meeting(x,y+1,collisionCheck)
        {
            horizontal_speed = max_horizontal_speed;
        }
        else
        {
            horizontal_speed = horizontal_speed;
        }
    }
}

//Right key no press
if !KeyRight
{
    if place_meeting(x+horizontal_speed,y,collisionCheck)
    {
        horizontal_speed = 0;
    }
    else if !place_meeting(x+horizontal_speed,y,collisionCheck)
    {
        if horizontal_speed != 0
        {
            horizontal_speed -= accelerative_horizontal_speed;
        }
        else
        {
            horizontal_speed = 0;
        }
    }
}

//Left key//
//Left key press
if KeyLeft
{
    if place_meeting(x-horizontal_speed,y,collisionCheck)
    {
        while(!place_meeting(x+sin(horizontal_speed),y,collisionCheck))
        {
            x += minimal_horizontal_acceleration;
        }
        horizontal_speed = 0;
    }
    else if !place_meeting(x-horizontal_speed,y,collisionCheck)
    {
        if (horizontal_speed != -max_horizontal_speed) && place_meeting(x,y+1,collisionCheck)
        {
            horizontal_speed -= accelerative_horizontal_speed;
        }
        else if place_meeting(x,y+1,collisionCheck)
        {
            horizontal_speed = -max_horizontal_speed;
        }
        else
        {
            horizontal_speed = horizontal_speed;
        }
    }
}

//Left key no press
if !KeyLeft
{
    if place_meeting(x-horizontal_speed,y,collisionCheck)
    {
        horizontal_speed = 0;
    }
    else if !place_meeting(x-horizontal_speed,y,collisionCheck)
    {
        if horizontal_speed != 0
        {
            horizontal_speed += accelerative_horizontal_speed;
        }
        else
        {
            horizontal_speed = 0;
        }
    }
}

x += horizontal_speed;

Movable object's Alarm 0
Code:
vertical_speed += accelerative_vertical_speed;

if accelerative_vertical_speed != minimal_vertical_acceleration
{
    accelerative_vertical_speed = accelerative_vertical_speed / 2;
    alarm[0] = 1;
}

Problems that I am having is that the object slows down sometimes when moving horizontally near a wall, sometimes gets stuck in a wall, can't be moved in the opposite direction whilst next to the wall (so, left if there's a wall on the right and vice versa), the object doesn't decelerate horizontally when right or left key is let go of (but does so when the other horizontal movement control key is pressed, so, if I'm moving to the right and I press left, the character will move to the right slower over time and once it reaches 0, it starts moving to the right, which is intended) and the object doesn't jump at all. Another thing that might be of note is that I've purposefully made it so that you cannot move the object left or right whilst in mid-air (at least that works nicely).

And, I think I should also mention, before anyone brings this up that yes, I do understand my own code for the most part and what each thing is supposed to do. What I don't understand is why it does those glitches when it's not supposed to by my understanding.
 

TheouAegis

Member
Instead of checking for a collision at x+horizontal_speed, make it x+min(horizontal_speed + minimal_horizontal_acceleration, max_horizontal_speed).
 
X

XirmiX

Guest
Instead of checking for a collision at x+horizontal_speed, make it x+min(horizontal_speed + minimal_horizontal_acceleration, max_horizontal_speed).
Nope, the same bug seems to happen and there is still no deceleration when left or right is let go of :/

It's quite weird that it does that, I mean the logic is there, right? So how does it still interpret it as something entirely different?

EDIT: It seems that, apparently, I can just make the movable object collide with static objects by putting in a colliding event in the movable object and do all of this very simply:


However, although that could make things work out very quickly with barely any effort at all, it's not without cutting out some possible creativity and features or whatever the like and I've actually thought about adding some weird things to my game and the current type of code seems to be very friendly towards it (although very tedious to fix glitches with, unfortunately).
 
Last edited by a moderator:

Nux

GameMaker Staff
GameMaker Dev.
I can't help but think you're over complicating things a tad.
I've always thought of acceleration being a constant, anyway.

question:
Code:
if KeyRight
{
    if place_meeting(x+horizontal_speed,y,collisionCheck)
    {
        while(!place_meeting(x+sin(horizontal_speed),y,collisionCheck))
        {
            x += minimal_horizontal_acceleration;
        }
        horizontal_speed = 0;
    }
in that while loop did you mean to take the sine of horizontal speed? because this results in a floating point number, not a rounded integer.
 
X

XirmiX

Guest
I can't help but think you're over complicating things a tad.
I've always thought of acceleration being a constant, anyway.

question:
Code:
if KeyRight
{
    if place_meeting(x+horizontal_speed,y,collisionCheck)
    {
        while(!place_meeting(x+sin(horizontal_speed),y,collisionCheck))
        {
            x += minimal_horizontal_acceleration;
        }
        horizontal_speed = 0;
    }
in that while loop did you mean to take the sine of horizontal speed? because this results in a floating point number, not a rounded integer.
Hmm, I see what you mean and no, I don't want any floating point values for movement, although even removing that sin thing still makes the bugs mentioned previously occur (turning it from x+sin(horizontal_speed) to x+horizontal_speed) and I don't think the while loop would actually work too well here either, considering the if statement that the while loop is in... actually this just confused me even more :~

Gradual acceleration and deceleration is kind of important for my game. Also, strangely, even setting friction to a certain value doesn't make the thing slow down after letting go of the keys. And the jumping doesn't work either for some reason and... Ugh, this doesn't make sense and I don't get why.

Perhaps there's some easier way of implementing acceleration and deceleration as well as jumping, but without making collisions in such a way that you just drop in a collision event and be done with it, but instead make code-based checks on x and y axes? Although for me nothing's really coming to mind.
 
Code:
if KeyRight
{
if place_meeting(x+horizontal_speed,y,collisionCheck)
{
while(!place_meeting(x+sin(horizontal_speed),y,collisionCheck))
{
x += minimal_horizontal_acceleration;
}
horizontal_speed = 0;
}
Change sin to sign. sin is trig (-1 thru 1) where sign gives (-1,0,1).
 

Nux

GameMaker Staff
GameMaker Dev.
I think you should proof read your code, make sure all sign functions are spelt like "sign" and not "sin" etc...
 
X

XirmiX

Guest
Did that, still, nothing changes at all; still all the same bugs :/

Edit: I made an attempt at making the movable object/playable character object to jump (vertical movement) in such a way so that it is moved 16 pixels up, then the next frame 14 pixels up, and so on and so froth until it reaches 0, after which it it starts to do the opposite and go 2 pixels down, then the next frame 4 pixels, then 6 and so forth until it reaches maximum acceleration speed or hits the floor (is 1 pixel above the ground). I've also, of course, tried to make it so that the code would check if at the current speed that the object is moving upwards or downwards would meet a wall, either above or below. So, here's the old code that I showed you before:
Code:
//Up key//
//Up key not pressed
if !KeyUp
{
   if place_meeting(x,y+1,collisionCheck)
    {
        vertical_speed = 0;
    }
    else
    {
        if vertical_speed != max_vertical_speed
        {
            vertical_speed += accelerative_vertical_speed;
        }
    }
}

//Up key pressed
if KeyUp
{
    if place_meeting(x,y+1,collisionCheck)
    {
        //Start jumping only after 4 frames
        alarm[0] = 4;
    }
}

y += vertical_speed;

//Up key//
//Up key not pressed
if !KeyUp
{
    if place_meeting(x,y+1,collisionCheck)
    {
        vertical_speed = 0;
    }
    else
    {
        if vertical_speed != max_vertical_speed
        {
            vertical_speed += accelerative_vertical_speed;
        }
    }
}

//Up key pressed
if KeyUp
{
    if place_meeting(x,y+1,collisionCheck)
    {
        //Start jumping only after 4 frames
        alarm[0] = 4;
    }
}

y += vertical_speed;
And here's the code that I changed it to:
Code:
if place_meeting(x,y+1,collisionCheck)
{
    if KeyUp
    {
        while accelerative_vertical_speed != 0
        {
            if !place_meeting(x,y+accelerative_vertical_speed,collisionCheck)
            {
                y -= accelerative_vertical_speed;
                accelerative_vertical_speed -= 2;
            }
            else
            {
                y -= distance_to_object(collisionCheck);
            }
        }
        if accelerative_vertical_speed == 0
        {
            while (accelerative_vertical_speed != max_vertical_speed) || (!place_meeting(x,y-accelerative_vertical_speed,collisionCheck))
            {
                y += accelerative_vertical_speed;
                accelerative_vertical_speed -= 2;
            }
            if place_meeting(x,y-accelerative_vertical_speed,colisionCheck)
            {
                y += distance_to_object(collisionCheck);
            }
        }
    }
}
else
{
    if !place_meeting(x,y-accelerative_vertical_speed,collisionCheck)
    {
        accelerative_vertical_speed = max_vertical_speed;
        y += accelerative_vertical_speed;
    }
    else
    {
        y += distance_to_object(collisionCheck);
    }
}
Yet still, it doesn't jump at all, sadly and I have no idea why :( although the falling works (not exactly the way I want it, but it's fine at the moment).
 
Last edited by a moderator:

Nux

GameMaker Staff
GameMaker Dev.
I'm pretty sure it's because you're using while loops incorrectly.
Technically, you are jumping... it's just all happening in 1 step. To fix this, try change all the while loops in this code to if statements.

Falling works correctly because there isn't a while loop:
Code:
else
{
   if !place_meeting(x,y-accelerative_vertical_speed,collisionCheck)
    {
        accelerative_vertical_speed = max_vertical_speed;
        y += accelerative_vertical_speed;
    }
    else
    {
        y += distance_to_object(collisionCheck);
    }
}
Above this you had a collision check for the floor, because there isn't a floor, you fall as you desired.
 
X

XirmiX

Guest
I'm pretty sure it's because you're using while loops incorrectly.
Technically, you are jumping... it's just all happening in 1 step. To fix this, try change all the while loops in this code to if statements.

Falling works correctly because there isn't a while loop:

Above this you had a collision check for the floor, because there isn't a floor, you fall as you desired.
Just changing While loops to If statements doesn't improve or change anything if we take in mind the code that I posted above. I tried a code with using for loops instead of while and for whatever reason the jumping was instant as well and for whatever reason, a while loop that I had set was doing its stuff one step at a time and not all at once for whatever reason (this bit was for horizontal movement whilst being near a wall and moving towards is), so I thought I'd swap the train of thought and, well, it seems to be wrong again. Something isn't right here...

Either way, I've gone to a point of becoming so enraged, I just want to quit completely. Just this stupid piece of crap that is the most basic movement done differently than usual (no setting up of collision event and instead doing things manually via code, whilst retaining acceleration and deceleration in jumping/falling (vertical movement) AND horizontal movement) is pissing me off so much, I just can't even. Perhaps I'll just describe exactly what I am trying to achieve with my movement and may be then we'll get somewhere (although, I want to do the code mainly myself for the sake of learning and, well so I don't get problems, considering I'm trying to make a game that I will later on put for sale... I honestly don't know what to do at this point or how):

* Collides with walls (using code, NOT using collision event at all, under any circumstance. Especially considering that I'm checking for collision objects within a list and not individual ones, because that would be a drag for some stuff that I'm doing).
* Acceleration and deceleration in horizontal movement (so, lets say maximum horizontal speed could be -4 and 4, depending on which direction you move and whilst you're accelerating/decelerating, you would become -1/1 point of speed faster).
* Jumping and falling acceleratively (I am on the ground. I press the jump key. I move up 16 pixels. I move up 14 pixels. I move up 12 pixels. I move up 10 pixels. I move up 8 pixels. I move up 6 pixels. I move up 4 pixels. I move up 2 pixels (this is all if at no point I am colliding (y+1) with a collision object above me. Otherwise, this would be interrupted, I would move whatever amount of pixels I need in order to be y+1 from the wall and then start doing the whole process as here, but backwards, so starting from -2 pixels, then -4 pixels etc. until I hit a collision object below me or -16 pixels, which just continues until I hit a collision object below me). If I reach 0 pixel movement upwards and have not collided with a wall, I start to move downwards, so -2 pixels, -4 pixels etc. until I hit a collision object below or start to move at 16 pixels per frame downwards until I hit a collision object below me. At which point the vertical movement speed would be 0 and I could jump again. Also notice how vertical acceleration is going in 2s).

Fairly simple stuff, doesn't 💩💩💩💩ing work at all. There's no tutorials on this specific kind of platformer logic via programming. The only tutorial that I've found that achieves this exact thing uses Collision event instead of doing it via code, which is something I do not want to do because of reasons mentioned earlier. Oh, and the tutorial also didn't have accelerative/decelerative vertical speed; it was just a constant 4 pixels up and down per frame.
 
X

XirmiX

Guest
Well, it seems I've figured it out... after many trials and logical bugs, these two tutorials solved it for me:
For accelerative/decelerative vertical movement


For accelerative/decelerative horizontal movement


Just that apparently you need to make it so that, for whatever reason, if you're adding horizontal acceleration, remove the "-" from the keyboard_check(vk_left). Why? I have no goddamn idea, but this will make sure that you actually move left and not not move left. May be someone can give an insight on this? Because the non-accelerative horizontal movement does need the "-" there.
 
B

Ben Hubble

Guest
Well, it seems I've figured it out... after many trials and logical bugs, these two tutorials solved it for me:
For accelerative/decelerative vertical movement


For accelerative/decelerative horizontal movement


Just that apparently you need to make it so that, for whatever reason, if you're adding horizontal acceleration, remove the "-" from the keyboard_check(vk_left). Why? I have no goddamn idea, but this will make sure that you actually move left and not not move left. May be someone can give an insight on this? Because the non-accelerative horizontal movement does need the "-" there.
keyboard_check returns boolean (true or false/0 or 1), and putting a - before it will invert it so instead of returning 0 or 1 it will instead return 0 or -1.
In the non accelerative movement, you're setting the speed with:
Code:
move = key_left + key_right;
hsp = move * movespeed;
So, if you're holding down right but not left, it'd be 0 + 1, which is 1, which is then multiplied by movespeed, which i believe was 4. So, 1*4 would be 4. You then add that to the x coordinate and move 4 pixels to the right. if you're holding down left and not right, it'd -1 + 0, which is -1. -1 * 4 = -4. Which is then added to the x coordinate and so your player moves 4 pixels to the left. If you're holding both, it's 0 because -1 + 1 = 0, so you move nowhere, same with holding none.

However, in the second video there is a few if statements asking if(rkey) and if(lkey) like this:
Code:
if(rkey) {
     if(hspd < spd) {
           hsp += fric;
     }else{
           hsp = spd;
     }
}

if(lkey) {
     if(hspd > spd) {
           hsp -= fric;
     }else{
           hsp = -spd;
     }
}
If you set lkey to -keyboard_check(vk_left), then the if statement would never be true and wouldn't run. This is because lkey would be -1 or 0, but for it to run, lkey needs to be 1 (which is the same as writing true).

Hope this helps!
 
Top