From 0eaf6d19ea1a92fc0da40fa2fe3000b499f2e9c5 Mon Sep 17 00:00:00 2001 From: aibrash Date: Wed, 28 Oct 2026 13:24:28 +0500 Subject: [PATCH] =?UTF-8?q?=D0=94=D0=B2=D0=BE=D0=B9=D0=BD=D0=BE=D0=B9=20?= =?UTF-8?q?=D0=BF=D1=80=D1=8B=D0=B6=D0=BE=D0=BA:=20=D0=BA=D0=B0=D0=BC?= =?UTF-8?q?=D0=B5=D1=80=D0=B0=20=D0=B4=D0=B5=D0=BB=D0=B0=D0=B5=D1=82=20?= =?UTF-8?q?=D1=81=D0=B0=D0=BB=D1=8C=D1=82=D0=BE=20=D0=B2=D0=BF=D0=B5=D1=80?= =?UTF-8?q?=D1=91=D0=B4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Камера вынесена в узел CameraPivot на уровне глаз; им крутим оборот за AIR_JUMP_FLIP_TIME (0,6 с, как у анимации air_jump), взгляд мышью не мешает - Рывок берёт направление без учёта сальто, смерть сбрасывает его - README: строка про сальто в таблице управления Co-Authored-By: Claude Sonnet 5.5 Claude-Session: https://claude.ai/code/session_01WxZo3ekR5m1af437Qzqwc1 --- README.md | 2 +- player/player.gd | 26 ++++++++++++++++++++++++-- 2 files changed, 25 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 51f0262..5edc3a0 100644 --- a/README.md +++ b/README.md @@ -53,7 +53,7 @@ godot --path . # можно запустить несколько ок |---|---| | W A S D, стрелки | движение | | Shift | спринт | -| Пробел | прыжок; держать у уступа в воздухе — подтянуться; у стены — прыжок от стены; в воздухе — двойной прыжок | +| Пробел | прыжок; держать у уступа в воздухе — подтянуться; у стены — прыжок от стены; в воздухе — двойной прыжок (камера делает сальто, `AIR_JUMP_FLIP_TIME` в `player.gd`, 0 — выключить) | | C (держать) | **присед** (скорость 3,5, капсула вдвое ниже, пролезает под низкое) | | Shift + C на бегу | **подкат** | | Q | рывок | diff --git a/player/player.gd b/player/player.gd index cb3724c..0527a3f 100644 --- a/player/player.gd +++ b/player/player.gd @@ -20,6 +20,7 @@ const SLIDE_JUMP_BOOST = 1.15 # Бонус скорости при прыжк # --- Двойной прыжок --- const AIR_JUMPS = 1 # Сколько прыжков в воздухе (0 — отключить) const AIR_JUMP_VELOCITY = 5.5 +const AIR_JUMP_FLIP_TIME = 0.6 # Сальто камеры при двойном прыжке, сек (как у анимации air_jump; 0 — отключить) # --- Рывок (клавиша Q) --- const DASH_SPEED = 20.0 # Не больше MAX_SPEED @@ -159,6 +160,8 @@ var mantle_target: Vector3 = Vector3.ZERO var mantle_dir: Vector3 = Vector3.ZERO # Камера +var flip_pivot: Node3D = null # Ось на уровне глаз: ею крутим сальто, не мешая взгляду мышью +var flip_timer: float = 0.0 var head_base_pos: Vector3 = Vector3.ZERO var head_offset_y: float = 0.0 var land_offset: float = 0.0 @@ -193,6 +196,12 @@ var default_collision_y: float = 0.0 func _ready() -> void: add_to_group("local_player") Input.mouse_mode = Input.MOUSE_MODE_CAPTURED + flip_pivot = Node3D.new() + flip_pivot.name = "CameraPivot" + flip_pivot.position = head.position + add_child(flip_pivot) + head.reparent(flip_pivot, false) + head.position = Vector3.ZERO head_base_pos = head.position base_fov = head.fov @@ -484,6 +493,7 @@ func _air_jump(direction: Vector3) -> void: velocity.y = AIR_JUMP_VELOCITY air_jumps_left -= 1 jump_buffer_timer = 0.0 + flip_timer = AIR_JUMP_FLIP_TIME # Можно сменить направление полёта прямо в прыжке if direction != Vector3.ZERO: var h_speed: float = maxf(Vector2(velocity.x, velocity.z).length(), WALK_SPEED) @@ -497,7 +507,7 @@ func _try_dash() -> void: if is_dashing or is_mantling or dashes_left <= 0 or dash_cooldown_timer > 0.0: return - var look := -head.global_transform.basis.z + var look := (global_transform.basis * Basis(Vector3.RIGHT, head.rotation.x)) * Vector3.FORWARD # без сальто камеры var dir: Vector3 if is_on_floor(): # На земле рвёмся по направлению ввода, а без ввода — вперёд @@ -794,7 +804,17 @@ func _can_stand() -> bool: # --- КАМЕРА И ЭФФЕКТЫ --- +# Сальто вперёд: ось камеры делает полный оборот за AIR_JUMP_FLIP_TIME (плавно, с разгоном и торможением) +func _update_flip(delta: float) -> void: + flip_timer = maxf(flip_timer - delta, 0.0) + if flip_timer <= 0.0: + flip_pivot.rotation.x = 0.0 + return + var u := 1.0 - flip_timer / AIR_JUMP_FLIP_TIME + flip_pivot.rotation.x = -TAU * u * u * (3.0 - 2.0 * u) + func _update_camera(delta: float, input_dir: Vector2) -> void: + _update_flip(delta) var h_speed := Vector2(velocity.x, velocity.z).length() var sprint_factor: float = clamp((h_speed - WALK_SPEED) / (SPRINT_SPEED - WALK_SPEED), 0.0, 1.0) @@ -905,6 +925,8 @@ func die() -> void: return is_dead = true death_timer = DEATH_TIME + flip_timer = 0.0 + flip_pivot.rotation.x = 0.0 if is_sliding: _end_slide() if is_crouching: @@ -923,7 +945,7 @@ func _process_death(delta: float) -> void: # Камера падает и заваливается набок, экран краснеет var k := 1.0 - exp(-6.0 * delta) - head.position = head.position.lerp(Vector3(head_base_pos.x, DEATH_CAMERA_HEIGHT, head_base_pos.z), k) + head.position = head.position.lerp(Vector3(head_base_pos.x, DEATH_CAMERA_HEIGHT - flip_pivot.position.y, head_base_pos.z), k) head.rotation.z = lerpf(head.rotation.z, deg_to_rad(DEATH_ROLL), k) head.fov = lerpf(head.fov, base_fov, k) shake_strength = lerpf(shake_strength, 0.0, 10.0 * delta)