extends CharacterBody3D class_name PlayerCharacter var aceleration = 3.32 #Current aceleration var maxSpeed = 5.3 #Maximum Speed var sprintSpeed = 2.31 #Additional Speed gained while Sprinting var slowdownSpeedLimit: float = 0.8 #How fast the player can go when slowed var gear: String = "neutral" #Weather the player is going forward, backward or standing still var slowed: bool = false var momentum: Vector3 = Vector3(0,0,0) var deceleration:float = 6.0 var turnSpeed = 0.469 #Speed at wich legs turn sideways var sprintStillTurnSpeed = 1.169 #Speed at wich the legs turns sideways when holding sprint and standing still var drivingTurnSpeed = 0.2569 #Speed at wich legs turn sideways while driving var driftingTurnSpeed = 1.5 #Speed increase of turn while drifting var facingDirection = Vector2(0,1) #Where the legs are facing var sprinting = false #While Player is sprinting var sprintEnergy = 100 #Energy used for Sprinting var sprintEnergyUse = 17.5 #How much % energy is used per 1 sec of sprint var sprintEnergyGain = 30 #How much % energy is gained per 1 sec of recovery var maxDriftAngle = 0.12 #Quaternion(0,0,0.06,0.998).normalized() #How much the playesr turns to the side while drifting (radians) var rightLeftLean: float = 0.0 #How much the player leans right or left from -1 to 1 with negative numbers being left and 0 being no lean var currentControlState: int = 0 enum controls {DEFAULT,STANDARD_MINIGAME} var health: float = 100.0 var invoulnerable: bool = false var alive: bool = true @onready var camera := $pivot/CameraPivot/Camera3D @onready var cameraPivot := $pivot/CameraPivot @onready var flashlightR := $pivot/pivotRightLeg/pivotLeftLeg/body/flashlightR @onready var flashlightL :=$pivot/CameraPivot/Camera3D/flashlightL @onready var backlightR := $pivot/pivotRightLeg/pivotLeftLeg/body/BacklightR @onready var backlightL := $pivot/pivotRightLeg/pivotLeftLeg/body/BacklightL @onready var pivot: = $pivot @onready var headPivot: = $pivot/pivotRightLeg/pivotLeftLeg/HeadBinoculars/HeadPivot @onready var headBinoculars: = $pivot/pivotRightLeg/pivotLeftLeg/HeadBinoculars @onready var binoculars := $pivot/pivotRightLeg/pivotLeftLeg/HeadBinoculars/HeadPivot/Binoculars @onready var legs := $pivot/pivotRightLeg/pivotLeftLeg/CaterpillarLegs @onready var body: = $pivot/pivotRightLeg/pivotLeftLeg/body @onready var hud = $/root/Main/Hud @onready var interactCross := $/root/Main/Hud/InteractCross @onready var sprintBar := $/root/Main/Hud/TextureProgressBar @onready var grabRaycast: = $pivot/CameraPivot/Camera3D/GrabDetector @onready var grabPivot: = $pivot/pivotRightLeg/pivotLeftLeg/body/GrabPivot @onready var grabBox: = $pivot/pivotRightLeg/pivotLeftLeg/body/GrabBox var grabbedObject: GrabableObject @onready var interactRaycast = $pivot/CameraPivot/Camera3D/InteractDetector @onready var pivotRightLeg = $pivot/pivotRightLeg @onready var pivotLeftLeg = $pivot/pivotRightLeg/pivotLeftLeg var mouseSensetivity := 0.1 #How much mouse movement affects ingame camera movement var spectatorScene: PackedScene = preload("res://actors/Player/Spectator.tscn") var spectatorParent: Node3D var mapLogic: MapLogic #Camera Shake Stuff var traumaReductionRate:float = 0.34 var trauma: float = 0 @export var maxX = 12 @export var maxY = 12 @export var maxZ = 7 @export var shakeIntensety := 7.0 var time: float = 0 @export var noise: Noise var noiseSpeed: float = 50 var initialRotation = rotation_degrees as Vector3 # Camera Shake Stuff end func _enter_tree() -> void: set_multiplayer_authority(name.to_int()) if is_multiplayer_authority(): $/root/Main/Hud/Identifier.show() $"pivot/CameraPivot/Camera3D".make_current() $pivot/pivotRightLeg/pivotLeftLeg/HeadBinoculars.hide() $/root/Main/Hud/TextureProgressBar.show() func _ready() -> void: Multiplayer.peer_connected(int(name)) Input.mouse_mode = Input.MOUSE_MODE_CAPTURED mapLogic = Multiplayer.currentMapLogic spectatorParent = get_node("/root/Main/Spectators") if mapLogic: mapLogic.onCollision.connect(onCollision) if is_multiplayer_authority(): position.y += 2 return func _process(delta: float) -> void: if not is_multiplayer_authority(): return if not alive: return #$/root/Main/Hud/Identifier.text = str(cameraPivot.global_rotation.y*180/PI) var cam_rot = cameraPivot.global_rotation.y*180/PI if cam_rot < 135 and cam_rot > 45: #NORTH (x+) $/root/Main/Hud/Identifier.text="North" elif cam_rot > -45 and cam_rot < 45: #EAST (z+) $/root/Main/Hud/Identifier.text="East" elif cam_rot > -135 and cam_rot < -45: #SOUTH (x-) $/root/Main/Hud/Identifier.text="South" else: #WEST $/root/Main/Hud/Identifier.text="West" if invoulnerable and trauma == 0.0: invoulnerable = false if Input.is_action_just_pressed("debug"): die() match currentControlState: controls.DEFAULT: regularControlsIdle(delta) controls.STANDARD_MINIGAME: standardMinigameControlsIdle(delta) func _physics_process(delta: float) -> void: if not is_multiplayer_authority(): return if not alive: return match currentControlState: controls.DEFAULT: regularControlsPhysics(delta) controls.STANDARD_MINIGAME: endOfPhysicsCleanup(delta) func standardMinigameControlsIdle(_delta:float): if Input.is_action_just_pressed("moveDown") or Input.is_action_just_pressed("interact"): currentControlState = controls.DEFAULT func regularControlsIdle(_delta:float): #Interacting Logic var InteractCollider: InteractBox = interactRaycast.get_collider() if InteractCollider and Input.is_action_just_pressed("interact"): InteractCollider.playerRef = self InteractCollider.interact() if InteractCollider.type == "minigame": currentControlState = controls.STANDARD_MINIGAME momentum = Vector3(0,0,0) #Grabbing Logic var GrabCollider: GrabBox = grabRaycast.get_collider() var grabBoxCollider: Array[Area3D] = grabBox.get_overlapping_areas() if(grabBoxCollider and Input.is_action_just_pressed("interact") and !grabbedObject): if grabBoxCollider.has(GrabCollider): #If the player is looking at an object and it is in the grab box grabbedObject = GrabCollider.grab() else: #If the player is not looking at an object, grab the closet one in the grab box var closestObj: GrabBox var distanceToClosestObj: float = 100 for grabObj in grabBoxCollider: if (getDistance(self,grabObj) < distanceToClosestObj): closestObj = grabObj distanceToClosestObj = getDistance(self, grabObj) grabbedObject = closestObj.grab() if InteractCollider or grabBoxCollider: interactCross.show() else: interactCross.hide() if Input.is_action_just_pressed("flashlight"): #flashlightL.visible = !flashlightL.visible flashlightR.visible = !flashlightR.visible if gear == "backward": backlightL.show() backlightR.show() else: backlightR.hide() backlightL.hide() if grabbedObject: grabbedObject.global_position = grabPivot.global_position# + grabbedObject.grabPositionPositionOffset grabbedObject.rotation = grabPivot.global_rotation + grabbedObject.grabPositionRotationOffset if grabbedObject.grabBox.heavy: slowed = true if Input.is_action_just_pressed("drop"): grabbedObject.release.rpc() grabbedObject = null slowed = false momentum = Vector3(0,0,0) if Input.is_action_just_pressed("throw"): grabbedObject.release.rpc() grabbedObject.throw.rpc_id(1,facingDirection.x,facingDirection.y,camera.rotation.x) grabbedObject = null slowed = false momentum = Vector3(0,0,0) func regularControlsPhysics(delta: float): gear = "neutral" if Input.is_action_pressed("moveUp"): gear = "forward" if Input.is_action_pressed("moveDown"): gear = "backward" if Input.is_action_pressed("Sprint"): sprinting = true else: sprinting = false #Rotating Basis without affecting some children var _bodyRotationKeep = body.global_rotation var headBinocularsKeep = headBinoculars.global_basis var headPivotKeepX = headPivot.global_rotation.x var headPivotKeepY = headPivot.global_rotation.y var cameraPivotKeepRot = cameraPivot.global_rotation pivot.rotation.y = atan2(facingDirection.x,facingDirection.y) if !sprinting: sprintEnergy = clamp(sprintEnergy + sprintEnergyGain * delta, 0 , 100) if not is_on_floor(): momentum = get_gravity() if Input.is_action_pressed("moveLeft"): turn(-1,delta) if Input.is_action_pressed("moveRight"): turn(1,delta) #Apply Speed match gear: "forward": momentum += Vector3(facingDirection.x,0,facingDirection.y) * aceleration * delta if sprinting and sprintEnergy >= 5: momentum += Vector3(facingDirection.x,0,facingDirection.y) * (aceleration + sprintSpeed) * delta useSprintEnergy(delta) momentum = clampVectorLength(momentum,0,maxSpeed + sprintSpeed) else: momentum = clampVectorLength(momentum,0,maxSpeed) "neutral": momentum -= momentum.normalized() * deceleration * delta #decelerate by deceleration/ seccond if momentum.length() < 0.1: momentum = Vector3(0,0,0) "backward": momentum -= Vector3(facingDirection.x,0,facingDirection.y) * (aceleration) * delta momentum = clampVectorLength(momentum,0,maxSpeed/2.0) if momentum.length() < 6: unTilt(delta) #End of Frame cleanup #Rotation Stuff cameraPivot.global_rotation.x = cameraPivotKeepRot.x cameraPivot.global_rotation.y = cameraPivotKeepRot.y headPivot.global_rotation.x = headPivotKeepX headPivot.global_rotation.y = headPivotKeepY headBinoculars.global_basis = headBinocularsKeep cameraPivot.rotation.z = pivotLeftLeg.rotation.z + pivotRightLeg.rotation.z endOfPhysicsCleanup(delta) if slowed: velocity = clampVectorLength(momentum,0,slowdownSpeedLimit) else: velocity = momentum move_and_slide() #applies movement func turn(leftRight: int,delta:float): match gear: "backward": drivingTurn(-leftRight,1,delta) "neutral": if sprinting and sprintEnergy >= 5: facingDirection = facingDirection.rotated(leftRight * PI * delta * sprintStillTurnSpeed) useSprintEnergy(delta) else: facingDirection = facingDirection.rotated(leftRight * PI * delta * turnSpeed) "forward": if momentum.length() >= 6: setRightLeftLean(leftRight,0.75,delta) tiltRightLeft() drivingTurn(leftRight,driftingTurnSpeed,delta) else: drivingTurn(leftRight,1,delta) func endOfPhysicsCleanup(delta: float): trauma = max(trauma-delta*traumaReductionRate,0) time += delta rotation_degrees.x = initialRotation.x + maxX * getShakeIntensity() * getNoiseFromSeed(343) rotation_degrees.y = initialRotation.y + maxY * getShakeIntensity() * getNoiseFromSeed(123) rotation_degrees.z = initialRotation.z + maxZ * getShakeIntensity() * getNoiseFromSeed(234) #Rotate head based on camera movement headPivot.rotation.y = cameraPivot.rotation.y headPivot.rotation.x = -camera.rotation.x if trauma == 0.0: headPivot.rotation.z = 0.0 headBinoculars.rotation.z = 0.0 sprintBar.value = sprintEnergy func drivingTurn(leftRight: int,mult: float, delta: float) -> void: facingDirection = facingDirection.rotated(leftRight * PI * delta * drivingTurnSpeed * mult) momentum = momentum.rotated(Vector3(0,1,0),-leftRight * PI * delta * drivingTurnSpeed * mult) func useSprintEnergy(delta: float): sprintEnergy = clamp(sprintEnergy - sprintEnergyUse * delta, 0, 100) func setRightLeftLean(direction: int, strength: float, delta: float) -> void: if direction > 0 and rightLeftLean < 0: rightLeftLean = 0 elif direction < 0 and rightLeftLean > 0: rightLeftLean = 0 rightLeftLean = clamp(rightLeftLean + strength * delta * direction,-1,1) func getDistance(a: Node3D, b: Node3D) -> float: var distanceVector: Vector3 distanceVector = b.global_position - a.global_position return distanceVector.length() func tiltRightLeft() -> void: if rightLeftLean < 0: pivotLeftLeg.rotation.z = lerp_angle(pivotLeftLeg.rotation.z,-maxDriftAngle,abs(rightLeftLean)) else: pivotRightLeg.rotation.z = lerp_angle(pivotRightLeg.rotation.z,maxDriftAngle,abs(rightLeftLean)) func unTilt(delta: float) -> void: rightLeftLean = lerpf(rightLeftLean,0,0.5*delta) pivotLeftLeg.rotation.z = lerp_angle(pivotLeftLeg.rotation.z,0.0,1-abs(rightLeftLean)) pivotRightLeg.rotation.z = lerp_angle(pivotRightLeg.rotation.z,0.0,1-abs(rightLeftLean)) func clampVectorLength(Vector: Vector3, minLength: float, maxLength: float) -> Vector3: #scales Vector up/ down to the max/ min length givin. If the Vector has a length of 0 it will be returned without being scaled. if Vector.length() == 0: return Vector if Vector.length() < minLength: return Vector * minLength / Vector.length() elif Vector.length() > maxLength: return Vector * maxLength / Vector.length() return Vector func onCollision() -> void: trauma = 1 func addTrauma(traumaAmount: float): trauma = clamp(trauma+traumaAmount,0,1) func getShakeIntensity() -> float: return shakeIntensety * trauma * trauma func getNoiseFromSeed(seed_: int) -> float: noise.seed = seed_ return noise.get_noise_1d(time*noiseSpeed) func _input(event: InputEvent) -> void: #Camera movement with mouse if event is InputEventMouseMotion && Input.mouse_mode == 2: camera.rotation.x -= clamp(deg_to_rad(event.relative.y * mouseSensetivity),-180,180) cameraPivot.rotation.y -= deg_to_rad(event.relative.x * mouseSensetivity) camera.rotation_degrees.x = clamp(camera.rotation_degrees.x, -70, 70) cameraPivot.rotation.z = 0 func _on_hurt_box_hit_taken(attack: Attack) -> void: if invoulnerable: return trauma = attack.trauma health -= attack.damage if health <= 0.0: die() invoulnerable = true func die() -> void: Multiplayer.alivePlayerDict.erase(int(name)) headBinoculars.show() headPivot.position = Vector3(0,0.382,0.063) headPivot.rotation = Vector3(0,0,0) $"pivot/pivotRightLeg/pivotLeftLeg/body/Grabby Arms_L".rotation.x = deg_to_rad(90) $"pivot/pivotRightLeg/pivotLeftLeg/body/Grabby Arms_R".rotation.x = deg_to_rad(90) var spectator = spectatorScene.instantiate() spectatorParent.add_child(spectator) camera.current = false alive = false