I'm pretty amazing when it comes to coding, brute force solutions and if else tree's at least 16 deep and redeclaring variables repeatedly etc...yeah, I know my stuff.

...seriously, I'm an idiot :)

I recently decided to take a crack at godot(again) but I am totally lost when I am writing my movement(3D) I've been looking at documentation and tutorials but I'm falling short..I simply can't get simple movement in local coords working..I've looked at transform.babsis.xform etc, but I'm just lost..

can anyone point me to a "very" straightforward tutorial(for absolute idiots) or provide a simple code snippet to get me going? ....about as far as I got after all day is passing inputs into a vector and running that through move_and_slide(some vecotor)...but it's all global :(

yeah read it...I'm just trying to avoid over complicated coding for such a trivial aspect...I don't want to crack open the full transfrom matrix to get simple local axis movement.(yes, using kinematic controller, and floor raycast :) )

-simplified: I check inputs like w,a,s or d(if statements or switch case if it gets complex) and they in turn pass a value to a tuple(vec3) I take said vec and feed it to the move_and_slide(vec) function...

I would assume this could be done in about 7-10 lines...but nope :(

I need to use transform.basis, is this correct? I know that was long winded...I'm tired and maybe a bit frustrated or grumpy...just personal failure makes me moody :)

What kind of game are you making? I don't fully understand what kind of movement you're hoping to create, but either way, it seems that you want your character to move in a relative direction. An FPS where your character moves relative to their rotation is a good example.

transform.basis is what you're looking for. Here's a simplification of what I did for my player movement script in psuedocode:

-Get the player's movement input (WASD) as a Vector2 (x represents A/D, y represents W/S) -Multiply the movement input along the x-axis by transform.basis.x.normalized() -Multiply the movement input along the y-axis by -transform.basis.z.normalized() -Add the multiplied input values together and store them in a variable called horizontal_movement -move_and_slide the player controller by horizontal_movement (I made vertical movement a separate variable)

If you're still having trouble, I may consider making a tutorial that goes in depth explaining how I made my player move relative to the camera. Good luck :)

I know this is horrible, but this is what I have... I don't want to do a chain of if else testing to call this function repeatedly for W,A,S and D

if Input.is_action_pressed('ui_up'):
	move_and_slide(transform.basis.z.normalized() * move_spd * delta)

can someone show me a better method(I mean way, not method :) ) or point me to a good tutorial?

I'd recommend only calling move_and_slide once, in the process(delta) function. Here's a nicer way to keep track of the player's WASD inputs:

func get_input_vect():
	var movement_vect = Vector3(0, 0, 0);
	if (Input.is_key_pressed(KEY_A)):
		movement_vect.x -= 1
	if (Input.is_key_pressed(KEY_D)):
		movement_vect.x += 1
	if (Input.is_key_pressed(KEY_S)):
		movement_vect.z -= 1
	if (Input.is_key_pressed(KEY_W)):
		movement_vect.z += 1
	return movement_vect

You should only need to call move_and_slide once in the _process(delta) function, using certain axes of get_input_vect multiplied by the respective axes of transform.basis.normalized(). You may have to normalize the input if you want to prevent players from straferunning.

@Megalomaniak : 3rd person kinematic, but I honestly don't see the difference in local movement whether it be 3rd or first person.... AND match is what I want....

@"Moire Software" :AFAIK though you cannot simply throw a vec at transform.basis as it's a multi dimensional array...matrix whatnot...please correct me if I am incorrect....I am slow to pick things up, but once I get them...I'm golden. that is how I did it initially and I passed the vector to the move_and_slide() function.

if key this and that
    vec[0] = 10
move_and_slide(vec)

that is a short version(obviously)

To move the player around relative to the camera, you to know where the camera is facing. You can do this using transform.basis, which has three vectors (x, y, and z) which each of the three dimension axes relative to the rotation of the object. To put it another way, the three vectors stored in transform.basis correspond to the X, Y, and Z arrows seen when selecting an object in the Godot editor with "Use Local Space" (the 3D square icon in next to snapping options) mode enabled.

So long as you are trying to move the player along one of those axis, the code is not too difficult. Something like this, in theory, should allow for basic movement relative to a Camera node (untested):

Extends KinematicBody
var velocity = Vector3.ZERO
var move_speed = 6
var camera_node

func _ready():
	camera_node = get_node("Camera")

func _process(delta):
	# Get the camera's Z and X vectors
	# (Note: we are getting the negative Z because that is what the Camera node faces)
	var camera_forward_vector = -camera_node.global_transform.basis.z
	var camera_right_vector = camera_node.global_transform.basis.z
	# Normalize both vectors so the scale of the Camera node does not change anything
	# (While this is unlikely, I have had it happen a few times)
	camera_forward_vector = camera_forward_vector.normalized()
	camera_right_vector = camera_right_vector.normalized()
	# (Optional) Remove any movement on the Y axis so the player cannot fly
	# or sink into the ground simply by walking
	camera_forward_vector.y = 0
	camera_right_vector.y = 0

	# Simple movement example.
	# Check out the FPS tutorial for a, potentially, better solution
	if (Input.is_key_pressed(KEY_RIGHT)):
		# Add the vector pointing in the X direction relative to the camera
		# so the player moves right relative to the camera.
		# Multiply the vector by move_speed and delta to the player moves
		# move_speed many units every second.
		velocity += camera_right_vector * move_speed * delta
	elif (Input.is_key_pressed(KEY_LEFT)):
		# Same thing, use the negative X axis so the player moves left
		# relative to the camera instead of right.
		velocity -= camera_right_vector * move_speed * delta
	if (Input.is_key_pressed(KEY_UP)):
		# Add the vector pointing in the -Z direction relative to the camera
		# so the player moves forward relative to the camera.
		velocity.z += camera_forward_vector * move_speed * delta
	elif (Input.is_key_pressed(KEY_DOWN)):
		# Same thing, but for backwards movement
		velocity.z -= camera_forward_vector * move_speed * delta
	
	# Then use move_and_slide like normal, and movement should be relative
	# to the camera
	move_and_slide(velocity, Vector3.UP)

Hopefully this makes sense and helps a bit! Movement in 3D can be kinda tricky. :smile:


Bonus answer: You can also use a Vector3 and the Basis, though it is not how I normally tackle the issue. It is entirely doable, and for some things it is the best way to do it (like for IK), but I personally find using the vectors stored within the basis is easier to understand and debug.

You can use the code above, just change _process to the following (untested):

func _process(delta):
	# Store where the player intends to go in this variable
	var player_input_direction = Vector3.ZERO

	# Simple movement example.
	# Modify the player input direction like normal.
	if (Input.is_key_pressed(KEY_RIGHT)):
		player_input_direction.x = 1
	elif (Input.is_key_pressed(KEY_LEFT)):
		player_input_direction.x = -1
	if (Input.is_key_pressed(KEY_UP)):
		player_input_direction.z = -1
	elif (Input.is_key_pressed(KEY_DOWN)):
		player_input_direction.z = 1
	
	# Use the basis to rotate the player_input_direction vector
	# relative to the rotation of the Camera node!
	var player_world_input_direction = (
		camera_node.global_transform.basis.xform(player_input_direction)
	)
	# Normalize to remove any scaling stored in the Camera's basis
	player_world_input_direction = player_world_input_direction.normalized()
	# Now we have a normalized vector that is pointing in the direction the player
	# wants to go, relative to the Camera node's rotation!
	
	# Now we want to multiply by move_speed and delta, then add to velocity
	player_world_input_direction *= move_speed * delta
	velocity += player_world_input_direction

	# Then use move_and_slide like normal, and movement should be relative
	# to the camera
	move_and_slide(velocity, Vector3.UP)

thanks...I'm not moving based on the camera facing dir, but I appreciate it...I did figure it out....thanks for your time.

2 months later

I stumbled upon this article recently and it helped clarify the basic concepts but I'm nocloser on the code.

http://codetuto.com/2016/01/godot-engine-movement-and-rotation-basics/

I understand the difference between local and global, but as someone trying to make a camera that imitates super mario kart and f zero I could really use some help.

I'm still just starting in godot but I can't move forward until I figure out how to control my player. Can someone please walk me through how to set up my scripting?

Here is my current script that moves the character along the global x and z. All I want to do is move forward from my relative orientation when I press up, and rotate locally when I press left or right. Ideally I could be holding up to continue moving "forward" while simaltaneously pressing left or right to adjust my steering/orientation.

Hope it's not rude to dig up this old thread, but I figured there were some people already familiar with the dilemma here.

The trick is to use basis and xform. Here is a simple example for just moving forward.

At the top of script with other variables.

var forward_vec = Vector3(0.0, 0.0, -1.0)
var up_vec = Vector3(0.0, 1.0, 0.0)

In _physics_process or your controller update code:

var basis = get_transform().basis
var forward = basis.xform(forward_vec)
move_and_slide(forward * move_speed, up_vec)

You can do the same thing for the right vector to move side to side.

Actually, there might be an easier way using your same code. Just paste this before move and slide:

var basis = get_transform().basis
velocity = basis.xform(velocity)
3 years later