Help with Transform

Godot Version

4.5.1

Question

Hello,

New to Godot and GDScript, and have been trying to do a demo by making a 'drone' (a Box mesh) be able to strafe. However, it's not gone very well:
1) Whenever the drone's 'move_right'/'move_left' inputs are used, if the drone is pointing down, it'll move in the right direction but up/down away from the camera as well
2) Whenever the 'sprint' (ascend - using the same input from another scene) or 'descend' inputs are used and the camera + drone points down (I assume it's the same when facing up), it'll move to the right/left repectively and slowly ascend
3) 'move_forward'/'move_back' doesn't move in the direction the camera is pointing vertically - instead it travels at same height irregardless of camera pitch but in the right direction horizontally.
4) My 'battery' get_gravity() only moves it down very slowly, despite it doing it much more rapidly and correctly in another script for testing.

Code:

extends CharacterBody3D

#drone
@export var move_speed = 5
@export var battery = 100

#camera
@onready var FPV = $FPV
@onready var Chase = $Chase
var mouse_sensitivity = 0.02
var rot_x = 0
var rot_y = 0
var rot_z = 0

func _ready():
Input.set_mouse_mode(Input.MOUSE_MODE_CAPTURED)
var hud = $FPV/DroneHUD
if hud:
hud.drone = self

func _physics_process(delta: float) → void:

velocity = Vector3.ZERO

#movement
if Input.is_action_pressed("move_forward"):
	velocity += -transform.basis.z * move_speed
if Input.is_action_pressed("move_back"):
	velocity += transform.basis.z * move_speed
if Input.is_action_pressed("move_right"):
	velocity += transform.basis.x * move_speed
if Input.is_action_pressed("move_left"):
	velocity += -transform.basis.x * move_speed
if Input.is_action_pressed("sprint"):
	velocity += transform.basis.y * move_speed
if Input.is_action_pressed("descend"):
	velocity += -transform.basis.y * move_speed

if velocity.length() > move_speed:
	velocity = velocity.normalized() * move_speed
	
transform = transform.orthonormalized()

#battery
if is_on_floor():
	if battery < 100:
		battery += 1 * delta
else:
	battery -= 1 * delta
	if battery < 0:
		battery = 0
		velocity += get_gravity() * delta
	
if Input.is_action_pressed("exit"):
	Input.set_mouse_mode(Input.MOUSE_MODE_VISIBLE)

move_and_slide()

func _input(event):

if event is InputEventMouseMotion:
	rot_y += -event.screen_relative.x * mouse_sensitivity 
	rot_z += -event.screen_relative.y * mouse_sensitivity  
	rot_z = clamp(rot_z, -1.5, 1.5)  
	
	transform.basis = Basis()
	rotate_object_local(Vector3.UP, rot_y)     
	rotate_object_local(Vector3.RIGHT, rot_x)  
	rotate_object_local(Vector3.FORWARD, rot_z)

if event.is_action_pressed("FPV"):
	FPV.current = true
elif event.is_action_pressed("Chase"):
	Chase.current = true

If anyone is able to help with these (or just general script stuff), it’d be greatly appreciated - I’ve spent far too long trying to fix the first 3 (and only breaking the camera rotation in return).

Do you want controls to operate in drone space or in camera space?

You reset the velocity every frame so gravity contribution cannot accumulate.

1 Like

Ah. That would make sense.

I might be misunderstanding you here/my noobiness might be showing here, but if I have the camera a (fixed, non-rotating) child node of the ‘drone’ character body, would having it operate in drone space not be the same as camera space?

Not necessarily if their bases are not aligned. Can you show a video of what you have vs. an example (in an existing game) of what type of control you’re after.

Also post your scene structure.

For start, you should always use the global basis instead of local basis when constructing the velocity vector. That vector is expected to be in global space.

1 Like

Am a new User (as in of 15 mins ago), so ‘can’t post attachments’

so: Failure1 - Google Vids

Starts with ‘W’ and ‘S’, then ‘D’ and ‘A’ and finishes with ‘Shift’ (sprint) and ‘Ctrl’ (Descend)

Would the fact the Node3D is rotated by 90 have any effect?

The character body should be the top node in your drone scene.

So this is a first person control?

Changed - Thanks!

Essentially, though there is also a chase cam (minus UI overlay)

Just a note that all my knowledge on transformations is by reading the Transforms page on the Docs, so is very limited

Start by using an independent camera that’s outside of the drone scene looking at the drone from an arbitrary angle and implement the proper movement in drone’s space, using character body’s global_basis vectors to construct the final velocity vector.

1 Like

Just realised that I’ve tried to make the ‘forwards’ pointing down the x axis - would this be something I need to rectify?

Also, thanks a lot for the help

The convention is that forward is pointing up the z axis so it’s the -z basis vector. Right is then x, and up is y.

Ah - changing the axes worked, and now does what I was hoping it to do (all movement is now based off local axes). Only thing I changed in the script was this part:

if event is InputEventMouseMotion:
	rot_y += -event.screen_relative.x * mouse_sensitivity 
	rot_x += -event.screen_relative.y * mouse_sensitivity  
	rot_x = clamp(rot_x, -1.5, 1.5)  

I’ll try changing it to the global_vectors as well, if that is what should be done, and fix the battery get_gravity() bit using what you said above.

Thanks a lot for all the help!

1 Like