Часть 1
1 мая 2026 г., 22:01
extends CharacterBody2D
@onready var animated_sprite_2d: AnimatedSprite2D = $AnimatedSprite2D
@onready var jump_sound: AudioStreamPlayer2D = $JumpSound
@onready var grab_hand: RayCast2D = $GrabHand
@onready var grab_check: RayCast2D = $GrabCheck
const SPEED := 300.0
const JUMP_VELOCITY := -600.0
enum States { IDLE, RUN, JUMP, FALL, LAND, LEDGE_GRAB, LEDGE_CLIMB }
var state: int = States.IDLE
var was_on_floor := false
# --- LIFECYCLE ---
func _ready() -> void:
change_state(States.IDLE)
func _physics_process(delta: float) -> void:
apply_gravity(delta)
handle_horizontal_input()
# --- GLOBAL TRANSITIONS ---
if try_global_transitions():
move_and_slide()
return
# --- LOCAL TRANSITIONS ---
update_state(delta)
move_and_slide()
update_flip()
update_landing_flag()
# --- GLOBAL TRANSITIONS (PRIORITIES) ---
func try_global_transitions() -> bool:
if state in [States.JUMP, States.FALL]:
if can_grab_ledge():
change_state(States.LEDGE_GRAB)
return true
return false
# --- FUCKING STATE MACHINE CORE ---
func change_state(new_state: int) -> void:
if state == new_state:
return
exit_state(state)
state = new_state
enter_state(new_state)
func enter_state(s: int) -> void:
match s:
States.IDLE:
animated_sprite_2d.play("idle")
States.RUN:
animated_sprite_2d.play("running")
States.JUMP:
animated_sprite_2d.play("jumping")
jump_sound.play()
States.FALL:
animated_sprite_2d.play("falling")
States.LAND:
animated_sprite_2d.play("landing")
States.LEDGE_GRAB:
velocity = Vector2.ZERO
animated_sprite_2d.play("ledge-grab")
States.LEDGE_CLIMB:
animated_sprite_2d.play("ledge-climb")
func exit_state(_s: int) -> void:
pass
# --- FUCKING STATE LOGIC ---
func update_state(_delta: float) -> void:
match state:
States.IDLE:
if not is_on_floor():
change_state(States.FALL)
elif is_moving():
change_state(States.RUN)
elif is_jump_pressed():
do_jump()
States.RUN:
if not is_on_floor():
change_state(States.FALL)
elif not is_moving():
change_state(States.IDLE)
elif is_jump_pressed():
do_jump()
States.JUMP:
if velocity.y > 0:
change_state(States.FALL)
States.FALL:
if is_on_floor():
change_state(States.LAND)
States.LAND:
if is_moving():
change_state(States.RUN)
else:
change_state(States.IDLE)
States.LEDGE_GRAB:
ledge_grab_logic()
States.LEDGE_CLIMB:
ledge_climb_logic()
# --- FUCKING LEDGE LOGIC ---
func can_grab_ledge() -> bool:
if is_on_floor():
return false
var moving_towards_wall = sign(velocity.x) != 0
if not moving_towards_wall:
return false
return (
grab_hand.is_colliding() and
not grab_check.is_colliding()
)
func ledge_grab_logic() -> void:
velocity = Vector2.ZERO
if Input.is_action_just_pressed("down"):
change_state(States.FALL)
elif Input.is_action_just_pressed("jump"):
var dir := Input.get_axis("left", "right")
velocity.x = dir * SPEED
velocity.y = JUMP_VELOCITY
change_state(States.JUMP)
elif Input.is_action_pressed("up"):
change_state(States.LEDGE_CLIMB)
func ledge_climb_logic() -> void:
position.y -= 40.0
if not grab_hand.is_colliding():
change_state(States.IDLE)
# --- MOVEMENT HELPERS ---
func apply_gravity(delta: float) -> void:
if not is_on_floor() and state != States.LEDGE_GRAB:
velocity += get_gravity() * delta
func handle_horizontal_input() -> void:
if state == States.LEDGE_GRAB:
return
var axis := Input.get_axis("left", "right")
if axis != 0:
velocity.x = axis * SPEED
else:
velocity.x = move_toward(velocity.x, 0, SPEED)
# --- SMALL HELPERS ---
func is_moving() -> bool:
return abs(velocity.x) > 1
func is_jump_pressed() -> bool:
return Input.is_action_just_pressed("jump")
func do_jump() -> void:
velocity.y = JUMP_VELOCITY
change_state(States.JUMP)
# --- VISUALS ---
func update_flip() -> void:
if velocity.x > 0:
animated_sprite_2d.flip_h = false
elif velocity.x < 0:
animated_sprite_2d.flip_h = true
var dir = sign(velocity.x)
if dir != 0:
grab_hand.target_position.x = 10 * dir
grab_check.target_position.x = 10 * dir
func update_landing_flag() -> void:
var just_landed := not was_on_floor and is_on_floor()
was_on_floor = is_on_floor()
if just_landed and state in [States.FALL, States.JUMP]:
change_state(States.LAND)
func snap_to_ledge() -> void:
var point = grab_hand.get_collision_point()
position.x = point.x - sign(velocity.x) * 5
position.y = point.y - 5
Примечания:
Что, закибербулили тебя, да?
Можете считать это крайне запоздалым первоапрельским рофлом.