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

520 lines
21 KiB
GDScript

class_name GameSceneRuntimeAssembler
extends RefCounted
const UiMotionScript := preload("res://scripts/ui/common/ui_motion.gd")
const FarmViewportControllerScript := preload("res://scripts/ui/farm/farm_viewport_controller.gd")
const ModalLayerControllerScript := preload("res://scripts/ui/common/modal_layer_controller.gd")
const MainMenuControllerScript := preload("res://scripts/ui/menus/main_menu_controller.gd")
const TopBarViewScript := preload("res://scripts/ui/hud/top_bar_view.gd")
const LandGridViewScript := preload("res://scripts/ui/farm/land_grid_view.gd")
const LandActionMenuScript := preload("res://scripts/ui/farm/land_action_menu.gd")
const PlantTipViewScript := preload("res://scripts/ui/farm/plant_tip_view.gd")
const SeedBagViewScript := preload("res://scripts/ui/farm/seed_bag_view.gd")
const FarmInteractionCoordinatorScript := preload("res://scripts/ui/farm/farm_interaction_coordinator.gd")
const SceneHitRouterScript := preload("res://scripts/ui/scene_hit_router.gd")
const GameTitleFont := preload("res://assets/fonts/google/LilitaOne-Regular.ttf")
const LandLevel0Texture := preload("res://assets/egret/land/land0.png")
const LandLevel1Texture := preload("res://assets/egret/land/land1.png")
const LandLevel2Texture := preload("res://assets/egret/assets/icon/land/land2.png")
const LandLevel3Texture := preload("res://assets/egret/assets/icon/land/land3.png")
const LockedLandTexture := preload("res://assets/egret/land/land-1.png")
const LandLightTexture := preload("res://assets/egret/common/land_light_png.tres")
const BagBgTexture := preload("res://assets/egret/common/bag_bg_png.tres")
const BagLineTexture := preload("res://assets/egret/common/bag_line_png.tres")
const LogItemBgTexture := preload("res://assets/egret/common/log_itembg_png.tres")
const PhaseClockTexture := preload("res://assets/egret/common/m_phase_clock_png.tres")
const PhaseBarTexture := preload("res://assets/egret/common/m_phase_pro_bar_png.tres")
const PhaseBarBgTexture := preload("res://assets/egret/common/m_phase_pro_bg_png.tres")
const MenuPlantTexture := preload("res://assets/egret/menu/menu_p_plant.png")
const MenuGainTexture := preload("res://assets/egret/menu/menu_p_gain.png")
const MenuUprootTexture := preload("res://assets/egret/menu/menu_p_uproot.png")
const MenuManureTexture := preload("res://assets/egret/menu/menu_p_manure.png")
const MenuWaterTexture := preload("res://assets/egret/assets/game/menu/menu_p_put_water.png")
const MenuDieBugTexture := preload("res://assets/egret/menu/menu_p_die_bug.png")
const MenuDieGrassTexture := preload("res://assets/egret/menu/menu_p_die_grass.png")
const MenuStealTexture := preload("res://assets/egret/assets/game/menu/menu_p_steal.png")
const MenuPutBugTexture := preload("res://assets/egret/assets/game/menu/menu_p_put_bug.png")
const MenuPutGrassTexture := preload("res://assets/egret/assets/game/menu/menu_p_put_grass.png")
const PlantStateGrassTexture := preload("res://assets/egret/menu/plant_state1.png")
const PlantStateBugTexture := preload("res://assets/egret/menu/plant_state2.png")
const PlantStateDryTexture := preload("res://assets/egret/menu/plant_state3.png")
const MainMenuHomeTexture := preload("res://assets/egret/menu2/menu2_m_home_png.tres")
const MainMenuShopTexture := preload("res://assets/egret/menu2/menu2_m_shop_png.tres")
const MainMenuWarehouseTexture := preload("res://assets/egret/menu2/menu2_m_warehouse_png.tres")
const MainMenuFriendTexture := preload("res://assets/egret/menu2/menu2_m_rank_png.tres")
const MarketIconTexture := preload("res://assets/replacement/menu2/market.png")
var _owner: Control
var _texture_provider
var _callbacks: Dictionary = {}
var _nodes: Dictionary = {}
var _constants: Dictionary = {}
var _modal_controller
var _farm_viewport_controller
var _farm_scene_root: Control
var _pet_display: Control
func setup(options: Dictionary) -> Dictionary:
_owner = options.get("owner") as Control
_texture_provider = options.get("texture_provider")
_callbacks = options.get("callbacks", {})
_nodes = options.get("nodes", {})
_constants = options.get("constants", {})
var top_bar_view = _setup_top_bar_view()
_setup_market_button()
_setup_menu_title_labels()
var main_menu_controller = _setup_main_menu()
_modal_controller = _setup_modal_layer()
var pet_modules := _setup_pet_display()
var viewport_controller = _setup_farm_scene_root()
var farm_modules := _setup_farm_interaction()
var modules := {
"top_bar_view": top_bar_view,
"main_menu_controller": main_menu_controller,
"modal_controller": _modal_controller,
"modal_layer": _modal_controller.layer() if _modal_controller != null else null,
"toast_label": _modal_controller.toast_label() if _modal_controller != null else null,
"farm_viewport_controller": viewport_controller,
"farm_scene_root": _farm_scene_root,
}
modules.merge(pet_modules, true)
modules.merge(farm_modules, true)
return modules
func _setup_top_bar_view():
var top_bar_view = TopBarViewScript.new()
top_bar_view.setup(
{
"owner": _owner,
"top_layer": _node("top_layer"),
"top_button_group": _node("top_button_group"),
"top_hide": _node("top_hide"),
"label_name": _node("label_name"),
"label_level": _node("label_level"),
"label_gold": _node("label_gold"),
"label_diamond": _node("label_diamond"),
"label_score": _node("label_score"),
"label_exp": _node("label_exp"),
"exp_fill": _node("exp_fill"),
"avatar": _node("avatar"),
"game_config": _constants.get("game_config"),
},
_callback("style_label"),
Callable(self, "_style_menu_title")
)
return top_bar_view
func _setup_main_menu():
var controller = MainMenuControllerScript.new()
controller.setup(
_owner,
_node("main_menu"),
_node("home_button_art"),
MainMenuHomeTexture,
{
"shop": MainMenuShopTexture,
"warehouse": MainMenuWarehouseTexture,
"friend": MainMenuFriendTexture,
},
Callable(self, "_style_menu_title"),
_callback("hide_selection_ui"),
Callable(self, "_on_main_menu_action_pressed")
)
return controller
func _setup_modal_layer():
var controller = ModalLayerControllerScript.new()
controller.setup(_owner, _screen_size(), _callback("style_label"))
return controller
func _setup_pet_display() -> Dictionary:
var pet_layer := Control.new()
pet_layer.name = "PetLayer"
pet_layer.mouse_filter = Control.MOUSE_FILTER_IGNORE
pet_layer.set_anchors_preset(Control.PRESET_FULL_RECT)
_owner.add_child(pet_layer)
_pet_display = Control.new()
_pet_display.name = "BattlePetDisplay"
_pet_display.position = Vector2(430.0, 482.0)
_pet_display.size = Vector2(118.0, 128.0)
_pet_display.pivot_offset = _pet_display.size * 0.5
_pet_display.visible = false
pet_layer.add_child(_pet_display)
var pet_panel_view = _callbacks.get("pet_panel_view", Callable())
if pet_panel_view is Callable and pet_panel_view.is_valid():
var panel_view = pet_panel_view.call()
if panel_view != null:
panel_view.set_display(_pet_display)
return {
"pet_layer": pet_layer,
"pet_display": _pet_display,
}
func _setup_farm_scene_root():
_farm_viewport_controller = FarmViewportControllerScript.new()
_farm_viewport_controller.setup(_owner, _screen_size(), float(_constants.get("scene_zoom_min", 0.6667)), float(_constants.get("scene_zoom_max", 1.3)))
_farm_scene_root = _farm_viewport_controller.scene_root()
return _farm_viewport_controller
func _setup_farm_interaction() -> Dictionary:
var game_view := _node("game_view") as Control
var land_grid_view = LandGridViewScript.new()
land_grid_view.setup({
"owner": _owner,
"game_view": game_view,
"game_config": _constants.get("game_config"),
"crop_phase_rules": _constants.get("crop_phase_rules"),
"get_land_node": _callback("get_land_node"),
"render_add_land_indicator": _callback("render_add_land_indicator"),
"land_count": int(_constants.get("land_count", 12)),
"land_texture_size": _constants.get("land_texture_size", Vector2(172.0, 102.0)),
"textures": _land_grid_textures(),
})
var hit_layer := Control.new()
hit_layer.name = "LandHitLayer"
hit_layer.mouse_filter = Control.MOUSE_FILTER_IGNORE
hit_layer.set_anchors_preset(Control.PRESET_FULL_RECT)
game_view.add_child(hit_layer)
var land_light := TextureRect.new()
land_light.name = "LandLight"
land_light.texture = LandLightTexture
land_light.size = _constants.get("land_texture_size", Vector2(172.0, 102.0))
land_light.expand_mode = TextureRect.EXPAND_IGNORE_SIZE
land_light.stretch_mode = TextureRect.STRETCH_SCALE
land_light.mouse_filter = Control.MOUSE_FILTER_IGNORE
land_light.visible = false
game_view.add_child(land_light)
var land_action_menu = LandActionMenuScript.new()
land_action_menu.setup({
"owner": _owner,
"get_land_node": _callback("get_land_node"),
"on_action": _callback("cool_menu_pressed"),
"on_dismiss": _callback("menu_dismiss_pressed"),
"textures": _land_action_menu_textures(),
"button_size": _constants.get("menu_button_size", Vector2(92.0, 88.0)),
})
var long_press_timer := Timer.new()
long_press_timer.name = "LandLongPressTimer"
long_press_timer.one_shot = true
long_press_timer.wait_time = 0.35
_owner.add_child(long_press_timer)
var seed_bag_view = SeedBagViewScript.new()
seed_bag_view.setup({
"owner": _owner,
"style_label": _callback("style_label"),
"get_item_icon_texture": _callback("get_item_icon_texture"),
"seed_icon_id": _callback("seed_icon_id"),
"on_item_pressed": _callback("bag_item_pressed"),
"textures": _seed_bag_textures(),
})
var bag_panel = seed_bag_view.panel()
var bag_list: VBoxContainer = null
if bag_panel != null:
bag_list = bag_panel.get_node_or_null("SeedScroll/SeedList") as VBoxContainer
var plant_tip_view = PlantTipViewScript.new()
plant_tip_view.setup({
"owner": _owner,
"game_config": _constants.get("game_config"),
"crop_phase_rules": _constants.get("crop_phase_rules"),
"get_land_node": _callback("get_land_node"),
"style_label": _callback("style_label"),
"format_duration": _callback("format_duration"),
"phase_names": _constants.get("phase_names", []),
"textures": _plant_tip_textures(),
})
var plant_phase_timer := Timer.new()
plant_phase_timer.name = "PlantPhaseRefreshTimer"
plant_phase_timer.wait_time = float(_constants.get("plant_phase_refresh_seconds", 1.0))
plant_phase_timer.timeout.connect(_callback("plant_phase_timer_timeout"))
_owner.add_child(plant_phase_timer)
plant_phase_timer.start()
var farm_interaction = FarmInteractionCoordinatorScript.new()
farm_interaction.setup({
"owner": _owner,
"hit_layer": hit_layer,
"land_light": land_light,
"land_action_menu": land_action_menu,
"seed_bag_view": seed_bag_view,
"plant_tip_view": plant_tip_view,
"long_press_timer": long_press_timer,
"constants": _farm_interaction_constants(),
"callbacks": _farm_interaction_callbacks(),
})
farm_interaction.setup_land_hit_areas()
if _farm_viewport_controller != null and _farm_viewport_controller.has_method("set_pan_started_callback"):
_farm_viewport_controller.set_pan_started_callback(Callable(farm_interaction, "on_scene_pan_started"))
if _farm_viewport_controller != null and _farm_viewport_controller.has_method("set_pan_finished_callback"):
_farm_viewport_controller.set_pan_finished_callback(Callable(farm_interaction, "on_scene_pan_finished"))
var scene_hit_router = SceneHitRouterScript.new()
scene_hit_router.setup({
"owner": _owner,
"farm_scene_root": _farm_scene_root,
"pet_display": _pet_display,
"farm_targets": {
"house_art": _node("house_art"),
"dog_house_art": _node("dog_house_art"),
"add_land_art": _node("add_land_art"),
},
"callbacks": _scene_hit_callbacks(),
})
return {
"land_grid_view": land_grid_view,
"plant_layer": land_grid_view.plant_layer(),
"plant_state_layer": land_grid_view.plant_state_layer(),
"hit_layer": hit_layer,
"land_light": land_light,
"land_action_menu": land_action_menu,
"cool_menu_layer": land_action_menu.layer(),
"long_press_timer": long_press_timer,
"seed_bag_view": seed_bag_view,
"bag_panel": bag_panel,
"bag_list": bag_list,
"plant_tip_view": plant_tip_view,
"plant_tip": plant_tip_view.node(),
"plant_phase_timer": plant_phase_timer,
"farm_interaction_coordinator": farm_interaction,
"scene_hit_router": scene_hit_router,
"scene_hit_layer": scene_hit_router.scene_hit_layer(),
"farm_hit_layer": scene_hit_router.farm_hit_layer(),
"add_land_hit": scene_hit_router.add_land_hit(),
}
func _setup_menu_title_labels() -> void:
_add_menu_title(_node("market_button_art"), "Market", Vector2(-15.0, 96.0), Vector2(148.0, 34.0), 24)
_add_menu_title(_node("home_button_art"), "Home", Vector2(-5.0, 112.0), Vector2(165.0, 34.0), 25)
_add_menu_title(_node_path("LeftMiddleMenu/Notice"), "News", Vector2(-8.0, 53.0), Vector2(102.0, 27.0), 21)
_add_menu_title(_node_path("LeftMiddleMenu/Sign"), "Check-In", Vector2(-10.0, 52.0), Vector2(106.0, 28.0), 18)
_add_menu_title(_node_path("LeftMiddleMenu/RewardGift"), "Gift", Vector2(-8.0, 51.0), Vector2(101.0, 28.0), 21)
_add_menu_title(_node("exchange_gold_art"), "Exchange", Vector2(-10.0, 56.0), Vector2(115.0, 30.0), 18)
_add_menu_title(_node_path("TopLayer/TopButtonGroup/TopLog"), "Log", Vector2(-8.0, 48.0), Vector2(90.0, 28.0), 21)
_add_menu_title(_node_path("TopLayer/TopButtonGroup/TopLandup"), "Land Up", Vector2(-10.0, 53.0), Vector2(116.0, 30.0), 18)
_add_menu_title(_node_path("TopLayer/TopButtonGroup/TopPay"), "Top Up", Vector2(-18.0, 53.0), Vector2(92.0, 30.0), 18)
_add_menu_title(_node_path("TopLayer/TopButtonGroup/TopPayGift"), "Pack", Vector2(-8.0, 53.0), Vector2(101.0, 30.0), 21)
_add_menu_title(_node_path("TopLayer/TopButtonGroup/TopLottery"), "Wheel", Vector2(-10.0, 54.0), Vector2(108.0, 30.0), 20)
func _setup_market_button() -> void:
var market_art := _node("market_button_art") as TextureRect
if market_art == null:
return
market_art.texture = MarketIconTexture
market_art.position = Vector2(30.0, 34.0)
market_art.size = Vector2(118.0, 118.0)
market_art.scale = Vector2.ONE
market_art.pivot_offset = market_art.size * 0.5
market_art.expand_mode = TextureRect.EXPAND_FIT_WIDTH_PROPORTIONAL
market_art.stretch_mode = TextureRect.STRETCH_KEEP_ASPECT_CENTERED
market_art.mouse_filter = Control.MOUSE_FILTER_IGNORE
func _add_menu_title(target: Control, text: String, offset: Vector2, size: Vector2, font_size: int) -> void:
if target == null or target.get_parent() == null:
return
if not target.visible:
return
var title_name := "%sTitle" % target.name
var existing := target.get_parent().get_node_or_null(title_name)
if existing != null:
existing.queue_free()
var label := Label.new()
label.name = title_name
label.text = text
label.position = target.position + offset
label.size = size
label.mouse_filter = Control.MOUSE_FILTER_IGNORE
label.horizontal_alignment = HORIZONTAL_ALIGNMENT_CENTER
label.vertical_alignment = VERTICAL_ALIGNMENT_CENTER
label.clip_text = false
_style_menu_title(label, font_size)
target.get_parent().add_child(label)
func _style_menu_title(label: Label, size: int) -> void:
if label == null:
return
label.add_theme_font_override("font", GameTitleFont)
label.add_theme_font_size_override("font_size", size)
label.add_theme_color_override("font_color", Color.WHITE)
label.add_theme_constant_override("outline_size", 4)
label.add_theme_color_override("font_outline_color", Color.html("#7a3a12"))
label.add_theme_color_override("font_shadow_color", Color.html("#2e1708"))
label.add_theme_constant_override("shadow_offset_x", 1)
label.add_theme_constant_override("shadow_offset_y", 2)
func _land_grid_textures() -> Dictionary:
return {
"level_0": LandLevel0Texture,
"level_1": LandLevel1Texture,
"level_2": LandLevel2Texture,
"level_3": LandLevel3Texture,
"locked": LockedLandTexture,
"state_grass": PlantStateGrassTexture,
"state_bug": PlantStateBugTexture,
"state_dry": PlantStateDryTexture,
}
func _land_action_menu_textures() -> Dictionary:
var textures := {}
textures[str(_constants.get("action_plant", "plant"))] = MenuPlantTexture
textures[str(_constants.get("action_gain", "gain"))] = MenuGainTexture
textures[str(_constants.get("action_uproot", "uproot"))] = MenuUprootTexture
textures[str(_constants.get("action_manure", "manure"))] = MenuManureTexture
textures[str(_constants.get("action_water", "water"))] = MenuWaterTexture
textures[str(_constants.get("action_die_bug", "die_bug"))] = MenuDieBugTexture
textures[str(_constants.get("action_die_grass", "die_grass"))] = MenuDieGrassTexture
textures[str(_constants.get("action_steal", "steal"))] = MenuStealTexture
textures[str(_constants.get("action_put_bug", "put_bug"))] = MenuPutBugTexture
textures[str(_constants.get("action_put_grass", "put_grass"))] = MenuPutGrassTexture
return textures
func _seed_bag_textures() -> Dictionary:
return {
"bg": BagBgTexture,
"line": BagLineTexture,
}
func _plant_tip_textures() -> Dictionary:
return {
"bg": LogItemBgTexture,
"clock": PhaseClockTexture,
"bar_bg": PhaseBarBgTexture,
"bar": PhaseBarTexture,
}
func _farm_interaction_constants() -> Dictionary:
return {
"land_count": int(_constants.get("land_count", 12)),
"bag_mode_seed": str(_constants.get("bag_mode_seed", "seed")),
"bag_mode_fertilizer": str(_constants.get("bag_mode_fertilizer", "fertilizer")),
"action_plant": str(_constants.get("action_plant", "plant")),
"action_gain": str(_constants.get("action_gain", "gain")),
"action_uproot": str(_constants.get("action_uproot", "uproot")),
"action_manure": str(_constants.get("action_manure", "manure")),
"action_water": str(_constants.get("action_water", "water")),
"action_die_bug": str(_constants.get("action_die_bug", "die_bug")),
"action_die_grass": str(_constants.get("action_die_grass", "die_grass")),
"action_steal": str(_constants.get("action_steal", "steal")),
"action_put_bug": str(_constants.get("action_put_bug", "put_bug")),
"action_put_grass": str(_constants.get("action_put_grass", "put_grass")),
"disease_type_water": int(_constants.get("disease_type_water", 0)),
"disease_type_bug": int(_constants.get("disease_type_bug", 1)),
"disease_type_grass": int(_constants.get("disease_type_grass", 2)),
}
func _farm_interaction_callbacks() -> Dictionary:
return {
"get_land_node": _callback("get_land_node"),
"land_data": _callback("land_data"),
"land_actions": _callback("land_actions"),
"is_visiting_friend": _callback("is_visiting_friend"),
"is_operation_in_progress": _callback("is_operation_in_progress"),
"open_land_extend_panel": _callback("open_land_extend_panel"),
"apply_empty_button_style": Callable(UiMotionScript, "apply_empty_button_style"),
"seed_items": _callback("seed_items"),
"fertilizer_items": _callback("fertilizer_items"),
"refresh_store_house": _callback("refresh_store_house"),
"sow_seed": _callback("sow_seed"),
"use_fertilizer": _callback("use_fertilizer"),
"gather_crop": _callback("gather_crop"),
"clear_land": _callback("clear_land"),
"kick_disease": _callback("kick_disease"),
"interact_friend_land": _callback("interact_friend_land"),
}
func _scene_hit_callbacks() -> Dictionary:
return {
"apply_empty_button_style": Callable(UiMotionScript, "apply_empty_button_style"),
"keep_modal_layers_on_top": _callback("keep_modal_layers_on_top"),
"open_log_panel": _callback("open_log_panel"),
"open_land_upgrade_panel": _callback("open_land_upgrade_panel"),
"open_pay_panel": _callback("open_pay_panel"),
"open_level_gift_panel": _callback("open_level_gift_panel"),
"open_lottery_panel": _callback("open_lottery_panel"),
"toggle_top_button_group": _callback("toggle_top_button_group"),
"open_market_panel": _callback("open_market_panel"),
"open_notice_panel": _callback("open_notice_panel"),
"open_sign_panel": _callback("open_sign_panel"),
"open_online_gift_panel": _callback("open_online_gift_panel"),
"open_gold_exchange_panel": _callback("open_gold_exchange_panel"),
"open_house_upgrade_panel": _callback("open_house_upgrade_panel"),
"open_land_extend_panel": _callback("open_land_extend_panel"),
"open_pet_panel": _callback("open_pet_panel"),
"open_player_info_panel": _callback("open_player_info_panel"),
"back_to_own_farm": _callback("back_to_own_farm"),
}
func _on_main_menu_action_pressed(action: String) -> void:
match action:
"shop":
_call("open_shop_panel")
"warehouse":
_call("open_warehouse_panel")
"friend":
_call("open_friend_panel")
func _play_press_scale(target: Control) -> void:
UiMotionScript.play_press_scale(_owner, target)
func _play_release_scale(target: Control) -> void:
UiMotionScript.play_release_scale(_owner, target)
func _node(name: String) -> Variant:
return _nodes.get(name)
func _node_path(path: NodePath) -> Control:
if _owner == null:
return null
return _owner.get_node_or_null(path) as Control
func _screen_size() -> Vector2:
return _constants.get("panel_screen_size", Vector2(640.0, 960.0))
func _callback(name: String) -> Callable:
var callback: Callable = _callbacks.get(name, Callable())
return callback
func _call(name: String, args: Array = []) -> Variant:
var callback := _callback(name)
if not callback.is_valid():
return null
return callback.callv(args)