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:
@@ -22,10 +22,16 @@ var _text_edit: LineEdit = null
|
||||
var _duration_spin: SpinBox = null
|
||||
var _target_label: Label = null
|
||||
var _set_target_btn: Button = null
|
||||
var _prop_target_label: Label = null
|
||||
var _set_prop_target_btn: Button = null
|
||||
var _hand_option: OptionButton = null
|
||||
var _stop_current_check: CheckBox = null
|
||||
var _show_reactive_options: bool = false
|
||||
var _has_target: bool = false
|
||||
var _target_pos: Vector2 = Vector2.ZERO
|
||||
var _prop_target_id: String = ""
|
||||
var _has_throw_target: bool = false
|
||||
var _throw_target_pos: Vector2 = Vector2.ZERO
|
||||
|
||||
## Theme font overrides (set via apply_font from sandbox_theme.json). Size 0 = no
|
||||
## override (engine default); Font null = no override.
|
||||
@@ -53,6 +59,9 @@ func open_new(show_reactive_options: bool = false) -> void:
|
||||
_initial = {}
|
||||
_has_target = false
|
||||
_target_pos = Vector2.ZERO
|
||||
_prop_target_id = ""
|
||||
_has_throw_target = false
|
||||
_throw_target_pos = Vector2.ZERO
|
||||
_select_type("walk_to")
|
||||
_rebuild_params("walk_to")
|
||||
title = "Add Action"
|
||||
@@ -67,6 +76,9 @@ func open_edit(action: Dictionary, show_reactive_options: bool = false) -> void:
|
||||
var type := String(action.get("type", "walk_to"))
|
||||
_has_target = action.has("target") and action["target"] is Vector2
|
||||
_target_pos = action.get("target", Vector2.ZERO) if _has_target else Vector2.ZERO
|
||||
_prop_target_id = String(action.get("target_prop_id", ""))
|
||||
_has_throw_target = action.has("target_position") and action["target_position"] is Vector2
|
||||
_throw_target_pos = action.get("target_position", Vector2.ZERO) if _has_throw_target else Vector2.ZERO
|
||||
_select_type(type)
|
||||
_rebuild_params(type)
|
||||
title = "Edit Action"
|
||||
@@ -81,6 +93,23 @@ func set_walk_target(pos: Vector2) -> void:
|
||||
popup_centered()
|
||||
|
||||
|
||||
func set_prop_target(prop_id: String) -> void:
|
||||
_prop_target_id = prop_id
|
||||
_update_prop_target_label()
|
||||
popup_centered()
|
||||
|
||||
|
||||
func set_throw_target(pos: Vector2) -> void:
|
||||
_has_throw_target = true
|
||||
_throw_target_pos = pos
|
||||
_update_throw_target_label()
|
||||
popup_centered()
|
||||
|
||||
|
||||
func current_action_type() -> String:
|
||||
return _current_type()
|
||||
|
||||
|
||||
func _build_ui() -> void:
|
||||
var margin := MarginContainer.new()
|
||||
margin.add_theme_constant_override("margin_left", 12)
|
||||
@@ -184,6 +213,9 @@ func _rebuild_params(type: String) -> void:
|
||||
_duration_spin = null
|
||||
_target_label = null
|
||||
_set_target_btn = null
|
||||
_prop_target_label = null
|
||||
_set_prop_target_btn = null
|
||||
_hand_option = null
|
||||
_stop_current_check = null
|
||||
|
||||
match type:
|
||||
@@ -198,6 +230,39 @@ func _rebuild_params(type: String) -> void:
|
||||
_set_target_btn.pressed.connect(func() -> void: target_requested.emit())
|
||||
trow.add_child(_set_target_btn)
|
||||
_update_walk_target_label()
|
||||
"pick_up_prop":
|
||||
var prop_row := HBoxContainer.new()
|
||||
_params_box.add_child(prop_row)
|
||||
_prop_target_label = Label.new()
|
||||
_prop_target_label.size_flags_horizontal = Control.SIZE_EXPAND_FILL
|
||||
prop_row.add_child(_prop_target_label)
|
||||
_set_prop_target_btn = Button.new()
|
||||
_set_prop_target_btn.text = "🎯 Click prop…"
|
||||
_set_prop_target_btn.pressed.connect(func() -> void: target_requested.emit())
|
||||
prop_row.add_child(_set_prop_target_btn)
|
||||
_update_prop_target_label()
|
||||
var hand_row := HBoxContainer.new()
|
||||
_params_box.add_child(hand_row)
|
||||
var hand_label := Label.new()
|
||||
hand_label.text = "Hand:"
|
||||
hand_row.add_child(hand_label)
|
||||
_hand_option = OptionButton.new()
|
||||
for label: String in ["Auto", "Left", "Right"]:
|
||||
_hand_option.add_item(label)
|
||||
var hand_idx := ["auto", "left", "right"].find(String(_initial.get("hand", "auto")))
|
||||
_hand_option.select(maxi(hand_idx, 0))
|
||||
hand_row.add_child(_hand_option)
|
||||
"throw_prop":
|
||||
var throw_row := HBoxContainer.new()
|
||||
_params_box.add_child(throw_row)
|
||||
_target_label = Label.new()
|
||||
_target_label.size_flags_horizontal = Control.SIZE_EXPAND_FILL
|
||||
throw_row.add_child(_target_label)
|
||||
_set_target_btn = Button.new()
|
||||
_set_target_btn.text = "🎯 Click target…"
|
||||
_set_target_btn.pressed.connect(func() -> void: target_requested.emit())
|
||||
throw_row.add_child(_set_target_btn)
|
||||
_update_throw_target_label()
|
||||
"speak":
|
||||
var tlabel := Label.new()
|
||||
tlabel.text = "Text:"
|
||||
@@ -247,6 +312,20 @@ func _update_walk_target_label() -> void:
|
||||
_target_label.text = "Target: not set"
|
||||
|
||||
|
||||
func _update_prop_target_label() -> void:
|
||||
if _prop_target_label != null:
|
||||
_prop_target_label.text = "Prop: %s" % (_prop_target_id if not _prop_target_id.is_empty() else "not set")
|
||||
|
||||
|
||||
func _update_throw_target_label() -> void:
|
||||
if _target_label == null:
|
||||
return
|
||||
if _has_throw_target:
|
||||
_target_label.text = "Target: (%d, %d)" % [int(roundf(_throw_target_pos.x)), int(roundf(_throw_target_pos.y))]
|
||||
else:
|
||||
_target_label.text = "Target: not set"
|
||||
|
||||
|
||||
func _on_ok_pressed() -> void:
|
||||
var type := _current_type()
|
||||
var action: Dictionary = { "type": type }
|
||||
@@ -257,6 +336,18 @@ func _on_ok_pressed() -> void:
|
||||
target_requested.emit()
|
||||
return
|
||||
action["target"] = _target_pos
|
||||
"pick_up_prop":
|
||||
if _prop_target_id.is_empty():
|
||||
target_requested.emit()
|
||||
return
|
||||
var hands: Array[String] = ["auto", "left", "right"]
|
||||
action["target_prop_id"] = _prop_target_id
|
||||
action["hand"] = hands[_hand_option.selected] if _hand_option != null and _hand_option.selected >= 0 else "auto"
|
||||
"throw_prop":
|
||||
if not _has_throw_target:
|
||||
target_requested.emit()
|
||||
return
|
||||
action["target_position"] = _throw_target_pos
|
||||
"speak":
|
||||
action["text"] = _text_edit.text if _text_edit != null else ""
|
||||
action["duration"] = _duration_spin.value if _duration_spin != null else 2.0
|
||||
|
||||
Reference in New Issue
Block a user