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)