Link's Movement in The Legend of Zelda (Snapping to the Grid)
Tags: gamedev, pico8, lua
Published: 2021-01-29 02:57:32

---
title: Link's Movement in The Legend of Zelda (Snapping to the Grid)
published: true
description: Snapping player movement to a grid 
tags: gamedev, pico8, lua
series: Game Studies
cover_image: https://github.com/robotspacefish/blog-photos/blob/master/game_studies/loz_movement_cover.png?raw=true
---

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:

<center>
  <img src="https://github.com/robotspacefish/blog-photos/blob/master/game_studies/link.gif?raw=true" alt="Link movement snapping to grid as the player turns">
</center>

I wanted to know more so I googled a bit and came across a blog post called [Movement Mechanics](https://troygilbert.com/deconstructing-zelda/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](https://www.youtube.com/watch?v=ffDibENc3UU) 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.

```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.

```lua
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.

<center>
  <img src="https://github.com/robotspacefish/blog-photos/blob/master/game_studies/link2.gif?raw=true" alt="Link movement snapping to grid as the player turns">
</center>

---

A few months ago [I entered a game jam](https://dev.to/robotspacefish/my-experience-entering-js13k-80i) 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](https://troygilbert.com/deconstructing-zelda/movement-mechanics/)
* [Making Zelda in Game Maker: E015 - Aligning Player to Grid](https://www.youtube.com/watch?v=ffDibENc3UU)
* [Nerdy Teachers](https://nerdyteachers.com) - an awesome resource I used to refresh my memory on some Pico-8 stuff since it's been a while!