hy-farm/godot/FarmGodot/scripts/ui/menus/main_menu_controller.gd
2026-05-29 19:54:56 +08:00

234 lines
6.7 KiB
GDScript

class_name MainMenuController
extends RefCounted
const UiMotionScript := preload("res://scripts/ui/common/ui_motion.gd")
const ACTION_SHOP := "shop"
const ACTION_WAREHOUSE := "warehouse"
const ACTION_FRIEND := "friend"
const HOME_POSITION := Vector2(24.0, 34.0)
const HOME_SIZE := Vector2(155.0, 145.0)
const WAVE_CENTER := Vector2(77.5, 72.5)
const WAVE_RADIUS := 155.0
const HIDDEN_POSITION := Vector2(1000.0, 1000.0)
var _owner: Control
var _menu: Control
var _home_art: TextureRect
var _home_texture: Texture2D
var _item_textures: Dictionary = {}
var _style_menu_title: Callable
var _hide_selection: Callable
var _action_pressed: Callable
var _dismiss_button: Button
var _home_hit: Button
var _buttons: Array[TextureButton] = []
var _tween: Tween
var _open := false
func setup(owner: Control, menu: Control, home_art: TextureRect, home_texture: Texture2D, item_textures: Dictionary, style_menu_title: Callable, hide_selection: Callable, action_pressed: Callable) -> void:
_owner = owner
_menu = menu
_home_art = home_art
_home_texture = home_texture
_item_textures = item_textures
_style_menu_title = style_menu_title
_hide_selection = hide_selection
_action_pressed = action_pressed
_setup()
func toggle() -> void:
if _open:
hide(true)
return
if _hide_selection.is_valid():
_hide_selection.call()
show()
func hide(animated := false) -> void:
if _menu == null:
return
if not _open and not animated:
_finish_hide()
return
if _tween != null:
_tween.kill()
_open = false
if animated:
for button in _buttons:
button.disabled = true
_tween = _owner.create_tween()
_tween.tween_method(Callable(self, "_apply_wave_angle"), 275.0, 135.0, 0.35)
_tween.tween_callback(_finish_hide)
return
_finish_hide()
func is_open() -> bool:
return _open
func handle_direct_hit(screen_position: Vector2) -> bool:
if _menu == null:
return false
if _control_contains(_home_hit, screen_position):
toggle()
return true
if not _open:
return false
for button in _buttons:
if button == null or not button.visible or button.disabled:
continue
if _control_contains(button, screen_position):
_on_item_pressed(str(button.get_meta("action", "")))
return true
hide(true)
return true
func _setup() -> void:
if _owner == null or _menu == null:
return
if _home_art != null:
_home_art.texture = _home_texture
_home_art.size = HOME_SIZE
_home_art.pivot_offset = HOME_SIZE * 0.5
_home_art.mouse_filter = Control.MOUSE_FILTER_IGNORE
_dismiss_button = Button.new()
_dismiss_button.name = "MainMenuDismissHit"
_dismiss_button.set_anchors_preset(Control.PRESET_FULL_RECT)
_dismiss_button.focus_mode = Control.FOCUS_NONE
_dismiss_button.text = ""
_dismiss_button.visible = false
UiMotionScript.apply_empty_button_style(_dismiss_button)
_dismiss_button.pressed.connect(func() -> void: hide(true))
_owner.add_child(_dismiss_button)
_owner.move_child(_dismiss_button, _owner.get_child_count() - 1)
_owner.move_child(_menu, _owner.get_child_count() - 1)
_create_item(ACTION_SHOP, _item_textures.get(ACTION_SHOP), 0)
_create_item(ACTION_WAREHOUSE, _item_textures.get(ACTION_WAREHOUSE), 1)
_create_item(ACTION_FRIEND, _item_textures.get(ACTION_FRIEND), 3)
_finish_hide()
_home_hit = Button.new()
_home_hit.name = "HomeMenuHit"
_home_hit.position = HOME_POSITION
_home_hit.size = HOME_SIZE
_home_hit.focus_mode = Control.FOCUS_NONE
_home_hit.text = ""
UiMotionScript.apply_empty_button_style(_home_hit)
_home_hit.pressed.connect(toggle)
if _home_art != null:
_home_hit.button_down.connect(func() -> void: UiMotionScript.play_press_scale(_owner, _home_art))
_home_hit.button_up.connect(func() -> void: UiMotionScript.play_release_scale(_owner, _home_art))
_menu.add_child(_home_hit)
func _create_item(action: String, texture: Texture2D, wave_index: int) -> void:
if texture == null:
return
var button := TextureButton.new()
button.name = "MainMenu%s" % action.capitalize()
button.texture_normal = texture
button.size = texture.get_size()
button.pivot_offset = button.size * 0.5
button.focus_mode = Control.FOCUS_NONE
button.visible = false
button.disabled = true
button.position = HIDDEN_POSITION
button.set_meta("wave_index", wave_index)
button.set_meta("action", action)
button.pressed.connect(_on_item_pressed.bind(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))
_add_item_title(button, action)
_menu.add_child(button)
_buttons.append(button)
func _add_item_title(button: TextureButton, action: String) -> void:
var title_text := _item_title(action)
if title_text.is_empty():
return
var title := Label.new()
title.name = "Title"
title.text = title_text
var label_width := 118.0 if action == ACTION_WAREHOUSE else 98.0
title.position = Vector2((button.size.x - label_width) * 0.5, button.size.y - 27.0)
title.size = Vector2(label_width, 30.0)
title.mouse_filter = Control.MOUSE_FILTER_IGNORE
title.horizontal_alignment = HORIZONTAL_ALIGNMENT_CENTER
title.vertical_alignment = VERTICAL_ALIGNMENT_CENTER
title.clip_text = false
if _style_menu_title.is_valid():
_style_menu_title.call(title, 18 if action == ACTION_WAREHOUSE else 20)
button.add_child(title)
func _item_title(action: String) -> String:
match action:
ACTION_SHOP:
return "Store"
ACTION_WAREHOUSE:
return "Storage"
ACTION_FRIEND:
return "Friends"
_:
return ""
func show() -> void:
if _menu == null:
return
if _tween != null:
_tween.kill()
_open = true
if _dismiss_button != null:
_dismiss_button.visible = true
for button in _buttons:
button.visible = true
button.disabled = false
button.scale = Vector2.ONE
button.modulate = Color.WHITE
_apply_wave_angle(180.0)
_tween = _owner.create_tween()
_tween.tween_method(Callable(self, "_apply_wave_angle"), 180.0, 280.0, 0.25)
func _finish_hide() -> void:
if _dismiss_button != null:
_dismiss_button.visible = false
for button in _buttons:
button.visible = false
button.disabled = true
button.position = HIDDEN_POSITION
button.scale = Vector2.ONE
button.modulate = Color.WHITE
func _apply_wave_angle(angle: float) -> void:
for button in _buttons:
var wave_index := int(button.get_meta("wave_index", 0))
var radians := deg_to_rad(angle - 36.0 * float(wave_index))
button.position = Vector2(
WAVE_RADIUS * cos(radians) + WAVE_CENTER.x,
WAVE_RADIUS * sin(radians) + WAVE_CENTER.y
)
func _on_item_pressed(action: String) -> void:
if action.is_empty():
return
hide(true)
if _action_pressed.is_valid():
_action_pressed.call(action)
func _control_contains(control: Control, screen_position: Vector2) -> bool:
return control != null and control.is_visible_in_tree() and control.get_global_rect().has_point(screen_position)