Legacy GM Custom Simple Platformer Code; requesting tips on adjusting

Calvert

Member
Hello, you can call me Calvert, and I am almost totally inexperienced in programming. Especially when it comes to making a platformer engine with gravity and pixel-perfect movements/collision.

Like many people here, I have dreams to make some great games. Since I'm inexperienced with GML, I'm working on a minimalist/micro platformer game with a 4x4 tileset to improve my skills. My goal right now is to make a solid gravity system with pixel-perfect collision. I want a character that can run and jump around a room without having collision issues. This is critical, due to the micro-resolution I am going for.

I have tried many of the platformer codes that all of the "popular Gamemaker experts" have made, but as soon as I want to make some additions to the code I find myself incapable due to not fully understanding it, or I find out that the framework needs to be totally re-written if I am going to add what I want to add. I always end up working with a gamemaker file that is full of random code that doesn't work and it becomes frustrating.

So, today I have decided to create my own platformer from scratch. This way, I can get help from you (the community) without being totally confused, because the code we are working with is code that I'm familiar with. My code is straight-up amateur, basic and embarrassing, but hey, that's okay. We all need to start somewhere.

I started by adding framework for state machines. I don't understand much about them, but I hear it's helpful to have in the long run. Besides having a state machine system that I'm not even really utilizing yet, I have an object that can move horizontally until it hits a wall, falls if it is not standing on a solid object and it can jump. The jumping feels totally unnatural at the moment, so that's what I'm mainly seeking guidance on tweaking right now. it jumps super fast and doesn't go very high. Keep in mind that I have set many values in this system to be very low, because the game is working with a 4x4 grid.

obj_player create event:
Code:
grav = 0.5;
spd = 0.5

state = states.basic;
obj_player step event:
Code:
switch (state)
{
    case states.basic: scr_player_basic(); break;
}
I have two main scripts at the moment. One handles inputs and some basic variables and the other handles the player's object movement.

scr_player_state:

Code:
// Get Keys
key_left = keyboard_check(vk_left);
key_right = keyboard_check(vk_right);
key_down = keyboard_check(vk_down);
key_up = keyboard_check_pressed(vk_up);
key_action = keyboard_check_pressed(ord("X"));

//Get Position
position_ground = (place_meeting(x,y+1,obj_solid));
position_air = (!place_meeting(x,y+1,obj_solid));
position_solidl = (!place_meeting(x-1,y,obj_solid));
position_solidr = (!place_meeting(x+1,y,obj_solid));

// position_solidl and position_solidr checks to see if their is a solid object to the players left and right. This may be a somewhat useless variable but It is easy for me to read by having it at the moment.
scr_player_basic:
Code:
scr_player_state();

//Horizontal Movement & Collision

if position_solidl && key_left
{
x -= spd;
}

if position_solidr && key_right
{
x += spd;
}

//Apply Gravity
if position_air
{
    y += grav;
}

//Apply Jump

if position_ground && key_up
{
y -= 4;
}
I would like your input on how I may tweak and simplify/complicate things here. Obviously there are many fatal flaws with this engine, so I'm excited to receive your feedback.

Thoughts?
 

Bentley

Member
The jumping feels totally unnatural at the moment, so that's what I'm mainly seeking guidance on
You're falling by "grav" every frame. I would add grav to a variable and change your y by that variable.
Ex:
vspd = min(vspd + grav, vspd_max);

Edit: I'd do the same for jumping:
if (key_jump && on_ground)
{
vspd = -jump_height;
}
 

Calvert

Member
You're falling by "grav" every frame. I would add grav to a variable and change your y by that variable.
Ex:
vspd = min(vspd + grav, vspd_max);

Edit: I'd do the same for jumping:
if (key_jump && on_ground)
{
vspd = -jump_height;
}
Thanks for the reply Bentley!

I have some questions, because I really want to learn.

- Is there anything wrong with falling by "grav" every frame? If so, what?
- How exactly is adding grav to a variable and changing y by that variable changing/improving the original system?
- Where do I put your code?
- I'm seeing new variables like "jump_height" and "vspd_max" that I'm not understanding, how are they supposed to fit in the original code? - Should I establish these variables in the obj_player create event or in my player_state script?
 
Last edited:

Bentley

Member
Thanks for the reply Bentley!

I have some questions, because I really want to learn.

- Is there anything wrong with falling by "grav" every frame? If so, what?
- How exactly is adding grav to a variable and changing y by that variable changing/improving the original system?
- Where do I put your code?
- I'm seeing new variables like "jump_height" and "vspd_max" that I'm not understanding, how are they supposed to fit in the original code? - Should I establish these variables in the obj_player create event or in my player_state script?
"Is there anything wrong with adding gravity every step"
There is nothing wrong with that.
But that will give you a fall that doesn't get faster.
It just depends on what you're going for.

"How is adding a vspd variable improving things"
I can speak for platformers and having a variable
for your horizontal speed and your vertical speed is helpful.
It allows you to collision check and move pixel perfect against walls. Ex:
Code:
if (!place_meeting(x, y + vspd, obj_solid))
{
    y += vspd;
}
else
{
    while (!place_meeting(x, y + sign(vspd), obj_solid))
    {
        y += sign(vspd);
    }
    vspd = 0;
}
You could still collision check the way you have it,
you'd just have to backtrack out of the wall.
I think it's easier to check ahead.
Also, if your game is a puzzle / grid game, you can just
move x += TILE_SIZE or w/e it may be.
I'm not an expert on any of this stuff. Someone smarter will
be able to tell you the pros and cons.

"Where do the new variables go"
They would go in the create event. For example, this is how the player object's create event looks in most my platformer attempts:
Code:
hspd = 0;
vspd = 0;
hspd_frac = 0; // For carrying over fractions
vspd_frac = 0;
hspd_max = 6;
jump_height = 8;
fall_speed = 10;
accel = 0.3;
fric = 0.2;
grav = 0.2;
The actual movement, where you use hspd and vspd, can go in the End Step event.
Code:
var hspd_int, vspd_int;

hspd_frac += hspd;
vspd_frac += vspd;
hspd_int = round(hspd_frac);
vspd_int = round(vspd_frac);
hspd_frac -= hspd_int;
vspd_frac -= vspd_int;

repeat (abs(hspd_int))
{
    if (!place_meeting(x + sign(hspd_int), y, obj_solid))
    {
        x += sign(hspd_int);
    }
    else
    {
        hspd = 0;
        hspd_frac = 0;
        break;
    }
}
// Same for vspd
All that code is doing is getting your horizontal speed for this step. Let's say it's 5. The repeat loop runs 5 times in this step. Each iteration it checks 1 pixel ahead (in your x direction) for a wall.
If there's not a wall, move 1 pixel.
If there's a wall, set your hspd to 0 and break the loop.
So if there's nothing in your way, you just move 5 pixels.
If there's something in your way, you move next to it.

Edit: I learned a lot about platformers from Zach Bell's Market Place assets. He has a few that are free too. Look for his Advanced Platformer Tutorial. Obviously not a substitute for learning how to do it. You are approaching it the right way imo. Trying it yourself and asking questions as you go. If you have any more questions I'd be happy to answer.
 
Last edited:
Top