Files
Godot-test/scripts/ui/DynamicTabManager.cs
2025-06-16 07:59:50 +08:00

733 lines
26 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

using Godot;
using System.Collections.Generic;
public partial class DynamicTabManager : TabContainer
{
private PackedScene itemPanelScene;
private PackedScene craftingItemScene;
public override void _Ready()
{
GD.Print("DynamicTabManager _Ready 开始");
// 设置标签靠左对齐
TabAlignment = TabBar.AlignmentMode.Left;
// 加载ItemPanel场景用于生产线
itemPanelScene = GD.Load<PackedScene>("res://scenes/ItemPanel.tscn");
if (itemPanelScene == null)
{
GD.PrintErr("无法加载ItemPanel场景");
return;
}
// 加载CraftingItem场景用于合成
craftingItemScene = GD.Load<PackedScene>("res://scenes/CraftingItem.tscn");
if (craftingItemScene == null)
{
GD.PrintErr("无法加载CraftingItem场景");
return;
}
GD.Print("开始初始化标签页");
InitializeTabs();
}
private void InitializeTabs()
{
GD.Print("开始创建固定标签页");
// 清空现有标签页
foreach (Node child in GetChildren())
{
child.QueueFree();
}
// 创建固定的标签页
CreateFixedTabs();
GD.Print("成功创建固定标签页");
}
private void CreateFixedTabs()
{
// 创建"合成"标签
CreateTabForCrafting();
// 创建"生产线"标签
CreateTabForProduction();
}
private void CreateTabForCrafting()
{
GD.Print("创建合成标签");
// 创建合成标签的滚动容器
var scrollContainer = new ScrollContainer();
scrollContainer.Name = "CraftingScroll";
// 创建垂直容器来放置所有分类块
var vboxContainer = new VBoxContainer();
vboxContainer.SizeFlagsHorizontal = Control.SizeFlags.ExpandFill;
vboxContainer.SizeFlagsVertical = Control.SizeFlags.ExpandFill;
scrollContainer.AddChild(vboxContainer);
// 获取所有分类
var categoryManager = ResourceCategoryManager.Instance;
if (categoryManager == null)
{
GD.PrintErr("ResourceCategoryManager 实例为null");
return;
}
var allCategories = categoryManager.GetAllCategories();
// 为合成相关的分类创建块
foreach (var category in allCategories)
{
// 合成标签包含:手动采集、冶炼、建筑设施
if (category.CategoryName == "手动采集" ||
category.CategoryName == "冶炼" ||
category.CategoryName == "建筑设施")
{
CreateCategoryBlock(vboxContainer, category, "合成");
}
}
// 添加到TabContainer
AddChild(scrollContainer);
SetTabTitle(GetTabCount() - 1, "合成");
}
private void CreateTabForProduction()
{
GD.Print("创建生产线标签");
// 创建生产线标签的滚动容器
var scrollContainer = new ScrollContainer();
scrollContainer.Name = "ProductionScroll";
// 创建垂直容器来放置所有分类块
var vboxContainer = new VBoxContainer();
vboxContainer.SizeFlagsHorizontal = Control.SizeFlags.ExpandFill;
vboxContainer.SizeFlagsVertical = Control.SizeFlags.ExpandFill;
scrollContainer.AddChild(vboxContainer);
// 获取所有分类
var categoryManager = ResourceCategoryManager.Instance;
if (categoryManager == null)
{
GD.PrintErr("ResourceCategoryManager 实例为null");
return;
}
var allCategories = categoryManager.GetAllCategories();
// 为生产线相关的分类创建块
foreach (var category in allCategories)
{
// 生产线标签包含:生产设备
if (category.CategoryName == "生产设备")
{
CreateCategoryBlock(vboxContainer, category, "生产线");
}
}
// 添加到TabContainer
AddChild(scrollContainer);
SetTabTitle(GetTabCount() - 1, "生产线");
}
private void CreateCategoryBlock(VBoxContainer parentContainer, ResourceCategoryManager.ResourceCategory category, string tabType)
{
GD.Print($"创建分类块: {category.CategoryName}");
// 创建分类块的容器
var categoryContainer = new VBoxContainer();
categoryContainer.Name = $"{category.CategoryName}Block";
// 添加间距
var topSpacer = new Control();
topSpacer.CustomMinimumSize = new Vector2(0, 10);
categoryContainer.AddChild(topSpacer);
// 创建标题行(分类名称 + 横线)
var titleContainer = new HBoxContainer();
// 分类名称标签
var titleLabel = new Label();
titleLabel.Text = category.CategoryName;
titleLabel.HorizontalAlignment = HorizontalAlignment.Left;
titleContainer.AddChild(titleLabel);
// 添加小间距
var labelSpacer = new Control();
labelSpacer.CustomMinimumSize = new Vector2(10, 0);
titleContainer.AddChild(labelSpacer);
// HSeparator 横线分隔符
var separator = new HSeparator();
separator.SizeFlagsHorizontal = Control.SizeFlags.ExpandFill;
separator.SizeFlagsVertical = Control.SizeFlags.ShrinkCenter;
titleContainer.AddChild(separator);
categoryContainer.AddChild(titleContainer);
// 添加小间距
var spacer = new Control();
spacer.CustomMinimumSize = new Vector2(0, 5);
categoryContainer.AddChild(spacer);
// 创建物品网格 - 使用HFlowContainer实现自适应宽度
var flowContainer = new HFlowContainer();
flowContainer.Name = $"{category.CategoryName}Grid";
flowContainer.SizeFlagsHorizontal = Control.SizeFlags.ExpandFill;
flowContainer.AddThemeConstantOverride("h_separation", 10); // 水平间距
flowContainer.AddThemeConstantOverride("v_separation", 8); // 垂直间距
// 添加该分类的所有物品
AddItemsToFlow(flowContainer, category.CategoryName, tabType);
categoryContainer.AddChild(flowContainer);
// 添加到父容器
parentContainer.AddChild(categoryContainer);
}
private void AddItemsToFlow(HFlowContainer flowContainer, string categoryName, string tabType)
{
GD.Print($"为分类 '{categoryName}' 添加物品到流容器,标签类型: {tabType}");
var categoryManager = ResourceCategoryManager.Instance;
if (categoryManager == null)
{
GD.PrintErr("ResourceCategoryManager 实例为null");
return;
}
var items = categoryManager.GetItemsByCategory(categoryName);
GD.Print($"分类 '{categoryName}' 中有 {items.Count} 个物品");
foreach (var kvp in items)
{
var itemId = kvp.Key;
var itemData = kvp.Value;
GD.Print($"创建物品面板: {itemId} - {itemData.Name}");
Control itemPanel;
// 手动采集始终使用ItemPanel保持按住采集功能
if (categoryName == "手动采集")
{
// 手动采集使用ItemPanel
itemPanel = itemPanelScene.Instantiate<Control>();
if (itemPanel == null)
{
GD.PrintErr($"无法实例化ItemPanel for {itemId}");
continue;
}
// 添加手动采集脚本
var manualCollectionScript = new ManualCollectionPanel();
manualCollectionScript.SetAnchorsAndOffsetsPreset(Control.LayoutPreset.FullRect);
manualCollectionScript.MouseFilter = Control.MouseFilterEnum.Stop; // 拦截鼠标事件
itemPanel.AddChild(manualCollectionScript);
manualCollectionScript.SetItemId(itemId);
GD.Print($"为 {itemId} 添加手动采集功能");
// 设置物品数据(手动采集不是生产设备)
SetupItemPanel(itemPanel, itemData, false);
}
// 其他合成物品根据标签类型选择面板
else if (tabType == "合成")
{
// 合成标签的非手动采集物品使用CraftingItem
itemPanel = craftingItemScene.Instantiate<Control>();
if (itemPanel == null)
{
GD.PrintErr($"无法实例化CraftingItem for {itemId}");
continue;
}
// 设置合成物品数据
SetupCraftingItem(itemPanel, itemData, categoryName);
}
else
{
// 生产线标签使用ItemPanel
itemPanel = itemPanelScene.Instantiate<Control>();
if (itemPanel == null)
{
GD.PrintErr($"无法实例化ItemPanel for {itemId}");
continue;
}
// 判断是否为生产设备
bool isProductionDevice = categoryName != "手动采集";
// 设置物品数据
SetupItemPanel(itemPanel, itemData, isProductionDevice);
}
// 添加到流容器
flowContainer.AddChild(itemPanel);
}
}
private void SetupItemPanel(Control itemPanel, GameData.ItemData itemData, bool isProductionDevice = true)
{
try
{
// 设置图标
var iconTexture = itemPanel.GetNode<TextureRect>("MarginContainer/VBoxContainer/TopRow/IconTexture");
if (iconTexture != null && !string.IsNullOrEmpty(itemData.IconPath))
{
// 检查文件是否存在
if (Godot.FileAccess.FileExists(itemData.IconPath))
{
var texture = GD.Load<Texture2D>(itemData.IconPath);
if (texture != null)
{
iconTexture.Texture = texture;
GD.Print($"设置图标成功: {itemData.IconPath}");
}
else
{
GD.PrintErr($"无法加载图标: {itemData.IconPath}");
}
}
else
{
GD.Print($"图标文件不存在: {itemData.IconPath},使用默认图标");
// 默认使用icon.svg
var defaultIcon = GD.Load<Texture2D>("res://assets/textures/icon.svg");
if (defaultIcon != null)
{
iconTexture.Texture = defaultIcon;
}
else
{
GD.PrintErr("无法加载默认图标-1");
}
}
}
// 设置名称
var nameLabel = itemPanel.GetNode<Label>("MarginContainer/VBoxContainer/TopRow/MiddleContainer/TopInfoRow/NameLabel");
if (nameLabel != null)
{
nameLabel.Text = itemData.Name;
GD.Print($"设置名称成功: {itemData.Name}");
}
// 设置产率
var productionLabel = itemPanel.GetNode<Label>("MarginContainer/VBoxContainer/TopRow/MiddleContainer/TopInfoRow/ProductionLabel");
if (productionLabel != null)
{
if (isProductionDevice)
{
productionLabel.Text = "0/s"; // 生产设备显示产率
}
else
{
productionLabel.Text = "手动"; // 手动采集显示"手动"
productionLabel.Modulate = new Color(0.8f, 1.0f, 0.8f, 1.0f); // 淡绿色
}
}
// 根据isProductionDevice决定是否显示设备相关UI
var rightContainer = itemPanel.GetNode<VBoxContainer>("MarginContainer/VBoxContainer/TopRow/RightContainer");
if (rightContainer != null)
{
rightContainer.Visible = isProductionDevice;
}
if (isProductionDevice)
{
// 设置设备数量
var deviceLabel = itemPanel.GetNode<Label>("MarginContainer/VBoxContainer/TopRow/RightContainer/BottomDeviceRow/DeviceLabel");
if (deviceLabel != null)
{
deviceLabel.Text = "设备: 0"; // 默认设备数量
}
// 设置功耗
var powerLabel = itemPanel.GetNode<Label>("MarginContainer/VBoxContainer/TopRow/RightContainer/PowerLabel");
if (powerLabel != null)
{
powerLabel.Text = "-0W"; // 默认功耗
}
}
// 设置进度条
var progressFill = itemPanel.GetNode<ColorRect>("MarginContainer/VBoxContainer/ProgressContainer/ProgressFill");
if (progressFill != null)
{
if (isProductionDevice)
{
progressFill.AnchorRight = 0.0f; // 生产设备默认0%进度
}
else
{
// 手动采集默认0%进度,采集时会动态变化
progressFill.AnchorRight = 0.0f; // 0% 进度
progressFill.Color = new Color(0.3f, 0.8f, 0.3f, 1.0f); // 绿色
}
}
}
catch (System.Exception e)
{
GD.PrintErr($"设置ItemPanel时出错: {e.Message}");
}
}
private void SetupCraftingItem(Control craftingItem, GameData.ItemData itemData, string categoryName)
{
try
{
// 设置图标
var iconTexture = craftingItem.GetNode<TextureRect>("MarginContainer/HBoxContainer/IconTexture");
if (iconTexture != null && !string.IsNullOrEmpty(itemData.IconPath))
{
// 检查文件是否存在
if (Godot.FileAccess.FileExists(itemData.IconPath))
{
var texture = GD.Load<Texture2D>(itemData.IconPath);
if (texture != null)
{
iconTexture.Texture = texture;
GD.Print($"设置合成物品图标成功: {itemData.IconPath}");
}
else
{
LoadDefaultIconForCrafting(iconTexture);
}
}
else
{
GD.Print($"合成物品图标文件不存在: {itemData.IconPath},使用默认图标");
LoadDefaultIconForCrafting(iconTexture);
}
}
// 设置名称
var nameLabel = craftingItem.GetNode<Label>("MarginContainer/HBoxContainer/MiddleContainer/NameLabel");
if (nameLabel != null)
{
nameLabel.Text = itemData.Name;
GD.Print($"设置合成物品名称成功: {itemData.Name}");
}
// 从合成配方系统获取真实信息
var recipes = CraftingRecipeManager.Instance?.GetRecipesForItem(itemData.Id);
var recipe = recipes?.Count > 0 ? recipes[0] : null;
// 设置材料需求(现在在物品名称下面)
var materialsLabel = craftingItem.GetNode<Label>("MarginContainer/HBoxContainer/MiddleContainer/MaterialsLabel");
if (materialsLabel != null)
{
if (recipe != null && recipe.Ingredients.Count > 0)
{
// 显示第一个材料,如果有多个材料可以显示"..."
var firstIngredient = recipe.Ingredients[0];
var itemName = GameData.Instance?.GetItem(firstIngredient.ItemId)?.Name ?? firstIngredient.ItemId;
if (recipe.Ingredients.Count == 1)
{
materialsLabel.Text = $"材料: {firstIngredient.Quantity}x{itemName}";
}
else
{
materialsLabel.Text = $"材料: {firstIngredient.Quantity}x{itemName}...";
}
}
else
{
materialsLabel.Text = "无需材料";
}
}
// 设置合成时间(现在在材料下面)
var craftTimeLabel = craftingItem.GetNode<Label>("MarginContainer/HBoxContainer/MiddleContainer/InfoRow/CraftTimeLabel");
if (craftTimeLabel != null)
{
if (recipe != null)
{
craftTimeLabel.Text = $"{recipe.CraftingTime:F1}s";
}
else
{
craftTimeLabel.Text = "无配方";
craftTimeLabel.Modulate = new Color(1.0f, 0.5f, 0.5f, 1.0f); // 红色表示无配方
}
}
// 设置合成方式(现在在材料下面)
var methodLabel = craftingItem.GetNode<Label>("MarginContainer/HBoxContainer/MiddleContainer/InfoRow/MethodLabel");
if (methodLabel != null)
{
if (recipe != null)
{
methodLabel.Text = recipe.CraftingMethod;
}
else if (categoryName == "手动采集")
{
methodLabel.Text = "手动";
}
else if (categoryName == "冶炼")
{
methodLabel.Text = "冶炼";
}
else
{
methodLabel.Text = "制作";
}
}
// 设置合成按钮
var craftButton = craftingItem.GetNode<Button>("MarginContainer/HBoxContainer/RightContainer/CraftButton");
if (craftButton != null)
{
// 如果没有配方,禁用按钮
if (recipe == null)
{
craftButton.Disabled = true;
craftButton.Text = "无配方";
craftButton.Modulate = new Color(0.6f, 0.6f, 0.6f, 1.0f);
}
else
{
craftButton.Disabled = false;
craftButton.Text = "合成";
craftButton.Modulate = new Color(1.0f, 1.0f, 1.0f, 1.0f);
// 连接按钮点击事件
craftButton.Pressed += () => OnCraftButtonPressed(itemData.Id, craftingItem);
}
}
// 设置数量控制组件
SetupQuantityControls(craftingItem, recipe != null);
}
catch (System.Exception e)
{
GD.PrintErr($"设置CraftingItem时出错: {e.Message}");
}
}
private void LoadDefaultIconForCrafting(TextureRect iconTexture)
{
var defaultIcon = GD.Load<Texture2D>("res://assets/textures/icon.svg");
if (defaultIcon != null)
{
iconTexture.Texture = defaultIcon;
}
else
{
GD.PrintErr("无法加载默认图标");
}
}
private void OnCraftButtonPressed(string itemId, Control craftingItem)
{
GD.Print($"点击合成按钮: {itemId}");
// 检查合成配方管理器是否可用
if (CraftingRecipeManager.Instance == null)
{
GD.PrintErr("CraftingRecipeManager 实例为null无法进行合成");
return;
}
// 查询该物品的合成配方
var recipes = CraftingRecipeManager.Instance.GetRecipesForItem(itemId);
if (recipes == null || recipes.Count == 0)
{
GD.Print($"物品 {itemId} 没有找到合成配方");
return;
}
// 使用第一个找到的配方(后续可以扩展为让用户选择)
var recipe = recipes[0];
GD.Print($"找到合成配方: {recipe.Id} - {recipe.OutputItem}");
// 获取数量输入框的值
int quantity = 1;
try
{
var quantityInput = craftingItem.GetNode<LineEdit>("MarginContainer/HBoxContainer/RightContainer/QuantityContainer/QuantityInput");
if (quantityInput != null)
{
quantity = GetQuantityValue(quantityInput);
}
}
catch (System.Exception e)
{
GD.PrintErr($"获取数量输入值时出错: {e.Message}");
quantity = 1; // 默认为1
}
GD.Print($"准备合成 {quantity} 个 {itemId}");
// 检查是否有足够的材料制作指定数量
bool canCraftAll = true;
var insufficientMaterials = new List<string>();
foreach (var ingredient in recipe.Ingredients)
{
int currentAmount = InventoryManager.Instance?.GetItemQuantity(ingredient.ItemId) ?? 0;
int requiredAmount = ingredient.Quantity * quantity;
if (currentAmount < requiredAmount)
{
canCraftAll = false;
var itemName = GameData.Instance?.GetItem(ingredient.ItemId)?.Name ?? ingredient.ItemId;
insufficientMaterials.Add($"{itemName} (需要 {requiredAmount}, 当前 {currentAmount})");
}
}
if (!canCraftAll)
{
GD.Print($"材料不足,无法合成 {quantity} 个 {itemId}");
foreach (var material in insufficientMaterials)
{
GD.Print($"缺少材料: {material}");
}
return;
}
// 获取合成队列管理器
var craftingQueue = GetCraftingQueueManager();
if (craftingQueue == null)
{
GD.PrintErr("无法找到CraftingQueueManager无法添加到合成队列");
return;
}
// 批量添加到合成队列(一次性添加指定数量)
bool success = craftingQueue.AddToQueue(recipe.Id, quantity);
if (success)
{
GD.Print($"成功添加 {quantity} 个 {itemId} 到合成队列");
}
else
{
GD.Print($"添加 {itemId} 到合成队列失败(可能队列已满)");
}
}
private CraftingQueueManager GetCraftingQueueManager()
{
// 从场景树中查找CraftingQueueManager
// 它应该在GameScene下的左侧面板中
var gameScene = GetTree().CurrentScene;
if (gameScene == null)
{
GD.PrintErr("无法获取当前场景");
return null;
}
// 尝试通过路径查找CraftingQueueManager
var craftingQueue = gameScene.GetNode<CraftingQueueManager>("HSplitContainer/LeftPanel/VBoxContainer/CraftingQueue");
if (craftingQueue == null)
{
GD.PrintErr("无法找到CraftingQueueManager节点");
}
return craftingQueue;
}
private void SetupQuantityControls(Control craftingItem, bool hasRecipe)
{
try
{
var quantityInput = craftingItem.GetNode<LineEdit>("MarginContainer/HBoxContainer/RightContainer/QuantityContainer/QuantityInput");
var minusButton = craftingItem.GetNode<Button>("MarginContainer/HBoxContainer/RightContainer/QuantityContainer/MinusButton");
var plusButton = craftingItem.GetNode<Button>("MarginContainer/HBoxContainer/RightContainer/QuantityContainer/PlusButton");
if (quantityInput != null && minusButton != null && plusButton != null)
{
// 设置初始值
quantityInput.Text = "1";
// 如果没有配方,禁用数量控制
quantityInput.Editable = hasRecipe;
minusButton.Disabled = !hasRecipe;
plusButton.Disabled = !hasRecipe;
if (!hasRecipe)
{
quantityInput.Modulate = new Color(0.6f, 0.6f, 0.6f, 1.0f);
minusButton.Modulate = new Color(0.6f, 0.6f, 0.6f, 1.0f);
plusButton.Modulate = new Color(0.6f, 0.6f, 0.6f, 1.0f);
}
// 连接减号按钮事件
minusButton.Pressed += () => {
int currentValue = GetQuantityValue(quantityInput);
if (currentValue > 1)
{
quantityInput.Text = (currentValue - 1).ToString();
}
};
// 连接加号按钮事件
plusButton.Pressed += () => {
int currentValue = GetQuantityValue(quantityInput);
if (currentValue < 99) // 限制最大值为99
{
quantityInput.Text = (currentValue + 1).ToString();
}
};
// 连接输入框文本变化事件
quantityInput.TextChanged += (string newText) => {
ValidateQuantityInput(quantityInput, newText);
};
}
}
catch (System.Exception e)
{
GD.PrintErr($"设置数量控制组件时出错: {e.Message}");
}
}
private int GetQuantityValue(LineEdit quantityInput)
{
if (int.TryParse(quantityInput.Text, out int value))
{
return Mathf.Clamp(value, 1, 99);
}
return 1;
}
private void ValidateQuantityInput(LineEdit quantityInput, string newText)
{
// 只允许数字输入
if (string.IsNullOrEmpty(newText))
{
quantityInput.Text = "1";
return;
}
if (int.TryParse(newText, out int value))
{
// 限制范围在1-99之间
value = Mathf.Clamp(value, 1, 99);
if (value.ToString() != newText)
{
quantityInput.Text = value.ToString();
quantityInput.CaretColumn = quantityInput.Text.Length;
}
}
else
{
// 如果不是有效数字恢复为1
quantityInput.Text = "1";
quantityInput.CaretColumn = quantityInput.Text.Length;
}
}
}