Fix jetpack vectors, change seeking_climb behaviour

This commit is contained in:
2025-11-01 14:09:26 +01:00
parent 60f2ddb3d7
commit 14b24beb23
3 changed files with 51 additions and 43 deletions

8
Init_Prompt.md Normal file
View File

@ -0,0 +1,8 @@
You are a Godot 4.5 Code assistant. You are not overly agreeable or apologetic but still pleasant and you understand that coding can be quick with your help but that does not mean that you are infallible. Please wait for me to verify that code works before suggesting that we move on from the current task. Suggestions for next steps and features that are adjacent to what were working are very welcome however.
I will attach the full project files of the project being worked on which includes a game design document as well as a running note on the current state of the project which details implemented and planned features. Read these and report back to me. Please suggest potential bugs, features not working as intended, refactorizations for cleaner code, and missing best practices as part of this project ingestion.
Additionally you understand the following things about the version of Godot being used:
- To utilize the editor interface in you reference the global singleton `EditorInterface`. You do not need to call a function to get the a reference to it.
- `xform()` is not a function on transform objects. To achieve the same effect you would use simple transform multiplication (`Transform_A * Transform_B)`)

View File

@ -50,14 +50,14 @@ func process_movement(delta: float, move_input: Vector2, vertical_input: float,
_apply_floating_movement(delta, move_input, vertical_input, roll_input) _apply_floating_movement(delta, move_input, vertical_input, roll_input)
func apply_thrusters(pawn: CharacterPawn3D, delta: float, move_input: Vector2, vertical_input: float, roll_input: float): func apply_thrusters(pawn: CharacterPawn3D, delta: float, move_input: Vector2, vertical_input: float, roll_input: float):
if not is_instance_valid(pawn) or not camera: return if not is_instance_valid(pawn): return
# Apply Linear Velocity # Apply Linear Velocity
var camera_forward = -camera.global_transform.basis.z var pawn_forward = -pawn.global_basis.z
var camera_right = camera.global_transform.basis.x var pawn_right = pawn.global_basis.x
var camera_up = camera.global_transform.basis.y var pawn_up = pawn.global_basis.y
var move_dir_horizontal = (camera_forward * move_input.y + camera_right * move_input.x) var move_dir_horizontal = (pawn_forward * move_input.y + pawn_right * move_input.x)
var move_dir_vertical = camera_up * vertical_input var move_dir_vertical = pawn_up * vertical_input
var combined_move_dir = move_dir_horizontal + move_dir_vertical var combined_move_dir = move_dir_horizontal + move_dir_vertical
if combined_move_dir != Vector3.ZERO: if combined_move_dir != Vector3.ZERO:
@ -89,11 +89,11 @@ func on_exit_state():
func _apply_floating_movement(delta: float, move_input: Vector2, vertical_input: float, roll_input: float): func _apply_floating_movement(delta: float, move_input: Vector2, vertical_input: float, roll_input: float):
# Apply Linear Velocity # Apply Linear Velocity
var camera_forward = -camera.global_transform.basis.z var pawn_forward = -pawn.global_basis.z
var camera_right = camera.global_transform.basis.x # Use camera's right for consistency var pawn_right = pawn.global_basis.x # Use pawn's right for consistency
var camera_up = camera.global_transform.basis.y var pawn_up = pawn.global_basis.y
var move_dir_horizontal = (camera_forward * move_input.y + camera_right * move_input.x) var move_dir_horizontal = (pawn_forward * move_input.y + pawn_right * move_input.x)
var move_dir_vertical = camera_up * vertical_input var move_dir_vertical = pawn_up * vertical_input
var combined_move_dir = move_dir_horizontal + move_dir_vertical var combined_move_dir = move_dir_horizontal + move_dir_vertical
if combined_move_dir != Vector3.ZERO: if combined_move_dir != Vector3.ZERO:
@ -109,14 +109,14 @@ func _apply_floating_movement(delta: float, move_input: Vector2, vertical_input:
# --- Auto-Orientation Logic --- # --- Auto-Orientation Logic ---
func _orient_pawn(delta: float): func _orient_pawn(delta: float):
# 1. Determine Target Orientation Basis # 1. Determine Target Orientation Basis
var initial_cam_basis = camera_pivot.global_transform.basis var initial_cam_basis = camera_pivot.global_basis
var target_forward = -camera_pivot.global_transform.basis.z # Look where camera looks var target_forward = -camera_pivot.global_basis.z # Look where camera looks
var target_up = Vector3.UP # Default up initially var target_up = Vector3.UP # Default up initially
# --- THE FIX: Adjust how target_up is calculated --- # --- THE FIX: Adjust how target_up is calculated ---
# Calculate velocity components relative to camera orientation # Calculate velocity components relative to camera orientation
var _forward_velocity_component = pawn.velocity.dot(target_forward) var _forward_velocity_component = pawn.velocity.dot(target_forward)
var _right_velocity_component = pawn.velocity.dot(camera_pivot.global_transform.basis.x) var _right_velocity_component = pawn.velocity.dot(camera_pivot.global_basis.x)
# Only apply strong "feet trailing" if significant forward/backward movement dominates # Only apply strong "feet trailing" if significant forward/backward movement dominates
# and we are actually moving. # and we are actually moving.
@ -143,7 +143,7 @@ func _orient_pawn(delta: float):
# target_basis = target_basis.rotated(target_basis.x, target_pitch_rad) # Rotate around the target right vector # target_basis = target_basis.rotated(target_basis.x, target_pitch_rad) # Rotate around the target right vector
# 2. Smoothly Interpolate Towards Target Basis # 2. Smoothly Interpolate Towards Target Basis
var current_basis = pawn.global_transform.basis var current_basis = pawn.global_basis
var new_basis = current_basis.slerp(target_basis, delta * orientation_speed) var new_basis = current_basis.slerp(target_basis, delta * orientation_speed)
# Store the body's yaw *before* applying the new basis # Store the body's yaw *before* applying the new basis
@ -151,10 +151,10 @@ func _orient_pawn(delta: float):
var _old_body_pitch = current_basis.get_euler().x var _old_body_pitch = current_basis.get_euler().x
# 3. Apply the new orientation # 3. Apply the new orientation
pawn.global_transform.basis = new_basis pawn.global_basis = new_basis
# 4. Reset camera pivot to rotation to what it was before we rotated the parent # 4. Reset camera pivot to rotation to what it was before we rotated the parent
camera_pivot.global_transform.basis = initial_cam_basis camera_pivot.global_basis = initial_cam_basis
# --- Add new function placeholder --- # --- Add new function placeholder ---
# TODO: Implement Rotation Stabilization Logic # TODO: Implement Rotation Stabilization Logic

View File

@ -18,7 +18,6 @@ var nearby_grips: Array[GripArea3D] = []
@export var gripping_linear_damping: float = 5.0 # How quickly velocity stops @export var gripping_linear_damping: float = 5.0 # How quickly velocity stops
@export var gripping_angular_damping: float = 5.0 # How quickly spin stops @export var gripping_angular_damping: float = 5.0 # How quickly spin stops
@export var gripping_orient_speed: float = 2.0 # How quickly pawn rotates to face grip @export var gripping_orient_speed: float = 2.0 # How quickly pawn rotates to face grip
# var _movement_input_was_neutral: bool = true # Tracks if input was released, for coasting.
# --- Climbing parameters --- # --- Climbing parameters ---
@export var climb_speed: float = 2.0 @export var climb_speed: float = 2.0
@ -75,18 +74,7 @@ func process_movement(delta: float, move_input: Vector2, vertical_input: float,
match current_state: match current_state:
MovementState.IDLE: MovementState.IDLE:
# State is IDLE (free-floating). _process_idle(delta, move_input, vertical_input, roll_input, release_input)
# Check for EVA suit usage.
var has_movement_input = (move_input != Vector2.ZERO or vertical_input != 0.0 or roll_input != 0.0)
if has_movement_input and is_instance_valid(pawn.eva_suit_component):
# Use EVA suit
pawn.eva_suit_component.apply_thrusters(pawn, delta, move_input, vertical_input, roll_input)
# _movement_input_was_neutral = not has_movement_input
# Check for body orientation (if applicable)
if release_input.held and is_instance_valid(pawn.eva_suit_component):
pawn.eva_suit_component._orient_pawn(delta) # Use suit's orient
MovementState.REACHING: MovementState.REACHING:
_process_reaching(delta) _process_reaching(delta)
MovementState.GRIPPING: MovementState.GRIPPING:
@ -152,13 +140,16 @@ func _update_state(
_release_current_grip(move_input) _release_current_grip(move_input)
return return
# FIX: Check for launch charge *before* checking for climb, as it's a more specific action. # Check for launch charge *before* checking for climb, as it's a more specific action.
if (reach_input.pressed or reach_input.held) and move_input != Vector2.ZERO: if (reach_input.pressed or reach_input.held) and move_input != Vector2.ZERO:
_start_charge(move_input) _start_charge(move_input)
return return
elif move_input != Vector2.ZERO: elif move_input != Vector2.ZERO:
_start_climb(move_input) _start_climb(move_input) # This is overshadowed by the above check.
MovementState.CLIMBING: MovementState.CLIMBING:
if reach_input.pressed or reach_input.held:
_start_charge(move_input)
return
if release_input.pressed or release_input.held or not is_instance_valid(current_grip): if release_input.pressed or release_input.held or not is_instance_valid(current_grip):
_stop_climb(true) # Release grip and stop _stop_climb(true) # Release grip and stop
return return
@ -175,6 +166,18 @@ func _update_state(
# === MOVEMENT PROCESSING === # === MOVEMENT PROCESSING ===
func _process_idle(delta: float, move_input: Vector2, vertical_input: float, roll_input: float, release_input: PlayerController3D.KeyInput):
# State is IDLE (free-floating).
# Check for EVA suit usage.
var has_movement_input = (move_input != Vector2.ZERO or vertical_input != 0.0 or roll_input != 0.0)
if has_movement_input and is_instance_valid(pawn.eva_suit_component):
# Use EVA suit
pawn.eva_suit_component.apply_thrusters(pawn, delta, move_input, vertical_input, roll_input)
# Check for body orientation (if applicable)
if release_input.held and is_instance_valid(pawn.eva_suit_component):
pawn.eva_suit_component._orient_pawn(delta) # Use suit's orient
func _process_reaching(_delta: float): func _process_reaching(_delta: float):
# TODO: Drive IK target towards current_grip.get_grip_transform().origin # TODO: Drive IK target towards current_grip.get_grip_transform().origin
# TODO: Monitor distance / animation state # TODO: Monitor distance / animation state
@ -253,16 +256,15 @@ func _apply_climb_physics(delta: float, move_input: Vector2):
func _process_seeking_climb(_delta: float, move_input: Vector2): func _process_seeking_climb(_delta: float, move_input: Vector2):
# If the player's input has changed from what initiated the seek, cancel it. # If the player's input has changed from what initiated the seek, cancel it.
if not move_input.is_equal_approx(_seeking_climb_input): if not move_input.is_equal_approx(_seeking_climb_input):
current_state = MovementState.IDLE var target_grip = _find_best_grip()
_seeking_climb_input = Vector2.ZERO # Reset for next time _seeking_climb_input = Vector2.ZERO # Reset for next time
return # Exit, on next frame new input will be processed in IDLE state if _attempt_grip(target_grip):
# Successfully found and grabbed a grip. The state is now GRIPPING.
# Continuously look for a new grip in the direction of climbing. print("Seeking Climb ended, gripped new target.")
var climb_direction = move_input.y * pawn.global_basis.y + move_input.x * pawn.global_basis.x else:
next_grip_target = _find_best_grip(climb_direction.normalized(), INF, climb_angle_threshold_deg) current_state = MovementState.IDLE
if next_grip_target: # No grip found. Transition to IDLE.
# Found a grip, transition to REACHING. _seeking_climb_input is still active. print("Seeking Climb ended, no grip found. Reverting to IDLE.")
current_state = MovementState.REACHING
# --- Grip Helpers # --- Grip Helpers
@ -439,8 +441,6 @@ func _handle_launch_charge(delta: float):
launch_charge = min(launch_charge + launch_charge_rate * delta, max_launch_speed) launch_charge = min(launch_charge + launch_charge_rate * delta, max_launch_speed)
pawn.velocity = Vector3.ZERO pawn.velocity = Vector3.ZERO
pawn.angular_velocity = Vector3.ZERO pawn.angular_velocity = Vector3.ZERO
# _movement_input_was_neutral = false # Ensure we don't immediately thrust after launch
func _execute_launch(move_input: Vector2): func _execute_launch(move_input: Vector2):
if not is_instance_valid(current_grip): return # Safety check if not is_instance_valid(current_grip): return # Safety check