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