diff --git a/scenes/tests/3d/zero_g_movement_component.gd b/scenes/tests/3d/zero_g_movement_component.gd index 3dd054f..86cba61 100644 --- a/scenes/tests/3d/zero_g_movement_component.gd +++ b/scenes/tests/3d/zero_g_movement_component.gd @@ -23,9 +23,8 @@ var nearby_grips: Array[GripArea3D] = [] @export var climb_speed: float = 2.0 @export var grip_handover_distance: float = 1 # How close to next grip to initiate handover @export var climb_acceleration: float = 10.0 # How quickly pawn reaches climb_speed -@export var climb_angle_threshold_deg: float = 80.0 # How wide the forward cone is +@export var climb_angle_threshold_deg: float = 120.0 # How wide the forward cone is @export var release_past_grip_threshold: float = 0.4 # How far past the grip origin before releasing -var climb_direction_world: Vector3 = Vector3.ZERO # Direction currently climbing var next_grip_target: GripArea3D = null # The grip we are trying to transition to # --- Launch Parameters --- @@ -84,7 +83,7 @@ func process_movement(delta: float, move_input: Vector2, vertical_input: float, _process_reaching(delta) MovementState.GRIPPING: _apply_grip_physics(delta, move_input, roll_input) - MovementState.CLIMBING: + MovementState.CLIMBING: _apply_climb_physics(delta, move_input) MovementState.CHARGING_LAUNCH: _handle_launch_charge(delta) @@ -99,7 +98,7 @@ func handle_collision(collision: KinematicCollision3D, collision_energy_loss: fl # === STATE MACHINE func _on_enter_state(state : MovementState): - print("ZeroGMovementComponent activated for state: ", MovementState.keys()[state]) + # print("ZeroGMovementComponent activated for state: ", MovementState.keys()[state]) if state == MovementState.GRIPPING: pawn.velocity = Vector3.ZERO pawn.angular_velocity = Vector3.ZERO @@ -107,11 +106,11 @@ func _on_enter_state(state : MovementState): # state = MovementState.IDLE # Or SEARCHING? func _on_exit_state(state: MovementState): - print("ZeroGMovementComponent deactivated for state: ", MovementState.keys()[state]) + # print("ZeroGMovementComponent deactivated for state: ", MovementState.keys()[state]) - # Ensure grip is released if pawn state changes unexpectedly - # if state == MovementState.GRIPPING: - # _release_current_grip() + # Ensure grip is released if state changes unexpectedly + if state == MovementState.GRIPPING: + _release_current_grip() func _update_state( _delta: float, @@ -221,33 +220,27 @@ func _apply_climb_physics(delta: float, move_input: Vector2): if not is_instance_valid(pawn) or not is_instance_valid(current_grip): _stop_climb(true); return - # 1. Calculate Climb Direction (same as _start_climb) - var pawn_forward = -pawn.global_transform.basis.z - var pawn_right = pawn.global_transform.basis.x - climb_direction_world = (pawn_forward * -move_input.y + pawn_right * move_input.x).normalized() + # 1. Calculate Climb Direction: For climbing we interpret W as up from the pawns perspective instead of forward + var climb_direction = move_input.y * pawn.global_basis.y + move_input.x * pawn.global_basis.x + climb_direction = climb_direction.normalized() # 2. Find Next Grip - next_grip_target = _find_best_grip(climb_direction_world, INF, climb_angle_threshold_deg) + next_grip_target = _find_best_grip(climb_direction, INF, climb_angle_threshold_deg) - # 3. Check for Handover - var performed_handover = false - if is_instance_valid(next_grip_target): - var next_grip_pos = next_grip_target.global_position - var dist_sq_to_next = pawn.global_position.distance_squared_to(next_grip_pos) - if dist_sq_to_next < grip_handover_distance * grip_handover_distance: - performed_handover = _perform_grip_handover() + # 3. Check for Handover: This should be more eager to mark a new grip as current than below check is to release when climbing past + var performed_handover = _perform_grip_handover() # 4. Check for Release Past Grip (if no handover) if not performed_handover: var current_grip_pos = current_grip.global_position var vector_from_grip_to_pawn = pawn.global_position - current_grip_pos - var distance_along_climb_dir = vector_from_grip_to_pawn.dot(climb_direction_world) - if distance_along_climb_dir > 0.2: # Release threshold + var distance_along_climb_dir = vector_from_grip_to_pawn.dot(climb_direction) + if distance_along_climb_dir > release_past_grip_threshold: # Release threshold _release_current_grip() return # State changed to IDLE # 5. Apply Movement Force - var target_velocity = climb_direction_world * climb_speed + var target_velocity = climb_direction * climb_speed pawn.velocity = pawn.velocity.lerp(target_velocity, delta * climb_acceleration) # 6. Apply Angular Force (Auto-Orient to current grip) @@ -341,7 +334,7 @@ func _find_best_grip(direction := Vector3.ZERO, max_distance_sq := INF, angle_th if angle_rad > max_allowed_angle_rad: # print("Grip ", grip.get_parent().name, " outside cone. Angle: ", rad_to_deg(angle_rad), " > ", rad_to_deg(max_allowed_angle_rad)) continue # Skip this grip if it's outside the cone - + # If it passes all filters and is closer than the previous best: min_dist_sq = dist_sq best_grip = grip @@ -382,17 +375,12 @@ func _start_climb(move_input: Vector2): var pawn_up = pawn.global_basis.y var pawn_right = pawn.global_basis.x - # Project input onto plane perpendicular to grip normal? Or just use camera space? - # Let's use camera space initially for simplicity - climb_direction_world = (pawn_up * move_input.y + pawn_right * move_input.x).normalized() - - print("ZeroGMoveController: Started Climbing in direction: ", climb_direction_world) + print("ZeroGMoveController: Started Climbing in direction: ", (pawn_up * move_input.y + pawn_right * move_input.x).normalized()) func _stop_climb(release_grip: bool): print("ZeroGMoveController: Stopping Climb. Release Grip: ", release_grip) pawn.velocity = pawn.velocity.lerp(Vector3.ZERO, 0.5) # Apply some braking next_grip_target = null - climb_direction_world = Vector3.ZERO if release_grip: _release_current_grip() # Transitions to IDLE else: