class_name FollowCamera extends Camera3D const ROTATE_SPEED: float = 1.5 const ROTATE_WEIGHT: float = 8.0 const ROTATE_UP_SPEED: float = 0.7 const ROTATE_UP_WEIGHT: float = 4.0 const ANGLE_UP_MIN: float = 0.5 const ANGLE_UP_MAX: float = 1.2 const LOOK_WEIGHT: float = 8.0 const MOVE_WEIGHT: float = 2.0 const CAMERA_DISTANCE: float = 10 @export var target: Node3D var angle_target: float = 0 var angle: float = 0 var angle_up_target: float = 1 var angle_up: float = 1 var ground: Vector3 func _ready(): if target == null: push_warning("target is not set") else: ground = target.position func _process(delta): if target != null: follow(delta) func follow(delta): var new_transform = transform.looking_at(target.position) transform.basis = transform.basis.from_euler(Vector3( lerp_angle(transform.basis.get_euler().x, new_transform.basis.get_euler().x, delta * LOOK_WEIGHT), lerp_angle(transform.basis.get_euler().y, new_transform.basis.get_euler().y, delta * LOOK_WEIGHT), lerp_angle(transform.basis.get_euler().z, new_transform.basis.get_euler().z, delta * LOOK_WEIGHT) )) angle_target += Input.get_axis("rotate_left", "rotate_right") * ROTATE_SPEED * delta angle = lerp_angle(angle, angle_target, delta * ROTATE_WEIGHT) angle_up_target += Input.get_axis("rotate_down", "rotate_up") * ROTATE_UP_SPEED * delta angle_up_target = clamp(angle_up_target, ANGLE_UP_MIN, ANGLE_UP_MAX) angle_up = lerp_angle(angle_up, angle_up_target, delta * ROTATE_UP_WEIGHT) ground = ground.lerp(target.position, delta * MOVE_WEIGHT) position = ground + Vector3(0, sin(angle_up) * CAMERA_DISTANCE, cos(angle_up) * CAMERA_DISTANCE).rotated(Vector3.UP, angle)