216 lines
8.5 KiB
GDScript
216 lines
8.5 KiB
GDScript
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
|