Files
millimeters-of-aluminum/scenes/ship/components/grips/grip_area_3d.gd
2025-12-05 15:50:48 +01:00

71 lines
2.4 KiB
GDScript

extends Area3D
class_name GripArea3D
## Signal emitted when a pawn successfully grabs this grip.
signal grabbed(pawn: CharacterPawn3D)
## Signal emitted when a pawn releases this grip.
signal released(pawn: CharacterPawn3D)
## Enum to differentiate grip types. Add more as needed.
enum GripType { POINT, BAR, LADDER_RUNG, SEAT_HANDLE }
## The type of this specific grip. Should be set by inheriting classes.
@export var grip_type: GripType
## Can more than one pawn grab this simultaneously? (Usually false)
@export var allow_multiple_occupants: bool = false
## Tracks the pawn currently holding this grip.
var occupant: CharacterPawn3D = null
# --- Virtual Methods (to be overridden by subclasses) ---
## Calculates the ideal global transform (position and orientation)
## the pawn should aim for when grabbing *this specific* grip.
## The pawn_global_pos helps determine the closest point on extended grips like bars.
func get_grip_transform(_pawn_global_pos: Vector3) -> Transform3D:
# Default implementation: return the grip's own global transform.
# Subclasses (like BarGrip) MUST override this for correct behavior.
return global_transform
## Determines the direction the pawn should push off from this grip.
## Usually the opposite of the surface normal or grip's forward direction.
func get_push_off_normal() -> Vector3:
# Default: Push directly away along the grip's local -Z axis (assuming Z points into the wall)
return -global_transform.basis.z.normalized()
# --- Public API ---
## Check if a specific pawn *can* grab this grip right now.
func can_grab(pawn: CharacterPawn3D) -> bool:
if not is_instance_valid(pawn):
return false
if occupant != null and not allow_multiple_occupants:
return false # Already occupied
# Add distance checks or other conditions if needed
return true
## Called by the pawn to initiate grabbing.
func grab(pawn: CharacterPawn3D):
if can_grab(pawn):
occupant = pawn
emit_signal("grabbed", pawn)
# Disable collision? Monitor input? Subclasses might override.
print(pawn.name, " grabbed ", name)
return true
return false
## Called by the pawn to release the grip.
func release(pawn: CharacterPawn3D):
if occupant == pawn:
var released_pawn = occupant
occupant = null
emit_signal("released", released_pawn)
print(pawn.name, " released ", name)
# Re-enable collision?
return true
return false
func is_occupied() -> bool:
return occupant != null