Attention | Topic was automatically imported from the old Question2Answer platform. | |
Asked By | WhisperMain555 |
I am working on a 3D Sonic framework for Godot in GDScript, and currently I struggle to implement camera relative movement. I have already refractored several times, but the player keeps moving relative to it’s starting axises instead of relative to the camera! Help would be greatly appreciated.
I followed several tutorials to slowly build this (currently very early) framework, and similarly to GDScript’s 3D movement tutorials, the player object is a 3D KinematicBody and the camera is a springarm with the actual camera as it’s child object. Here is my current character controller script (attached to KinematicBody), minus some unused (commented-out) functions I removed:
extends KinematicBody
export var gravity = Vector3.DOWN * 10
export var speed = 8
export var rot_speed = 1.95
export var jump_speed = 9
var velocity = Vector3.ZERO
onready var _spring_arm: SpringArm = $SpringArm
onready var camera: Camera = $SpringArm/Camera
func _physics_process(delta):
velocity += gravity * delta
get_input(delta)
velocity = move_and_slide_with_snap(velocity, Vector3.DOWN*2, Vector3.UP, true)
if $RayCast.is_colliding():
var n = $RayCast.get_collision_normal()
var xform = align_with_y(global_transform, n)
global_transform = global_transform.interpolate_with(xform, 0.2)
else:
set_rotation(Vector3(0,rotation.y,0))
if Input.is_action_pressed("act_jump"):
velocity.y = jump_speed
velocity = move_and_slide_with_snap(velocity, Vector3.ZERO, Vector3.UP, true)
func align_with_y(xform, new_y):
xform.basis.y = new_y
xform.basis.x = -xform.basis.z.cross(new_y)
xform.basis = xform.basis.orthonormalized()
return xform
func get_input(_delta):
var vy = velocity.y
velocity = Vector3.ZERO
var move_direction := Vector3.ZERO
move_direction.x = Input.get_action_strength("act_right") - Input.get_action_strength("act_left")
move_direction.z = Input.get_action_strength("act_down") - Input.get_action_strength("act_up")
move_direction = move_direction.rotated(Vector3.UP, _spring_arm.rotation.y).normalized()
get_node("../Control/Label").text = str(move_direction) + "\n" + str(_spring_arm.rotation.y)
velocity.x = move_direction.x * speed
velocity.z = move_direction.z * speed
velocity.y = vy
I refractored the code several times, at one point get_input() used to look like this (I am including this anyway in case this is actually better that what I currently have, even though I really doubt it):
func get_input(_delta):
var vy = velocity.y
velocity = Vector3.ZERO
if Input.is_action_pressed("act_up"):
velocity += transform.basis.z * speed * Input.get_action_strength("act_up")
if Input.is_action_pressed("act_down"):
velocity += -transform.basis.z * speed * Input.get_action_strength("act_down")
if Input.is_action_pressed("act_right"):
velocity += -transform.basis.x * speed * Input.get_action_strength("act_right")
if Input.is_action_pressed("act_left"):
velocity += transform.basis.x * speed * Input.get_action_strength("act_left")
#velocity.x *= camera.global_transform.basis.x
#velocity.z *= camera.global_transform.basis.z
velocity.y = vy
And finally, here’s the script that controls the camera (attached to SpringArm):
extends SpringArm
export var mouse_sensitivity := 0.05
export var rstick_sensitivity := 2
func _ready() -> void:
#set_as_toplevel(true)
Input.set_mouse_mode(Input.MOUSE_MODE_CAPTURED)
func _unhandled_input(event: InputEvent) -> void:
if event is InputEventMouseMotion:
rotation_degrees.x -= event.relative.y * mouse_sensitivity
rotation_degrees.x = clamp(rotation_degrees.x, -78.0, 30.0)
rotation_degrees.y -= event.relative.x * mouse_sensitivity
rotation_degrees.y = wrapf(rotation_degrees.y, 0.0, 360.0)
func _process(_delta):
if Input.is_action_pressed("act_caml"):
rotation_degrees.y -= Input.get_action_strength("act_caml") * -rstick_sensitivity
rotation_degrees.y = wrapf(rotation_degrees.y,0.0, 360)
if Input.is_action_pressed("act_camr"):
rotation_degrees.y -= Input.get_action_strength("act_camr") * rstick_sensitivity
rotation_degrees.y = wrapf(rotation_degrees.y,0.0, 360)
if Input.is_action_pressed("act_camu"):
rotation_degrees.x -= Input.get_action_strength("act_camu") * -rstick_sensitivity
rotation_degrees.x = clamp(rotation_degrees.x, -78, 30)
if Input.is_action_pressed("act_camd"):
rotation_degrees.x -= Input.get_action_strength("act_camd") * rstick_sensitivity
rotation_degrees.x = clamp(rotation_degrees.x, -78, 30)
if Input.is_action_just_pressed("act_camreset"):
rotation_degrees.y = get_node("../SonicDashSonic").rotation_degrees.y + 180
rotation_degrees.x = -10
Sorry for my kinda messy code as well as not using Godot 4, I am still new to the engine and I haven’t had time to make the move to Godot 4 yet.
you can extract “right” vector from camera if it doesn’t rotate around Z axis
var right_vector = camera.global_transform.basis.x
with that you can get your “forward” vector like this
var forward_vector right_vector.cross( -gravity.normalized() )
LazyBigCat | 2023-03-05 22:32