J
Jordan Robinson
Guest
Pixel-Perfect Smooth Movement
Jordan Robinson
GM Version: 1.4.1757
Target Platform: ALL
Download: N/A
Links: N/A
Summary:
This tutorial will explain how you can easily make your player move smoothly (i.e. accelerate / decelerate) without any chance of juddering with small rounding errors that can often occur when trying to achieve such a result. The player's x and y position will always be an integer, so this method is great for people making pixel-art games where accuracy in collision checking and movement is important. Also, the theory behind this may be implemented in any game be it top-down, platformer, or any other.
Tutorial:
Like most of my other tutorials, I will be basing this method on the basic platformer code by Shaun Spalding, except with a few changes added in. Here is what we will be starting with:
This code should be put respectively in the create and step events of a player object, and the code assumes that the instances to collide with are called obj_solid.
Now, this system is going to work by having two variables each for horizontal and vertical speed.The first variable will hold the theoretical speed that we want the player to move at. It will be a floating point value, and will simply be used for calculating his acceleration. The second will be the rounded theoretical value (an integer), and will be used for collision checking and movement. We can start with the vertical speed, as this will be the quickest to implement.
I won't be changing the create event, as there is no need to have our rounded variables stored in any more than a local variable. Therefore, we will only be working in the step event from this point forward.
For simplicity sake in my example code, I have removed everything that is irrelevant to the vertical speed.
That is the vertical speed done. As you can see, the basic flow of the code is to do all of the speed settings with the theoretical code, round it into an integer, and then perform the collision checks and movement at the end. The horizontal movement is going to be the same methodology, except we need to add a small formula to make his speed accelerate and decelerate to make it feel a bit smoother. Again I will only include that code related to his horizontal speed.
And thats it. If you run the game, your player will be able to move smoothly whilst still sticking to perfect integer positions on the screen.
Hopefully this tutorial was useful to you. Cheers.
Jordan Robinson
GM Version: 1.4.1757
Target Platform: ALL
Download: N/A
Links: N/A
Summary:
This tutorial will explain how you can easily make your player move smoothly (i.e. accelerate / decelerate) without any chance of juddering with small rounding errors that can often occur when trying to achieve such a result. The player's x and y position will always be an integer, so this method is great for people making pixel-art games where accuracy in collision checking and movement is important. Also, the theory behind this may be implemented in any game be it top-down, platformer, or any other.
Tutorial:
Like most of my other tutorials, I will be basing this method on the basic platformer code by Shaun Spalding, except with a few changes added in. Here is what we will be starting with:
Code:
//Create Event
grav = 0.2; //Gravity
speed_x = 0;
speed_y = 0;
Code:
//Step Event
var k_left = keyboard_check(ord('A'));
var k_right = keyboard_check(ord('D'));
var k_jump = keyboard_check_pressed(vk_space);
var spd_wanted = 0; //The wanted horizontal speed for this step
if(k_left)
{
spd_wanted -= 3;
}
if(k_right)
{
spd_wanted += 3;
}
speed_x = spd_wanted; //Set the horizontal speed based on the wanted speed
speed_y += grav; //Apply gravity
if(k_jump && place_meeting(x, y + 1, obj_solid))
{
speed_y = -6;
}
//Horizontal collision
if(place_meeting(x + speed_x, y, obj_solid))
{
while(!place_meeting(x + sign(speed_x), y, obj_solid))
{
x += sign(speed_x);
}
speed_x = 0;
}
x += speed_x;
//Vertical collision
if(place_meeting(x, y + speed_y, obj_solid))
{
while(!place_meeting(x, y + sign(speed_y), obj_solid))
{
y += sign(speed_y);
}
speed_y = 0;
}
y += speed_y;
Now, this system is going to work by having two variables each for horizontal and vertical speed.The first variable will hold the theoretical speed that we want the player to move at. It will be a floating point value, and will simply be used for calculating his acceleration. The second will be the rounded theoretical value (an integer), and will be used for collision checking and movement. We can start with the vertical speed, as this will be the quickest to implement.
I won't be changing the create event, as there is no need to have our rounded variables stored in any more than a local variable. Therefore, we will only be working in the step event from this point forward.
For simplicity sake in my example code, I have removed everything that is irrelevant to the vertical speed.
Code:
speed_y += grav; //Apply gravity
if(k_jump && place_meeting(x, y + 1, obj_solid))
{
speed_y = -6;
}
var ysp = round(speed_y); //Turn the theoretical value into an integer for collision and movement
//Vertical collision
if(place_meeting(x, y + ysp, obj_solid))
{
while(!place_meeting(x, y + sign(ysp), obj_solid))
{
y += sign(ysp);
}
ysp = 0
speed_y = 0; //We still have to set the theoretical value to 0 here
}
y += ysp;
Code:
var spd_wanted = 0; //The wanted horizontal speed for this step
if(k_left)
{
spd_wanted -= 3;
}
if(k_right)
{
spd_wanted += 3;
}
speed_x += (spd_wanted - speed_x) * 0.1; //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, obj_solid))
{
while(!place_meeting(x + sign(xsp), y, obj_solid))
{
x += sign(xsp);
}
xsp = 0;
speed_x = 0; //We still have to set the theoretical value to 0 here
}
x += xsp;
Hopefully this tutorial was useful to you. Cheers.