1
\$\begingroup\$

The Context

In Godot 4.1, I have a third-person character controller. It's a CharacterBody3D with a child Node3D called PlayerContent. The visual components of the character (model, etc.) are all children of PlayerContent. To move the character, I've created a Vector3 called direction that gets the joystick input:

func get_input_direction():
  direction.x = Input.get_axis("move_left", "move_right")
  direction.z = Input.get_axis("move_forward", "move_backward")

The player can be Z-targeting or moving freely. In the case of moving freely, I rotate PlayerContent to match the direction of movement (giving the illusion that the character is turning, even though the CharacterBody3D isn't). In the case of Z-targeting, I rotate PlayerContent towards the target.

In order to make direction relative to the camera, I rotate direction by the camera's rotation.

func player_direction_to_camera():
  get_input_direction()
  direction = direction.rotated(Vector3.UP, camera.rotation.y)

Lastly, I set the velocity variable that move_and_slide() uses to equal direction.

The Question

I'd like to be able to tell which way direction is compared to the value the Vector2 is being rotated by. For example, if the player is moving left (relative to PlayerContent's rotation), I'd like to be able to specify the dodge type to be left_dodge (or something to that effect.) Or forward_dodge, or backflip, or anything like that.

I'm not very good at vector math, so I'd appreciate some help with this.

\$\endgroup\$

1 Answer 1

1
\$\begingroup\$

I'm not sure I understand the issue... So, I'll give you three scenarios, hopefully I cover your case.


First scenario: You want to know which way is camera.rotation.y rotating.

For that you can wrapf it:

wrapf(camera.rotation.y, -PI, PI)

Then the sign will tell you which way it is rotating.


Second scenario: You want to compare direction to the orientation of PlayerContent (or some other object).

The forward direction of PlayerContent would be:

var target_direction := -PlayerContent.global_transform.basis.z

If PlayerContent is not what you want, you can replace it with any other Node3D (e.g. the Camera3D or the CharacterBody3D).

And wince we know the rotation uses Vector3.UP as axis, we can use it in signed_angle_to:

direction.signed_angle_to(target_direction, Vector3.UP)

And again, you can use the sign to discriminate.


Scenario tree: You a Basis (perhaps from a Transform3D, for example from the Camera3D) or a Quaternion, and you want to know which way it rotates.

You need a vector that you know to be perpendicular to the axis. In our case the axis is Vector3.UP, so we can use Vector3.FORWARD...

Then compared with it transformed version:

Vector3.FORWARD.signed_angle_to(r * Vector3.FORWARD, Vector3.UP)

Where r is the Basis or Quaternion.

And once more, the angle will tell you which way it rotated.


Bonus: If you need the Transform3D of something relative to something else you can do this:

var r := something_else.global_transform.affine_inverse() * something.global_transform

That will give you a Transform3D such that something_else.global_transform* r is something.global_transform. That is the transform needed to go from something_else to something, in other words, the transform of something relative to something_else.

\$\endgroup\$

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .