Orthographic movement — horizontal appears faster

Godot Version

4.4

Question

I’m using an orthographic projection, camera angled -30 down. Unfortunately, horizontal (left/right) movement appears to be faster than vertical (up/down) due to the projection. How can I fix this so it all appears to be the same in screen space? I tried with multipliers etc, but this skews the diagonal movement.

extends CharacterBody3D

@export var move_speed := 6.0
@export var move_speed2 := 8.0
@export var rotation_speed := 8.6
@export var gravity := 0.0
@export var deceleration := 36.0

@onready var anim = $player/AnimationPlayer
@onready var anim2 = $"../NPCs/player2/AnimationPlayer"
@onready var anim3 = $"../player3/AnimationPlayer"
@onready var anim4 = $"../player4/AnimationPlayer"


# our “north star” yaw for the box
var desired_yaw: float

func _ready():
	# start off facing however the box is rotated in the editor
	desired_yaw = $Box4.rotation.y

func _input(event):
	# only catch key-presses for our movement actions
	if event is InputEventKey and event.pressed:
		for action in ["move_left","move_right","move_down","move_up"]:
			if event.is_action(action):
				_update_desired_yaw()
				break

func _ground_axes_from_camera(cam: Camera3D) -> Array[Vector3]:
	var right: Vector3 = cam.global_transform.basis.x
	var up:    Vector3 = cam.global_transform.basis.y
	right.y = 0.0
	up.y    = 0.0
	if right.length() > 0.0:
		right = right.normalized()
	if up.length() > 0.0:
		up = up.normalized()
	return [right, up]  # [screen-right on ground, screen-up on ground]

func _update_desired_yaw() -> void:
	var iv: Vector2 = Input.get_vector("move_left","move_right","move_down","move_up")
	if iv == Vector2.ZERO:
		return

	var cam: Camera3D = $"../../SubViewport/CameraRig/Camera3D"
	var axes: Array[Vector3] = _ground_axes_from_camera(cam)
	var right: Vector3 = axes[0]
	var up:    Vector3 = axes[1]

	# screen up is negative Y on the input vector
	var raw: Vector3 = right * iv.x + up * -iv.y
	var d: Vector3 = raw.normalized()
	desired_yaw = atan2(d.x, d.z)

func _process(delta: float) -> void:
	var iv: Vector2 = Input.get_vector("move_left","move_right","move_down","move_up")
	var cam: Camera3D = $"../../SubViewport/CameraRig/Camera3D"
	var axes: Array[Vector3] = _ground_axes_from_camera(cam)
	var right: Vector3 = axes[0]
	var up:    Vector3 = axes[1]

	if iv != Vector2.ZERO:
		var raw: Vector3 = right * iv.x + up * iv.y
		var d: Vector3 = raw
		
		# facing
		desired_yaw = atan2(d.x, d.z)

		# uniform speed (diag included)
		velocity.x = d.x * move_speed
		velocity.z = d.z * move_speed
	else:
		velocity.x = move_toward(velocity.x, 0.0, deceleration * delta)
		velocity.z = move_toward(velocity.z, 0.0, deceleration * delta)

	# rotate toward desired_yaw (unchanged)
	var box := $player
	var current: float = box.rotation.y
	var diff: float = wrapf(desired_yaw - current, -PI, PI)
	var step: float = rotation_speed * delta
	if abs(diff) <= step:
		box.rotation.y = desired_yaw
	else:
		box.rotation.y = lerp_angle(current, desired_yaw, step)

	# gravity & movement
	velocity.y -= gravity * delta
	move_and_slide()

I’d imagine that’s an artifact of the lack of perspective divide; your brain expects things to get smaller with depth, so when they don’t, you subtly misinterpret movement in depth. I’d imagine if you look closely it will seem like moving towards the camera is faster, and moving away from the camera looks slower.

I’m not sure you can fix this with an ortho cam looking at an angle. If you were top-down it would get rid of the problem. You could potentially hack around things by scaling your movement speed, but (as you noticed) you can’t just scale the two dimensions. You’d need to do something like:

  • get a normalized direction vector
  • scale the length of it based on speed and and angular distance from “up” or “down”

That will keep the direction of movement from being skewed while compensating for the illusory speed disparity, but it also means that in reality the player will go faster in some directions than others.

Ultimately, it’s kind of a “pick your hack” situation.

2 Likes

To @hexgrid 's point, if you know what direction the character is moving in when this movement speed change appears, you could alter it to “appear” correct.

1 Like

This topic was automatically closed 30 days after the last reply. New replies are no longer allowed.