extends Camera3D @export var height: float = 28.0 @export var horizontal_distance: float = 28.0 @export var horizontal_angle_deg: float = 45.0 @export var size_min: float = 5.0 @export var size_max: float = 30.0 @export var default_size: float = 15.0 @export var focus_slice_thickness: float = 6.0 @export var blur_transition: float = 15.0 var _shake_amount: float = 0.0 var _shake_decay: float = 0.0 var _user_size: float = 0.0 var _charge_active: bool = false func _ready() -> void: set_as_top_level(true) projection = Camera3D.PROJECTION_ORTHOGONAL _user_size = default_size size = default_size near = 0.1 far = 150.0 func _unhandled_input(event: InputEvent) -> void: if event.is_action_pressed("zoom_in"): _user_size = clamp(_user_size / 1.2, size_min, size_max) if event.is_action_pressed("zoom_out"): _user_size = clamp(_user_size * 1.2, size_min, size_max) func _process(delta: float) -> void: var zoom_target := _user_size * DP.f("charge_zoom_factor") if _charge_active else _user_size size = lerpf(size, zoom_target, delta * 8.0) var angle_rad := deg_to_rad(horizontal_angle_deg) var offset := Vector3( sin(angle_rad) * horizontal_distance, height, cos(angle_rad) * horizontal_distance, ) var target := get_parent() as Node3D global_position = target.global_position + offset look_at(target.global_position, Vector3.UP) _update_ortho_tilt_shift_dof(target.global_position) if _shake_amount > 0.005: global_position += Vector3( randf_range(-_shake_amount, _shake_amount), randf_range(-_shake_amount * 0.25, _shake_amount * 0.25), randf_range(-_shake_amount, _shake_amount), ) _shake_amount = move_toward(_shake_amount, 0.0, _shake_decay * delta) func trigger_hit(strength: float) -> void: _shake_amount = strength * 0.5 _shake_decay = _shake_amount / 0.4 func set_charge_active(active: bool) -> void: _charge_active = active func _update_ortho_tilt_shift_dof(target_pos: Vector3) -> void: var cam_attr: CameraAttributesPractical = null if "attributes" in self and self.attributes is CameraAttributesPractical: cam_attr = self.attributes elif "camera_attributes" in self and self.camera_attributes is CameraAttributesPractical: cam_attr = self.camera_attributes if cam_attr != null: var to_target := target_pos - global_position var forward_vector := -global_transform.basis.z var ortho_depth := to_target.dot(forward_vector) var zoom_factor := size / default_size var dynamic_slice := focus_slice_thickness * zoom_factor var half_slice := dynamic_slice * 0.5 var base_transition := blur_transition * zoom_factor cam_attr.dof_blur_far_distance = ortho_depth + half_slice cam_attr.dof_blur_near_distance = maxf(near + 0.1, ortho_depth - half_slice) cam_attr.dof_blur_far_transition = maxf(0.1, base_transition * 0.5) cam_attr.dof_blur_near_transition = maxf(1.0, base_transition * 1.5) cam_attr.dof_blur_far_enabled = false cam_attr.dof_blur_near_enabled = false