I recently spoke with someone about the original Legend of Zelda (my all-time fav game) and he mentioned how the developers kept Link's movement within a grid. I never thought about it before and I thought it was really cool. It's sort of subtle but you can see here how Link seems to snap into the grid when the player turns:
I wanted to know more so I googled a bit and came across a blog post called Movement Mechanics by Troy Gilbert in which he explains what's going on. To sum it up, the sprites that make up Link and the background tiles are 16x16 but Link moves along a half-tile grid that is 8x8. The player can move Link up, down, left, or right one pixel at a time and the game will always keep Link aligned to the 8x8 grid so he can walk between obstacles and through doorways without getting caught on the edges.
I also came across a YouTube video Making Zelda in Game Maker: E015 - Aligning Player to Grid by Code Workshop. I don't use Game Maker Studio but I followed what the instructor explained and adapted it for my needs so I could see how this technique works.
Code Workshop explains that when you move in a direction Link aligns to the grid on the other axis. So if you move left or right along the X-axis, Link aligns to the Y-axis and if you move up or down along the Y-Axis he aligns to the X-axis.
Since I created my demo in Pico-8 I'm going to show my re-creation of Code Workshop's align_to_grid
function using Lua.
function align(val, alignTo)
local remainder = val % alignTo
local halfway = alignTo/2
if (remainder > halfway) then
return alignTo - remainder
else
return -remainder
end
end
The align
function takes 2 parameters: val
which is the player's current x or y location (I'll explain more in a bit), and alignTo
, which is the amount of pixels you want your player to align to. Since Link aligns to an 8x8 grid, 8 will get passed in for alignTo
.
remainder
is what's left from the x or y location divided by the alignTo
value.
If the remainder is larger than the halfway point of the pixels you want to align to, then return alignTo - remainder
, otherwise return -remainder
.
The value returned from this function will be added to either the player's x
or y
value.
For example, if the player presses left
they want to move along the negative X-axis (vx
is multiplied by the player's speed
and added to the x
value further down in the function), which means they might need to be realigned along the Y-axis. In this instance, the value returned from align()
will be added to the player's y
value.
if (btn(⬅️)) then
vx = -1
y+=align(y, 8)
end
The way I did this differs a bit from how Code Workshop did it so if you are interested you should definitely check out his video.
Here is a gif of my version in Pico-8 to show the player's 16x16 sprite snapping along an 8x8 grid.
A few months ago I entered a game jam and made a game (featuring that robot buddy in the gif above) where the player moves by pixels within a 16x16 grid but the movement was...well, bad. My character stuck to the corners every time I turned because the size of the player was just about equal to the space the sprite had to move and I wasn't sure at the time how to fix it. I can't wait to go back and update the movement logic with this technique!
References
- Movement Mechanics by Troy Gilbert
- Making Zelda in Game Maker: E015 - Aligning Player to Grid
- Nerdy Teachers - an awesome resource I used to refresh my memory on some Pico-8 stuff since it's been a while!
Top comments (3)
This code can be simplified a bit:
dev.to (or rather, whatever it sues for HL) can do syntax highlighting for Lua if you start your code blocks with
<3 backticks>lua
:Dawesome, thanks for the tip!