diff --git a/godot/combat/interface/circular_menu/CircularButton.gd b/godot/combat/interface/circular_menu/CircularButton.gd index bd591bd8cc4f7a8ef5ad4db127ad718cf0724273..9309d4d14753f13b0c17fb8be4bacb9a98fac333 100644 --- a/godot/combat/interface/circular_menu/CircularButton.gd +++ b/godot/combat/interface/circular_menu/CircularButton.gd @@ -6,9 +6,13 @@ onready var button_icon : = $Background/Icon as TextureRect var mouse_over : bool var active : bool +var target_position : Vector2 +var unfocused_scale : Vector2 func initialize(action : CombatAction, target_position : Vector2) -> void: - rect_position = target_position + unfocused_scale = rect_scale + rect_scale = Vector2() + self.target_position = target_position disabled = not action.can_use() if disabled: modulate = Color("#555555") diff --git a/godot/combat/interface/circular_menu/CircularMenu.gd b/godot/combat/interface/circular_menu/CircularMenu.gd index 22825aeef9643edab3ffeae387568576a89ea6a6..c7aaff2553e2600ce5d9a3c57b89c39400214586 100644 --- a/godot/combat/interface/circular_menu/CircularMenu.gd +++ b/godot/combat/interface/circular_menu/CircularMenu.gd @@ -4,9 +4,14 @@ signal action_selected(action) const ContextualAction = preload("CircularButton.tscn") +onready var tween : = $Tween as Tween +onready var buttons : = $Buttons as Control + export(float, 0.0, 300.0) var radius : float = 190 setget set_radius export(float, 0, 1.0) var spacing : float = 0.2 setget set_spacing export(float, -1.0, 1.0) var offset : float = -0.1 setget set_offset +export(float, 0.01, 0.1) var animation_offset : float = 0.08 +export(float, 0.1, 0.5) var animation_duration : float = 0.2 enum Layout { CENTERED = 0, CLOCKWISE = 1, COUNTER_CLOCKWISE = -1} export(Layout) var layout : int = CENTERED @@ -18,36 +23,64 @@ func initialize(actor : Battler) -> void: var actions = actor.actions.get_actions() for action in actions: var button = ContextualAction.instance() - add_child(button) + buttons.add_child(button) var target_position = _calculate_position(button, actions.size()) button.initialize(action, target_position) button.connect("pressed", self, "_on_CircularButton_pressed", [action]) -func open(): +func open() -> void: show() - var first_button = get_child(0) + for button_index in buttons.get_child_count(): + var button = buttons.get_child(button_index) + tween.interpolate_property(button, "rect_scale", Vector2(), button.unfocused_scale, animation_duration, Tween.TRANS_EXPO, Tween.EASE_IN_OUT, animation_offset * button_index) + tween.interpolate_property(button, "rect_position", Vector2(), button.target_position, animation_duration, Tween.TRANS_ELASTIC, Tween.EASE_IN_OUT, animation_offset * button_index) + tween.start() + yield(tween, "tween_completed") + var first_button = buttons.get_child(0) first_button.grab_focus() func _unhandled_input(event: InputEvent) -> void: if event.is_action_pressed("ui_right") or event.is_action_pressed("ui_focus_next"): - var next_button_index = (get_focus_owner().get_index() + 1) % get_child_count() - get_child(next_button_index).grab_focus() + if tween.is_active(): + cancel_animation() + var next_button_index = (get_focus_owner().get_index() + 1) % buttons.get_child_count() + buttons.get_child(next_button_index).grab_focus() accept_event() if event.is_action_pressed("ui_left") or event.is_action_pressed("ui_focus_prev"): - var next_button_index = (get_focus_owner().get_index() - 1 + get_child_count()) % get_child_count() - get_child(next_button_index).grab_focus() + if tween.is_active(): + cancel_animation() + var next_button_index = (get_focus_owner().get_index() - 1 + buttons.get_child_count()) % buttons.get_child_count() + buttons.get_child(next_button_index).grab_focus() accept_event() -func close(): +func close() -> void: + for button_index in buttons.get_child_count(): + var button = buttons.get_child(button_index) + button.animation_player.stop() + tween.interpolate_property(button, "rect_scale", button.rect_scale, Vector2(), animation_duration, Tween.TRANS_EXPO, Tween.EASE_IN_OUT, animation_offset * button_index) + tween.interpolate_property(button, "rect_position", button.rect_position, Vector2(), animation_duration, Tween.TRANS_ELASTIC, Tween.EASE_IN_OUT, animation_offset * button_index) + tween.start() + yield(tween, "tween_completed") queue_free() +func cancel_animation() -> void: + tween.stop_all() + for button_index in buttons.get_child_count(): + var button = buttons.get_child(button_index) + button.rect_scale = button.unfocused_scale + button.rect_position = button.target_position + var first_button = buttons.get_child(0) + first_button.grab_focus() + func _on_CircularButton_pressed(action): + yield(close(), "completed") emit_signal("action_selected", action) - close() func _update() -> void: - for button in get_children(): - button.rect_position = _calculate_position(button, get_child_count()) + if not is_inside_tree(): + return + for button in buttons.get_children(): + button.rect_position = _calculate_position(button, buttons.get_child_count()) func _calculate_position(button, buttons_count : int) -> Vector2: """ diff --git a/godot/combat/interface/circular_menu/CircularMenu.tscn b/godot/combat/interface/circular_menu/CircularMenu.tscn index 3a2de14a2e7ea49a781fe384eee4174cecea7090..cfbd3721b8763f4efa42b4245f5b0f575f66ed19 100644 --- a/godot/combat/interface/circular_menu/CircularMenu.tscn +++ b/godot/combat/interface/circular_menu/CircularMenu.tscn @@ -20,5 +20,27 @@ __meta__ = { radius = 190 spacing = 0.2 offset = -0.1 +animation_offset = 0.08 +animation_duration = 0.2 layout = 0 +[node name="Tween" type="Tween" parent="."] +repeat = false +playback_process_mode = 1 +playback_speed = 1.0 +playback/active = false +playback/repeat = false +playback/speed = 1.0 + +[node name="Buttons" type="Control" parent="."] +anchor_left = 0.0 +anchor_top = 0.0 +anchor_right = 0.0 +anchor_bottom = 0.0 +rect_pivot_offset = Vector2( 0, 0 ) +rect_clip_content = false +mouse_filter = 0 +mouse_default_cursor_shape = 0 +size_flags_horizontal = 1 +size_flags_vertical = 1 +