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:
@@ -9,7 +9,7 @@ const SPEECH_BUBBLE_SCRIPT := preload("res://scripts/stickman_speech_bubble.gd")
|
||||
const SPEECH_BUBBLE_OFFSET := Vector2(0.0, -640.0)
|
||||
|
||||
enum RunnerState { IDLE, EXECUTING }
|
||||
enum ActionPhase { NONE, WALKING, SPEAKING, WAITING, RAGDOLLING, RECOVERING }
|
||||
enum ActionPhase { NONE, WALKING, SPEAKING, WAITING, RAGDOLLING, RECOVERING, PROP_INTERACTION }
|
||||
enum QueueStatus { NOT_STARTED, COMPLETED, INTERRUPTED, ACTIVE, PENDING }
|
||||
|
||||
signal action_started(action: Dictionary, index: int)
|
||||
@@ -29,6 +29,7 @@ var action_queue: Array[Dictionary]:
|
||||
set_authored_queue(value)
|
||||
var _rig: StickmanRig = null
|
||||
var _locomotion: StickmanLocomotion = null
|
||||
var _prop_interactor: Node = null
|
||||
var _runner_state: RunnerState = RunnerState.IDLE
|
||||
var _action_phase: ActionPhase = ActionPhase.NONE
|
||||
var _current_index: int = -1
|
||||
@@ -46,11 +47,15 @@ var _completed_ids: Dictionary = {}
|
||||
var _interrupted_ids: Dictionary = {}
|
||||
var _paused: bool = false
|
||||
var _session_started: bool = false
|
||||
var _prop_action_finished: bool = false
|
||||
|
||||
|
||||
func configure(rig: StickmanRig, locomotion: StickmanLocomotion) -> void:
|
||||
func configure(rig: StickmanRig, locomotion: StickmanLocomotion, prop_interactor: Node = null) -> void:
|
||||
_rig = rig
|
||||
_locomotion = locomotion
|
||||
_prop_interactor = prop_interactor
|
||||
if _prop_interactor != null and not _prop_interactor.is_connected("action_completed", _on_prop_action_completed):
|
||||
_prop_interactor.connect("action_completed", _on_prop_action_completed)
|
||||
|
||||
|
||||
func tick(delta: float, rig_state: int, ragdoll_at_rest: bool) -> void:
|
||||
@@ -78,6 +83,10 @@ func tick(delta: float, rig_state: int, ragdoll_at_rest: bool) -> void:
|
||||
ActionPhase.RECOVERING:
|
||||
if rig_state == StickmanRig.RigState.ANIMATED:
|
||||
_finish_action()
|
||||
ActionPhase.PROP_INTERACTION:
|
||||
if _prop_action_finished:
|
||||
_prop_action_finished = false
|
||||
_finish_action()
|
||||
|
||||
|
||||
func speak(text: String, duration: float) -> void:
|
||||
@@ -358,7 +367,9 @@ func _advance_to_next_action() -> void:
|
||||
_current_action_id = int(_current_run_item.get("action_id", -1))
|
||||
_current_index = _index_for_action_id(_current_action_id) if _current_action_id >= 0 else -1
|
||||
var action: Dictionary = _current_run_item.get("action", {})
|
||||
if String(action.get("type", "")) == "walk_to" and _rig != null:
|
||||
var action_type := String(action.get("type", ""))
|
||||
var requires_animated := action_type == "walk_to" or action_type == "pick_up_prop" or action_type == "drop_prop" or action_type == "throw_prop"
|
||||
if requires_animated and _rig != null:
|
||||
if _rig.state == StickmanRig.RigState.RECOVERING:
|
||||
_run_queue.insert(_run_cursor, _current_run_item.duplicate(true))
|
||||
_current_run_item.clear()
|
||||
@@ -394,6 +405,12 @@ func _begin_action(action: Dictionary) -> void:
|
||||
"recover":
|
||||
_action_phase = ActionPhase.RECOVERING
|
||||
recovery_requested.emit()
|
||||
"pick_up_prop", "drop_prop", "throw_prop":
|
||||
if _rig == null or not _rig.start_prop_action(action):
|
||||
_finish_action()
|
||||
else:
|
||||
_prop_action_finished = false
|
||||
_action_phase = ActionPhase.PROP_INTERACTION
|
||||
_:
|
||||
push_warning("StickmanActionRunner: unknown action type '%s'; skipped." % String(action.get("type", "")))
|
||||
_finish_action()
|
||||
@@ -420,9 +437,12 @@ func _cancel_current_primary(notify: bool = false) -> void:
|
||||
active_action_cancelled.emit(action.duplicate(true))
|
||||
if _locomotion != null:
|
||||
_locomotion.cancel_walk(not _is_blocked())
|
||||
if _rig != null:
|
||||
_rig.cancel_prop_action()
|
||||
_primary_speech.clear()
|
||||
_phase_timer = 0.0
|
||||
_action_phase = ActionPhase.NONE
|
||||
_prop_action_finished = false
|
||||
_current_run_item.clear()
|
||||
_current_index = -1
|
||||
_current_action_id = -1
|
||||
@@ -430,6 +450,10 @@ func _cancel_current_primary(notify: bool = false) -> void:
|
||||
_speech_bubble.hide_bubble()
|
||||
|
||||
|
||||
func _on_prop_action_completed() -> void:
|
||||
_prop_action_finished = true
|
||||
|
||||
|
||||
func _allocate_action_id() -> int:
|
||||
var result: int = _next_action_id
|
||||
_next_action_id += 1
|
||||
|
||||
Reference in New Issue
Block a user