Files
Godot-test/scripts/production/CraftingQueueManager.cs

386 lines
13 KiB
C#
Raw Permalink 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 CraftingQueueManager : Panel
{
public class CraftingQueueItem
{
public string RecipeId { get; set; }
public int Quantity { get; set; } = 1;
public float RemainingTime { get; set; }
public float TotalTime { get; set; }
public bool IsActive { get; set; }
}
private const int MAX_QUEUE_SIZE = 8;
private List<CraftingQueueItem> craftingQueue = new List<CraftingQueueItem>();
private List<Panel> slotPanels = new List<Panel>();
public override void _Ready()
{
GD.Print("CraftingQueueManager _Ready 开始");
// 获取所有槽位面板
var queueContainer = GetNode<HBoxContainer>("MarginContainer/VBoxContainer/QueueContainer");
for (int i = 1; i <= MAX_QUEUE_SIZE; i++)
{
var slot = queueContainer.GetNode<Panel>($"Slot{i}");
slotPanels.Add(slot);
}
// 初始化队列显示
UpdateQueueDisplay();
GD.Print("CraftingQueueManager 初始化完成");
}
public override void _Process(double delta)
{
ProcessCrafting((float)delta);
}
private void ProcessCrafting(float deltaTime)
{
if (craftingQueue.Count == 0) return;
// 处理第一个(当前正在制作的)物品
var currentItem = craftingQueue[0];
if (!currentItem.IsActive)
{
// 开始制作
currentItem.IsActive = true;
GD.Print($"开始制作: {currentItem.RecipeId}");
// 重新更新显示以确保进度条正确初始化
UpdateQueueDisplay();
return; // 这一帧先不处理时间让UI先更新
}
currentItem.RemainingTime -= deltaTime;
if (currentItem.RemainingTime <= 0)
{
// 制作完成
CompleteCrafting(currentItem);
craftingQueue.RemoveAt(0);
UpdateQueueDisplay();
}
else
{
// 更新进度显示
float progress = 1.0f - (currentItem.RemainingTime / currentItem.TotalTime);
UpdateSlotProgress(0, progress);
}
}
private void CompleteCrafting(CraftingQueueItem item)
{
var recipe = CraftingRecipeManager.Instance?.GetRecipe(item.RecipeId);
if (recipe == null || InventoryManager.Instance == null)
{
GD.PrintErr($"无法完成制作: {item.RecipeId}");
return;
}
// 添加产品到库存(数量 = 配方产出数量 × 批量数量)
int totalOutputQuantity = recipe.OutputQuantity * item.Quantity;
InventoryManager.Instance.AddItem(recipe.OutputItem, totalOutputQuantity);
GD.Print($"制作完成: {recipe.OutputItem} x{totalOutputQuantity} (批量: {item.Quantity})");
}
public bool AddToQueue(string recipeId, int quantity = 1)
{
if (craftingQueue.Count >= MAX_QUEUE_SIZE)
{
GD.Print("合成队列已满");
return false;
}
var recipe = CraftingRecipeManager.Instance?.GetRecipe(recipeId);
if (recipe == null)
{
GD.PrintErr($"找不到配方: {recipeId}");
return false;
}
// 检查是否有足够的材料制作指定数量
foreach (var ingredient in recipe.Ingredients)
{
int requiredQuantity = ingredient.Quantity * quantity;
if (InventoryManager.Instance.GetItemQuantity(ingredient.ItemId) < requiredQuantity)
{
GD.Print($"材料不足,无法制作 {quantity} 个: {recipeId}");
return false;
}
}
// 扣除材料(数量 = 配方需求 × 批量数量)
foreach (var ingredient in recipe.Ingredients)
{
int totalRequired = ingredient.Quantity * quantity;
InventoryManager.Instance.RemoveItem(ingredient.ItemId, totalRequired);
GD.Print($"扣除材料: {ingredient.ItemId} x{totalRequired} (批量: {quantity})");
}
// 计算总制作时间(时间 = 基础时间 × 数量)
float totalCraftingTime = recipe.CraftingTime * quantity;
var queueItem = new CraftingQueueItem
{
RecipeId = recipeId,
Quantity = quantity,
RemainingTime = totalCraftingTime,
TotalTime = totalCraftingTime,
IsActive = false
};
craftingQueue.Add(queueItem);
UpdateQueueDisplay();
GD.Print($"添加到合成队列: {recipeId} x{quantity},总时间: {totalCraftingTime}s已扣除材料");
return true;
}
private void UpdateQueueDisplay()
{
// 清空所有槽位
for (int i = 0; i < slotPanels.Count; i++)
{
ClearSlot(i);
}
// 显示队列中的物品
for (int i = 0; i < craftingQueue.Count && i < slotPanels.Count; i++)
{
var queueItem = craftingQueue[i];
var recipe = CraftingRecipeManager.Instance?.GetRecipe(queueItem.RecipeId);
if (recipe != null)
{
UpdateSlotDisplay(i, recipe, queueItem);
}
}
}
private void UpdateSlotDisplay(int slotIndex, CraftingRecipeManager.CraftingRecipe recipe, CraftingQueueItem queueItem)
{
var slot = slotPanels[slotIndex];
// 立即清除现有的子节点而不是使用QueueFree
var childrenToRemove = new List<Node>();
foreach (Node child in slot.GetChildren())
{
childrenToRemove.Add(child);
}
foreach (Node child in childrenToRemove)
{
slot.RemoveChild(child);
child.QueueFree();
}
// 创建背景层(灰色)
var backgroundRect = new ColorRect();
backgroundRect.Name = "Background";
backgroundRect.Color = new Color(0.3f, 0.3f, 0.3f, 1.0f);
backgroundRect.AnchorLeft = 0.0f;
backgroundRect.AnchorTop = 0.0f;
backgroundRect.AnchorRight = 1.0f;
backgroundRect.AnchorBottom = 1.0f;
slot.AddChild(backgroundRect);
// 创建图标显示层
var iconTexture = new TextureRect();
iconTexture.Name = "ProductIcon";
iconTexture.ExpandMode = TextureRect.ExpandModeEnum.FitHeightProportional;
iconTexture.StretchMode = TextureRect.StretchModeEnum.KeepAspectCentered;
iconTexture.AnchorLeft = 0.0f;
iconTexture.AnchorTop = 0.0f;
iconTexture.AnchorRight = 1.0f;
iconTexture.AnchorBottom = 1.0f;
// 获取产物的图标
var outputItemData = GameData.Instance?.GetItem(recipe.OutputItem);
if (outputItemData != null && !string.IsNullOrEmpty(outputItemData.IconPath))
{
// 尝试加载物品图标
if (ResourceLoader.Exists(outputItemData.IconPath))
{
// 尝试加载为Texture2D资源
var resource = ResourceLoader.Load(outputItemData.IconPath);
if (resource is Texture2D texture)
{
iconTexture.Texture = texture;
GD.Print($"槽位{slotIndex}加载产物图标: {outputItemData.IconPath}");
}
else
{
GD.PrintErr($"资源不是Texture2D类型: {outputItemData.IconPath}");
// 使用默认图标
LoadDefaultIcon(iconTexture);
}
}
else
{
// 使用默认图标
LoadDefaultIcon(iconTexture);
}
}
else
{
// 使用默认图标
LoadDefaultIcon(iconTexture);
}
slot.AddChild(iconTexture);
// 创建进度层(白色半透明,覆盖在图标上面)
var progressRect = new ColorRect();
progressRect.Name = "Progress";
progressRect.AnchorLeft = 0.0f;
progressRect.AnchorRight = 1.0f;
progressRect.AnchorBottom = 1.0f;
progressRect.Color = new Color(1.0f, 1.0f, 1.0f, 0.3f); // 白色透明度0.3
// 根据是否激活设置初始进度
if (queueItem.IsActive)
{
float progress = 1.0f - (queueItem.RemainingTime / queueItem.TotalTime);
progressRect.AnchorTop = 1.0f - progress; // 从下往上填充
GD.Print($"槽位{slotIndex}初始化进度条,进度: {progress:F2}");
}
else
{
progressRect.AnchorTop = 1.0f; // 等待状态,无进度显示
}
slot.AddChild(progressRect);
// 添加数量标签如果数量大于1
if (queueItem.Quantity > 1)
{
var quantityLabel = new Label();
quantityLabel.Name = "QuantityLabel";
quantityLabel.Text = queueItem.Quantity.ToString();
quantityLabel.AnchorLeft = 0.6f;
quantityLabel.AnchorTop = 0.6f;
quantityLabel.AnchorRight = 1.0f;
quantityLabel.AnchorBottom = 1.0f;
quantityLabel.HorizontalAlignment = HorizontalAlignment.Center;
quantityLabel.VerticalAlignment = VerticalAlignment.Center;
quantityLabel.AddThemeStyleboxOverride("normal", new StyleBoxFlat());
var styleBox = quantityLabel.GetThemeStylebox("normal") as StyleBoxFlat;
if (styleBox != null)
{
styleBox.BgColor = new Color(0.2f, 0.2f, 0.2f, 0.8f); // 半透明黑色背景
styleBox.CornerRadiusTopLeft = 3;
styleBox.CornerRadiusTopRight = 3;
styleBox.CornerRadiusBottomLeft = 3;
styleBox.CornerRadiusBottomRight = 3;
}
quantityLabel.AddThemeColorOverride("font_color", new Color(1.0f, 1.0f, 1.0f, 1.0f)); // 白色文字
quantityLabel.AddThemeFontSizeOverride("font_size", 8);
slot.AddChild(quantityLabel);
}
// 重置槽位颜色为默认
slot.Modulate = new Color(1.0f, 1.0f, 1.0f, 1.0f);
}
private void LoadDefaultIcon(TextureRect iconTexture)
{
var defaultIcon = GD.Load<Texture2D>("res://assets/textures/icon.svg");
if (defaultIcon != null)
{
iconTexture.Texture = defaultIcon;
GD.Print("使用默认图标 icon.svg");
}
else
{
GD.PrintErr("无法加载默认图标 icon.svg");
}
}
private void UpdateSlotProgress(int slotIndex, float progress)
{
if (slotIndex >= slotPanels.Count)
{
GD.PrintErr($"UpdateSlotProgress: 无效的槽位索引 {slotIndex}");
return;
}
var slot = slotPanels[slotIndex];
if (slot == null || !IsInstanceValid(slot))
{
GD.PrintErr($"UpdateSlotProgress: 槽位{slotIndex}无效");
return;
}
// 安全获取Progress节点
ColorRect progressRect = null;
try
{
if (slot.HasNode("Progress"))
{
progressRect = slot.GetNode<ColorRect>("Progress");
}
else
{
GD.PrintErr($"UpdateSlotProgress: 槽位{slotIndex}没有Progress节点");
return;
}
}
catch (System.Exception e)
{
GD.PrintErr($"UpdateSlotProgress: 获取Progress节点失败: {e.Message}");
return;
}
if (progressRect != null && IsInstanceValid(progressRect))
{
// 从下往上填充progress为0时AnchorTop为1.0progress为1时AnchorTop为0.0
float anchorTop = 1.0f - progress;
progressRect.AnchorTop = anchorTop;
// GD.Print($"更新槽位{slotIndex}进度: {progress:F2}, AnchorTop: {anchorTop:F2}");
}
else
{
GD.PrintErr($"UpdateSlotProgress: 槽位{slotIndex}的Progress节点无效");
}
}
private void ClearSlot(int slotIndex)
{
var slot = slotPanels[slotIndex];
// 立即清除子节点
var childrenToRemove = new List<Node>();
foreach (Node child in slot.GetChildren())
{
childrenToRemove.Add(child);
}
foreach (Node child in childrenToRemove)
{
slot.RemoveChild(child);
child.QueueFree();
}
// 为空槽位添加灰色背景
var backgroundRect = new ColorRect();
backgroundRect.Name = "Background";
backgroundRect.Color = new Color(0.2f, 0.2f, 0.2f, 1.0f); // 更深的灰色表示空槽位
backgroundRect.AnchorLeft = 0.0f;
backgroundRect.AnchorTop = 0.0f;
backgroundRect.AnchorRight = 1.0f;
backgroundRect.AnchorBottom = 1.0f;
slot.AddChild(backgroundRect);
// 重置槽位颜色
slot.Modulate = new Color(1.0f, 1.0f, 1.0f, 1.0f);
}
// 公共方法,供外部调用添加铁块制作
public void StartIronIngotCrafting()
{
AddToQueue("iron_ingot_smelting");
}
}