Files
fps_project_1/scripts/player.gd
2024-11-06 16:47:18 -06:00

480 lines
16 KiB
GDScript

extends CharacterBody3D
const WALK_TRANSITION_SPEED = 8
const MAX_AIR_DASH = 1
const FLASHLIGHT_BRIGHTNESS = 30
const KICK_AMOUNT = 20
const LAND_CAMERA_TILT : Vector3 = Vector3(-1,0,0)
const WALK_SPEED = 12.0
const SPRINT_SPEED = 15.0
const DASH_SPEED = 40
const SLOWSPEED = .15
const STAMINA_DRAIN = 100
var speed
var double_jump = true
var air_dash = MAX_AIR_DASH
var gravity = 9.8
var is_climbing = false
var ladder_center
var default_gravity = gravity
var moving_fast = false
var moving_fast_top_speed = 0.0
var mouse_input : Vector2
var rng = RandomNumberGenerator.new()
@export_group("Game Settings")
@export var AUDIO = true
@export_group("Player Movement")
@export var DASH_STAM_REQ = 10
@export var MAX_STAMINA = 1800
@export var JUMP_VELOCITY = 6
@export var SENSITIVITY = .01
@export var sensitivity_shift = true
var start_sensitivity
@export_subgroup("Head Bob & Gun Sway")
@export var BOB_FREQ = 2.0
@export var BOB_AMP = 0.08
@export var t_bob = 1.0
@export var weapon_holder : Node3D
@export var weapon_sway_amount : float = .07
@export var weapon_rotation_amount : float = .07
@export_subgroup("FOV")
@export var BASE_FOV : float = 80
@export var FOV_CHANGE = 1.5
var gun : Node
@onready var dead_player : Resource = load("res://assets/dead_cam.tscn")
@onready var pause_menu: Control = $Head/Recoil/Camera3D/PauseMenu
@onready var gun_ray = $Head/Recoil/Camera3D/GunRay
@onready var level_control = get_tree().current_scene
@onready var interact_ray = $Head/Recoil/Camera3D/InteractRay
@onready var bullet_ray = $Head/Recoil/Camera3D/BulletRay
@onready var hitmarker = load("res://hitmarker.tscn")
var instance_bullet
var instance_casing
var instance_mag
var reloading = false
var ammo
var ammo_reserve
var bullet_damage
var def_weapon_holder_pos : Vector3
var weapon_holder_start_rot
var weapon_holder_start_pos
var gun_folded = false
var recoiling_fade = 0
var bullet_destination
var gun_fire_pitch_starting
var current_weapon_index
var recoiling = false
var dead = false
var hud_visible : bool = true
var held_item : Node
var held_item_linear_damp_cache
var held_item_angular_damp_cache
var held_item_gravity_cache
var held_item_mass_cache
var held_item_rotation = Vector3(0,0,0)
# Slow Down Variables
var remaining_stamina = MAX_STAMINA
# Pickups
var picked_up = false
var picked_up_text
var pickup_announce = load("res://assets/pickup_announce.tscn")
var dead_announce = load("res://assets/dead_announce.tscn")
var pickupmsg
@onready var crosshair = $Head/Recoil/Camera3D/Crosshair
@onready var head = $Head
@onready var camera = $Head/Recoil/Camera3D
@onready var world_environment = $"../WorldEnvironment"
@onready var pickup_sound = $Audio/PickupSound
@onready var ear_wind = $Audio/EarWind
@onready var land_sound: AudioStreamPlayer = $Audio/LandSound
@onready var hurt_audio = $Audio/Hurt
@onready var health_indicator = $HealthIndicator
@onready var ammo_counter = $Head/Recoil/Camera3D/AmmoCounter
@onready var stamina_counter = $Head/Recoil/Camera3D/StaminaCounter
@onready var recoil: Node3D = $Head/Recoil
@onready var weapon_spawner = $Head/Recoil/Camera3D/WeaponHolder/WeaponSpawner
@onready var pick_up_detection = $pick_up_detection
@onready var item_holder: Node3D = $Head/ItemHolder
@onready var flashlight: SpotLight3D = $Head/Recoil/Camera3D/WeaponHolder/Flashlight
@onready var flashlight_audio: AudioStreamPlayer3D = $Head/Recoil/Camera3D/WeaponHolder/FlashlightButton
@onready var kick_audio: AudioStreamPlayer3D = $Head/Recoil/Camera3D/Audio/Kick
@onready var weapon_pickup_audio: AudioStreamPlayer = $Audio/WeaponPickup
@onready var crt_filter: ColorRect = $Head/Recoil/Camera3D/crtFilter
@onready var moveable_holder: Node3D = $Head/MoveableHolder
@onready var stand_check: RayCast3D = $StandCheck
@onready var r_hand_test: MeshInstance3D = $Head/Recoil/Camera3D/WeaponHolder/RHandTest
@onready var l_hand_test: MeshInstance3D = $Head/Recoil/Camera3D/WeaponHolder/LHandTest
func _ready():
SignalBus.enemy_hit.connect(enemy_hit)
weapon_holder_start_rot = weapon_holder.rotation
weapon_holder_start_pos = weapon_holder.position
Input.set_mouse_mode(Input.MOUSE_MODE_CAPTURED)
start_sensitivity = SENSITIVITY
var viewportWidth = get_viewport().size.x
var viewportHeight = get_viewport().size.y
health_indicator.size = Vector2(viewportWidth,viewportHeight)
health_indicator.color = Color(0.471, 0, 0, 0)
crt_filter.visible = false
#turn off audio if unchecked in player
if AUDIO == false:
AudioServer.set_bus_volume_db(0,-80)
func _input(event) -> void:
if !level_control.paused:
if event is InputEventMouseMotion:
self.rotate_y(-event.relative.x * SENSITIVITY)
head.rotate_x(-event.relative.y * SENSITIVITY)
head.rotation.x = clamp(head.rotation.x, deg_to_rad(-90), deg_to_rad(85))
mouse_input = event.relative
else:
if event is InputEventMouseMotion:
self.rotate_y(event.relative.x * .00001)
head.rotate_x(event.relative.y * .00001)
head.rotation.x = clamp(head.rotation.x, deg_to_rad(-90), deg_to_rad(85))
mouse_input = event.relative
func _physics_process(delta):
if !dead and !level_control.paused:
# Add the gravity.
if is_on_floor():
double_jump = true
air_dash = MAX_AIR_DASH
else:
velocity.y -= gravity * delta
if abs(velocity.y) >= .1:
moving_fast = true
# Handle jump.
if Input.is_action_just_pressed("jump") and is_on_floor() and !is_climbing:
velocity.y += JUMP_VELOCITY
elif Input.is_action_just_pressed("jump") and double_jump == true and !is_climbing:
velocity.y += JUMP_VELOCITY
double_jump = false
speed = WALK_SPEED #the fuck is this line doing
# Get the input direction and handle the movement/deceleration.
var input_dir = Input.get_vector("move_left", "move_right", "move_up", "move_down")
var direction = (self.transform.basis * Vector3(input_dir.x, 0, input_dir.y)).normalized()
# Handle Sprint
if Input.is_action_just_pressed("sprint") and !is_on_floor():
if air_dash > 0:
velocity.x += direction.x * DASH_SPEED
velocity.z += direction.z * DASH_SPEED
air_dash -= 1
print("AIR DASH " +str(air_dash))
#walking
if is_on_floor() and !is_climbing:
if direction:
velocity.x = lerp(velocity.x, direction.x * speed, delta * WALK_TRANSITION_SPEED)
velocity.z = lerp(velocity.z, direction.z * speed, delta * WALK_TRANSITION_SPEED)
else:
velocity.x = lerp(velocity.x, direction.x * speed, delta * 6.5) + (direction.x * DASH_SPEED)
velocity.z = lerp(velocity.z, direction.z * speed, delta * 6.5) + (direction.z * DASH_SPEED)
#ladder movement
elif is_climbing:
gravity = 0.0
if direction:
velocity.y = -direction.z * speed * .75
velocity.x = direction.x * speed * .3
else:
velocity.y = lerp(velocity.y, -direction.z * speed, delta * 6.5)
velocity.x = lerp(velocity.x, direction.x * speed, delta * 6.5)
#movement in air
else:
velocity.x = lerp(velocity.x, direction.x * speed, delta * 6.5)
velocity.z = lerp(velocity.z, direction.z * speed, delta * 6.5)
# Head bob
t_bob += delta * velocity.length() * float(is_on_floor())
camera.transform.origin = _headbob(t_bob)
# FOV
var velocity_clamped = clamp(velocity.length(), 0.5, SPRINT_SPEED)
var target_fov = BASE_FOV + FOV_CHANGE * velocity_clamped
camera.fov = lerp(camera.fov, target_fov, delta * 8)
# Health Indicator
var health_opacity = 1.5 - level_control.health / level_control.start_health
if level_control.health < (level_control.start_health/2):
health_indicator.color = lerp(Color(0.471, 0, 0, 0), Color(0.471, 0, 0, .25),health_opacity)
# Moving Fast Sound
#initiate fast movement -- may be done with this block
#change sounds with speed
if moving_fast:
var wind_volume = clamp( velocity.length() - 20 ,-80,10)
ear_wind.volume_db = wind_volume
#reset at apex
#cache fastest speed
if abs(velocity.y) > moving_fast_top_speed:
moving_fast_top_speed = abs(velocity.y)
#Land Sound
if velocity.y < .1 and self.is_on_floor() and moving_fast == true:
var land_volume = clamp( moving_fast_top_speed - 20 ,-10,0)
var recoil_amount = Vector3(-.3,0,0)
land_sound.volume_db = land_volume
land_sound.play()
recoil.add_recoil(recoil_amount,10,2)
moving_fast_top_speed = 0.0
moving_fast = false
# Game Speed
if !level_control.paused:
if Input.is_action_pressed("slow_down") and remaining_stamina >0:
Engine.time_scale = lerp(0, 1, SLOWSPEED)
gun.random_spread_amt = 0
AudioServer.set_bus_effect_enabled(0,0,true)
camera.fov = lerp(camera.fov, camera.fov * gun.fov_zoom_amt, delta * 100)
if sensitivity_shift == true:
SENSITIVITY = lerp(SENSITIVITY, SENSITIVITY * .998, delta * 100)
if remaining_stamina >0:
remaining_stamina -= 1000 * delta
else:
Engine.time_scale = 1
gun.random_spread_amt = gun.random_spread_start
AudioServer.set_bus_effect_enabled(0,0,false)
if sensitivity_shift == true:
camera.fov = lerp(camera.fov, BASE_FOV, delta * .5)
SENSITIVITY = start_sensitivity
if remaining_stamina < MAX_STAMINA:
remaining_stamina += STAMINA_DRAIN * delta
elif remaining_stamina > MAX_STAMINA * 1.01:
remaining_stamina -= (STAMINA_DRAIN)/2 * delta
# Reloading
if Input.is_action_just_pressed("reload"):
gun.reload(delta)
if Input.is_action_pressed("inspect") and !gun.anim_player.is_playing():
gun.anim_player.play("inspect")
if Input.is_action_just_pressed("flashlight"):
flashlight_audio.play()
if flashlight.light_energy == 0:
while flashlight.light_energy != FLASHLIGHT_BRIGHTNESS:
flashlight.light_energy = FLASHLIGHT_BRIGHTNESS
elif flashlight.light_energy > 0:
flashlight.light_energy = 0
# Shooting & fire modes
if Input.is_action_pressed("shoot"):
gun.shoot(delta)
if Input.is_action_just_released("shoot"):
gun.cycle_count = gun.cycle_count_start
# Gun folding out of the way
if gun_ray.is_colliding():
weapon_holder.rotation = lerp(weapon_holder.rotation, Vector3(2, -1, -1), delta * 7)
weapon_holder.position = lerp(weapon_holder.position, Vector3(-.02,-.1,.06),(delta * 7))
gun_folded = true
elif !gun_ray.is_colliding():
weapon_holder.rotation = lerp(weapon_holder.rotation, weapon_holder_start_rot,delta*7)
weapon_holder.position = lerp(weapon_holder.position, weapon_holder_start_pos,delta*7)
gun_folded = false
#Weapon Swap Up
if Input.is_action_just_pressed("scroll_up") and !gun.anim_player.is_playing():
if held_item == null:
if level_control.held_guns.size() > 1:
gun.anim_player.play("swap_out")
level_control.gun_spawn(level_control.current_gun_index + 1)
else:
held_item_rotation.y += deg_to_rad(45)
#Weapon Swap Down
if Input.is_action_just_pressed("scroll_down") and !gun.anim_player.is_playing():
if held_item == null:
if level_control.held_guns.size() > 1:
gun.anim_player.play("swap_out")
level_control.gun_spawn(level_control.current_gun_index - 1)
else:
held_item_rotation.y -= deg_to_rad(45)
# Weapon Swap by Numbers
if Input.is_action_just_pressed("numb_1"):
weapon_select(0)
if Input.is_action_just_pressed("numb_2"):
weapon_select(1)
if Input.is_action_just_pressed("numb_3"):
weapon_select(2)
if Input.is_action_just_pressed("numb_4"):
weapon_select(3)
if Input.is_action_just_pressed("numb_5"):
weapon_select(4)
if Input.is_action_just_pressed("numb_6"):
weapon_select(5)
if Input.is_action_just_pressed("numb_7"):
weapon_select(6)
if Input.is_action_just_pressed("numb_8"):
weapon_select(7)
if Input.is_action_just_pressed("numb_9"):
weapon_select(8)
if Input.is_action_just_pressed("numb_0"):
weapon_select(9)
# Move Held Items
if held_item != null:
var held_force_dir = moveable_holder.global_position - held_item.global_position
held_item.set_constant_force(held_force_dir * 30)
held_item.rotation = held_item_rotation #lerp(held_item.rotation, held_item_rotation, delta * 30)
#break when moved too far away
var distance_from_player = abs(self.global_position - held_item.global_position)
if distance_from_player.length() > 5:
release_moveable()
if stand_check.is_colliding():
if stand_check.get_collider() == held_item:
release_moveable()
#interact button
if Input.is_action_just_pressed("interact"):
if held_item != null:
release_moveable()
elif interact_ray.is_colliding():
var body = interact_ray.get_collider()
if interact_ray.get_collider().is_in_group("interact"):
body.get_parent().interact()
if interact_ray.get_collider().is_in_group("moveable"):
grab_moveable(body)
#kick
if Input.is_action_just_pressed("kick"):
if interact_ray.is_colliding():
if interact_ray.get_collider().is_in_group("scene_rigidbody"):
kick_audio.play()
interact_ray.get_collider().linear_velocity += interact_ray.global_transform.basis * Vector3(0,0, -KICK_AMOUNT)
if held_item != null:
release_moveable()
if level_control.health <= 0:
level_control.die()
move_and_slide()
weapon_tilt(input_dir.x, delta)
weapon_sway(delta)
weapon_bob(velocity.length(), delta)
func _headbob(time) -> Vector3:
var pos = Vector3.ZERO
pos.y = sin(time * BOB_FREQ) * BOB_AMP
pos.x = cos(time * BOB_FREQ / 2) * BOB_AMP
return pos
func _on_pick_up_detection_body_entered(body):
if body.is_in_group("pickup"):
if body.pickupable:
body.picked_up()
if body.is_in_group("weapon_pickup"):
weapon_pickup_audio.play()
func ladder_collide(is_climbing):
if is_climbing == true:
gravity = 0.0
else:
gravity = default_gravity
func _on_pick_up_magnet_body_entered(body):
if body.is_in_group("pickup") and body.is_in_group("magnet"):
body.player_follow = self
body.collision_shape.disabled = true
func weapon_tilt(input_x, delta):
if weapon_holder:
weapon_holder.rotation.z = lerp(weapon_holder.rotation.z, -input_x * weapon_rotation_amount * 10, 4 * delta)
if camera:
camera.rotation.z = lerp(camera.rotation.z, -input_x * .075, 5 * delta)
func weapon_sway(delta):
mouse_input = lerp(mouse_input, Vector2.ZERO, 10 * delta)
weapon_holder.rotation.x = lerp(weapon_holder.rotation.x, mouse_input.y * weapon_sway_amount, 5 * delta)
weapon_holder.rotation.y = lerp(weapon_holder.rotation.y, mouse_input.x * weapon_sway_amount, 5 * delta)
func weapon_bob(vel : float, delta):
if weapon_holder:
if vel > 2 and is_on_floor():
var bob_amount : float = 0.05
var bob_freq : float = 0.01
weapon_holder.position.y = lerp(weapon_holder.position.y, def_weapon_holder_pos.y + sin(Time.get_ticks_msec() * bob_freq) * bob_amount, 10 * delta)
weapon_holder.position.x = lerp(weapon_holder.position.x, def_weapon_holder_pos.x + sin(Time.get_ticks_msec() * bob_freq) * bob_amount, 10 * delta)
else:
weapon_holder.position.y = lerp(weapon_holder.position.y, def_weapon_holder_pos.y, .1 * delta)
weapon_holder.position.x = lerp(weapon_holder.position.x, def_weapon_holder_pos.x, .1 * delta)
func weapon_select(gun_id):
if !gun.anim_player.is_playing():
if level_control.held_guns.size() >= (gun_id + 1) and level_control.current_gun_index != gun_id:
gun.anim_player.play("swap_out")
level_control.gun_spawn(gun_id)
func enemy_hit():
var hitmarker_spawn = hitmarker.instantiate()
camera.add_child(hitmarker_spawn)
func toggle_hud(hud_on):
if dead:
crt_filter.visible = hud_on
else:
crosshair.visible = hud_on
ammo_counter.visible = hud_on
stamina_counter.visible = hud_on
func grab_moveable(body):
moveable_holder.global_position = body.global_position
held_item = body
held_item_rotation = body.rotation
#cache rigidbody settings
held_item_linear_damp_cache = body.linear_damp
held_item_angular_damp_cache = body.angular_damp
held_item_gravity_cache = body.gravity_scale
held_item_mass_cache = body.mass
#change rigidbody settings
body.linear_damp = 5
body.angular_damp = 5
body.mass = 1
held_item.gravity_scale = 0
func release_moveable():
held_item_rotation = Vector3(0,0,0)
held_item.gravity_scale = held_item_gravity_cache
held_item.linear_damp = held_item_linear_damp_cache
held_item.angular_damp = held_item_angular_damp_cache
held_item.mass = held_item_mass_cache
held_item.set_constant_force(Vector3(0,0,0))
held_item = null
func hit(damage,fired_by):
level_control.health -= damage
level_control.last_hit = fired_by
recoil.add_recoil(Vector3(.5,.1,.1),10,10)
hurt_audio.play()