I removed diagonal movement in my 2d tile game. How can I buffer two keys simultaniously to let players move diagonally only using up, down, left and right to end up on that same diagonal tile?

Godot Version

Godot 4.2

Question

I would like my player character to not be able to move diagonally. However, I would like them to still end up on the diagonal tile they choose by buffering two keys simultaneously. So for example, if I wanted to move diagonal right, pressing both up and right will get me there versus pressing up and then right.


extends CharacterBody2D

@export var walk_speed = 16.0
const TILE_SIZE = 16

@onready var anim_tree = $AnimationTree
@onready var anim_state = anim_tree.get("parameters/playback")
@onready var ray = $RayCast2D

enum PlayerState {IDLE, TURNING, WALKING}
enum FacingDirection {LEFT, RIGHT, UP, DOWN}

var player_state = PlayerState.IDLE
var facing_direction = FacingDirection.DOWN


var initial_position = Vector2(0,0)
var input_direction = Vector2(0,0)

var is_moving = false
var percent_moved_to_next_tile = 0.0



func _ready ():
	anim_tree.active = true
	initial_position = position
	
		
		
func _physics_process(delta):
	if player_state == PlayerState.TURNING:
		return
	elif is_moving == false:
		process_player_input()
	elif input_direction != Vector2.ZERO:
		anim_state.travel("Walk")
		move(delta)
	else:
		anim_state.travel("Idle")
		is_moving = false
		
func process_player_input():
	if input_direction.y == 0:
		input_direction.x = int(Input.is_action_pressed("ui_right")) - int(Input.is_action_pressed("ui_left"))
	if input_direction.x == 0:
		input_direction.y = int(Input.is_action_pressed("ui_down")) - int(Input.is_action_pressed("ui_up"))
	
	if input_direction != Vector2.ZERO:
		anim_tree.set("parameters/Idle/blend_position", input_direction)
		anim_tree.set("parameters/Walk/blend_position", input_direction)
		anim_tree.set("parameters/Turn/blend_position", input_direction)
		
		if need_to_turn():
			player_state = PlayerState.TURNING
			anim_state.travel("Turn")
		else:
			initial_position = position
			is_moving = true
	else:
		anim_state.travel("Idle")
		
		
func need_to_turn():
	var new_facing_direction
	if  input_direction.x < 0:
			new_facing_direction = FacingDirection.LEFT
	elif input_direction.x > 0:
		new_facing_direction = FacingDirection.RIGHT
	elif input_direction.y < 0:
		new_facing_direction = FacingDirection.UP
	elif input_direction.y > 0:
		new_facing_direction = FacingDirection.DOWN
	
	if facing_direction != new_facing_direction:
		facing_direction = new_facing_direction
		return true
	facing_direction = new_facing_direction
	return false
		
	
func finished_turning():
	player_state = PlayerState.IDLE

func move(delta):
	
	var desired_step: Vector2 = input_direction * TILE_SIZE / 2
	ray.target_position = desired_step
	ray.force_raycast_update()
	if !ray.is_colliding():
		percent_moved_to_next_tile += walk_speed * delta
		if percent_moved_to_next_tile >= 1.0:
			position = initial_position + (input_direction * TILE_SIZE)
			percent_moved_to_next_tile = 0.0
			is_moving = false
	
		else:
			position = initial_position + (input_direction * TILE_SIZE * percent_moved_to_next_tile)
	else:	
		is_moving = false

this video let you do what you wanted:

it basically:

var MAX_SPEED=100
var ACCEL=100
const FRICTION=200000

var input=Vector2.ZERO

...

func get_input():
	input.x=int(Input.is_action_pressed("ui_right"))-int(Input.is_action_pressed("ui_left"))
	input.y=int(Input.is_action_pressed("ui_down"))-int(Input.is_action_pressed("ui_up"))
	return input.normalized()

...

func player_movement(delta):
	input=get_input()
	if input==Vector2.ZERO:
		if velocity.length()>FRICTION*delta:
			velocity-=velocity.normalized()*FRICTION*delta
		else:
			velocity=Vector2.ZERO
	else:
		velocity+=(input*ACCEL)
		velocity=velocity.limit_length(MAX_SPEED)

...
func _physics_process(delta):
	player_movement(delta)


This removes the point of tilemap-based grid movement. This is just standard movement and acceleration.

the thing is to know the input direction, not the way it moves. something to harvest from that
the input can be Vector2(1,1) or Vector2(-1,-1)
so you can use that to move your character