Add prop interaction system and throw mechanics specification
- Introduced `stickman_prop_interactor.gd` to manage prop interactions. - Created `phase_11_prop_interactions.md` detailing the design and implementation of prop pickup, drop, and throw mechanics. - Defined interaction states, action lifecycles, and event triggers for prop handling. - Specified constraints for throw actions, including target positioning and velocity calculations. - Established acceptance criteria for prop interactions and lifecycle management.
This commit is contained in:
+42
-1
@@ -179,6 +179,7 @@ signal action_finished(action: Dictionary, index: int)
|
||||
signal queue_finished # queue ran to completion (not on stop)
|
||||
signal queue_changed # any queue mutation
|
||||
signal speech_finished # bubble auto-hid after speak()
|
||||
signal prop_interaction_event(event_type: String, prop: PropBlock, reason: String)
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Internal state
|
||||
@@ -225,6 +226,7 @@ var source_stk_path: String = ""
|
||||
var _locomotion_component: StickmanLocomotion = null
|
||||
var _ragdoll_component: StickmanRagdoll = null
|
||||
var _action_runner_component: StickmanActionRunner = null
|
||||
var _prop_interactor_component: Node = null
|
||||
var _simulation_paused: bool = false
|
||||
var _phase12_paused_animation: bool = false
|
||||
var _phase12_paused_animation_name: StringName = &""
|
||||
@@ -238,12 +240,15 @@ func _ready() -> void:
|
||||
_locomotion_component = get_node_or_null(NodePath("RigComponents/Locomotion")) as StickmanLocomotion
|
||||
_ragdoll_component = get_node_or_null(NodePath("RigComponents/Ragdoll")) as StickmanRagdoll
|
||||
_action_runner_component = get_node_or_null(NodePath("RigComponents/ActionRunner")) as StickmanActionRunner
|
||||
_prop_interactor_component = get_node_or_null(NodePath("RigComponents/PropInteractor"))
|
||||
if _locomotion_component == null:
|
||||
push_warning("StickmanRig: missing RigComponents/Locomotion; locomotion boundary unavailable.")
|
||||
if _ragdoll_component == null:
|
||||
push_warning("StickmanRig: missing RigComponents/Ragdoll; ragdoll boundary unavailable.")
|
||||
if _action_runner_component == null:
|
||||
push_warning("StickmanRig: missing RigComponents/ActionRunner; action boundary unavailable.")
|
||||
if _prop_interactor_component == null:
|
||||
push_warning("StickmanRig: missing RigComponents/PropInteractor; prop interactions unavailable.")
|
||||
if _locomotion_component != null:
|
||||
_locomotion_component.configure(self)
|
||||
_locomotion_component.arrived.connect(func(target: Vector2) -> void: arrived.emit(target))
|
||||
@@ -251,8 +256,11 @@ func _ready() -> void:
|
||||
_ragdoll_component.configure(self, _locomotion_component)
|
||||
_ragdoll_component.recovery_requested.connect(func() -> void: request_recovery())
|
||||
_ragdoll_component.state_transition_requested.connect(_set_state)
|
||||
if _prop_interactor_component != null:
|
||||
_prop_interactor_component.call("configure", self, _locomotion_component, Callable())
|
||||
_prop_interactor_component.connect("prop_event", _on_prop_interaction_event)
|
||||
if _action_runner_component != null:
|
||||
_action_runner_component.configure(self, _locomotion_component)
|
||||
_action_runner_component.configure(self, _locomotion_component, _prop_interactor_component)
|
||||
_action_runner_component.action_queue = _pending_action_queue
|
||||
_action_runner_component.action_started.connect(func(action: Dictionary, index: int) -> void: action_started.emit(action, index))
|
||||
_action_runner_component.action_finished.connect(func(action: Dictionary, index: int) -> void: action_finished.emit(action, index))
|
||||
@@ -315,6 +323,8 @@ func _physics_process(delta: float) -> void:
|
||||
_ragdoll_component.tick_pre_movement(delta, int(state), rest_timeout, auto_recover)
|
||||
if _locomotion_component != null:
|
||||
_locomotion_component.tick_movement(delta, int(state))
|
||||
if _prop_interactor_component != null:
|
||||
_prop_interactor_component.call("tick", delta)
|
||||
if _action_runner_component != null:
|
||||
_action_runner_component.tick(delta, int(state), is_ragdoll_at_rest())
|
||||
_pin_mirrored_head_rotation()
|
||||
@@ -457,6 +467,8 @@ func _set_state(next_state: int) -> void:
|
||||
|
||||
func set_ragdoll(enabled: bool) -> void:
|
||||
if enabled:
|
||||
if _prop_interactor_component != null:
|
||||
_prop_interactor_component.call("disarm_for_ragdoll")
|
||||
if _locomotion_component != null:
|
||||
_locomotion_component.reset_for_ragdoll_handoff()
|
||||
match state:
|
||||
@@ -480,6 +492,35 @@ func toggle_ragdoll() -> void:
|
||||
set_ragdoll(not is_in_ragdoll())
|
||||
|
||||
|
||||
func set_prop_resolver(resolver: Callable) -> void:
|
||||
if _prop_interactor_component != null:
|
||||
_prop_interactor_component.call("configure", self, _locomotion_component, resolver)
|
||||
|
||||
|
||||
func start_prop_action(action: Dictionary) -> bool:
|
||||
return bool(_prop_interactor_component.call("start_action", action)) if _prop_interactor_component != null else false
|
||||
|
||||
|
||||
func cancel_prop_action() -> void:
|
||||
if _prop_interactor_component != null:
|
||||
_prop_interactor_component.call("cancel_action")
|
||||
|
||||
|
||||
func preview_prop_throw(target: Vector2, queue_prefix: Array[Dictionary] = []) -> Dictionary:
|
||||
if _prop_interactor_component == null:
|
||||
return {}
|
||||
return _prop_interactor_component.call("preview_throw", target, queue_prefix)
|
||||
|
||||
|
||||
func reset_prop_interactions_for_scene_exit() -> void:
|
||||
if _prop_interactor_component != null:
|
||||
_prop_interactor_component.call("reset_for_scene_exit")
|
||||
|
||||
|
||||
func _on_prop_interaction_event(event_type: String, prop: PropBlock, reason: String) -> void:
|
||||
prop_interaction_event.emit(event_type, prop, reason)
|
||||
|
||||
|
||||
## Public stand-up request. No-op unless the rig is in RAGDOLL.
|
||||
func request_recovery() -> void:
|
||||
if state == RigState.RAGDOLL and _ragdoll_component != null:
|
||||
|
||||
Reference in New Issue
Block a user