точно есть дэшм

This commit is contained in:
2026-07-21 00:27:17 +07:00
parent 1df926f1d8
commit d74fa3bd80
601 changed files with 2375919 additions and 0 deletions
@@ -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,59 @@
extends State
class_name DashState
var stateName : String = "Dash"
var cR : CharacterBody3D
var dash_timer : float = 0.0
func enter(charRef : CharacterBody3D):
cR = charRef
# 1. Задаем таймер длительности дэша из настроек игрока
dash_timer = cR.dash_duration
cR.dash_cooldown_timer = cR.dash_cooldown
cR.is_dashing = true
# 2. Определяем направление рывка
# Если игрок бежал — дэшим в сторону бега. Если стоял — строго вперед, куда смотрит камера
cR.dash_direction = cR.moveDirection
if cR.dash_direction == Vector3.ZERO:
cR.dash_direction = -cR.camHolder.global_transform.basis.z
cR.dash_direction.y = 0 # Чтобы не улетать в небо
cR.dash_direction = cR.dash_direction.normalized()
# 3. Включаем сочный эффект FOV на камере игрока
if cR.player_camera:
var tween = create_tween()
tween.tween_property(cR.player_camera, "fov", cR.normal_fov + 15.0, 0.1)
func physics_update(delta : float):
# Отсчитываем время действия дэша
dash_timer -= delta
if dash_timer <= 0:
# Рывок окончен! Возвращаем FOV камеры назад
cR.is_dashing = false
if cR.player_camera:
var tween = create_tween()
tween.tween_property(cR.player_camera, "fov", cR.normal_fov, 0.15)
# Плавно переходим обратно в ходьбу, бег или воздух в зависимости от того, где мы оказались
if cR.is_on_floor():
if cR.walkOrRun == "RunState":
transitioned.emit(self, "RunState")
else:
transitioned.emit(self, "WalkState")
else:
transitioned.emit(self, "InairState")
return
# Принудительно толкаем физическое тело игрока во время рывка
cR.velocity.x = cR.dash_direction.x * cR.dash_speed
cR.velocity.z = cR.dash_direction.z * cR.dash_speed
# Применяем гравитацию (опционально, чтобы игрок мог дэшиться в воздухе и плавно падать)
cR.gravityApply(delta)
cR.modifyPhysicsProperties()
@@ -0,0 +1 @@
uid://t4bhhfuq3vda
@@ -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,215 @@
extends CharacterBody3D
class_name PlayerCharacter
@export_group("Dash Mechanics")
@export var dash_speed: float = 15.0 # Скорость игрока во время рывка
@export var dash_duration: float = 0.45 # Длительность рывка в секундах
@export var dash_cooldown: float = 2.0 # Перезарядка дэша (в секундах)
var is_dashing: bool = false
var dash_timer: float = 0.0
var dash_cooldown_timer: float = 0.0
var dash_direction: Vector3 = Vector3.ZERO
@onready var player_camera: Camera3D = %Camera # Ссылка на камеру (убедись, что %Camera есть в сцене)
var normal_fov: float = 75.0 # Стандартный угол обзора
@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_group("Jump variables continuation") # Разделили одинаковые группы, чтобы Godot не ругался
@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():
# Запоминаем дефолтный FOV камеры, если она подключена
if player_camera:
normal_fov = player_camera.fov
#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):
# 1. Отсчет кулдауна перезарядки дэша
if dash_cooldown_timer > 0:
dash_cooldown_timer -= _delta
# 2. ЕСЛИ ИДЕТ ДЭШ: двигаем игрока силой кода
if is_dashing:
dash_timer -= _delta
if dash_timer <= 0:
is_dashing = false
# Возвращаем FOV камеры обратно
if player_camera:
var tween = create_tween()
tween.tween_property(player_camera, "fov", normal_fov, 0.15)
# ВКЛЮЧАЕМ СТEЙТ-МАШИНУ ОБРАТНО
if stateMachine:
stateMachine.process_mode = Node.PROCESS_MODE_INHERIT
else:
# Принудительно толкаем персонажа со скоростью дэша
velocity.x = dash_direction.x * dash_speed
velocity.z = dash_direction.z * dash_speed
# Применяем перемещение и ВЫХОДИМ, полностью блокируя ходьбу ассета во время рывка
modifyPhysicsProperties()
move_and_slide()
return
# 3. ПРОВЕРКА НАЖАТИЯ КНОПКИ ДЭША
if Input.is_action_just_pressed("dash") and dash_cooldown_timer <= 0 and not is_dashing:
# Если игрок бежит — берем направление moveDirection, если стоит — направление камеры
var final_dir = moveDirection
if final_dir == Vector3.ZERO:
final_dir = -camHolder.global_transform.basis.z
final_dir.y = 0 # Чтобы не летать вверх/вниз
final_dir = final_dir.normalized()
# Запускаем дэш
is_dashing = true
dash_timer = dash_duration
dash_cooldown_timer = dash_cooldown
dash_direction = final_dir
# Эффект наплыва камеры (FOV)
if player_camera:
var tween = create_tween()
tween.tween_property(player_camera, "fov", normal_fov + 15.0, 0.1)
# ВЫКЛЮЧАЕМ СТEЙТ-МАШИНУ НА ВРЕМЯ РЫВКА, чтобы она не сбивала скорость!
if stateMachine:
stateMachine.process_mode = Node.PROCESS_MODE_DISABLED
# Стандартная физика ходьбы из твоего ассета (работает, когда дэша нет)
modifyPhysicsProperties()
move_and_slide()
# Проверяем нажатие на кнопку дэша (кнопка "dash" должна быть настроена в Input Map)
if Input.is_action_just_pressed("dash") and dash_cooldown_timer <= 0 and not is_dashing:
# Если игрок бежит — дэшимся в сторону бега, если стоит — строго вперед по взгляду камеры
var final_dir = moveDirection
if final_dir == Vector3.ZERO:
final_dir = -camHolder.global_transform.basis.z # Берем направление взгляда камеры
final_dir.y = 0 # Обнуляем вертикальную ось, чтобы игрок не улетал в небо или под пол
final_dir = final_dir.normalized()
# Активируем рывок
is_dashing = true
dash_timer = dash_duration
dash_cooldown_timer = dash_cooldown
dash_direction = final_dir
# Эффект скорости: плавно увеличиваем угол обзора (FOV) камеры на +15 градусов
if player_camera:
var tween = create_tween()
tween.tween_property(player_camera, "fov", normal_fov + 15.0, 0.1)
# Стандартная физика ассета (вызывается, только когда мы не в дэше)
modifyPhysicsProperties()
move_and_slide()
func displayProperties():
if hud != null:
hud.displayCurrentState(stateMachine.currStateName)
hud.displayCurrentDirection(moveDirection)
hud.displayDesiredMoveSpeed(desiredMoveSpeed)
hud.displayVelocity(velocity.length())
hud.displayNbJumpsInAirAllowed(nbJumpsInAirAllowed)
func modifyPhysicsProperties():
lastFramePosition = position
lastFrameVelocity = velocity
wasOnFloor = !is_on_floor()
func gravityApply(delta : float):
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,83 @@
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("dash") and cR.dash_cooldown_timer <= 0:
transitioned.emit(self, "DashState")
return # Выходим из функции, чтобы не вызывать другие стейты
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