first commit
This commit is contained in:
@@ -0,0 +1,114 @@
|
||||
extends Node3D
|
||||
|
||||
#class name
|
||||
class_name CameraObject
|
||||
|
||||
@export_group("Camera variables")
|
||||
@export_range(0.0, 5.0, 0.01) var XAxisSens : float
|
||||
@export_range(0.0, 5.0, 0.01) var YAxisSens : float
|
||||
@export var maxUpAngleView : float
|
||||
@export var maxDownAngleView : float
|
||||
|
||||
@export_group("FOV variables")
|
||||
@export var startFOV : float
|
||||
@export var runFOV : float
|
||||
@export var fovTransitionSpeed : float
|
||||
|
||||
@export_group("Movement changes variables")
|
||||
@export var baseCamAngle : float
|
||||
@export var crouchCamAngle : float
|
||||
@export var baseCameraLerpSpeed : float
|
||||
@export var crouchCameraLerpSpeed : float
|
||||
@export var crouchCameraDepth : float
|
||||
|
||||
@export_group("Camera bob variables")
|
||||
@export var enableBob : bool = true
|
||||
var headBobValue : float
|
||||
@export var bobFrequency : float
|
||||
@export var bobAmplitude : float
|
||||
|
||||
@export_group("Camera tilt variables")
|
||||
@export var enableTilt : bool = true
|
||||
@export var tiltRotationValue : float
|
||||
@export var tiltRotationSpeed : float
|
||||
@export var inAirTiltValDivider : float
|
||||
|
||||
@export_group("Input variables")
|
||||
var mouseInput : Vector2
|
||||
@export var mouseInputSpeed : float
|
||||
var playCharInputDir : Vector2
|
||||
|
||||
#Mouse variables
|
||||
var mouseFree : bool = false
|
||||
|
||||
@export_group("Keybind variables")
|
||||
@export var mouseModeAction : String = ""
|
||||
|
||||
#References variables
|
||||
@onready var camera : Camera3D = %Camera
|
||||
@onready var playChar : PlayerCharacter = $".."
|
||||
@onready var weaponManager : Node3D = %WeaponManager
|
||||
|
||||
func _ready():
|
||||
Input.set_mouse_mode(Input.MOUSE_MODE_CAPTURED) #set mouse as captured
|
||||
|
||||
func _unhandled_input(event):
|
||||
#this function manage camera rotation (360 on x axis, blocked at <= -60 and >= 60 on y axis, to not having the character do a complete head turn, which will be kinda weird)
|
||||
if event is InputEventMouseMotion:
|
||||
rotate_y(-event.relative.x * (XAxisSens / 10))
|
||||
camera.rotate_x(-event.relative.y * (YAxisSens / 10))
|
||||
camera.rotation.x = clamp(camera.rotation.x, deg_to_rad(maxUpAngleView), deg_to_rad(maxDownAngleView))
|
||||
mouseInput = event.relative #get position of the mouse in a 2D sceen, so save it in a Vector2
|
||||
|
||||
func _process(delta):
|
||||
applies(delta)
|
||||
|
||||
cameraBob(delta)
|
||||
|
||||
cameraTilt(delta)
|
||||
|
||||
func applies(delta : float):
|
||||
#manage the differents camera modifications relative to a specific state, except for the FOV
|
||||
if playChar.stateMachine.currStateName == "Crouch":
|
||||
position.y = lerp(position.y, 0.715 + crouchCameraDepth, crouchCameraLerpSpeed * delta)
|
||||
rotation.z = lerp(rotation.z, deg_to_rad(crouchCamAngle) * playChar.inputDirection.x if playChar.inputDirection.x != 0.0 else deg_to_rad(crouchCamAngle), crouchCameraLerpSpeed * delta)
|
||||
elif playChar.stateMachine.currStateName == "Run":
|
||||
camera.fov = lerp(camera.fov, runFOV, fovTransitionSpeed * delta)
|
||||
rotation.z = lerp(rotation.z, deg_to_rad(baseCamAngle), baseCameraLerpSpeed * delta)
|
||||
elif playChar.stateMachine.currStateName == "Jump":
|
||||
# Maintain the current FOV when jumping
|
||||
camera.fov = lerp(camera.fov, camera.fov, fovTransitionSpeed * delta)
|
||||
elif playChar.stateMachine.currStateName == "Inair":
|
||||
# Maintain the current FOV when in air
|
||||
camera.fov = lerp(camera.fov, camera.fov, fovTransitionSpeed * delta)
|
||||
else:
|
||||
position.y = lerp(position.y, 0.715, baseCameraLerpSpeed * delta)
|
||||
rotation.z = lerp(rotation.z, deg_to_rad(baseCamAngle), baseCameraLerpSpeed * delta)
|
||||
camera.fov = lerp(camera.fov, startFOV, fovTransitionSpeed * delta)
|
||||
|
||||
func cameraBob(delta):
|
||||
if enableBob:
|
||||
headBobValue += delta * playChar.velocity.length() * float(playChar.is_on_floor())
|
||||
camera.transform.origin = headbob(headBobValue, bobFrequency, bobAmplitude)
|
||||
|
||||
func headbob(time, bobFreq, bobAmpli):
|
||||
#some trigonometry stuff here, basically it uses the cosinus and sinus functions (sinusoidal function) to get a nice and smooth bob effect
|
||||
var pos = Vector3.ZERO
|
||||
pos.y = sin(time * bobFreq) * bobAmpli
|
||||
pos.x = cos(time * bobFreq / 2) * bobAmpli
|
||||
return pos
|
||||
|
||||
func cameraTilt(delta):
|
||||
if enableTilt:
|
||||
#this function manage the camera tilting when the character is moving on the x axis (left and right)
|
||||
if playChar.moveDirection != Vector3.ZERO and playChar.inputDirection != Vector2.ZERO:
|
||||
playCharInputDir = playChar.inputDirection #get input direction to know where the character is heading to
|
||||
#apply smooth tilt movement
|
||||
if !playChar.is_on_floor(): rotation.z = lerp(rotation.z, -playCharInputDir.x * tiltRotationValue/inAirTiltValDivider, tiltRotationSpeed * delta)
|
||||
else: rotation.z = lerp(rotation.z, -playCharInputDir.x * tiltRotationValue, tiltRotationSpeed * delta)
|
||||
|
||||
func mouseMode():
|
||||
#manage the mouse mode (visible = can use mouse on the screen, captured = mouse not visible and locked in at the center of the screen)
|
||||
if Input.is_action_just_pressed(mouseModeAction): mouseFree = !mouseFree
|
||||
if !mouseFree: Input.set_mouse_mode(Input.MOUSE_MODE_CAPTURED)
|
||||
else: Input.set_mouse_mode(Input.MOUSE_MODE_VISIBLE)
|
||||
@@ -0,0 +1 @@
|
||||
uid://b0fbr48rbvn27
|
||||
@@ -0,0 +1,6 @@
|
||||
extends Camera3D
|
||||
|
||||
@onready var cam : Camera3D = %Camera
|
||||
|
||||
func _process(_delta : float):
|
||||
global_transform = cam.global_transform
|
||||
@@ -0,0 +1 @@
|
||||
uid://ba0b0ekmy1qub
|
||||
@@ -0,0 +1,18 @@
|
||||
extends Node3D
|
||||
|
||||
@onready var ammoManager : Node3D = %AmmunitionManager
|
||||
@onready var weaponManager : Node3D = %WeaponManager
|
||||
|
||||
func ammoRefillLink(ammoDict : Dictionary):
|
||||
for key in ammoDict.keys():
|
||||
if key in ammoManager.ammoDict:
|
||||
#two cases for the min function here :
|
||||
#1 :
|
||||
var nbAmmoToRefill : int = min(ammoManager.maxNbPerAmmoDict[key] - ammoManager.ammoDict[key], ammoDict[key])
|
||||
ammoManager.ammoDict[key] += nbAmmoToRefill
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
uid://cnpa03x4ajc8b
|
||||
@@ -0,0 +1,86 @@
|
||||
extends State
|
||||
|
||||
class_name CrouchState
|
||||
|
||||
var stateName : String = "Crouch"
|
||||
|
||||
var cR : CharacterBody3D
|
||||
|
||||
func enter(charRef : CharacterBody3D):
|
||||
cR = charRef
|
||||
|
||||
verifications()
|
||||
|
||||
func verifications():
|
||||
cR.moveSpeed = cR.crouchSpeed
|
||||
cR.moveAccel = cR.crouchAccel
|
||||
cR.moveDeccel = cR.crouchDeccel
|
||||
|
||||
cR.floor_snap_length = 1.0
|
||||
if cR.jumpCooldown > 0.0: cR.jumpCooldown = -1.0
|
||||
if cR.nbJumpsInAirAllowed < cR.nbJumpsInAirAllowedRef: cR.nbJumpsInAirAllowed = cR.nbJumpsInAirAllowedRef
|
||||
if cR.coyoteJumpCooldown < cR.coyoteJumpCooldownRef: cR.coyoteJumpCooldown = cR.coyoteJumpCooldownRef
|
||||
|
||||
func physics_update(delta : float):
|
||||
checkIfFloor()
|
||||
|
||||
applies(delta)
|
||||
|
||||
cR.gravityApply(delta)
|
||||
|
||||
inputManagement()
|
||||
|
||||
move(delta)
|
||||
|
||||
func checkIfFloor():
|
||||
if !cR.is_on_floor() and !cR.is_on_wall():
|
||||
if cR.velocity.y < 0.0:
|
||||
transitioned.emit(self, "InairState")
|
||||
if cR.is_on_floor():
|
||||
if cR.jumpBuffOn:
|
||||
cR.bufferedJump = true
|
||||
cR.jumpBuffOn = false
|
||||
transitioned.emit(self, "JumpState")
|
||||
|
||||
func applies(delta : float):
|
||||
if cR.hitGroundCooldown > 0.0: cR.hitGroundCooldown -= delta
|
||||
|
||||
cR.hitbox.shape.height = lerp(cR.hitbox.shape.height, cR.crouchHitboxHeight, cR.heightChangeSpeed * delta)
|
||||
cR.model.scale.y = lerp(cR.model.scale.y, cR.crouchModelHeight, cR.heightChangeSpeed * delta)
|
||||
|
||||
func inputManagement():
|
||||
if Input.is_action_just_pressed(cR.jumpAction):
|
||||
if !raycastVerification(): #if nothing block the player character when it will leaves the crouch state
|
||||
transitioned.emit(self, "JumpState")
|
||||
|
||||
if cR.continiousCrouch:
|
||||
#has to press run button once to run
|
||||
if Input.is_action_just_pressed(cR.crouchAction):
|
||||
if !raycastVerification():
|
||||
cR.walkOrRun = "WalkState"
|
||||
transitioned.emit(self, "WalkState")
|
||||
else:
|
||||
#has to continuously press crouch button to crouch
|
||||
if !Input.is_action_pressed(cR.crouchAction):
|
||||
if !raycastVerification():
|
||||
cR.walkOrRun = "WalkState"
|
||||
transitioned.emit(self, "WalkState")
|
||||
|
||||
func raycastVerification():
|
||||
#check if the raycast used to check ceilings is colliding or not
|
||||
return cR.ceilingCheck.is_colliding()
|
||||
|
||||
func move(delta : float):
|
||||
cR.inputDirection = Input.get_vector(cR.moveLeftAction, cR.moveRightAction, cR.moveForwardAction, cR.moveBackwardAction)
|
||||
cR.moveDirection = (cR.camHolder.global_basis * Vector3(cR.inputDirection.x, 0.0, cR.inputDirection.y)).normalized()
|
||||
|
||||
if cR.moveDirection and cR.is_on_floor():
|
||||
cR.velocity.x = lerp(cR.velocity.x, cR.moveDirection.x * cR.moveSpeed, cR.moveAccel * delta)
|
||||
cR.velocity.z = lerp(cR.velocity.z, cR.moveDirection.z * cR.moveSpeed, cR.moveAccel * delta)
|
||||
else:
|
||||
cR.velocity.x = lerp(cR.velocity.x, 0.0, cR.moveDeccel * delta)
|
||||
cR.velocity.z = lerp(cR.velocity.z, 0.0, cR.moveDeccel * delta)
|
||||
|
||||
if cR.hitGroundCooldown <= 0: cR.desiredMoveSpeed = cR.velocity.length()
|
||||
|
||||
if cR.desiredMoveSpeed >= cR.maxSpeed: cR.desiredMoveSpeed = cR.maxSpeed
|
||||
@@ -0,0 +1 @@
|
||||
uid://bhoqhv7escpyx
|
||||
@@ -0,0 +1,83 @@
|
||||
extends State
|
||||
|
||||
class_name IdleState
|
||||
|
||||
var stateName : String = "Idle"
|
||||
|
||||
var cR : CharacterBody3D
|
||||
|
||||
func enter(char_ref : CharacterBody3D):
|
||||
#pass play char reference
|
||||
cR = char_ref
|
||||
|
||||
verifications()
|
||||
|
||||
func verifications():
|
||||
#manage the appliements that need to be set at the start of the state
|
||||
cR.floor_snap_length = 1.0
|
||||
if cR.jumpCooldown > 0.0: cR.jumpCooldown = -1.0
|
||||
if cR.nbJumpsInAirAllowed < cR.nbJumpsInAirAllowedRef: cR.nbJumpsInAirAllowed = cR.nbJumpsInAirAllowedRef
|
||||
if cR.coyoteJumpCooldown < cR.coyoteJumpCooldownRef: cR.coyoteJumpCooldown = cR.coyoteJumpCooldownRef
|
||||
|
||||
func physics_update(delta : float):
|
||||
checkIfFloor()
|
||||
|
||||
applies(delta)
|
||||
|
||||
cR.gravityApply(delta)
|
||||
|
||||
inputManagement()
|
||||
|
||||
move(delta)
|
||||
|
||||
func checkIfFloor():
|
||||
#manage the appliements and state transitions that needs to be sets/checked/performed
|
||||
#every time the play char pass through one of the following : floor-inair-onwall
|
||||
if !cR.is_on_floor() and !cR.is_on_wall():
|
||||
transitioned.emit(self, "InairState")
|
||||
if cR.is_on_floor():
|
||||
if cR.jumpBuffOn:
|
||||
cR.bufferedJump = true
|
||||
cR.jumpBuffOn = false
|
||||
transitioned.emit(self, "JumpState")
|
||||
|
||||
func applies(delta : float):
|
||||
#manage the appliements of things that needs to be set/checked/performed every frame
|
||||
if cR.hitGroundCooldown > 0.0: cR.hitGroundCooldown -= delta
|
||||
|
||||
cR.hitbox.shape.height = lerp(cR.hitbox.shape.height, cR.baseHitboxHeight, cR.heightChangeSpeed * delta)
|
||||
cR.model.scale.y = lerp(cR.model.scale.y, cR.baseModelHeight, cR.heightChangeSpeed * delta)
|
||||
|
||||
func inputManagement():
|
||||
#manage the state transitions depending on the actions inputs
|
||||
if Input.is_action_just_pressed(cR.jumpAction):
|
||||
transitioned.emit(self, "JumpState")
|
||||
|
||||
if Input.is_action_just_pressed(cR.crouchAction):
|
||||
transitioned.emit(self, "CrouchState")
|
||||
|
||||
if Input.is_action_just_pressed(cR.runAction):
|
||||
if cR.walkOrRun == "WalkState": cR.walkOrRun = "RunState"
|
||||
elif cR.walkOrRun == "RunState": cR.walkOrRun = "WalkState"
|
||||
|
||||
func move(delta : float):
|
||||
#manage the character movement
|
||||
|
||||
#direction input
|
||||
cR.inputDirection = Input.get_vector(cR.moveLeftAction, cR.moveRightAction, cR.moveForwardAction, cR.moveBackwardAction)
|
||||
#get the move direction depending on the input
|
||||
cR.moveDirection = (cR.camHolder.global_basis * Vector3(cR.inputDirection.x, 0.0, cR.inputDirection.y)).normalized()
|
||||
|
||||
if cR.moveDirection and cR.is_on_floor():
|
||||
#transition to corresponding state
|
||||
transitioned.emit(self, cR.walkOrRun)
|
||||
else:
|
||||
#apply smooth stop
|
||||
cR.velocity.x = lerp(cR.velocity.x, 0.0, cR.moveDeccel * delta)
|
||||
cR.velocity.z = lerp(cR.velocity.z, 0.0, cR.moveDeccel * delta)
|
||||
|
||||
#cancel desired move speed accumulation if the timer has elapsed (is up)
|
||||
if cR.hitGroundCooldown <= 0: cR.desiredMoveSpeed = cR.velocity.length()
|
||||
|
||||
#set to ensure the character don't exceed the max speed authorized
|
||||
if cR.desiredMoveSpeed >= cR.maxSpeed: cR.desiredMoveSpeed = cR.maxSpeed
|
||||
@@ -0,0 +1 @@
|
||||
uid://stil4xkf3tk0
|
||||
@@ -0,0 +1,77 @@
|
||||
extends State
|
||||
|
||||
class_name InairState
|
||||
|
||||
var stateName : String = "Inair"
|
||||
|
||||
var cR : CharacterBody3D
|
||||
|
||||
func enter(charRef : CharacterBody3D):
|
||||
cR = charRef
|
||||
|
||||
verifications()
|
||||
|
||||
func verifications():
|
||||
if cR.floor_snap_length != 0.0: cR.floor_snap_length = 0.0
|
||||
if cR.hitGroundCooldown != cR.hitGroundCooldownRef: cR.hitGroundCooldown = cR.hitGroundCooldownRef
|
||||
|
||||
func physics_update(delta : float):
|
||||
applies(delta)
|
||||
|
||||
cR.gravityApply(delta)
|
||||
|
||||
inputManagement()
|
||||
|
||||
checkIfFloor()
|
||||
|
||||
move(delta)
|
||||
|
||||
func applies(delta : float):
|
||||
if !cR.is_on_floor():
|
||||
if cR.jumpCooldown > 0.0: cR.jumpCooldown -= delta
|
||||
if cR.coyoteJumpCooldown > 0.0: cR.coyoteJumpCooldown -= delta
|
||||
|
||||
cR.hitbox.shape.height = lerp(cR.hitbox.shape.height, cR.baseHitboxHeight, cR.heightChangeSpeed * delta)
|
||||
cR.model.scale.y = lerp(cR.model.scale.y, cR.baseModelHeight, cR.heightChangeSpeed * delta)
|
||||
|
||||
func inputManagement():
|
||||
if Input.is_action_just_pressed(cR.jumpAction):
|
||||
#check if can jump buffer
|
||||
if cR.floorCheck.is_colliding() and cR.lastFramePosition.y > cR.position.y and cR.nbJumpsInAirAllowed <= 0: cR.jumpBuffOn = true
|
||||
#check if can coyote jump
|
||||
if cR.wasOnFloor and cR.coyoteJumpCooldown > 0.0 and cR.lastFramePosition.y > cR.position.y:
|
||||
cR.coyoteJumpOn = true
|
||||
transitioned.emit(self, "JumpState")
|
||||
transitioned.emit(self, "JumpState")
|
||||
|
||||
func checkIfFloor():
|
||||
if cR.is_on_floor():
|
||||
if cR.jumpBuffOn:
|
||||
cR.bufferedJump = true
|
||||
cR.jumpBuffOn = false
|
||||
transitioned.emit(self, "JumpState")
|
||||
else:
|
||||
if cR.moveDirection: transitioned.emit(self, cR.walkOrRun)
|
||||
else: transitioned.emit(self, "IdleState")
|
||||
|
||||
if cR.is_on_wall():
|
||||
cR.velocity.x = 0.0
|
||||
cR.velocity.z = 0.0
|
||||
|
||||
func move(delta : float):
|
||||
cR.inputDirection = Input.get_vector(cR.moveLeftAction, cR.moveRightAction, cR.moveForwardAction, cR.moveBackwardAction)
|
||||
cR.moveDirection = (cR.camHolder.global_basis * Vector3(cR.inputDirection.x, 0.0, cR.inputDirection.y)).normalized()
|
||||
|
||||
if !cR.is_on_floor():
|
||||
if cR.moveDirection:
|
||||
if cR.desiredMoveSpeed < cR.maxSpeed: cR.desiredMoveSpeed += cR.bunnyHopDmsIncre * delta
|
||||
|
||||
var contrdDesMoveSpeed : float = cR.desiredMoveSpeedCurve.sample(cR.desiredMoveSpeed)
|
||||
var contrdInAirMoveSpeed : float = cR.inAirMoveSpeedCurve.sample(cR.desiredMoveSpeed) * cR.inAirInputMultiplier
|
||||
|
||||
cR.velocity.x = lerp(cR.velocity.x, cR.moveDirection.x * contrdDesMoveSpeed, contrdInAirMoveSpeed * delta)
|
||||
cR.velocity.z = lerp(cR.velocity.z, cR.moveDirection.z * contrdDesMoveSpeed, contrdInAirMoveSpeed * delta)
|
||||
else:
|
||||
cR.desiredMoveSpeed = cR.velocity.length()
|
||||
|
||||
if cR.desiredMoveSpeed >= cR.maxSpeed: cR.desiredMoveSpeed = cR.maxSpeed
|
||||
@@ -0,0 +1 @@
|
||||
uid://bh3rdvokmrar1
|
||||
@@ -0,0 +1,111 @@
|
||||
extends State
|
||||
|
||||
class_name JumpState
|
||||
|
||||
var stateName : String = "Jump"
|
||||
|
||||
var cR : CharacterBody3D
|
||||
|
||||
func enter(charRef : CharacterBody3D):
|
||||
cR = charRef
|
||||
|
||||
verifications()
|
||||
|
||||
jump()
|
||||
|
||||
func verifications():
|
||||
if cR.floor_snap_length != 0.0: cR.floor_snap_length = 0.0
|
||||
if cR.jumpCooldown < cR.jumpCooldownRef: cR.jumpCooldown = cR.jumpCooldownRef
|
||||
if cR.hitGroundCooldown != cR.hitGroundCooldownRef: cR.hitGroundCooldown = cR.hitGroundCooldownRef
|
||||
|
||||
func physics_update(delta : float):
|
||||
|
||||
applies(delta)
|
||||
|
||||
cR.gravityApply(delta)
|
||||
|
||||
inputManagement()
|
||||
|
||||
checkIfFloor()
|
||||
|
||||
move(delta)
|
||||
|
||||
func applies(delta : float):
|
||||
if !cR.is_on_floor():
|
||||
if cR.jumpCooldown > 0.0: cR.jumpCooldown -= delta
|
||||
if cR.coyoteJumpCooldown > 0.0: cR.coyoteJumpCooldown -= delta
|
||||
|
||||
cR.hitbox.shape.height = lerp(cR.hitbox.shape.height, cR.baseHitboxHeight, cR.heightChangeSpeed * delta)
|
||||
cR.model.scale.y = lerp(cR.model.scale.y, cR.baseModelHeight, cR.heightChangeSpeed * delta)
|
||||
|
||||
func inputManagement():
|
||||
if Input.is_action_just_pressed(cR.jumpAction):
|
||||
jump()
|
||||
|
||||
func checkIfFloor():
|
||||
if !cR.is_on_floor() and cR.velocity.y < 0.0:
|
||||
transitioned.emit(self, "InairState")
|
||||
|
||||
if cR.is_on_floor():
|
||||
if cR.moveDirection: transitioned.emit(self, cR.walkOrRun)
|
||||
else: transitioned.emit(self, "IdleState")
|
||||
|
||||
#lose all velocity if play char hit a wall
|
||||
if cR.is_on_wall():
|
||||
cR.velocity.x = 0.0
|
||||
cR.velocity.z = 0.0
|
||||
|
||||
func move(delta : float):
|
||||
cR.inputDirection = Input.get_vector(cR.moveLeftAction, cR.moveRightAction, cR.moveForwardAction, cR.moveBackwardAction)
|
||||
cR.moveDirection = (cR.camHolder.global_basis * Vector3(cR.inputDirection.x, 0.0, cR.inputDirection.y)).normalized()
|
||||
|
||||
#move only apply when the character is not on the floor (so if he's in the air)
|
||||
if !cR.is_on_floor():
|
||||
if cR.moveDirection:
|
||||
if cR.desiredMoveSpeed < cR.maxSpeed: cR.desiredMoveSpeed += cR.bunnyHopDmsIncre * delta
|
||||
|
||||
var contrdDesMoveSpeed : float = cR.desiredMoveSpeedCurve.sample(cR.desiredMoveSpeed)
|
||||
var contrdInAirMoveSpeed : float = cR.inAirMoveSpeedCurve.sample(cR.desiredMoveSpeed) * cR.inAirInputMultiplier
|
||||
|
||||
cR.velocity.x = lerp(cR.velocity.x, cR.moveDirection.x * contrdDesMoveSpeed, contrdInAirMoveSpeed * delta)
|
||||
cR.velocity.z = lerp(cR.velocity.z, cR.moveDirection.z * contrdDesMoveSpeed, contrdInAirMoveSpeed * delta)
|
||||
|
||||
if cR.velocity.length() > cR.maxSpeed:
|
||||
cR.velocity = cR.velocity.normalized() * cR.maxSpeed
|
||||
else:
|
||||
#accumulate desired speed for bunny hopping
|
||||
cR.desiredMoveSpeed = cR.velocity.length()
|
||||
|
||||
if cR.desiredMoveSpeed >= cR.maxSpeed: cR.desiredMoveSpeed = cR.maxSpeed
|
||||
|
||||
func jump():
|
||||
#manage the jump behaviour, depending of the different variables and states the character is
|
||||
|
||||
var canJump : bool = false #jump condition
|
||||
|
||||
#in air jump
|
||||
if !cR.is_on_floor():
|
||||
if !cR.coyoteJumpOn and cR.nbJumpsInAirAllowed > 0:
|
||||
cR.nbJumpsInAirAllowed -= 1
|
||||
cR.jumpCooldown = cR.jumpCooldownRef
|
||||
canJump = true
|
||||
if cR.coyoteJumpOn:
|
||||
cR.jumpCooldown = cR.jumpCooldownRef
|
||||
cR.coyoteJumpCooldown = -1.0 #so that the character cannot immediately make another coyote jump
|
||||
cR.coyoteJumpOn = false
|
||||
canJump = true
|
||||
|
||||
#on floor jump
|
||||
if cR.is_on_floor():
|
||||
cR.jumpCooldown = cR.jumpCooldownRef
|
||||
canJump = true
|
||||
|
||||
#jump buffering
|
||||
if cR.bufferedJump:
|
||||
cR.bufferedJump = false
|
||||
cR.nbJumpsInAirAllowed = cR.nbJumpsInAirAllowedRef
|
||||
|
||||
#apply jump
|
||||
if canJump:
|
||||
cR.velocity.y = cR.jumpVelocity
|
||||
canJump = false
|
||||
@@ -0,0 +1 @@
|
||||
uid://dvu58wf01wils
|
||||
@@ -0,0 +1,136 @@
|
||||
extends CharacterBody3D
|
||||
|
||||
class_name PlayerCharacter
|
||||
|
||||
|
||||
|
||||
@export_group("Movement variables")
|
||||
var moveSpeed : float
|
||||
var moveAccel : float
|
||||
var moveDeccel : float
|
||||
var desiredMoveSpeed : float
|
||||
@export var desiredMoveSpeedCurve : Curve
|
||||
@export var maxSpeed : float
|
||||
@export var inAirMoveSpeedCurve : Curve
|
||||
var inputDirection : Vector2
|
||||
var moveDirection : Vector3
|
||||
@export var hitGroundCooldown : float #amount of time the character keep his accumulated speed before losing it (while being on ground)
|
||||
var hitGroundCooldownRef : float
|
||||
@export var bunnyHopDmsIncre : float #bunny hopping desired move speed incrementer
|
||||
@export var autoBunnyHop : bool = false
|
||||
var lastFramePosition : Vector3
|
||||
var lastFrameVelocity : Vector3
|
||||
var wasOnFloor : bool
|
||||
var walkOrRun : String = "WalkState" #keep in memory if play char was walking or running before being in the air
|
||||
#for crouch visible changes
|
||||
@export var baseHitboxHeight : float
|
||||
@export var baseModelHeight : float
|
||||
@export var heightChangeSpeed : float
|
||||
|
||||
@export_group("Crouch variables")
|
||||
@export var crouchSpeed : float
|
||||
@export var crouchAccel : float
|
||||
@export var crouchDeccel : float
|
||||
@export var continiousCrouch : bool = false #if true, doesn't need to keep crouch button on to crouch
|
||||
@export var crouchHitboxHeight : float
|
||||
@export var crouchModelHeight : float
|
||||
|
||||
@export_group("Walk variables")
|
||||
@export var walkSpeed : float
|
||||
@export var walkAccel : float
|
||||
@export var walkDeccel : float
|
||||
|
||||
@export_group("Run variables")
|
||||
@export var runSpeed : float
|
||||
@export var runAccel : float
|
||||
@export var runDeccel : float
|
||||
@export var continiousRun : bool = false #if true, doesn't need to keep run button on to run
|
||||
|
||||
@export_group("Jump variables")
|
||||
@export var jumpHeight : float
|
||||
@export var jumpTimeToPeak : float
|
||||
@export var jumpTimeToFall : float
|
||||
@onready var jumpVelocity : float = (2.0 * jumpHeight) / jumpTimeToPeak
|
||||
@export var jumpCooldown : float
|
||||
var jumpCooldownRef : float
|
||||
@export var nbJumpsInAirAllowed : int
|
||||
var nbJumpsInAirAllowedRef : int
|
||||
var jumpBuffOn : bool = false
|
||||
var bufferedJump : bool = false
|
||||
@export var coyoteJumpCooldown : float
|
||||
var coyoteJumpCooldownRef : float
|
||||
var coyoteJumpOn : bool = false
|
||||
@export_range(0.1, 1.0, 0.05) var inAirInputMultiplier: float = 1.0
|
||||
|
||||
@export_group("Gravity variables")
|
||||
@onready var jumpGravity : float = (-2.0 * jumpHeight) / (jumpTimeToPeak * jumpTimeToPeak)
|
||||
@onready var fallGravity : float = (-2.0 * jumpHeight) / (jumpTimeToFall * jumpTimeToFall)
|
||||
|
||||
@export_group("Keybind variables")
|
||||
@export var moveForwardAction : String = ""
|
||||
@export var moveBackwardAction : String = ""
|
||||
@export var moveLeftAction : String = ""
|
||||
@export var moveRightAction : String = ""
|
||||
@export var runAction : String = ""
|
||||
@export var crouchAction : String = ""
|
||||
@export var jumpAction : String = ""
|
||||
|
||||
#references variables
|
||||
@onready var camHolder : Node3D = $CameraHolder
|
||||
@onready var model : MeshInstance3D = $Model
|
||||
@onready var hitbox : CollisionShape3D = $Hitbox
|
||||
@onready var stateMachine : Node = %StateMachine
|
||||
@onready var hud : CanvasLayer = $HUD
|
||||
@onready var ceilingCheck : RayCast3D = $Raycasts/CeilingCheck
|
||||
@onready var floorCheck : RayCast3D = $Raycasts/FloorCheck
|
||||
|
||||
func _ready():
|
||||
#set move variables, and value references
|
||||
moveSpeed = walkSpeed
|
||||
moveAccel = walkAccel
|
||||
moveDeccel = walkDeccel
|
||||
|
||||
hitGroundCooldownRef = hitGroundCooldown
|
||||
jumpCooldownRef = jumpCooldown
|
||||
nbJumpsInAirAllowedRef = nbJumpsInAirAllowed
|
||||
coyoteJumpCooldownRef = coyoteJumpCooldown
|
||||
|
||||
func _process(_delta: float):
|
||||
displayProperties()
|
||||
|
||||
func _physics_process(_delta : float):
|
||||
modifyPhysicsProperties()
|
||||
|
||||
move_and_slide()
|
||||
|
||||
func displayProperties():
|
||||
#display properties on the hud
|
||||
if hud != null:
|
||||
hud.displayCurrentState(stateMachine.currStateName)
|
||||
hud.displayCurrentDirection(moveDirection)
|
||||
hud.displayDesiredMoveSpeed(desiredMoveSpeed)
|
||||
hud.displayVelocity(velocity.length())
|
||||
hud.displayNbJumpsInAirAllowed(nbJumpsInAirAllowed)
|
||||
|
||||
func modifyPhysicsProperties():
|
||||
lastFramePosition = position #get play char position every frame
|
||||
lastFrameVelocity = velocity #get play char velocity every frame
|
||||
wasOnFloor = !is_on_floor() #check if play char was on floor every frame
|
||||
|
||||
func gravityApply(delta : float):
|
||||
#if play char goes up, apply jump gravity
|
||||
#otherwise, apply fall gravity
|
||||
if !is_on_floor():
|
||||
if velocity.y >= 0.0: velocity.y += jumpGravity * delta
|
||||
elif velocity.y < 0.0: velocity.y += fallGravity * delta
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
uid://d3s8yxuvpmekm
|
||||
@@ -0,0 +1,84 @@
|
||||
extends State
|
||||
|
||||
class_name RunState
|
||||
|
||||
var stateName : String = "Run"
|
||||
|
||||
var cR : CharacterBody3D
|
||||
|
||||
func enter(charRef : CharacterBody3D):
|
||||
cR = charRef
|
||||
|
||||
verifications()
|
||||
|
||||
func verifications():
|
||||
cR.moveSpeed = cR.runSpeed
|
||||
cR.moveAccel = cR.runAccel
|
||||
cR.moveDeccel = cR.runDeccel
|
||||
|
||||
cR.floor_snap_length = 1.0
|
||||
if cR.jumpCooldown > 0.0: cR.jumpCooldown = -1.0
|
||||
if cR.nbJumpsInAirAllowed < cR.nbJumpsInAirAllowedRef: cR.nbJumpsInAirAllowed = cR.nbJumpsInAirAllowedRef
|
||||
if cR.coyoteJumpCooldown < cR.coyoteJumpCooldownRef: cR.coyoteJumpCooldown = cR.coyoteJumpCooldownRef
|
||||
|
||||
func physics_update(delta : float):
|
||||
checkIfFloor()
|
||||
|
||||
applies(delta)
|
||||
|
||||
cR.gravityApply(delta)
|
||||
|
||||
inputManagement()
|
||||
|
||||
move(delta)
|
||||
|
||||
func checkIfFloor():
|
||||
if !cR.is_on_floor():
|
||||
if cR.velocity.y < 0.0:
|
||||
transitioned.emit(self, "InairState")
|
||||
if cR.is_on_floor():
|
||||
if cR.autoBunnyHop and cR.hitGroundCooldown > 0.0 and cR.inputDirection != Vector2.ZERO:
|
||||
transitioned.emit(self, "JumpState")
|
||||
if cR.jumpBuffOn:
|
||||
cR.bufferedJump = true
|
||||
cR.jumpBuffOn = false
|
||||
transitioned.emit(self, "JumpState")
|
||||
|
||||
func applies(delta : float):
|
||||
if cR.hitGroundCooldown > 0.0: cR.hitGroundCooldown -= delta
|
||||
|
||||
cR.hitbox.shape.height = lerp(cR.hitbox.shape.height, cR.baseHitboxHeight, cR.heightChangeSpeed * delta)
|
||||
cR.model.scale.y = lerp(cR.model.scale.y, cR.baseModelHeight, cR.heightChangeSpeed * delta)
|
||||
|
||||
func inputManagement():
|
||||
if Input.is_action_just_pressed(cR.jumpAction):
|
||||
transitioned.emit(self, "JumpState")
|
||||
|
||||
if Input.is_action_just_pressed(cR.crouchAction):
|
||||
transitioned.emit(self, "CrouchState")
|
||||
|
||||
if cR.continiousRun:
|
||||
#has to press run button once to run
|
||||
if Input.is_action_just_pressed(cR.runAction):
|
||||
cR.walkOrRun = "WalkState"
|
||||
transitioned.emit(self, "WalkState")
|
||||
else:
|
||||
#has to continuously press run button to run
|
||||
if !Input.is_action_pressed(cR.runAction):
|
||||
cR.walkOrRun = "WalkState"
|
||||
transitioned.emit(self, "WalkState")
|
||||
|
||||
|
||||
func move(delta : float):
|
||||
cR.inputDirection = Input.get_vector(cR.moveLeftAction, cR.moveRightAction, cR.moveForwardAction, cR.moveBackwardAction)
|
||||
cR.moveDirection = (cR.camHolder.global_basis * Vector3(cR.inputDirection.x, 0.0, cR.inputDirection.y)).normalized()
|
||||
|
||||
if cR.moveDirection and cR.is_on_floor():
|
||||
cR.velocity.x = lerp(cR.velocity.x, cR.moveDirection.x * cR.moveSpeed, cR.moveAccel * delta)
|
||||
cR.velocity.z = lerp(cR.velocity.z, cR.moveDirection.z * cR.moveSpeed, cR.moveAccel * delta)
|
||||
|
||||
if cR.hitGroundCooldown <= 0: cR.desiredMoveSpeed = cR.velocity.length()
|
||||
else:
|
||||
transitioned.emit(self, "IdleState")
|
||||
|
||||
if cR.desiredMoveSpeed >= cR.maxSpeed: cR.desiredMoveSpeed = cR.maxSpeed
|
||||
@@ -0,0 +1 @@
|
||||
uid://5gk47o641xgt
|
||||
@@ -0,0 +1,45 @@
|
||||
extends Node
|
||||
|
||||
@export var initialState : State
|
||||
|
||||
var currState : State
|
||||
var currStateName : String
|
||||
var states : Dictionary = {}
|
||||
|
||||
@onready var charRef : CharacterBody3D = $".."
|
||||
|
||||
func _ready():
|
||||
#get all the state childrens
|
||||
for child in get_children():
|
||||
if child is State:
|
||||
states[child.name.to_lower()] = child
|
||||
child.transitioned.connect(onStateChildTransition)
|
||||
|
||||
#if initial state, transition to it
|
||||
if initialState:
|
||||
initialState.enter(charRef)
|
||||
currState = initialState
|
||||
currStateName = currState.stateName
|
||||
|
||||
func _process(delta : float):
|
||||
if currState: currState.update(delta)
|
||||
|
||||
func _physics_process(delta: float):
|
||||
if currState: currState.physics_update(delta)
|
||||
|
||||
func onStateChildTransition(state : State, newStateName : String):
|
||||
#manage the transition from one state to another
|
||||
|
||||
if state != currState: return
|
||||
|
||||
var newState = states.get(newStateName.to_lower())
|
||||
if !newState: return
|
||||
|
||||
#exit the current state
|
||||
if currState: currState.exit()
|
||||
|
||||
#enter the new state
|
||||
newState.enter(charRef)
|
||||
|
||||
currState = newState
|
||||
currStateName = currState.stateName
|
||||
@@ -0,0 +1 @@
|
||||
uid://sca7ypsol83f
|
||||
@@ -0,0 +1,21 @@
|
||||
extends Node
|
||||
|
||||
class_name State
|
||||
|
||||
signal transitioned
|
||||
|
||||
func enter(_charReference : CharacterBody3D):
|
||||
#enter state
|
||||
pass
|
||||
|
||||
func exit():
|
||||
#exit state
|
||||
pass
|
||||
|
||||
func update(_delta : float):
|
||||
#process update
|
||||
pass
|
||||
|
||||
func physics_update(_delta : float):
|
||||
#physics_process update
|
||||
pass
|
||||
@@ -0,0 +1 @@
|
||||
uid://gjekmtw4eb1e
|
||||
@@ -0,0 +1,80 @@
|
||||
extends State
|
||||
|
||||
class_name WalkState
|
||||
|
||||
var stateName : String = "Walk"
|
||||
|
||||
var cR : CharacterBody3D
|
||||
|
||||
func enter(charRef : CharacterBody3D):
|
||||
cR = charRef
|
||||
|
||||
verifications()
|
||||
|
||||
func verifications():
|
||||
cR.moveSpeed = cR.walkSpeed
|
||||
cR.moveAccel = cR.walkAccel
|
||||
cR.moveDeccel = cR.walkDeccel
|
||||
|
||||
cR.floor_snap_length = 1.0
|
||||
if cR.jumpCooldown > 0.0: cR.jumpCooldown = -1.0
|
||||
if cR.nbJumpsInAirAllowed < cR.nbJumpsInAirAllowedRef: cR.nbJumpsInAirAllowed = cR.nbJumpsInAirAllowedRef
|
||||
if cR.coyoteJumpCooldown < cR.coyoteJumpCooldownRef: cR.coyoteJumpCooldown = cR.coyoteJumpCooldownRef
|
||||
|
||||
func physics_update(delta : float):
|
||||
checkIfFloor()
|
||||
|
||||
applies(delta)
|
||||
|
||||
cR.gravityApply(delta)
|
||||
|
||||
inputManagement()
|
||||
|
||||
move(delta)
|
||||
|
||||
func checkIfFloor():
|
||||
if !cR.is_on_floor() and !cR.is_on_wall():
|
||||
if cR.velocity.y < 0.0:
|
||||
transitioned.emit(self, "InairState")
|
||||
if cR.is_on_floor():
|
||||
#check if can auto bunny hop
|
||||
if cR.autoBunnyHop and cR.hitGroundCooldown > 0.0 and cR.inputDirection != Vector2.ZERO:
|
||||
transitioned.emit(self, "JumpState")
|
||||
if cR.jumpBuffOn:
|
||||
#apply jump buffering
|
||||
cR.bufferedJump = true
|
||||
cR.jumpBuffOn = false
|
||||
transitioned.emit(self, "JumpState")
|
||||
|
||||
func applies(delta : float):
|
||||
if cR.hitGroundCooldown > 0.0: cR.hitGroundCooldown -= delta
|
||||
|
||||
cR.hitbox.shape.height = lerp(cR.hitbox.shape.height, cR.baseHitboxHeight, cR.heightChangeSpeed * delta)
|
||||
cR.model.scale.y = lerp(cR.model.scale.y, cR.baseModelHeight, cR.heightChangeSpeed * delta)
|
||||
|
||||
func inputManagement():
|
||||
if Input.is_action_just_pressed(cR.jumpAction):
|
||||
transitioned.emit(self, "JumpState")
|
||||
|
||||
if Input.is_action_just_pressed(cR.crouchAction):
|
||||
transitioned.emit(self, "CrouchState")
|
||||
|
||||
if Input.is_action_just_pressed(cR.runAction):
|
||||
cR.walkOrRun = "RunState"
|
||||
transitioned.emit(self, "RunState")
|
||||
|
||||
func move(delta : float):
|
||||
cR.inputDirection = Input.get_vector(cR.moveLeftAction, cR.moveRightAction, cR.moveForwardAction, cR.moveBackwardAction)
|
||||
cR.moveDirection = (cR.camHolder.global_basis * Vector3(cR.inputDirection.x, 0.0, cR.inputDirection.y)).normalized()
|
||||
|
||||
if cR.moveDirection and cR.is_on_floor():
|
||||
#apply smooth move
|
||||
cR.velocity.x = lerp(cR.velocity.x, cR.moveDirection.x * cR.moveSpeed, cR.moveAccel * delta)
|
||||
cR.velocity.z = lerp(cR.velocity.z, cR.moveDirection.z * cR.moveSpeed, cR.moveAccel * delta)
|
||||
|
||||
if cR.hitGroundCooldown <= 0: cR.desiredMoveSpeed = cR.velocity.length()
|
||||
|
||||
else:
|
||||
transitioned.emit(self, "IdleState")
|
||||
|
||||
if cR.desiredMoveSpeed >= cR.maxSpeed: cR.desiredMoveSpeed = cR.maxSpeed
|
||||
@@ -0,0 +1 @@
|
||||
uid://blt7dest23fk0
|
||||
@@ -0,0 +1,43 @@
|
||||
extends CanvasLayer
|
||||
|
||||
|
||||
@onready var currStateLabelText = %CurrStateLabelText
|
||||
@onready var currDirLabelText = %CurrDirectionLabelText
|
||||
@onready var desiredMoveSpeedLabelText = %DesiredMoveSpeedLabelText
|
||||
@onready var velocityLabelText = %VelocityLabelText
|
||||
@onready var nbJumpsInAirAllowedLabelText = %NbJumpsInAirAllowedLabelText
|
||||
|
||||
@onready var weaponStackLabelText = %WeaponStackLabelText
|
||||
@onready var weaponNameLabelText = %WeaponNameLabelText
|
||||
@onready var totalAmmoInMagLabelText = %TotalAmmoInMagLabelText
|
||||
@onready var totalAmmoLabelText = %TotalAmmoLabelText
|
||||
|
||||
func displayCurrentState(currState : String):
|
||||
currStateLabelText.set_text(str(currState))
|
||||
|
||||
func displayCurrentDirection(currDir : Vector3):
|
||||
currDirLabelText.set_text(str(currDir))
|
||||
|
||||
func displayDesiredMoveSpeed(desMoveSpeed : float):
|
||||
desiredMoveSpeedLabelText.set_text(str(desMoveSpeed))
|
||||
|
||||
func displayVelocity(vel : float):
|
||||
velocityLabelText.set_text(str(vel))
|
||||
|
||||
func displayNbJumpsInAirAllowed(nbJumpsInAirAllowed : int):
|
||||
nbJumpsInAirAllowedLabelText.set_text(str(nbJumpsInAirAllowed))
|
||||
|
||||
#----------------------------------------------------------------------------
|
||||
|
||||
func displayWeaponStack(weaponStack : int):
|
||||
weaponStackLabelText.set_text(str(weaponStack))
|
||||
|
||||
func displayWeaponName(weaponName : String):
|
||||
weaponNameLabelText.set_text(str(weaponName))
|
||||
|
||||
func displayTotalAmmoInMag(totalAmmoInMag : int, nbProjShotsAtSameTime : int):
|
||||
totalAmmoInMagLabelText.set_text(str(totalAmmoInMag/nbProjShotsAtSameTime))
|
||||
|
||||
func displayTotalAmmo(totalAmmo : int, nbProjShotsAtSameTime : int):
|
||||
totalAmmoLabelText.set_text(str(totalAmmo/nbProjShotsAtSameTime))
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
uid://dx02l6p6behb8
|
||||
Reference in New Issue
Block a user