Двойной прыжок: камера делает сальто вперёд

- Камера вынесена в узел CameraPivot на уровне глаз; им крутим оборот за
  AIR_JUMP_FLIP_TIME (0,6 с, как у анимации air_jump), взгляд мышью не мешает
- Рывок берёт направление без учёта сальто, смерть сбрасывает его
- README: строка про сальто в таблице управления

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01WxZo3ekR5m1af437Qzqwc1
This commit is contained in:
2026-10-28 13:24:28 +05:00
co-authored by Claude Sonnet 5.5
parent b8282b1438
commit 0eaf6d19ea
2 changed files with 25 additions and 3 deletions
+1 -1
View File
@@ -53,7 +53,7 @@ godot --path . # можно запустить несколько ок
|---|---|
| W A S D, стрелки | движение |
| Shift | спринт |
| Пробел | прыжок; держать у уступа в воздухе — подтянуться; у стены — прыжок от стены; в воздухе — двойной прыжок |
| Пробел | прыжок; держать у уступа в воздухе — подтянуться; у стены — прыжок от стены; в воздухе — двойной прыжок (камера делает сальто, `AIR_JUMP_FLIP_TIME` в `player.gd`, 0 — выключить) |
| C (держать) | **присед** (скорость 3,5, капсула вдвое ниже, пролезает под низкое) |
| Shift + C на бегу | **подкат** |
| Q | рывок |
+24 -2
View File
@@ -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)