feat: added grapple mechanic

This commit is contained in:
DottsGit
2026-06-05 02:05:07 -04:00
parent 0912669759
commit ecefeb9f7e
8 changed files with 232 additions and 0 deletions
+47
View File
@@ -20,6 +20,15 @@ var input_jump_pressed: bool = false
var input_jump_just_pressed: bool = false
var input_crouch: bool = false
var input_dash: bool = false
var input_grapple: bool = false
var input_grapple_just_pressed: bool = false
# Grapple state
var grapple_point: Vector3 = Vector3.ZERO
var grapple_length: float = 0.0
var grapple_travel_time: float = 0.0
var grapple_shoot_time: float = 0.0
var is_grapple_shooting: bool = false
# ── State tracking ────────────────────────────────────────────────────────────
var wall_normal: Vector3 = Vector3.ZERO
@@ -40,6 +49,12 @@ var is_crouched: bool = false
func _ready() -> void:
# Ensure grapple state is injected
var grapple_state = Node.new()
grapple_state.name = "state_grapple"
grapple_state.set_script(load("res://movement/states/state_grapple.gd"))
add_child(grapple_state)
for child in get_children():
if child is Node and child.name.begins_with("state_"):
states[child.name.replace("state_", "")] = child
@@ -72,6 +87,17 @@ func _physics_process(delta: float) -> void:
chain_count = 0
current_chain_bonus = 0.0
# Global grapple check: if just pressed, raycast from camera
if input_grapple_just_pressed and current_state != "grapple" and not is_grapple_shooting:
_try_start_grapple()
if is_grapple_shooting:
grapple_shoot_time += delta
if grapple_shoot_time >= grapple_travel_time:
is_grapple_shooting = false
movement_event.emit("grapple_latch", {})
switch_to("grapple")
# Manage global crouch state
var want_crouch = input_crouch
if current_state == "slide":
@@ -117,6 +143,27 @@ func switch_to(new_state_name: String, data: Dictionary = {}) -> void:
state_changed.emit(prev, new_state_name)
func _try_start_grapple() -> void:
if not player or not player.camera:
return
var camera: Camera3D = player.camera
var space_state := player.get_world_3d().direct_space_state
var origin := camera.global_position
var end := origin - camera.global_transform.basis.z * params.grapple_range
var ray := PhysicsRayQueryParameters3D.create(origin, end)
ray.exclude = [player.get_rid()]
var hit := space_state.intersect_ray(ray)
if not hit.is_empty():
grapple_point = hit.position
grapple_length = origin.distance_to(grapple_point)
# Travel at 45 m/s
grapple_travel_time = grapple_length / 45
grapple_shoot_time = 0.0
is_grapple_shooting = true
movement_event.emit("grapple_shoot", {})
func register_chain_mechanic(_mechanic_name: String) -> void:
if chain_timer > 0.0 and chain_count > 0:
chain_count += 1