REM/scripts/Player.gd
2026-03-26 20:37:29 -06:00

312 lines
10 KiB
GDScript

extends CharacterBody3D
@export var head_bob: bool = true
@export_category("Movement")
@export var WALK = 3
@export var RUN = 6
@export var CROUCH = 1.5
@export var JUMP_VELOCITY = 4
@export var HEAVY = 0.5
@export var run_toggle = false
@export_category("Jumping")
@export var floating_jump = false
@export var infinite_jump = false
@export var no_jump = false
@export_category("Constructs")
@export var grapple_speed = 20
#var grap_post = Vector3(0,0,0)
@export_category("Items")
@export var keys = []
@export var inventory = ["hydrogen_peroxide", "vinegar"]
# Get the gravity from the project settings to be synced with RigidBody nodes.
var gravity = ProjectSettings.get_setting("physics/3d/default_gravity")
## the current modifier to movement speed
## Changes based on whether player is walking, running, crouching...
var speed_mode: float
var con_mod: float = 1
var switch_state_run = false
var switch_state_crouch = false
var current_time: int = 12
var contains: bool = false
@onready var neck := $Neck
@onready var con_animation := $ConstructAnimation
@onready var player_animation: AnimationPlayer = $PlayerAnimation
@onready var interactor_ray: RayCast3D = $Neck/FirstPersonCamera/InteractorRay
@onready var dumping_ray: RayCast3D = $Neck/FirstPersonCamera/DumpingRay
@onready var grapple_ray: RayCast3D = $Neck/FirstPersonCamera/GrappleRay
@onready var mesh_instance: MeshInstance3D = $MeshInstance3D
@onready var collision: CollisionShape3D = $CollisionShape3D
@onready var camera := $Neck/FirstPersonCamera
@onready var construct: Node3D = $Neck/FirstPersonCamera/ItemRig/Construct
func _ready():
speed_mode = WALK
func _unhandled_input(event):
if event is InputEventMouseButton:
Input.set_mouse_mode(Input.MOUSE_MODE_CAPTURED)
if Input.get_mouse_mode() == Input.MOUSE_MODE_CAPTURED:
if event is InputEventMouseMotion:
if camera.current:
## First Person Camera
neck.rotate_y(-event.relative.x * 0.01)
camera.rotate_x(-event.relative.y * 0.01)
camera.rotation.x = clamp(camera.rotation.x, deg_to_rad(-60), deg_to_rad(60))
func _physics_process(delta):
##Neck is magically at 0.56 on the y after being set to 0.3 in the player scene???
#print("neck positon: " + str(neck.position.y))
##CONSTRUCT FUNCTIONS
if construct.CONSTRUCT_TYPE.name == "Stick":
use_stick()
##If the player is using the hammer then go into the hammer function.
elif construct.CONSTRUCT_TYPE.name == "Hammer":
use_hammer()
elif construct.CONSTRUCT_TYPE.name == "Weight":
use_weight()
##Change the the current_time when time changing occurs
elif construct.CONSTRUCT_TYPE.name == "Time":
use_time()
elif construct.CONSTRUCT_TYPE.name == "fishing_rod":
use_fishing_rod(delta)
elif construct.CONSTRUCT_TYPE.name == "shovel":
use_shovel()
##Gravity
##If not grappling (issue with gravity pulling the player down from grapple spot)
if not is_on_floor() and Global.grappling == false:
velocity.y -= gravity * delta
##Jumping
##Check that jumping is enabled
if not no_jump:
##Infinite Jump
if infinite_jump:
##Handle jump.
if Input.is_action_just_pressed("Jump"): #and is_on_floor():
velocity.y = JUMP_VELOCITY * con_mod
##Floating Jump
elif floating_jump:
## Will float up when space is held
## Mod on jump for TESTING
if Input.is_action_pressed("Jump"):
velocity.y = JUMP_VELOCITY * con_mod
else:
if Input.is_action_just_pressed("Jump") and is_on_floor():
velocity.y = JUMP_VELOCITY * con_mod
##Player Crouch
if Input.is_action_just_pressed("Crouch") and is_on_floor():
if !switch_state_crouch:
speed_mode = CROUCH
collision.shape.height = 1
player_animation.play("crouch")
switch_state_crouch = true
elif switch_state_crouch:
speed_mode = WALK
collision.shape.height = 2
player_animation.play_backwards("crouch")
switch_state_crouch = false
switch_state_run = false
if camera.current:
# Get the input direction and handle the movement/deceleration.
var input_dir = Input.get_vector("Left", "Right", "Forward", "Back")
var direction = (neck.global_basis * Vector3(input_dir.x, 0, input_dir.y)).normalized()
if direction:
velocity.x = direction.x * speed_mode * con_mod
velocity.z = direction.z * speed_mode * con_mod
##Run set to toggle
if run_toggle == true:
if Input.is_action_just_pressed("Run") and switch_state_crouch == false:
if !switch_state_run:
speed_mode = RUN
switch_state_run = true
elif switch_state_run:
speed_mode = WALK
switch_state_run = false
##Run set to hold
elif run_toggle == false:
if Input.is_action_pressed("Run") and switch_state_crouch == false:
speed_mode = RUN
switch_state_run = true
else:
if switch_state_crouch == false:
speed_mode = WALK
switch_state_run = false
else:
#Don't move
velocity.x = move_toward(velocity.x, 0, WALK)
velocity.z = move_toward(velocity.z, 0, WALK)
#switch_state_run = false
#if switch_state_crouch == false and (run_toggle == true and switch_state_run == false):
#speed_mode = WALK
## Top Down Movement mode
#if camera_top_down.current:
#top_down_movement()
make_head_bob()
move_and_slide()
func make_head_bob():
#Allows head bob to be disabled
if head_bob == true:
#Track if the player is moving
if self.velocity.x != 0 or self.velocity.z != 0:
#Do a head bob animation and have it play at a speed equiv to move speed
player_animation.speed_scale = speed_mode / 4
player_animation.play("head_bob")
else:
player_animation.stop()
func use_shovel():
if Input.is_action_just_pressed("UseConstruct"):
##Change this to be a shovel animation
if not con_animation.is_playing():
con_animation.play("swing")
if interactor_ray.is_colliding():
print("is colliding")
if interactor_ray.get_collider().is_in_group("snow_spot") and contains == false:
##Make sure the pile has snow
if interactor_ray.get_collider().get_parent().snow_amount > 0:
interactor_ray.get_collider().get_parent().snow_amount -= 1
contains = true
##Show the shovel as having snow
self.find_child("shovel").find_child("snow").show()
if Input.is_action_just_pressed("UseConstructAlt"):
##Change this to shovel dump
if not con_animation.is_playing():
con_animation.play("swing")
if contains:
##If dumping snow not in pile
if dumping_ray.is_colliding():
if !dumping_ray.get_collider().is_in_group("snow_spot"):
contains = false
##Hide the snow
self.find_child("shovel").find_child("snow").hide()
else:
contains = false
##Hide the snow
self.find_child("shovel").find_child("snow").hide()
##Add snow to snow spot if it is colliding
if dumping_ray.is_colliding():
if dumping_ray.get_collider().is_in_group("snow_spot"):
##Make sure the pile is not full
if dumping_ray.get_collider().get_parent().snow_amount < 3:
dumping_ray.get_collider().get_parent().snow_amount += 1
contains = false
##Hide the snow
self.find_child("shovel").find_child("snow").hide()
func use_fishing_rod(delta):
##Play the animation every time the construct is used
if Input.is_action_just_pressed("UseConstruct"):
if not con_animation.is_playing():
con_animation.play("swing")
##Use the grapple
grapple(delta)
## If the player is using the hammer play the animation and check for breakable objects
func use_hammer():
if Input.is_action_just_pressed("UseConstruct"):
if not con_animation.is_playing():
con_animation.play("swing")
if interactor_ray.is_colliding():
if interactor_ray.get_collider().is_in_group("breakable"):
interactor_ray.get_collider().stability -= 1
func use_tape():
if Input.is_action_just_pressed("UseConstruct"):
if not con_animation.is_playing():
pass ##TODO Add Construct Animation: con_animation.play("toss")
##TODO Remove this and apply it to tape!!!
if interactor_ray.get_collider().is_in_group("fixable"):
interactor_ray.get_collider().fixed = true
##If the player has the weight selected, play a lil animation when they try to use the construct
func use_weight():
if Input.is_action_just_pressed("UseConstruct"):
if not con_animation.is_playing():
con_animation.play("toss")
func use_stick():
if Input.is_action_just_pressed("UseConstruct"):
if not con_animation.is_playing():
con_animation.play("swing")
func use_time():
if Input.is_action_just_pressed("UseConstruct"):
construct.construct_mesh2.rotation += Vector3(0,deg_to_rad(-30),0)
if current_time < 24:
current_time += 1
else:
current_time = 1
#print("current_time: " + str(current_time))
func grapple(delta):
#print(Global.grap_post)
#print(Global.grappling)
##If valid grapple point in range and grapple button pressed then set grapple true and get grapple point position
if grapple_ray.is_colliding() and grapple_ray.get_collider().is_in_group("grapple_point") and Global.grappling == false:
if Input.is_action_just_pressed("UseConstruct"):
Global.grappling = true
Global.grap_post = grapple_ray.get_collider().position
##If the use item button is released stop grappling
##If the player jumps cancel the grapple
if Input.is_action_just_released("UseConstruct") or Input.is_action_just_pressed("Jump"):
Global.grappling = false
## If grappling move the player towards the target point
##TODO Make it so the player can only get so close to the grapple point?
if Global.grappling:
#for i in range(0, grapple_speed):
self.position = position.move_toward(Global.grap_post - Vector3(0,1.5,0), delta * grapple_speed)
## Test function to shift between two different areas in the same scene
## Based on time travel mechanic implementation in Dishonered 2
## Idea with this would be to allow "instance" transfer between different dreamscapes
## This test allows the player to do it with a key press but later implementations would require the right interactable prompt
func shift():
if Input.is_action_just_pressed("shift"):
if self.global_position.y > 1000:
self.translate(Vector3(0,-1002,0))
elif self.global_position.y < 1000:
self.translate(Vector3(0,1001,0))
else:
print(self.global_position)