Fix character's movement based on camera direction

Godot Version

4.3

Question

How can I make the character that contains this movement script not go to the top center of the screen? I’ve tried everything, but I couldn’t solve it.

I’m trying to make a movement script like Devil May Cry where the player walks towards the camera, which is fixed. But I’m failing :frowning:

Idk how to explain it, I’m not perfect in English XD

# entity.gd

class_name Entity
extends CharacterBody3D

@export var is_ai: bool = false
@export var is_player: bool = false
@export_range(0, 1000, 2) var life: int = 500
@export_range(0, 1000, 2) var regular_speed: float = 10

@onready var camera: Camera3D = get_viewport().get_camera_3d()

func handle_velocity() -> Vector3:
	var _input: Vector2 = Input.get_vector("move_left", "move_right", "move_up", "move_down")
	var _camera_forward: Vector3 = -camera.transform.basis.z
	var _camera_right: Vector3 = camera.transform.basis.x
	var _direction: Vector3 = _camera_forward * -_input.y + _camera_right * _input.x
	_direction.y = 0
	return _direction

func _physics_process(delta: float) -> void:
	velocity = handle_velocity() * regular_speed
	move_and_slide()

sorry if you didn’t understand me

That’s cool, but it looks like a normal third person controller in the gameplay. But I am not sure how you are trying to do it, but you can also check some tutorials on it.

I have created an advanced third person controller but unfortunately I am too poor in blender and the default animations are made by me, so I failed to make it famous. Here, it is, please forgive the animations. The Demo Video of the template.

If you need any help personally with interacting with the template, then you can message me.

Its actually off-topic, but I just wanted to say, I can`t able to help you with it as I am n̶o̶t̶ s̶o̶ good at maths. Actually I am not understanding your codes properly. Anyways, here my small project that I can share somehow:


Its created by adjusting that template

2 Likes

thank you for answer me! i watched some tutorials but i didnt get it.

it’s ok if you’re not that good in maths. but i will leave a comment here:

this is my character. if i press forward, he goes up. back, he goes down.

important: the camera is static

but, if i change the position of my character, sending him to top right corner, a thing happens:

that green arrow means “i’m pushing the forward + right”
the red means “forward” (yes! only forward)
yellow, “back” (only back)
and the blue arrow, “back + left”

the problem is with the red and yellow. for example when I press the forward button, I want him to walk exactly in the upward of the screen, not the in direction of the camera (that is the top center)

the red means what i want. like, when you press the forward button, you go up, not the top center .

i dont know how to explain it without a video, i hope that somebody understood

the horizontal buttons works well btw

1 Like

Okay, I am not too bad in maths :sweat_smile: So I am still able to help you. But can you tell me what is the function of the camera? why are you using the transform basis of the camera, is it moves or static. If it does not, then why are you not using the player`s transform basis?

1 Like

The camera views my character? It’s a camera :slight_smile:

I’m using camera.transform.basis because I found a snippet in somewhere. This moves the character into direction of the camera. I don’t want this. I want to follow the screen orientation. Up goes up in screen orientation, not up center.

It’s static, but I plan to rotate and translate it sometimes. Not frequently

Because I’m basing the player movement at the view of the camera. like, the player.transform.basis is a matrix of rotation, scale and, if I don’t miss, translation, right? I don’t know if I can mix the player.transform.basis with the Input.get_vector() perfectly, and I think this method doesn’t work.

I think I will not find a answer for my question :frowning:

1 Like

Look if it works, I am not 100% sure, just wanted to know the result:

var basis = transform.basis.z
var _direction: Vector3 = Vector3(basis.x * _input.x, 0, basis.z * _input.y)

If it does not work then I have my own formula, I would like to use that in case.

1 Like

There are many developers who can help you if I fail. So do not worry, you will find the solution one day.

1 Like

I guess you did not get it.

I am pressing forward and he is going to the up center of the screen.

I think I have to use some property of the camera or the viewport actually, but I don’t know what property is. Because the player has to base in something, and certainly is not himself.

1 Like

Hmm now I can understand, but can’t solve it… Because it’s still a bit confusion. Anyway, forgive me, you can get someone else for help.

1 Like

Your problem is with the perspective, meaning the farther away from the camera’s center your object is, the more skewed its path forward will be.
Maybe simply using an orthogonal projection type on your Camera3D node will solve your issue? Let me know if that works for you.

3 Likes

It worked, but I don’t want orthogonal. Thanks man, now I know how it works a little bit more :slight_smile:

1 Like

I’m not sure if there’s anything built in to make it work easily without the orthogonal projection.
I’m in mobile, so I can’t send you a proper code, but my idea would be to calculate the forward vector as player.global_position - camera.global_position, normalized, and with its y component set to a constant, e.g. 0, so it doesn’t move vertically. This way your character will always move in a straight line away from a camera when forward is pressed, which will look like in an orthogonal projection. All the other directions you’d need to calculate off this forward vector.
Hope you get what I mean, if not - let me know, I can try to rephrase or debug.

1 Like

Like that?

func handle_velocity() -> Vector3:
	var _input: Vector2 = Input.get_vector("move_left", "move_right", "move_forward", "move_back")
	var _camera_forward: Vector3 = (global_position - camera.global_position).normalized()
	var _camera_right: Vector3 = camera.transform.basis.x
	var _direction: Vector3 = _camera_forward * -_input.y + _camera_right * _input.x
	_direction.y = 0
	return _direction

It still has that thing. But it is less than the other. I think this is not the perfect solution yet, thanks

Ah, I see. I think if your camera wouldn’t have any rotation on the x axis, this would work fine. The fact that it’s leaned forward makes it a bit more complicated.
Would it work for you to just readjust the camera’s rotation? Otherwise the proper calculation need to be a bit more complex, as it needs to include the camera angle as well

1 Like