forked from xiangwang25/whale-town-front-v2
refactor: unify interactable components
This commit is contained in:
@@ -6,9 +6,8 @@ const MAX_ACTIONS_VISIBLE: int = 5
|
||||
const ACCENT: Color = Color("58c7db")
|
||||
const PANEL_COLOR: Color = Color(0.035, 0.071, 0.106, 0.94)
|
||||
const INTERACTION_POINT_MARKERS_SCRIPT: Script = preload("res://_Core/ui/InteractionPointMarkers.gd")
|
||||
const InteractionAnchorUtil = preload("res://_Core/utils/InteractionAnchor.gd")
|
||||
|
||||
var _actions: Array[Dictionary] = []
|
||||
var _actions: Array[InteractionAction] = []
|
||||
var _selected_index: int = 0
|
||||
var _last_selected_id: String = ""
|
||||
var _scan_elapsed: float = SCAN_INTERVAL
|
||||
@@ -58,32 +57,23 @@ func _refresh_actions() -> void:
|
||||
if player == null:
|
||||
_set_actions([])
|
||||
return
|
||||
var collected: Array[Dictionary] = []
|
||||
for node in get_tree().get_nodes_in_group("whaletown_interactable"):
|
||||
if not is_instance_valid(node) or not node.has_method("get_interaction_actions"):
|
||||
var collected: Array[InteractionAction] = []
|
||||
for node: Node in get_tree().get_nodes_in_group(InteractableComponent.GROUP):
|
||||
var interactable: InteractableComponent = node as InteractableComponent
|
||||
if interactable == null:
|
||||
continue
|
||||
var actions_variant: Variant = node.call("get_interaction_actions", player)
|
||||
if not (actions_variant is Array):
|
||||
continue
|
||||
for item in actions_variant as Array:
|
||||
if item is Dictionary:
|
||||
var action: Dictionary = item
|
||||
if bool(action.get("available", true)):
|
||||
collected.append(action)
|
||||
collected.sort_custom(func(a: Dictionary, b: Dictionary) -> bool:
|
||||
var priority_a := int(a.get("priority", 100))
|
||||
var priority_b := int(b.get("priority", 100))
|
||||
if priority_a != priority_b:
|
||||
return priority_a < priority_b
|
||||
var distance_a := float(a.get("distance", INF))
|
||||
var distance_b := float(b.get("distance", INF))
|
||||
if not is_equal_approx(distance_a, distance_b):
|
||||
return distance_a < distance_b
|
||||
return str(a.get("title", "")) < str(b.get("title", ""))
|
||||
for action: InteractionAction in interactable.get_actions(player):
|
||||
collected.append(action)
|
||||
collected.sort_custom(func(a: InteractionAction, b: InteractionAction) -> bool:
|
||||
if a.priority != b.priority:
|
||||
return a.priority < b.priority
|
||||
if not is_equal_approx(a.distance, b.distance):
|
||||
return a.distance < b.distance
|
||||
return a.title < b.title
|
||||
)
|
||||
_set_actions(collected)
|
||||
|
||||
func _set_actions(next_actions: Array[Dictionary]) -> void:
|
||||
func _set_actions(next_actions: Array[InteractionAction]) -> void:
|
||||
_actions = next_actions
|
||||
if _actions.is_empty():
|
||||
_selected_index = 0
|
||||
@@ -92,30 +82,29 @@ func _set_actions(next_actions: Array[Dictionary]) -> void:
|
||||
return
|
||||
var matched_index := -1
|
||||
for index in _actions.size():
|
||||
if str(_actions[index].get("id", "")) == _last_selected_id:
|
||||
if _actions[index].id == _last_selected_id:
|
||||
matched_index = index
|
||||
break
|
||||
_selected_index = matched_index if matched_index >= 0 else clampi(_selected_index, 0, _actions.size() - 1)
|
||||
_last_selected_id = str(_actions[_selected_index].get("id", ""))
|
||||
_last_selected_id = _actions[_selected_index].id
|
||||
_render()
|
||||
|
||||
func _select_offset(offset: int) -> void:
|
||||
if _actions.is_empty():
|
||||
return
|
||||
_selected_index = posmod(_selected_index + offset, _actions.size())
|
||||
_last_selected_id = str(_actions[_selected_index].get("id", ""))
|
||||
_last_selected_id = _actions[_selected_index].id
|
||||
_render()
|
||||
|
||||
func _execute_selected() -> void:
|
||||
if _executing or _actions.is_empty():
|
||||
return
|
||||
var action := _actions[_selected_index]
|
||||
var callback_variant: Variant = action.get("callback", Callable())
|
||||
if not (callback_variant is Callable) or not (callback_variant as Callable).is_valid():
|
||||
var action: InteractionAction = _actions[_selected_index]
|
||||
if not action.activate.is_valid():
|
||||
return
|
||||
_executing = true
|
||||
_render()
|
||||
(callback_variant as Callable).call()
|
||||
action.activate.call()
|
||||
await get_tree().create_timer(0.18).timeout
|
||||
_executing = false
|
||||
_refresh_actions()
|
||||
@@ -168,13 +157,13 @@ func _render() -> void:
|
||||
var start: int = clampi(_selected_index - 2, 0, maxi(0, _actions.size() - MAX_ACTIONS_VISIBLE))
|
||||
var finish: int = mini(_actions.size(), start + MAX_ACTIONS_VISIBLE)
|
||||
for index in range(start, finish):
|
||||
var action := _actions[index]
|
||||
var action: InteractionAction = _actions[index]
|
||||
var row := Label.new()
|
||||
row.custom_minimum_size = Vector2(0, 29)
|
||||
row.vertical_alignment = VERTICAL_ALIGNMENT_CENTER
|
||||
row.add_theme_font_size_override("font_size", 16)
|
||||
var selected := index == _selected_index
|
||||
row.text = ("› " if selected else " ") + str(action.get("title", "交互")) + (" …" if selected and _executing else "")
|
||||
row.text = ("› " if selected else " ") + action.title + (" …" if selected and _executing else "")
|
||||
row.add_theme_color_override("font_color", ACCENT if selected else Color(0.92, 0.96, 0.98, 1.0))
|
||||
if selected:
|
||||
row.add_theme_stylebox_override("normal", _selected_style())
|
||||
@@ -191,19 +180,12 @@ func _render_interaction_points() -> void:
|
||||
if markers == null:
|
||||
return
|
||||
var positions: Array[Vector2] = []
|
||||
for node: Node in get_tree().get_nodes_in_group("whaletown_interactable"):
|
||||
if not is_instance_valid(node) or not node.has_method("get_interaction_actions"):
|
||||
for node: Node in get_tree().get_nodes_in_group(InteractableComponent.GROUP):
|
||||
var interactable: InteractableComponent = node as InteractableComponent
|
||||
if interactable == null:
|
||||
continue
|
||||
if node.has_method("get_interaction_marker_positions"):
|
||||
var marker_positions_variant: Variant = node.call("get_interaction_marker_positions")
|
||||
if marker_positions_variant is Array:
|
||||
for position_variant: Variant in marker_positions_variant as Array:
|
||||
if position_variant is Vector2:
|
||||
positions.append(position_variant as Vector2)
|
||||
continue
|
||||
var source_node: Node2D = node as Node2D
|
||||
if source_node != null:
|
||||
positions.append(InteractionAnchorUtil.get_position(source_node))
|
||||
for position: Vector2 in interactable.get_marker_positions():
|
||||
positions.append(position)
|
||||
markers.call("set_points", positions)
|
||||
|
||||
func _ensure_point_markers() -> Node2D:
|
||||
|
||||
Reference in New Issue
Block a user