3D movement based on camera

How can I make the character walk based on the camera angle instead of the world axis? Is there a way to achieve this using the current pre-built scripts?

	# Get the input direction and handle the movement/deceleration.
	var input_dir := Input.get_vector("left", "right", "forward", "backward")
	var direction := (transform.basis * Vector3(input_dir.x, 0, input_dir.y)).normalized()
	
	if direction:
		velocity.x = direction.x * SPEED
		velocity.z = direction.z * SPEED
	else:
		velocity.x = move_toward(velocity.x, 0, SPEED)
		velocity.z = move_toward(velocity.z, 0, SPEED)
1 Like

If your camera is a child of this object then you could try using $Camera3D.global_basis instead of transform.basis

How are you rotating the character in the script?

2 Likes

Im using this script for movement, it says there is an error

extends CharacterBody3D
var hp = 125
const SPEED = 5.1
var angular_aceleration = 10
var attacknumb = 1 
var canattack = true
var isattack1 = false #animation
var isattack2 = false #animation
var is_dash = false #animation
var candash = true
var is_idle = false #animation
var iswalking = false #animation
var grounded = false

@export var animation_three : AnimationTree
@onready var stepCast = $StepCast
@export var Eloy : CharacterBody3D
@onready var sword: Node3D = $Armature/Skeleton3D/SwordBack/Sword
@onready var PlayerAnimationTree = $AnimationTree.get_path()
@onready var animation_tree = get_node(PlayerAnimationTree)
@onready var playback = animation_tree.get("parameters/playback")
@onready var camera3d = $Camera3D
#So many numbers and boleans for this guy... HELP

func _physics_process(delta: float) -> void: # Add the gravity.
	if not is_on_floor():
		velocity += get_gravity() * delta
	

	if Input.is_action_just_pressed("Attack") and canattack: # Dash system, make the player dash.
		#canattack = false
		if attacknumb == 1 and canattack and !isattack1:
			canattack = false
			sword.reparent($Armature/Skeleton3D/SwordHand, false)
			$Attack1.start()
			$Attack1/Attack1CD.start()
			$Guardar.start()
			isattack1 = true
			is_idle= false
			iswalking= false
	if Input.is_action_just_pressed("Attack") and canattack: # Dash system, make the player dash.
		#canattack = false
		if  attacknumb == 2 and canattack and !isattack2:
			canattack = false
			sword.reparent($Armature/Skeleton3D/SwordHand, false)
			$Attack2.start()
			$Attack2/Attack2CD.start()
			$Guardar.start()
			isattack2 = true
			is_idle= false
			iswalking= false

	if Input.is_action_just_pressed("Dash") and candash: # Dash system, make the player dash.
		candash = false
		if !is_dash:
			#CharacterBody3D.transform.forward + 100 HELP 
			sword.reparent($Armature/Skeleton3D/SwordHand, false)
			$DashTimer.start()
			$DashTimer/DashCD.start()
			$Guardar.start()
			is_dash = true
			is_idle= false
			iswalking= false

	# Get the input direction and handle the movement/deceleration.
	var input_dir := Input.get_vector("left", "right", "forward", "backward")
	var direction := ($Camera3D.global_basis * Vector3(input_dir.x, 0, input_dir.y)).normalized()
	
	if direction:
		velocity.x = direction.x * SPEED
		velocity.z = direction.z * SPEED
		if !is_dash and !isattack1 and !isattack2:
			$Armature.rotation.y = lerp_angle($Armature.rotation.y, atan2 (direction.x, direction.z), delta * angular_aceleration)
		if !is_dash and !isattack1 and !isattack2:
			isattack2 = false
			is_idle = false 
			iswalking = true
	else:
		velocity.x = move_toward(velocity.x, 0, SPEED)
		velocity.z = move_toward(velocity.z, 0, SPEED)
		if !is_dash and !isattack1 and !isattack2:
			isattack2 = false
			is_idle = true 
			iswalking = false

	move(delta);
	# Set an animation
	animation_tree["parameters/conditions/IsWalking"] = iswalking
	animation_tree["parameters/conditions/IsIdle"] = is_idle
	animation_tree["parameters/conditions/Dash"] = is_dash
	animation_tree["parameters/conditions/IsAttack1"] = isattack1
	animation_tree["parameters/conditions/IsAttack2"] = isattack2

func _on_guardar_timeout() -> void: # sword to back
	sword.reparent($Armature/Skeleton3D/SwordBack, false)

func _on_dash_cd_timeout() -> void:
	candash = true

func _on_dash_timer_timeout() -> void:
	is_dash = false

func _on_attack_1_timeout() -> void:
	isattack1 = false
	attacknumb=2
	#canattack = true

func _on_attack_1cd_timeout() -> void:
	canattack = true

func _on_attack_2_timeout() -> void:
	isattack2 = false
	attacknumb=1
	#canattack = true

func _on_attack_2cd_timeout() -> void:
	canattack = true

func move(delta: float):
	stepCast.global_position.x = global_position.x + velocity.x * delta;
	stepCast.global_position.z = global_position.z + velocity.z * delta;
	
	if is_grounded():
		stepCast.target_position.y = -1;
	else:
		stepCast.target_position.y = -0.45;
	
	var query = PhysicsShapeQueryParameters3D.new()
	query.exclude = [self];
	query.shape = stepCast.shape;
	query.transform = stepCast.global_transform;
	var result = get_world_3d().direct_space_state.intersect_shape(query,1);
	if !result:
		stepCast.force_shapecast_update();
	
	if stepCast.is_colliding() && velocity.y  <= 0.0:
		global_position.y = stepCast.get_collision_point(0).y;
		velocity.y =  0.0;
		grounded = true
	else:
		grounded = false
		
	move_and_slide();
func is_grounded() -> bool:
	return grounded || is_on_floor();

You could add a type to your camera here and use the variable instead of the node path

@onready var camera3d := $Camera3D as Camera3D
1 Like

it still not working :frowning:

1 Like

Camera3D is a type, your variable is camera3d with no capital letters. The editor paints types as teal, where most variables are white.

If you are on a version lower than 4.3 try camera3d.global_transform.basis

1 Like

im on godot 4.3 stable version, i tried with no capital letters and this is the result… “Cannot infer the type of “direction” variable because the value doesn’t have a set type.”


soorry

1 Like

Of which I’m betting your camera3d declaration is untyped. Another way to fix this error is to remove the colon, this will remove auto complete for the direction variable, or explicitly declare the type.

var direction = etc... # no type (how your camera3d is)
var direction := etc... # infering type (currently erroring)
var direction: Vector3 = etc... # explicit type
1 Like

i dont understand

1 Like

Your error says it cannot infer the type of “direction” because part of the equation does not have a type. That would be camera3d, you could make camera3d an explicit type, as I suggested first, or avoid trying to type direction by removing the colon (:) in it’s declaration.

2 Likes

oh… finality it works :smiley: Thank you. and sorry for bothering you

1 Like