155 lines
4.7 KiB
GDScript
155 lines
4.7 KiB
GDScript
class_name CameraEffects extends Camera3D
|
|
|
|
@export_category("References")
|
|
@export var player: PlayerController
|
|
|
|
@export_category("Effects")
|
|
@export var enable_tilt: bool = true
|
|
@export var enable_fall_kick: bool = true
|
|
@export var enable_damage_kick: bool = true
|
|
@export var enable_weapon_kick: bool = true
|
|
@export var enable_screen_shake: bool = true
|
|
@export var enable_head_bob: bool = true
|
|
@export_category("Kick & Recoil")
|
|
@export_group("Run Tilt")
|
|
@export var run_pitch: float = 0.1 # Degrees
|
|
@export var run_roll: float = 0.25 # Degrees
|
|
@export var max_pitch: float = 1.0 # Degrees
|
|
@export var max_roll: float = 2.5 # Degrees
|
|
@export_group("Camera Kick")
|
|
@export_subgroup("Fall Kick")
|
|
@export var fall_time: float = 0.3
|
|
@export_subgroup("Damage Kick")
|
|
@export var damage_time: float = 0.3
|
|
@export_subgroup("Weapon Kick")
|
|
@export var weapon_decay: float = 0.5
|
|
@export_subgroup("HeadBob")
|
|
@export_range(0.0, 0.1, 0.001) var bob_pitch: float = 0.05
|
|
@export_range(0.0, 0.1, 0.001) var bob_roll: float = 0.025
|
|
@export_range(0.0, 0.04, 0.001) var bob_up: float = 0.005
|
|
@export_range(3.0, 8.0, 0.1) var bob_frequency: float = 6.0
|
|
|
|
# fall kick private vars
|
|
var _fall_value: float = 0.0
|
|
var _fall_timer: float = 0.0
|
|
|
|
# damage kick private vars
|
|
var _damage_pitch: float = 0.0
|
|
var _damage_roll: float = 0.0
|
|
var _damage_timer: float = 0.0
|
|
|
|
# weapon kick private variable
|
|
var _weapon_kick_angle: Vector3 = Vector3.ZERO
|
|
|
|
# screen shake private variables
|
|
var _screen_shake_tween: Tween
|
|
|
|
# head bob private variables
|
|
var _step_timer: float = 0.0
|
|
|
|
const MIN_SCREEN_SHAKE: float = 0.05
|
|
const MAX_SCREEN_SHAKE: float = 0.5
|
|
|
|
func _process(delta: float) -> void:
|
|
calc_view_offset(delta)
|
|
|
|
|
|
func calc_view_offset(delta: float):
|
|
assert(player, "player is not attached to camera effects script")
|
|
|
|
var offset = Vector3.ZERO
|
|
var angles = Vector3.ZERO
|
|
var velocity = player.velocity
|
|
|
|
if enable_tilt:
|
|
var forward = global_transform.basis.z
|
|
var right = global_transform.basis.x
|
|
|
|
var forward_dot = velocity.dot(forward)
|
|
var forward_tilt = clampf(forward_dot * deg_to_rad(run_pitch), deg_to_rad(-max_pitch), deg_to_rad(max_pitch))
|
|
|
|
var right_dot = velocity.dot(right)
|
|
var side_tilt = clampf(right_dot * deg_to_rad(run_roll), deg_to_rad(-max_roll), deg_to_rad(max_roll))
|
|
|
|
angles.z -= side_tilt
|
|
angles.x += forward_tilt
|
|
|
|
if enable_fall_kick:
|
|
_fall_timer -= delta
|
|
|
|
var fall_ratio = max(0.0, _fall_timer / fall_time)
|
|
var fall_kick_amount = fall_ratio * _fall_value
|
|
|
|
offset.y -= fall_kick_amount
|
|
angles.x -= fall_kick_amount
|
|
|
|
if enable_fall_kick:
|
|
_damage_timer -= delta
|
|
|
|
var damage_ratio = max(0.0, _damage_timer / damage_time)
|
|
angles.x += damage_ratio * _damage_pitch
|
|
angles.z += damage_ratio * _damage_roll
|
|
|
|
if enable_weapon_kick:
|
|
_weapon_kick_angle = _weapon_kick_angle.move_toward(Vector3.ZERO, weapon_decay * delta)
|
|
angles += _weapon_kick_angle
|
|
|
|
if enable_head_bob:
|
|
var speed = Vector2(velocity.x, velocity.z).length()
|
|
|
|
if speed > 0.1 and player.is_on_floor():
|
|
_step_timer += delta * (speed / bob_frequency)
|
|
_step_timer = fmod(_step_timer, 1.0)
|
|
else:
|
|
_step_timer = 0.0
|
|
|
|
var bob_sin = sin(_step_timer * 2.0 * PI) * 0.5
|
|
|
|
var pitch_delta = bob_sin * deg_to_rad(bob_pitch) * speed
|
|
var roll_delta = bob_sin * deg_to_rad(bob_roll) * speed
|
|
var height_delta = bob_sin * delta * bob_up
|
|
|
|
angles.x -= pitch_delta
|
|
angles.z -= roll_delta
|
|
offset.y += height_delta
|
|
|
|
self.position = offset
|
|
self.rotation = angles
|
|
|
|
|
|
func add_fall_kick(fall_strength: float):
|
|
_fall_value = deg_to_rad(fall_strength)
|
|
_fall_timer = fall_time
|
|
|
|
|
|
func add_damage_kick(pitch: float, roll: float, source: Vector3):
|
|
var forward = global_transform.basis.z
|
|
var right = global_transform.basis.x
|
|
var direction = global_position.direction_to(source)
|
|
var forward_dot = direction.dot(forward)
|
|
var right_dot = direction.dot(right)
|
|
_damage_pitch = deg_to_rad(pitch) * forward_dot
|
|
_damage_roll = deg_to_rad(roll) * right_dot
|
|
_damage_timer = damage_time
|
|
|
|
|
|
func add_weapon_kick(pitch: float, yaw: float, roll: float):
|
|
_weapon_kick_angle.x += deg_to_rad(pitch)
|
|
_weapon_kick_angle.y += deg_to_rad(randf_range(-yaw, yaw))
|
|
_weapon_kick_angle.z += deg_to_rad(randf_range(-roll, roll))
|
|
|
|
|
|
func add_screen_shake(amount: float, seconds: float) -> void:
|
|
if _screen_shake_tween:
|
|
_screen_shake_tween.kill()
|
|
|
|
_screen_shake_tween = create_tween()
|
|
_screen_shake_tween.tween_method(update_screen_shake.bind(amount), 0.0, 1.0, seconds).set_ease(Tween.EASE_OUT)
|
|
|
|
|
|
func update_screen_shake(alpha: float, amount: float) -> void:
|
|
amount = remap(amount, 0.0, 1.0, MIN_SCREEN_SHAKE, MAX_SCREEN_SHAKE)
|
|
var current_shake_amount = amount * (1.0 - alpha)
|
|
h_offset = randf_range(-current_shake_amount, current_shake_amount)
|
|
v_offset = randf_range(-current_shake_amount, current_shake_amount)
|