388 lines
14 KiB
Plaintext
388 lines
14 KiB
Plaintext
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
|