FPS Controller
This commit is contained in:
154
demo/assets/scripts/player/camera_effects.gd
Normal file
154
demo/assets/scripts/player/camera_effects.gd
Normal file
@@ -0,0 +1,154 @@
|
||||
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)
|
||||
Reference in New Issue
Block a user