124 lines
4.4 KiB
GDScript
124 lines
4.4 KiB
GDScript
extends CharacterBody2D
|
|
|
|
# SoundManager resolved from the autoload tree at runtime
|
|
func _get_sound() -> Node:
|
|
return get_tree().root.get_node_or_null("SoundManager")
|
|
|
|
# === НАСТРОЙКИ ФИЗИКИ ===
|
|
const GRAVITY: float = 980.0
|
|
const WALK_SPEED: float = 200.0
|
|
const RUN_SPEED: float = 350.0
|
|
const JUMP_VELOCITY: float = -450.0
|
|
|
|
# === ПРОДВИНУТЫЕ МЕХАНИКИ ===
|
|
const COYOTE_TIME: float = 0.1 # Секунды после схода с платформы, когда ещё можно прыгнуть
|
|
const JUMP_BUFFER: float = 0.15 # Секунды, когда нажатие прыжка "запоминается" до приземления
|
|
const JUMP_CUT_MULT: float = 0.4 # Обрезка скорости подъёма при отпускании кнопки прыжка
|
|
|
|
# Высота, ниже которой лиса считается упавшей в пропасть
|
|
const DEATH_Y: float = 900.0
|
|
|
|
var coyote_timer: float = 0.0
|
|
var jump_buffer_timer: float = 0.0
|
|
var is_running: bool = false
|
|
var jump_cut_done: bool = true # true = обрезка уже применена (или прыжка нет)
|
|
|
|
# Направление взгляда (для будущего спрайта)
|
|
var facing_right: bool = true
|
|
|
|
# Точка возрождения (задаётся уровнем)
|
|
var spawn_point: Vector2 = Vector2.ZERO
|
|
# Защита от повторной обработки смерти в одном кадре
|
|
var is_dying: bool = false
|
|
|
|
func _ready() -> void:
|
|
spawn_point = position
|
|
|
|
func _physics_process(delta: float) -> void:
|
|
if is_dying:
|
|
return
|
|
|
|
# 1. Гравитация + Coyote Time
|
|
# ВАЖНО: maxf (не maxi!) — таймеры дробные, maxi обнулял бы их каждый кадр.
|
|
if not is_on_floor():
|
|
velocity.y += GRAVITY * delta
|
|
coyote_timer = maxf(coyote_timer - delta, 0.0)
|
|
else:
|
|
coyote_timer = COYOTE_TIME # Сброс при касании земли
|
|
|
|
# 2. Jump Buffer
|
|
if Input.is_action_just_pressed("jump"):
|
|
jump_buffer_timer = JUMP_BUFFER
|
|
else:
|
|
jump_buffer_timer = maxf(jump_buffer_timer - delta, 0.0)
|
|
|
|
# 3. Выполнение прыжка (буфер + coyote)
|
|
if jump_buffer_timer > 0.0 and coyote_timer > 0.0:
|
|
velocity.y = JUMP_VELOCITY
|
|
jump_buffer_timer = 0.0
|
|
coyote_timer = 0.0 # запрет повторного прыжка в воздухе
|
|
jump_cut_done = false
|
|
# TODO: Звук прыжка + эмиссия частиц
|
|
|
|
# 4. Variable Jump Height — обрезаем ОДИН раз при отпускании кнопки
|
|
if not jump_cut_done and velocity.y < 0.0 and not Input.is_action_pressed("jump"):
|
|
velocity.y *= JUMP_CUT_MULT
|
|
jump_cut_done = true
|
|
|
|
# 5. Горизонтальное движение
|
|
var direction: float = Input.get_axis("move_left", "move_right")
|
|
is_running = Input.is_action_pressed("run")
|
|
var current_speed: float = RUN_SPEED if is_running else WALK_SPEED
|
|
|
|
if direction != 0.0:
|
|
velocity.x = direction * current_speed
|
|
facing_right = direction > 0.0
|
|
# TODO: сменить анимацию на 'run'
|
|
else:
|
|
velocity.x = move_toward(velocity.x, 0.0, current_speed)
|
|
# TODO: сменить анимацию на 'idle'
|
|
|
|
# 6. Движение и коллизии
|
|
var was_rising: bool = velocity.y < 0.0
|
|
move_and_slide()
|
|
|
|
# 6.1 Удар головой снизу — сообщаем блоку
|
|
if was_rising:
|
|
for i in range(get_slide_collision_count()):
|
|
var col := get_slide_collision(i)
|
|
# normal указывает ОТ поверхности к телу; при ударе снизу normal.y > 0
|
|
if col.get_normal().y > 0.5:
|
|
var other := col.get_collider()
|
|
if other != null and other.has_method("on_hit_from_below"):
|
|
other.on_hit_from_below()
|
|
|
|
# 7. Падение в пропасть
|
|
if position.y > DEATH_Y:
|
|
die()
|
|
|
|
func hit_coin(points: int) -> void:
|
|
GameManager.add_score(points)
|
|
var sfx := _get_sound()
|
|
if sfx != null and sfx.has_method("play"):
|
|
sfx.call("play", "coin")
|
|
|
|
func die() -> void:
|
|
if is_dying:
|
|
return
|
|
is_dying = true
|
|
velocity = Vector2.ZERO
|
|
var sfx := _get_sound()
|
|
if sfx != null and sfx.has_method("play"):
|
|
sfx.call("play", "die")
|
|
if GameManager.lose_life():
|
|
# Возрождение
|
|
GameManager.respawn()
|
|
position = spawn_point
|
|
velocity = Vector2.ZERO
|
|
is_dying = false
|
|
else:
|
|
# Жизни кончились
|
|
get_tree().quit()
|
|
|
|
# TODO: переключение анимаций (idle / run / jump / fall)
|