feat: implement movement state machine, FPS camera rig, and test level builder scaffolding
This commit is contained in:
@@ -65,7 +65,10 @@ func _process(delta: float) -> void:
|
||||
camera.fov = lerpf(camera.fov, _target_fov, 1.0 - exp(-params.fov_lerp_speed * delta))
|
||||
|
||||
# ── Head bob ──────────────────────────────────────────────────────────
|
||||
if player.is_on_floor() and hspeed > 1.0:
|
||||
var sm = player.get_node_or_null("MovementStateMachine")
|
||||
var is_sliding = sm and sm.current_state == "slide"
|
||||
|
||||
if player.is_on_floor() and hspeed > 1.0 and not is_sliding:
|
||||
_bob_timer += delta * params.head_bob_frequency * (hspeed / params.walk_speed)
|
||||
var bob_y := sin(_bob_timer) * params.head_bob_amplitude
|
||||
var bob_x := cos(_bob_timer * 0.5) * params.head_bob_amplitude * 0.5
|
||||
|
||||
@@ -124,11 +124,6 @@ func _build_floor() -> void:
|
||||
# Main arena floor (80x80)
|
||||
_box_static(Vector3(0, -0.5, 0), Vector3(80, 1.0, 80), Color(0.22, 0.22, 0.25), "Floor_Main")
|
||||
|
||||
# Grid lines on floor for spatial reference
|
||||
for i in range(-40, 41, 5):
|
||||
_box_static(Vector3(float(i), 0.01, 0), Vector3(0.05, 0.02, 80), Color(0.35, 0.35, 0.4), "GridX_%d" % i)
|
||||
_box_static(Vector3(0, 0.01, float(i)), Vector3(80, 0.02, 0.05), Color(0.35, 0.35, 0.4), "GridZ_%d" % i)
|
||||
|
||||
|
||||
# ── Arena Walls ───────────────────────────────────────────────────────────────
|
||||
|
||||
|
||||
@@ -62,7 +62,7 @@ func _physics_process(delta: float) -> void:
|
||||
jump_buffer_time = maxf(jump_buffer_time - delta, 0.0)
|
||||
|
||||
# Update chain timer
|
||||
if chain_timer > 0.0:
|
||||
if chain_timer > 0.0 and on_ground:
|
||||
chain_timer -= delta
|
||||
if chain_timer <= 0.0:
|
||||
chain_count = 0
|
||||
@@ -115,14 +115,23 @@ func switch_to(new_state_name: String, data: Dictionary = {}) -> void:
|
||||
|
||||
func register_chain_mechanic(_mechanic_name: String) -> void:
|
||||
if chain_timer > 0.0 and chain_count > 0:
|
||||
chain_count = mini(chain_count + 1, 10)
|
||||
chain_count += 1
|
||||
else:
|
||||
chain_count = 1
|
||||
chain_timer = params.chain_window
|
||||
current_chain_bonus = minf(
|
||||
float(chain_count) * params.chain_bonus_per_success,
|
||||
params.chain_bonus_cap
|
||||
)
|
||||
|
||||
# Shrink the chain window as the chain gets longer to make it increasingly punishing
|
||||
# Drops by 0.05 seconds per successful chain, down to a minimum of 0.4 seconds
|
||||
var current_window = maxf(0.4, params.chain_window - (float(chain_count) * 0.05))
|
||||
chain_timer = current_window
|
||||
|
||||
var raw_bonus = float(chain_count) * params.chain_bonus_per_success
|
||||
if raw_bonus <= params.chain_bonus_cap:
|
||||
current_chain_bonus = raw_bonus
|
||||
else:
|
||||
# Soft cap: diminishing returns past the cap
|
||||
var over_bonus = raw_bonus - params.chain_bonus_cap
|
||||
current_chain_bonus = params.chain_bonus_cap + (over_bonus / (1.0 + over_bonus * 3.0))
|
||||
|
||||
movement_event.emit("chain_updated", {
|
||||
"count": chain_count,
|
||||
"bonus": current_chain_bonus
|
||||
|
||||
Reference in New Issue
Block a user