198 lines
5.9 KiB
GDScript
198 lines
5.9 KiB
GDScript
class_name LandActionMenu
|
|
extends RefCounted
|
|
|
|
const UiMotionScript := preload("res://scripts/ui/common/ui_motion.gd")
|
|
const DIRECT_HIT_GROW := 8.0
|
|
|
|
var _owner: Control
|
|
var _layer: Control
|
|
var _dismiss_button: Button
|
|
var _get_land_node: Callable
|
|
var _on_action: Callable
|
|
var _on_dismiss: Callable
|
|
var _textures: Dictionary = {}
|
|
var _button_size := Vector2(92.0, 88.0)
|
|
var _origin := Vector2.ZERO
|
|
var _hide_tween: Tween
|
|
|
|
|
|
func setup(options: Dictionary) -> void:
|
|
_owner = options.get("owner") as Control
|
|
_get_land_node = options.get("get_land_node", Callable())
|
|
_on_action = options.get("on_action", Callable())
|
|
_on_dismiss = options.get("on_dismiss", Callable())
|
|
_textures = options.get("textures", {})
|
|
_button_size = options.get("button_size", _button_size)
|
|
_create_layer()
|
|
|
|
|
|
func show(position: int, actions: Array[String]) -> void:
|
|
if _layer == null:
|
|
return
|
|
var land_node := _get_land_node_for(position)
|
|
if land_node == null:
|
|
return
|
|
_clear_children(_layer)
|
|
if actions.is_empty():
|
|
_layer.visible = false
|
|
return
|
|
_layer.add_child(_dismiss_button)
|
|
|
|
var center := _land_anchor_in_layer(land_node)
|
|
_origin = center
|
|
var count := actions.size()
|
|
var angle_start := -90.0
|
|
if center.x < 150.0 and count > 2:
|
|
angle_start = 0.0
|
|
elif center.x > 490.0 and count > 2:
|
|
angle_start = 180.0
|
|
|
|
var angle_step := 50.0
|
|
var radius := 110.0
|
|
if count >= 2:
|
|
if count == 2:
|
|
angle_step = 55.0
|
|
elif count == 3:
|
|
angle_step = 72.0
|
|
else:
|
|
if count == 4:
|
|
radius = 95.0
|
|
angle_step = 360.0 / float(count)
|
|
if center.x < 150.0 or center.x > 490.0:
|
|
angle_step = 270.0 / float(count)
|
|
if count == 5:
|
|
radius = 125.0
|
|
angle_start -= float(count - 1) * angle_step * 0.5
|
|
else:
|
|
radius = 60.0
|
|
|
|
for index in range(count):
|
|
var action := actions[index]
|
|
var button := TextureButton.new()
|
|
button.name = "Menu%s" % action.capitalize()
|
|
button.texture_normal = _textures.get(action, _textures.get("plant"))
|
|
button.size = _button_size
|
|
button.pivot_offset = _button_size * 0.5
|
|
button.focus_mode = Control.FOCUS_NONE
|
|
button.set_meta("action", action)
|
|
button.pressed.connect(func() -> void: _handle_action(action))
|
|
button.button_down.connect(func() -> void: UiMotionScript.play_press_scale(_owner, button))
|
|
button.button_up.connect(func() -> void: UiMotionScript.play_release_scale(_owner, button))
|
|
var radians := deg_to_rad(angle_start + float(index) * angle_step)
|
|
var button_center := center + Vector2(cos(radians), sin(radians)) * radius
|
|
var final_position := button_center - _button_size * 0.5
|
|
button.position = center - _button_size * 0.5
|
|
button.scale = Vector2(0.18, 0.18)
|
|
button.modulate = Color(1.0, 1.0, 1.0, 0.0)
|
|
_layer.add_child(button)
|
|
|
|
var tween := _owner.create_tween().set_parallel(true)
|
|
var delay := float(index) * 0.035
|
|
tween.tween_property(button, "position", final_position, 0.2).set_delay(delay).set_trans(Tween.TRANS_BACK).set_ease(Tween.EASE_OUT)
|
|
tween.tween_property(button, "scale", Vector2.ONE, 0.2).set_delay(delay).set_trans(Tween.TRANS_BACK).set_ease(Tween.EASE_OUT)
|
|
tween.tween_property(button, "modulate:a", 1.0, 0.12).set_delay(delay)
|
|
|
|
_layer.visible = true
|
|
|
|
|
|
func hide(animated := false) -> void:
|
|
if _layer == null or not _layer.visible:
|
|
return
|
|
if _hide_tween != null:
|
|
_hide_tween.kill()
|
|
if animated:
|
|
for child in _layer.get_children():
|
|
if child is TextureButton:
|
|
child.disabled = true
|
|
var tween := _owner.create_tween().set_parallel(true)
|
|
tween.tween_property(child, "position", _origin - _button_size * 0.5, 0.18).set_trans(Tween.TRANS_BACK).set_ease(Tween.EASE_IN)
|
|
tween.tween_property(child, "scale", Vector2(0.18, 0.18), 0.18).set_trans(Tween.TRANS_BACK).set_ease(Tween.EASE_IN)
|
|
tween.tween_property(child, "modulate:a", 0.0, 0.12)
|
|
_hide_tween = _owner.create_tween()
|
|
_hide_tween.tween_interval(0.19)
|
|
_hide_tween.tween_callback(_finish_hide)
|
|
return
|
|
_finish_hide()
|
|
|
|
|
|
func is_visible() -> bool:
|
|
return _layer != null and _layer.visible
|
|
|
|
|
|
func handle_direct_hit(screen_position: Vector2) -> bool:
|
|
if _layer == null or not _layer.visible:
|
|
return false
|
|
for child in _layer.get_children():
|
|
var button := child as TextureButton
|
|
if button == null or button.disabled or not button.is_visible_in_tree():
|
|
continue
|
|
if not button.get_global_rect().grow(DIRECT_HIT_GROW).has_point(screen_position):
|
|
continue
|
|
UiMotionScript.play_click_pulse(_owner, button)
|
|
_handle_action(str(button.get_meta("action", "")))
|
|
return true
|
|
_handle_dismiss()
|
|
return true
|
|
|
|
|
|
func layer() -> Control:
|
|
return _layer
|
|
|
|
|
|
func _create_layer() -> void:
|
|
if _owner == null:
|
|
return
|
|
_layer = Control.new()
|
|
_layer.name = "CoolMenuLayer"
|
|
_layer.mouse_filter = Control.MOUSE_FILTER_STOP
|
|
_layer.set_anchors_preset(Control.PRESET_FULL_RECT)
|
|
_layer.visible = false
|
|
_owner.add_child(_layer)
|
|
|
|
_dismiss_button = Button.new()
|
|
_dismiss_button.name = "MenuDismissHit"
|
|
_dismiss_button.set_anchors_preset(Control.PRESET_FULL_RECT)
|
|
_dismiss_button.focus_mode = Control.FOCUS_NONE
|
|
_dismiss_button.text = ""
|
|
UiMotionScript.apply_empty_button_style(_dismiss_button)
|
|
_dismiss_button.pressed.connect(_handle_dismiss)
|
|
|
|
|
|
func _handle_action(action: String) -> void:
|
|
if _on_action.is_valid():
|
|
_on_action.call(action)
|
|
|
|
|
|
func _handle_dismiss() -> void:
|
|
if _on_dismiss.is_valid():
|
|
_on_dismiss.call()
|
|
|
|
|
|
func _finish_hide() -> void:
|
|
if _layer != null:
|
|
_layer.visible = false
|
|
_clear_children(_layer)
|
|
|
|
|
|
func _get_land_node_for(position: int) -> Control:
|
|
if not _get_land_node.is_valid():
|
|
return null
|
|
return _get_land_node.call(position) as Control
|
|
|
|
|
|
func _land_anchor_in_layer(land_node: Control) -> Vector2:
|
|
var global_rect := land_node.get_global_rect()
|
|
var global_anchor := global_rect.position + global_rect.size * 0.5 + Vector2(0.0, -25.0)
|
|
return _layer.get_global_transform().affine_inverse() * global_anchor
|
|
|
|
|
|
func _clear_children(parent: Node) -> void:
|
|
if parent == null:
|
|
return
|
|
for child in parent.get_children():
|
|
if child == _dismiss_button:
|
|
parent.remove_child(child)
|
|
continue
|
|
parent.remove_child(child)
|
|
child.queue_free()
|