How to achieve 4-directional grid aligned movement?

:information_source: Attention Topic was automatically imported from the old Question2Answer platform.
:bust_in_silhouette: Asked By blank

Hey guys, I’ve read an interesting article about how movement in old zelda games was crafted, which in short used a half tile grid and four directions to move to, while moving in any of these directions the player was frame by frame aligned into the center of the grid cell in the direction of movement. So I took a stab at it and tried to come up with such a system myself. I used tilemap to create a grid and compared player vs cell position, but it came out quite buggy and not really usable (still had fun).

I just wanted to ask if any of you did something like this before or have an idea how this could work, or could suggest me a different approach for this particular thing, any help would be really appreciated.

The article : Movement Mechanics • Troy Gilbert

My code:

extends KinematicBody2D

var GridTileMap
var PlayerSpeed = 50
var PlayerDirection = Vector2(0,0)
var Velocity
var PlayerPosition
var GridBoundaries
var ActiveGridCell
var CellSize
var HalfCellSize

func _ready():
    GridTileMap = get_node("../GridTileMap")
    GridBoundaries = GridTileMap.get_used_cells()
    CellSize = GridTileMap.get_cell_size()
    HalfCellSize = CellSize.x / 2

    func _process(delta):

ActiveGridCell = GridTileMap.world_to_map(PlayerPosition)
PlayerPosition = self.get_global_position()

if Input.is_action_pressed("ui_up"):
    PlayerDirection.y = -1
    if int(PlayerPosition.x) > int(ActiveGridCell.x * CellSize.x + HalfCellSize):
        self.global_position.x -= PlayerSpeed * delta
    elif int(PlayerPosition.x) < int(ActiveGridCell.x * CellSize.x + HalfCellSize):
        self.global_position.x += PlayerSpeed * delta
elif Input.is_action_pressed("ui_right"):
    PlayerDirection = Vector2(1,0)
    if int(PlayerPosition.y) > int(ActiveGridCell.y * CellSize.y + HalfCellSize):
        self.global_position.y -= PlayerSpeed * delta
    elif int(PlayerPosition.y) < int(ActiveGridCell.y * CellSize.y + HalfCellSize):
        self.global_position.y += PlayerSpeed * delta
elif Input.is_action_pressed("ui_down"):
    PlayerDirection = Vector2(0,1)
    if int(PlayerPosition.x) > int(ActiveGridCell.x * CellSize.x + HalfCellSize):
        self.global_position.x -= PlayerSpeed * delta
    elif int(PlayerPosition.x) < int(ActiveGridCell.x * CellSize.x + HalfCellSize):
        self.global_position.x += PlayerSpeed * delta
elif Input.is_action_pressed("ui_left"):
    PlayerDirection = Vector2(-1,0)
    if int(PlayerPosition.y) > int(ActiveGridCell.y * CellSize.y + HalfCellSize):
        self.global_position.y -= PlayerSpeed * delta
    elif int(PlayerPosition.y) < int(ActiveGridCell.y * CellSize.y + HalfCellSize):
        self.global_position.y += PlayerSpeed * delta
else:
    PlayerDirection = Vector2(0,0)

if PlayerDirection != Vector2(0,0):

    Velocity = PlayerDirection.normalized() * PlayerSpeed
    move_and_collide(Velocity * delta)
:bust_in_silhouette: Reply From: kidscancode

You might find this helpful:
http://kidscancode.org/blog/2018/01/godot3_inheritance/

It’s an article I wrote on Godot’s inheritance system, but the example game uses grid-based movement.

GDQuest also has an example here (done in Godot 2.1, but the concepts still apply): https://www.youtube.com/watch?v=A7xcmDeIoLY

:bust_in_silhouette: Reply From: eons

Godot have some really handy function called stepify and the Vector2/3 equivalent snapped, that allows to fit elements in a grid.

These methods can be called when motion ends, give-take some epsilon as distance from previous-next grid part.