|
|
|
|
@ -1,205 +0,0 @@
|
|
|
|
|
extends CharacterBody2D
|
|
|
|
|
class_name PilotBall
|
|
|
|
|
|
|
|
|
|
# --- Movement Constants (Friction Simulation) ---
|
|
|
|
|
# When in open space (no module overlap), movement is zeroed out quickly.
|
|
|
|
|
const EXTERIOR_DRAG_FACTOR: float = 0.05
|
|
|
|
|
|
|
|
|
|
# When pushing off hullplates (low friction, slow acceleration)
|
|
|
|
|
const INTERIOR_SLUGGISH_SPEED: float = 100.0
|
|
|
|
|
const INTERIOR_SLUGGISH_ACCEL: float = 5 # Low acceleration, simulating mass and small push
|
|
|
|
|
|
|
|
|
|
# When gripping a ladder (high friction, direct control)
|
|
|
|
|
const LADDER_SPEED: float = 100.0
|
|
|
|
|
const LADDER_ACCEL: float = 20 # High acceleration, simulating direct grip
|
|
|
|
|
|
|
|
|
|
@onready var camera: Camera2D = $Camera2D
|
|
|
|
|
@onready var overlap_area: Area2D = $OverlapDetector
|
|
|
|
|
@onready var ui_container: Control = $CanvasLayer/UIContainer
|
|
|
|
|
|
|
|
|
|
var nearby_station: SystemStation = null
|
|
|
|
|
var current_station: SystemStation = null
|
|
|
|
|
|
|
|
|
|
# --- State Variables ---
|
|
|
|
|
enum MovementState {
|
|
|
|
|
NO_CONTROL,
|
|
|
|
|
ZERO_G_INTERIOR,
|
|
|
|
|
LADDER_GRIP,
|
|
|
|
|
IN_STATION
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
var current_state: MovementState = MovementState.NO_CONTROL
|
|
|
|
|
var ladder_area: Area2D = null # Area of the ladder currently overlapped
|
|
|
|
|
var is_grabbing_ladder: bool = false # True if 'Space' is held while on ladder
|
|
|
|
|
|
|
|
|
|
# --- Overlap Detection (Assuming you use Area2D for detection) ---
|
|
|
|
|
var overlapping_modules: int = 0
|
|
|
|
|
|
|
|
|
|
# --- Ladder Constants ---
|
|
|
|
|
const LAUNCH_VELOCITY: float = 300.0
|
|
|
|
|
|
|
|
|
|
var _movement_input: Vector2 = Vector2.ZERO
|
|
|
|
|
var _interact_just_pressed: bool = false
|
|
|
|
|
var _interact_held: bool = false
|
|
|
|
|
|
|
|
|
|
# --- PUBLIC INPUT METHODS (Called by the PlayerController) ---
|
|
|
|
|
func set_movement_input(input_dir: Vector2):
|
|
|
|
|
_movement_input = input_dir
|
|
|
|
|
|
|
|
|
|
func set_interaction_input(just_pressed: bool, is_held: bool):
|
|
|
|
|
_interact_just_pressed = just_pressed
|
|
|
|
|
_interact_held = is_held
|
|
|
|
|
|
|
|
|
|
# --- New: Physics Initialization (Assuming CharacterBody2D is parented to the scene root or Ship) ---
|
|
|
|
|
# NOTE: CharacterBody2D cannot inherit OrbitalBody2D, so we manage its velocity manually.
|
|
|
|
|
|
|
|
|
|
func _ready():
|
|
|
|
|
# Set up overlap signals if they aren't already connected in the scene file
|
|
|
|
|
# You must have an Area2D child on PilotBall to detect overlaps.
|
|
|
|
|
# overlap_area.body_entered.connect(on_body_entered)
|
|
|
|
|
# overlap_area.body_exited.connect(on_body_exited)
|
|
|
|
|
overlap_area.area_entered.connect(_on_station_area_entered)
|
|
|
|
|
overlap_area.area_exited.connect(_on_station_area_exited)
|
|
|
|
|
|
|
|
|
|
camera.make_current()
|
|
|
|
|
|
|
|
|
|
# func on_body_entered(body: OrbitalBody3D):
|
|
|
|
|
# # Detect Modules (which all inherit OrbitalBody2D via StructuralPiece)
|
|
|
|
|
# if body is StructuralPiece:
|
|
|
|
|
# overlapping_modules += 1
|
|
|
|
|
|
|
|
|
|
# # Detect Ladders
|
|
|
|
|
# if body is Ladder:
|
|
|
|
|
# ladder_area = body.find_child("ClimbArea") # Assuming the Ladder has a specific Area2D for climbing
|
|
|
|
|
|
|
|
|
|
# func on_body_exited(body: OrbitalBody3D):
|
|
|
|
|
# if body is StructuralPiece:
|
|
|
|
|
# overlapping_modules -= 1
|
|
|
|
|
|
|
|
|
|
# if body is Ladder:
|
|
|
|
|
# if body.find_child("ClimbArea") == ladder_area:
|
|
|
|
|
# ladder_area = null
|
|
|
|
|
# is_grabbing_ladder = false # Force detach if the ladder moves away
|
|
|
|
|
|
|
|
|
|
# --- NEW: Functions to be called by the Station ---
|
|
|
|
|
func enter_station_state():
|
|
|
|
|
current_state = MovementState.IN_STATION
|
|
|
|
|
velocity = Vector2.ZERO # FIX: Stop all movement when entering a station
|
|
|
|
|
|
|
|
|
|
func exit_station_state():
|
|
|
|
|
# When leaving, transition to a sensible default state.
|
|
|
|
|
current_state = MovementState.ZERO_G_INTERIOR
|
|
|
|
|
|
|
|
|
|
func _physics_process(delta):
|
|
|
|
|
# This script now runs on the server and its state is synced to clients.
|
|
|
|
|
# It no longer checks for local input authority.
|
|
|
|
|
if current_state == MovementState.IN_STATION:
|
|
|
|
|
move_and_slide()
|
|
|
|
|
return
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
_update_movement_state() # This function now uses the new variables
|
|
|
|
|
process_interaction() # Process any interaction presses
|
|
|
|
|
|
|
|
|
|
# Reset input flags for the next frame
|
|
|
|
|
_interact_just_pressed = false
|
|
|
|
|
_interact_held = false
|
|
|
|
|
# The 'input_dir' now comes from our variable, not the Input singleton.
|
|
|
|
|
var input_dir = _movement_input
|
|
|
|
|
|
|
|
|
|
match current_state:
|
|
|
|
|
MovementState.ZERO_G_INTERIOR:
|
|
|
|
|
_sluggish_movement(input_dir, delta)
|
|
|
|
|
MovementState.LADDER_GRIP:
|
|
|
|
|
_ladder_movement(input_dir, delta)
|
|
|
|
|
|
|
|
|
|
# Reset input for the next frame
|
|
|
|
|
_movement_input = Vector2.ZERO
|
|
|
|
|
|
|
|
|
|
move_and_slide()
|
|
|
|
|
|
|
|
|
|
# This function is called every physics frame by _physics_process().
|
|
|
|
|
func process_interaction():
|
|
|
|
|
# If the interact button was not pressed this frame, do nothing.
|
|
|
|
|
if not _interact_just_pressed:
|
|
|
|
|
return
|
|
|
|
|
|
|
|
|
|
# Priority 1: Disengage from a station if we are in one.
|
|
|
|
|
if current_station:
|
|
|
|
|
# current_station.disengage(self)
|
|
|
|
|
current_station = null
|
|
|
|
|
return
|
|
|
|
|
# Priority 2: Occupy a nearby station if we are not in one.
|
|
|
|
|
elif is_instance_valid(nearby_station):
|
|
|
|
|
current_station = nearby_station
|
|
|
|
|
# current_station.occupy(self)
|
|
|
|
|
return
|
|
|
|
|
|
|
|
|
|
# Priority 3: Handle ladder launch logic.
|
|
|
|
|
# This part of the old logic was in _handle_interaction_input,
|
|
|
|
|
# but it's cleaner to check for the release of the button here.
|
|
|
|
|
if current_state == MovementState.LADDER_GRIP and not _interact_held:
|
|
|
|
|
# Launch the player away from the ladder when the interact button is released.
|
|
|
|
|
var launch_direction = - _movement_input.normalized()
|
|
|
|
|
if launch_direction == Vector2.ZERO:
|
|
|
|
|
# Default launch: use the character's forward direction
|
|
|
|
|
launch_direction = Vector2.UP.rotated(rotation)
|
|
|
|
|
|
|
|
|
|
velocity = launch_direction * LAUNCH_VELOCITY
|
|
|
|
|
|
|
|
|
|
# Immediately switch to zero-G interior state
|
|
|
|
|
is_grabbing_ladder = false
|
|
|
|
|
current_state = MovementState.ZERO_G_INTERIOR
|
|
|
|
|
|
|
|
|
|
# --- State Machine Update ---
|
|
|
|
|
|
|
|
|
|
func _update_movement_state():
|
|
|
|
|
# Priority 1: Ladder Grip
|
|
|
|
|
# This now checks the variable instead of the Input singleton.
|
|
|
|
|
if ladder_area and _interact_held:
|
|
|
|
|
is_grabbing_ladder = true
|
|
|
|
|
current_state = MovementState.LADDER_GRIP
|
|
|
|
|
return
|
|
|
|
|
|
|
|
|
|
# Priority 2: Interior Zero-G (must overlap a module/piece AND not be grabbing)
|
|
|
|
|
if overlapping_modules > 0:
|
|
|
|
|
if is_grabbing_ladder:
|
|
|
|
|
# If we were grabbing a ladder but released 'interact', we transition to zero-G interior
|
|
|
|
|
is_grabbing_ladder = false
|
|
|
|
|
current_state = MovementState.ZERO_G_INTERIOR
|
|
|
|
|
return
|
|
|
|
|
|
|
|
|
|
current_state = MovementState.ZERO_G_INTERIOR
|
|
|
|
|
return
|
|
|
|
|
|
|
|
|
|
# Priority 3: No Control (floating free)
|
|
|
|
|
is_grabbing_ladder = false
|
|
|
|
|
current_state = MovementState.NO_CONTROL
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# --- Movement Implementations ---
|
|
|
|
|
|
|
|
|
|
func _sluggish_movement(input_dir: Vector2, delta: float):
|
|
|
|
|
# Simulates pushing off the wall: slow acceleration, but minimal drag
|
|
|
|
|
var target_velocity = input_dir * INTERIOR_SLUGGISH_ACCEL
|
|
|
|
|
velocity = velocity + target_velocity * delta
|
|
|
|
|
#velocity.lerp(velocity + interi, INTERIOR_SLUGGISH_ACCEL)
|
|
|
|
|
|
|
|
|
|
func _ladder_movement(input_dir: Vector2, delta: float):
|
|
|
|
|
# Simulates direct grip: fast acceleration, perfect control
|
|
|
|
|
var target_velocity = input_dir * LADDER_SPEED
|
|
|
|
|
velocity = velocity.lerp(target_velocity, LADDER_ACCEL * delta)
|
|
|
|
|
|
|
|
|
|
# --- New Functions for Station Interaction ---
|
|
|
|
|
func _on_station_area_entered(area: Area2D):
|
|
|
|
|
if area.get_parent() is SystemStation:
|
|
|
|
|
nearby_station = area.get_parent()
|
|
|
|
|
print("Near station: ", nearby_station.name)
|
|
|
|
|
|
|
|
|
|
func _on_station_area_exited(area: Area2D):
|
|
|
|
|
if area.get_parent() == nearby_station:
|
|
|
|
|
nearby_station = null
|
|
|
|
|
|
|
|
|
|
# Stations will call this to get the node where they should place their UIs.
|
|
|
|
|
func get_ui_container() -> Control:
|
|
|
|
|
return ui_container
|