添加基础的生产线内容-不少bug

This commit is contained in:
2025-06-17 00:05:47 +08:00
parent 7a6cd423fc
commit 50dc434ed9
11 changed files with 1435 additions and 17 deletions

View File

@ -6,7 +6,9 @@
"iron_ore", "iron_ore",
"copper_ore", "copper_ore",
"coal_ore", "coal_ore",
"water" "stone_ore",
"water",
"crude_oil"
] ]
}, },
{ {
@ -15,6 +17,17 @@
"iron_ingot", "iron_ingot",
"copper_ingot" "copper_ingot"
] ]
},
{
"categoryName": "建筑设施",
"items": [
"mining_drill",
"furnace",
"smelter",
"miner",
"assembler",
"chemical_plant"
]
} }
] ]
} }

View File

@ -7,6 +7,8 @@ water,水,RawMaterial,基础资源,可用于多种生产,null,0,0,res://assets
crude_oil,原油,RawMaterial,重要的能源资源,可用于生产燃料,null,0,0,res://assets/textures/items/crude_oil.png crude_oil,原油,RawMaterial,重要的能源资源,可用于生产燃料,null,0,0,res://assets/textures/items/crude_oil.png
iron_ingot,铁块,ProcessedMaterial,由铁矿冶炼而成的基础材料,iron_ore:1,1.0,60.0,res://assets/textures/items/iron_ingot.png iron_ingot,铁块,ProcessedMaterial,由铁矿冶炼而成的基础材料,iron_ore:1,1.0,60.0,res://assets/textures/items/iron_ingot.png
copper_ingot,铜块,ProcessedMaterial,由铜矿冶炼而成的基础材料,copper_ore:1,1.0,60.0,res://assets/textures/items/copper_ingot.png copper_ingot,铜块,ProcessedMaterial,由铜矿冶炼而成的基础材料,copper_ore:1,1.0,60.0,res://assets/textures/items/copper_ingot.png
mining_drill,钻机,Building,自动采集矿石的钻探设备,iron_ingot:5;copper_ingot:3,4.0,300.0,res://assets/textures/buildings/mining_drill.png
furnace,熔炉,Building,自动冶炼矿石的熔炉设备,iron_ingot:4;stone_ore:2,3.5,250.0,res://assets/textures/buildings/furnace.png
smelter,冶炼厂,Building,用于冶炼矿石的基础建筑,iron_ingot:4;copper_ingot:2,3.0,360.0,res://assets/textures/buildings/smelter.png smelter,冶炼厂,Building,用于冶炼矿石的基础建筑,iron_ingot:4;copper_ingot:2,3.0,360.0,res://assets/textures/buildings/smelter.png
miner,采矿机,Building,自动采集矿石的基础建筑,iron_ingot:3;copper_ingot:1,2.0,420.0,res://assets/textures/buildings/miner.png miner,采矿机,Building,自动采集矿石的基础建筑,iron_ingot:3;copper_ingot:1,2.0,420.0,res://assets/textures/buildings/miner.png
assembler,组装机,ProductionDevice,高级生产设备,可制造复杂物品,iron_ingot:6;copper_ingot:4,5.0,480.0,res://assets/textures/buildings/assembler.png assembler,组装机,ProductionDevice,高级生产设备,可制造复杂物品,iron_ingot:6;copper_ingot:4,5.0,480.0,res://assets/textures/buildings/assembler.png

1 Id Name Category Description Recipe CraftTime PowerConsumption IconPath
7 crude_oil 原油 RawMaterial 重要的能源资源,可用于生产燃料 null 0 0 res://assets/textures/items/crude_oil.png
8 iron_ingot 铁块 ProcessedMaterial 由铁矿冶炼而成的基础材料 iron_ore:1 1.0 60.0 res://assets/textures/items/iron_ingot.png
9 copper_ingot 铜块 ProcessedMaterial 由铜矿冶炼而成的基础材料 copper_ore:1 1.0 60.0 res://assets/textures/items/copper_ingot.png
10 mining_drill 钻机 Building 自动采集矿石的钻探设备 iron_ingot:5;copper_ingot:3 4.0 300.0 res://assets/textures/buildings/mining_drill.png
11 furnace 熔炉 Building 自动冶炼矿石的熔炉设备 iron_ingot:4;stone_ore:2 3.5 250.0 res://assets/textures/buildings/furnace.png
12 smelter 冶炼厂 Building 用于冶炼矿石的基础建筑 iron_ingot:4;copper_ingot:2 3.0 360.0 res://assets/textures/buildings/smelter.png
13 miner 采矿机 Building 自动采集矿石的基础建筑 iron_ingot:3;copper_ingot:1 2.0 420.0 res://assets/textures/buildings/miner.png
14 assembler 组装机 ProductionDevice 高级生产设备,可制造复杂物品 iron_ingot:6;copper_ingot:4 5.0 480.0 res://assets/textures/buildings/assembler.png

View File

@ -0,0 +1,152 @@
{
"ProductionLines": [
{
"id": "iron_ore_extraction",
"name": "铁矿采集",
"category": "资源采集",
"description": "自动采集铁矿石",
"productionTime": 2.0,
"powerConsumption": 10,
"buildingRequirements": [
{
"itemId": "mining_drill",
"quantity": 1
}
],
"recipe": {
"inputs": [],
"outputs": [
{
"itemId": "iron_ore",
"quantity": 1
}
]
}
},
{
"id": "copper_ore_extraction",
"name": "铜矿采集",
"category": "资源采集",
"description": "自动采集铜矿石",
"productionTime": 2.0,
"powerConsumption": 10,
"buildingRequirements": [
{
"itemId": "mining_drill",
"quantity": 1
}
],
"recipe": {
"inputs": [],
"outputs": [
{
"itemId": "copper_ore",
"quantity": 1
}
]
}
},
{
"id": "coal_extraction",
"name": "煤矿采集",
"category": "资源采集",
"description": "自动采集煤炭",
"productionTime": 1.5,
"powerConsumption": 8,
"buildingRequirements": [
{
"itemId": "mining_drill",
"quantity": 1
}
],
"recipe": {
"inputs": [],
"outputs": [
{
"itemId": "coal_ore",
"quantity": 1
}
]
}
},
{
"id": "stone_extraction",
"name": "石矿采集",
"category": "资源采集",
"description": "自动采集石头",
"productionTime": 1.8,
"powerConsumption": 8,
"buildingRequirements": [
{
"itemId": "mining_drill",
"quantity": 1
}
],
"recipe": {
"inputs": [],
"outputs": [
{
"itemId": "stone_ore",
"quantity": 1
}
]
}
},
{
"id": "iron_smelting_auto",
"name": "自动冶炼铁块",
"category": "冶炼加工",
"description": "使用冶炼炉自动生产铁块",
"productionTime": 3.2,
"powerConsumption": 15,
"buildingRequirements": [
{
"itemId": "furnace",
"quantity": 1
}
],
"recipe": {
"inputs": [
{
"itemId": "iron_ore",
"quantity": 1
}
],
"outputs": [
{
"itemId": "iron_ingot",
"quantity": 1
}
]
}
},
{
"id": "copper_smelting_auto",
"name": "自动冶炼铜块",
"category": "冶炼加工",
"description": "使用冶炼炉自动生产铜块",
"productionTime": 3.2,
"powerConsumption": 15,
"buildingRequirements": [
{
"itemId": "furnace",
"quantity": 1
}
],
"recipe": {
"inputs": [
{
"itemId": "copper_ore",
"quantity": 1
}
],
"outputs": [
{
"itemId": "copper_ingot",
"quantity": 1
}
]
}
}
]
}

View File

@ -36,13 +36,10 @@
{ {
"categoryName": "建筑设施", "categoryName": "建筑设施",
"itemIds": [ "itemIds": [
"mining_drill",
"furnace",
"smelter", "smelter",
"miner" "miner",
]
},
{
"categoryName": "生产设备",
"itemIds": [
"assembler", "assembler",
"chemical_plant" "chemical_plant"
] ]

View File

@ -0,0 +1,141 @@
[gd_scene load_steps=3 format=3 uid="uid://vao0wv2oib2a"]
[ext_resource type="Script" path="res://scripts/ui/ProductionLineItem.cs" id="1_1"]
[sub_resource type="StyleBoxFlat" id="StyleBoxFlat_1"]
bg_color = Color(0.15, 0.18, 0.22, 0.95)
border_width_left = 1
border_width_top = 1
border_width_right = 1
border_width_bottom = 1
border_color = Color(0.3, 0.4, 0.5, 0.8)
corner_radius_top_left = 8
corner_radius_top_right = 8
corner_radius_bottom_right = 8
corner_radius_bottom_left = 8
shadow_color = Color(0, 0, 0, 0.3)
shadow_size = 2
shadow_offset = Vector2(1, 1)
[node name="ProductionLineItem" type="Panel"]
custom_minimum_size = Vector2(240, 80)
theme_override_styles/panel = SubResource("StyleBoxFlat_1")
script = ExtResource("1_1")
[node name="MarginContainer" type="MarginContainer" parent="."]
layout_mode = 1
anchors_preset = 15
anchor_right = 1.0
anchor_bottom = 1.0
grow_horizontal = 2
grow_vertical = 2
theme_override_constants/margin_left = 8
theme_override_constants/margin_top = 6
theme_override_constants/margin_right = 8
theme_override_constants/margin_bottom = 6
[node name="VBoxContainer" type="VBoxContainer" parent="MarginContainer"]
layout_mode = 2
theme_override_constants/separation = 4
[node name="TopRow" type="HBoxContainer" parent="MarginContainer/VBoxContainer"]
layout_mode = 2
theme_override_constants/separation = 8
[node name="IconTexture" type="TextureRect" parent="MarginContainer/VBoxContainer/TopRow"]
custom_minimum_size = Vector2(32, 32)
layout_mode = 2
expand_mode = 1
stretch_mode = 5
[node name="MiddleContainer" type="VBoxContainer" parent="MarginContainer/VBoxContainer/TopRow"]
layout_mode = 2
size_flags_horizontal = 3
theme_override_constants/separation = 2
[node name="TopInfoRow" type="HBoxContainer" parent="MarginContainer/VBoxContainer/TopRow/MiddleContainer"]
layout_mode = 2
[node name="NameLabel" type="Label" parent="MarginContainer/VBoxContainer/TopRow/MiddleContainer/TopInfoRow"]
layout_mode = 2
size_flags_horizontal = 3
theme_override_font_sizes/font_size = 12
text = "产线名称"
vertical_alignment = 1
[node name="ProductionLabel" type="Label" parent="MarginContainer/VBoxContainer/TopRow/MiddleContainer/TopInfoRow"]
layout_mode = 2
theme_override_font_sizes/font_size = 10
text = "0/s"
horizontal_alignment = 2
[node name="InfoRow" type="HBoxContainer" parent="MarginContainer/VBoxContainer/TopRow/MiddleContainer"]
layout_mode = 2
theme_override_constants/separation = 8
[node name="TimeLabel" type="Label" parent="MarginContainer/VBoxContainer/TopRow/MiddleContainer/InfoRow"]
modulate = Color(0.8, 0.9, 1, 1)
layout_mode = 2
theme_override_font_sizes/font_size = 9
text = "2.0s"
[node name="PowerLabel" type="Label" parent="MarginContainer/VBoxContainer/TopRow/MiddleContainer/InfoRow"]
modulate = Color(1, 0.9, 0.7, 1)
layout_mode = 2
theme_override_font_sizes/font_size = 9
text = "10W"
[node name="BuildingLabel" type="Label" parent="MarginContainer/VBoxContainer/TopRow/MiddleContainer/InfoRow"]
modulate = Color(0.9, 0.8, 1, 1)
layout_mode = 2
theme_override_font_sizes/font_size = 9
text = "需要: 钻机"
[node name="RightContainer" type="VBoxContainer" parent="MarginContainer/VBoxContainer/TopRow"]
layout_mode = 2
[node name="BuildingCountRow" type="HBoxContainer" parent="MarginContainer/VBoxContainer/TopRow/RightContainer"]
layout_mode = 2
theme_override_constants/separation = 4
[node name="DeviceLabel" type="Label" parent="MarginContainer/VBoxContainer/TopRow/RightContainer/BuildingCountRow"]
layout_mode = 2
theme_override_font_sizes/font_size = 9
text = "设备: 0"
horizontal_alignment = 2
[node name="ButtonsRow" type="HBoxContainer" parent="MarginContainer/VBoxContainer/TopRow/RightContainer"]
layout_mode = 2
theme_override_constants/separation = 2
[node name="RemoveButton" type="Button" parent="MarginContainer/VBoxContainer/TopRow/RightContainer/ButtonsRow"]
custom_minimum_size = Vector2(20, 18)
layout_mode = 2
theme_override_font_sizes/font_size = 9
text = "-"
[node name="AddButton" type="Button" parent="MarginContainer/VBoxContainer/TopRow/RightContainer/ButtonsRow"]
custom_minimum_size = Vector2(20, 18)
layout_mode = 2
theme_override_font_sizes/font_size = 9
text = "+"
[node name="ProgressContainer" type="Control" parent="MarginContainer/VBoxContainer"]
custom_minimum_size = Vector2(0, 6)
layout_mode = 2
[node name="ProgressBackground" type="ColorRect" parent="MarginContainer/VBoxContainer/ProgressContainer"]
layout_mode = 1
anchors_preset = 15
anchor_right = 1.0
anchor_bottom = 1.0
grow_horizontal = 2
grow_vertical = 2
color = Color(0.2, 0.2, 0.2, 1)
[node name="ProgressFill" type="ColorRect" parent="MarginContainer/VBoxContainer/ProgressContainer"]
layout_mode = 1
anchors_preset = 9
anchor_bottom = 1.0
grow_vertical = 2
color = Color(0.3, 0.7, 0.9, 1)

View File

@ -43,6 +43,51 @@ public partial class GameScene : Control
{ {
GD.Print("GameScene _Ready 开始"); GD.Print("GameScene _Ready 开始");
// 先初始化管理器系统确保在UI创建之前完成
InitializeManagers();
// 等待一帧确保管理器完全初始化
CallDeferred(nameof(InitializeUI));
}
private void InitializeManagers()
{
// 创建ProductionLineManager
var productionLineManager = new ProductionLineManager();
productionLineManager.Name = "ProductionLineManager";
AddChild(productionLineManager);
// 创建ProductionProcessor
var productionProcessor = new ProductionProcessor();
productionProcessor.Name = "ProductionProcessor";
AddChild(productionProcessor);
GD.Print("自动产线管理器初始化完成");
}
private void InitializeUI()
{
GD.Print("开始初始化UI");
// 测试ProductionLineManager是否正常
var productionLineManager = ProductionLineManager.Instance;
if (productionLineManager != null)
{
var allLines = productionLineManager.GetAllProductionLines();
GD.Print($"ProductionLineManager已初始化共有 {allLines.Count} 个生产线");
var categories = productionLineManager.GetAllCategories();
GD.Print($"生产线分类数: {categories.Count}");
foreach (var category in categories)
{
GD.Print($"- 分类: {category}");
}
}
else
{
GD.PrintErr("ProductionLineManager 仍然为null");
}
// 获取UI引用 // 获取UI引用
powerGenerationLabel = GetNode<Label>("HSplitContainer/LeftPanel/VBoxContainer/PowerInfo/MarginContainer/VBoxContainer/PowerRow1/PowerGeneration"); powerGenerationLabel = GetNode<Label>("HSplitContainer/LeftPanel/VBoxContainer/PowerInfo/MarginContainer/VBoxContainer/PowerRow1/PowerGeneration");
powerConsumptionLabel = GetNode<Label>("HSplitContainer/LeftPanel/VBoxContainer/PowerInfo/MarginContainer/VBoxContainer/PowerRow1/PowerConsumption"); powerConsumptionLabel = GetNode<Label>("HSplitContainer/LeftPanel/VBoxContainer/PowerInfo/MarginContainer/VBoxContainer/PowerRow1/PowerConsumption");
@ -131,6 +176,246 @@ public partial class GameScene : Control
GD.Print("按下C键尝试开始铁块合成"); GD.Print("按下C键尝试开始铁块合成");
} }
} }
// 按P键测试自动产线
if (keyEvent.Keycode == Key.P)
{
TestProductionLine();
}
// 按L键列出所有产线
if (keyEvent.Keycode == Key.L)
{
ListAllProductionLines();
}
// 按B键测试生产线UI
if (keyEvent.Keycode == Key.B)
{
TestProductionLineUI();
}
// 按R键刷新标签页
if (keyEvent.Keycode == Key.R)
{
RefreshProductionLineTabs();
}
// 按I键查看库存状态
if (keyEvent.Keycode == Key.I)
{
ShowInventoryStatus();
} }
} }
} }
private void TestProductionLine()
{
var productionLineManager = ProductionLineManager.Instance;
if (productionLineManager == null)
{
GD.PrintErr("ProductionLineManager not found");
return;
}
// 给库存添加一些建筑和材料用于测试
var inventoryManager = InventoryManager.Instance;
if (inventoryManager != null)
{
inventoryManager.AddItem("mining_drill", 2); // 添加2个钻机
inventoryManager.AddItem("furnace", 1); // 添加1个熔炉
inventoryManager.AddItem("iron_ore", 10); // 添加10个铁矿用于冶炼测试
GD.Print("已添加测试物品到库存");
}
// 测试添加铁矿采集产线
productionLineManager.AddBuilding("iron_ore_extraction", 1);
// 测试添加自动冶炼产线
productionLineManager.AddBuilding("iron_smelting_auto", 1);
GD.Print("已启动测试产线");
}
private void ListAllProductionLines()
{
var productionLineManager = ProductionLineManager.Instance;
if (productionLineManager == null)
{
GD.PrintErr("ProductionLineManager not found");
return;
}
var allLines = productionLineManager.GetAllProductionLines();
GD.Print($"总共有 {allLines.Count} 个产线:");
foreach (var line in allLines)
{
string requirements = "";
if (line.BuildingRequirements != null && line.BuildingRequirements.Count > 0)
{
var req = line.BuildingRequirements[0];
var item = GameData.Instance?.GetItem(req.ItemId);
requirements = $"需要: {req.Quantity}x{item?.Name ?? req.ItemId}";
if (line.BuildingRequirements.Count > 1)
{
requirements += "...";
}
}
else
{
requirements = "无需求";
}
GD.Print($"- {line.Name} ({line.Category}): {line.ProductionTime}s, {line.PowerConsumption}W, {requirements}");
}
var activeLines = productionLineManager.GetAllActiveProductionLines();
GD.Print($"活跃产线: {activeLines.Count} 个");
foreach (var kvp in activeLines)
{
var activeLine = kvp.Value;
if (activeLine.IsActive)
{
var line = productionLineManager.GetProductionLine(activeLine.ProductionLineId);
GD.Print($" 活跃: {line?.Name} - {activeLine.BuildingCount} 个建筑, {activeLine.ProductionRate:F2}/s");
}
}
}
private void TestProductionLineUI()
{
// 给库存添加一些建筑用于测试
var inventoryManager = InventoryManager.Instance;
if (inventoryManager != null)
{
// 建筑设施
inventoryManager.AddItem("mining_drill", 10); // 添加10个钻机
inventoryManager.AddItem("furnace", 8); // 添加8个熔炉
inventoryManager.AddItem("smelter", 5); // 添加5个冶炼厂
inventoryManager.AddItem("miner", 6); // 添加6个采矿机
inventoryManager.AddItem("assembler", 3); // 添加3个组装机
inventoryManager.AddItem("chemical_plant", 2); // 添加2个化工厂
// 原材料
inventoryManager.AddItem("iron_ore", 50); // 添加50个铁矿
inventoryManager.AddItem("copper_ore", 40); // 添加40个铜矿
inventoryManager.AddItem("coal_ore", 60); // 添加60个煤矿修正ID
inventoryManager.AddItem("stone_ore", 80); // 添加80个石矿修正ID
inventoryManager.AddItem("water", 100); // 添加100个水
inventoryManager.AddItem("crude_oil", 30); // 添加30个原油
// 加工材料
inventoryManager.AddItem("iron_ingot", 25); // 添加25个铁块
inventoryManager.AddItem("copper_ingot", 20); // 添加20个铜块
GD.Print("已添加测试建筑设施和材料到库存:");
GD.Print("建筑设施: 钻机x10, 熔炉x8, 冶炼厂x5, 采矿机x6, 组装机x3, 化工厂x2");
GD.Print("原材料: 铁矿x50, 铜矿x40, 煤矿x60, 石矿x80, 水x100, 原油x30");
GD.Print("加工材料: 铁块x25, 铜块x20");
GD.Print("现在可以在生产线和合成标签中测试各种功能了!");
}
}
private void RefreshProductionLineTabs()
{
GD.Print("刷新生产线标签页");
if (categoryTabs != null)
{
var dynamicTabManager = categoryTabs as DynamicTabManager;
if (dynamicTabManager != null)
{
dynamicTabManager.RefreshTabs();
GD.Print("已刷新标签页");
}
else
{
GD.PrintErr("categoryTabs 不是 DynamicTabManager 类型");
}
}
else
{
GD.PrintErr("categoryTabs 为null");
}
}
private void ShowInventoryStatus()
{
GD.Print("=== 当前库存状态 ===");
var inventoryManager = InventoryManager.Instance;
if (inventoryManager == null)
{
GD.PrintErr("InventoryManager 实例为null");
return;
}
// 获取所有物品类别并显示库存
var gameData = GameData.Instance;
if (gameData == null)
{
GD.PrintErr("GameData 实例为null");
return;
}
var allItems = gameData.GetAllItems();
bool hasItems = false;
GD.Print("建筑设施:");
foreach (var kvp in allItems)
{
var itemId = kvp.Key;
var itemData = kvp.Value;
if (itemData.Category == GameData.ItemCategory.Building || itemData.Category == GameData.ItemCategory.ProductionDevice)
{
int quantity = inventoryManager.GetItemQuantity(itemId);
if (quantity > 0)
{
GD.Print($" {itemData.Name}: {quantity} 个");
hasItems = true;
}
}
}
GD.Print("原材料:");
foreach (var kvp in allItems)
{
var itemId = kvp.Key;
var itemData = kvp.Value;
if (itemData.Category == GameData.ItemCategory.RawMaterial)
{
int quantity = inventoryManager.GetItemQuantity(itemId);
if (quantity > 0)
{
GD.Print($" {itemData.Name}: {quantity} 个");
hasItems = true;
}
}
}
GD.Print("加工材料:");
foreach (var kvp in allItems)
{
var itemId = kvp.Key;
var itemData = kvp.Value;
if (itemData.Category == GameData.ItemCategory.ProcessedMaterial)
{
int quantity = inventoryManager.GetItemQuantity(itemId);
if (quantity > 0)
{
GD.Print($" {itemData.Name}: {quantity} 个");
hasItems = true;
}
}
}
if (!hasItems)
{
GD.Print("库存为空按B键添加测试物品");
}
GD.Print("=================");
}
}

View File

@ -11,6 +11,7 @@ public partial class GameData : Node
RawMaterial, // 原材料 RawMaterial, // 原材料
ProcessedMaterial, // 冶炼成品 ProcessedMaterial, // 冶炼成品
Building, // 建筑 Building, // 建筑
ProductionDevice, // 生产设备
Component, // 组件 Component, // 组件
Product // 产品 Product // 产品
} }

View File

@ -0,0 +1,267 @@
using Godot;
using System.Collections.Generic;
using System.Text.Json;
public partial class ProductionLineManager : Node
{
public static ProductionLineManager Instance { get; private set; }
public class ProductionRecipeItem
{
public string ItemId { get; set; }
public int Quantity { get; set; }
}
public class ProductionRecipe
{
public List<ProductionRecipeItem> Inputs { get; set; } = new List<ProductionRecipeItem>();
public List<ProductionRecipeItem> Outputs { get; set; } = new List<ProductionRecipeItem>();
}
public class ProductionLine
{
public string Id { get; set; }
public string Name { get; set; }
public string Category { get; set; }
public string Description { get; set; }
public float ProductionTime { get; set; }
public int PowerConsumption { get; set; }
public List<ProductionRecipeItem> BuildingRequirements { get; set; } = new List<ProductionRecipeItem>();
public ProductionRecipe Recipe { get; set; } = new ProductionRecipe();
}
public class ProductionLineData
{
public List<ProductionLine> ProductionLines { get; set; } = new List<ProductionLine>();
}
// 活跃的产线实例
public class ActiveProductionLine
{
public string ProductionLineId { get; set; }
public int BuildingCount { get; set; } = 0; // 建筑数量
public float RemainingTime { get; set; } = 0; // 当前循环剩余时间
public bool IsActive { get; set; } = false; // 是否激活
public float ProductionRate { get; set; } = 0; // 每秒产出率
public int TotalPowerConsumption { get; set; } = 0; // 总功耗
}
private ProductionLineData productionLineData;
private Dictionary<string, ProductionLine> productionLineMap = new Dictionary<string, ProductionLine>();
private Dictionary<string, List<ProductionLine>> categoryMap = new Dictionary<string, List<ProductionLine>>();
private Dictionary<string, ActiveProductionLine> activeProductionLines = new Dictionary<string, ActiveProductionLine>();
public override void _Ready()
{
if (Instance == null)
{
Instance = this;
LoadProductionLines();
}
else
{
QueueFree();
}
}
private void LoadProductionLines()
{
string configPath = "res://data/config/production_lines.json";
if (!FileAccess.FileExists(configPath))
{
GD.PrintErr($"自动产线配置文件不存在: {configPath}");
return;
}
using var file = FileAccess.Open(configPath, FileAccess.ModeFlags.Read);
if (file == null)
{
GD.PrintErr($"无法打开自动产线配置文件: {configPath}");
return;
}
string jsonContent = file.GetAsText();
try
{
var options = new JsonSerializerOptions
{
PropertyNameCaseInsensitive = true
};
productionLineData = JsonSerializer.Deserialize<ProductionLineData>(jsonContent, options);
if (productionLineData?.ProductionLines != null)
{
// 构建产线映射
foreach (var line in productionLineData.ProductionLines)
{
productionLineMap[line.Id] = line;
// 按分类分组
if (!categoryMap.ContainsKey(line.Category))
{
categoryMap[line.Category] = new List<ProductionLine>();
}
categoryMap[line.Category].Add(line);
GD.Print($"加载自动产线: {line.Id} - {line.Name} ({line.Category})");
}
GD.Print($"成功加载 {productionLineData.ProductionLines.Count} 个自动产线");
}
}
catch (JsonException e)
{
GD.PrintErr($"解析自动产线配置文件失败: {e.Message}");
}
}
public List<ProductionLine> GetAllProductionLines()
{
return productionLineData?.ProductionLines ?? new List<ProductionLine>();
}
public ProductionLine GetProductionLine(string lineId)
{
return productionLineMap.GetValueOrDefault(lineId);
}
public List<ProductionLine> GetProductionLinesByCategory(string category)
{
return categoryMap.GetValueOrDefault(category) ?? new List<ProductionLine>();
}
public List<string> GetAllCategories()
{
return new List<string>(categoryMap.Keys);
}
// 建筑管理
public void AddBuilding(string productionLineId, int count = 1)
{
var productionLine = GetProductionLine(productionLineId);
if (productionLine == null)
{
GD.PrintErr($"找不到产线: {productionLineId}");
return;
}
// 检查建筑需求
if (productionLine.BuildingRequirements == null || productionLine.BuildingRequirements.Count == 0)
{
GD.PrintErr($"产线 {productionLine.Name} 没有定义建筑需求");
return;
}
// 检查是否有足够的建筑材料
var inventoryManager = InventoryManager.Instance;
if (inventoryManager == null)
{
GD.PrintErr("InventoryManager实例为null");
return;
}
// 验证所有建筑需求
foreach (var requirement in productionLine.BuildingRequirements)
{
int available = inventoryManager.GetItemQuantity(requirement.ItemId);
int needed = requirement.Quantity * count;
if (available < needed)
{
var itemData = GameData.Instance?.GetItem(requirement.ItemId);
string itemName = itemData?.Name ?? requirement.ItemId;
GD.Print($"建筑材料不足,需要 {needed} 个 {itemName},当前只有 {available} 个");
return;
}
}
// 扣除建筑材料
foreach (var requirement in productionLine.BuildingRequirements)
{
int consumeAmount = requirement.Quantity * count;
inventoryManager.RemoveItem(requirement.ItemId, consumeAmount);
}
// 添加到活跃产线
if (!activeProductionLines.ContainsKey(productionLineId))
{
activeProductionLines[productionLineId] = new ActiveProductionLine
{
ProductionLineId = productionLineId
};
}
var activeLine = activeProductionLines[productionLineId];
activeLine.BuildingCount += count;
activeLine.IsActive = true;
activeLine.ProductionRate = activeLine.BuildingCount / productionLine.ProductionTime; // 每秒产出率
activeLine.TotalPowerConsumption = activeLine.BuildingCount * productionLine.PowerConsumption;
GD.Print($"成功添加 {count} 个设备到产线 {productionLine.Name}");
GD.Print($"当前产线状态: {activeLine.BuildingCount} 个建筑, 产出率: {activeLine.ProductionRate:F2}/s, 功耗: {activeLine.TotalPowerConsumption}W");
}
public void RemoveBuilding(string productionLineId, int count = 1)
{
if (!activeProductionLines.ContainsKey(productionLineId))
{
GD.Print($"产线 {productionLineId} 没有建筑可移除");
return;
}
var activeLine = activeProductionLines[productionLineId];
var productionLine = GetProductionLine(productionLineId);
count = Mathf.Min(count, activeLine.BuildingCount);
if (count <= 0) return;
activeLine.BuildingCount -= count;
if (activeLine.BuildingCount <= 0)
{
activeLine.IsActive = false;
activeLine.ProductionRate = 0;
activeLine.TotalPowerConsumption = 0;
}
else
{
activeLine.ProductionRate = activeLine.BuildingCount / productionLine.ProductionTime;
activeLine.TotalPowerConsumption = activeLine.BuildingCount * productionLine.PowerConsumption;
}
// 归还建筑材料到库存
var inventoryManager = InventoryManager.Instance;
if (inventoryManager != null && productionLine.BuildingRequirements != null)
{
foreach (var requirement in productionLine.BuildingRequirements)
{
int returnAmount = requirement.Quantity * count;
inventoryManager.AddItem(requirement.ItemId, returnAmount);
}
}
GD.Print($"移除 {count} 个设备从产线 {productionLine.Name}");
GD.Print($"当前产线状态: {activeLine.BuildingCount} 个建筑, 产出率: {activeLine.ProductionRate:F2}/s, 功耗: {activeLine.TotalPowerConsumption}W");
}
public ActiveProductionLine GetActiveProductionLine(string productionLineId)
{
return activeProductionLines.GetValueOrDefault(productionLineId);
}
public Dictionary<string, ActiveProductionLine> GetAllActiveProductionLines()
{
return activeProductionLines;
}
public override void _ExitTree()
{
if (Instance == this)
{
Instance = null;
}
}
}

View File

@ -0,0 +1,177 @@
using Godot;
using System.Collections.Generic;
public partial class ProductionProcessor : Node
{
public static ProductionProcessor Instance { get; private set; }
public override void _Ready()
{
if (Instance == null)
{
Instance = this;
GD.Print("ProductionProcessor 初始化完成");
}
else
{
QueueFree();
}
}
public override void _Process(double delta)
{
ProcessAllProductionLines((float)delta);
}
private void ProcessAllProductionLines(float deltaTime)
{
var productionLineManager = ProductionLineManager.Instance;
if (productionLineManager == null) return;
var activeLines = productionLineManager.GetAllActiveProductionLines();
foreach (var kvp in activeLines)
{
var activeLine = kvp.Value;
if (!activeLine.IsActive || activeLine.BuildingCount <= 0) continue;
ProcessProductionLine(activeLine, deltaTime);
}
}
private void ProcessProductionLine(ProductionLineManager.ActiveProductionLine activeLine, float deltaTime)
{
var productionLine = ProductionLineManager.Instance?.GetProductionLine(activeLine.ProductionLineId);
if (productionLine == null) return;
// 更新生产时间
activeLine.RemainingTime -= deltaTime;
if (activeLine.RemainingTime <= 0)
{
// 检查是否有足够的原料
if (CheckInputMaterials(productionLine, activeLine.BuildingCount))
{
// 消耗原料
ConsumeInputMaterials(productionLine, activeLine.BuildingCount);
// 生产产品
ProduceOutputItems(productionLine, activeLine.BuildingCount);
// 重置生产时间
activeLine.RemainingTime = productionLine.ProductionTime;
GD.Print($"产线 {productionLine.Name} 完成一轮生产,{activeLine.BuildingCount} 个建筑同时运行");
}
else
{
// 原料不足,暂停生产
activeLine.RemainingTime = 0.1f; // 短暂等待后再检查
GD.Print($"产线 {productionLine.Name} 原料不足,暂停生产");
}
}
}
private bool CheckInputMaterials(ProductionLineManager.ProductionLine productionLine, int buildingCount)
{
var inventoryManager = InventoryManager.Instance;
if (inventoryManager == null) return false;
// 检查所有输入材料
foreach (var input in productionLine.Recipe.Inputs)
{
int requiredQuantity = input.Quantity * buildingCount;
int availableQuantity = inventoryManager.GetItemQuantity(input.ItemId);
if (availableQuantity < requiredQuantity)
{
return false;
}
}
return true;
}
private void ConsumeInputMaterials(ProductionLineManager.ProductionLine productionLine, int buildingCount)
{
var inventoryManager = InventoryManager.Instance;
if (inventoryManager == null) return;
foreach (var input in productionLine.Recipe.Inputs)
{
int consumeQuantity = input.Quantity * buildingCount;
inventoryManager.RemoveItem(input.ItemId, consumeQuantity);
var itemData = GameData.Instance?.GetItem(input.ItemId);
string itemName = itemData?.Name ?? input.ItemId;
GD.Print($"消耗材料: {itemName} x{consumeQuantity}");
}
}
private void ProduceOutputItems(ProductionLineManager.ProductionLine productionLine, int buildingCount)
{
var inventoryManager = InventoryManager.Instance;
if (inventoryManager == null) return;
foreach (var output in productionLine.Recipe.Outputs)
{
int produceQuantity = output.Quantity * buildingCount;
inventoryManager.AddItem(output.ItemId, produceQuantity);
var itemData = GameData.Instance?.GetItem(output.ItemId);
string itemName = itemData?.Name ?? output.ItemId;
GD.Print($"生产物品: {itemName} x{produceQuantity}");
}
}
// 公共方法:获取产线当前状态信息
public ProductionLineStatus GetProductionLineStatus(string productionLineId)
{
var activeLine = ProductionLineManager.Instance?.GetActiveProductionLine(productionLineId);
var productionLine = ProductionLineManager.Instance?.GetProductionLine(productionLineId);
if (activeLine == null || productionLine == null)
{
return new ProductionLineStatus
{
IsActive = false,
Progress = 0,
ProductionRate = 0,
PowerConsumption = 0,
BuildingCount = 0
};
}
float progress = 0;
if (activeLine.IsActive && productionLine.ProductionTime > 0)
{
progress = 1.0f - (activeLine.RemainingTime / productionLine.ProductionTime);
}
return new ProductionLineStatus
{
IsActive = activeLine.IsActive,
Progress = Mathf.Clamp(progress, 0.0f, 1.0f),
ProductionRate = activeLine.ProductionRate,
PowerConsumption = activeLine.TotalPowerConsumption,
BuildingCount = activeLine.BuildingCount
};
}
public class ProductionLineStatus
{
public bool IsActive { get; set; }
public float Progress { get; set; } // 0-1的进度
public float ProductionRate { get; set; } // 每秒产出率
public int PowerConsumption { get; set; } // 功耗
public int BuildingCount { get; set; } // 建筑数量
}
public override void _ExitTree()
{
if (Instance == this)
{
Instance = null;
}
}
}

View File

@ -5,6 +5,7 @@ public partial class DynamicTabManager : TabContainer
{ {
private PackedScene itemPanelScene; private PackedScene itemPanelScene;
private PackedScene craftingItemScene; private PackedScene craftingItemScene;
private PackedScene productionLineItemScene;
public override void _Ready() public override void _Ready()
{ {
@ -29,7 +30,22 @@ public partial class DynamicTabManager : TabContainer
return; return;
} }
// 加载ProductionLineItem场景用于生产线
productionLineItemScene = GD.Load<PackedScene>("res://scenes/ProductionLineItem.tscn");
if (productionLineItemScene == null)
{
GD.PrintErr("无法加载ProductionLineItem场景");
return;
}
GD.Print("开始初始化标签页"); GD.Print("开始初始化标签页");
// 延迟初始化以确保所有管理器都已初始化
CallDeferred(nameof(InitializeTabs));
}
public void RefreshTabs()
{
GD.Print("刷新标签页");
InitializeTabs(); InitializeTabs();
} }
@ -113,29 +129,146 @@ public partial class DynamicTabManager : TabContainer
vboxContainer.SizeFlagsVertical = Control.SizeFlags.ExpandFill; vboxContainer.SizeFlagsVertical = Control.SizeFlags.ExpandFill;
scrollContainer.AddChild(vboxContainer); scrollContainer.AddChild(vboxContainer);
// 获取所有分类 // 获取生产线管理器
var categoryManager = ResourceCategoryManager.Instance; var productionLineManager = ProductionLineManager.Instance;
if (categoryManager == null) if (productionLineManager == null)
{ {
GD.PrintErr("ResourceCategoryManager 实例为null"); GD.PrintErr("ProductionLineManager 实例为null,创建空的生产线标签");
// 创建一个提示标签
var noDataLabel = new Label();
noDataLabel.Text = "生产线管理器未初始化";
noDataLabel.HorizontalAlignment = HorizontalAlignment.Center;
noDataLabel.VerticalAlignment = VerticalAlignment.Center;
vboxContainer.AddChild(noDataLabel);
// 添加到TabContainer
AddChild(scrollContainer);
SetTabTitle(GetTabCount() - 1, "生产线");
return; return;
} }
var allCategories = categoryManager.GetAllCategories(); // 获取所有生产线分类
var categories = productionLineManager.GetAllCategories();
GD.Print($"获取到 {categories.Count} 个生产线分类");
// 为生产线相关的分类创建块 if (categories.Count == 0)
foreach (var category in allCategories)
{ {
// 生产线标签包含:生产设备 GD.Print("没有找到生产线分类,创建提示标签");
if (category.CategoryName == "生产设备")
// 创建一个提示标签
var noDataLabel = new Label();
noDataLabel.Text = "暂无生产线配置";
noDataLabel.HorizontalAlignment = HorizontalAlignment.Center;
noDataLabel.VerticalAlignment = VerticalAlignment.Center;
vboxContainer.AddChild(noDataLabel);
}
else
{ {
CreateCategoryBlock(vboxContainer, category, "生产线"); // 为每个分类创建块
foreach (var category in categories)
{
GD.Print($"处理生产线分类: {category}");
CreateProductionCategoryBlock(vboxContainer, category);
} }
} }
// 添加到TabContainer // 添加到TabContainer
AddChild(scrollContainer); AddChild(scrollContainer);
SetTabTitle(GetTabCount() - 1, "生产线"); SetTabTitle(GetTabCount() - 1, "生产线");
GD.Print("生产线标签创建完成");
}
private void CreateProductionCategoryBlock(VBoxContainer parentContainer, string category)
{
GD.Print($"创建生产线分类块: {category}");
// 创建分类块的容器
var categoryContainer = new VBoxContainer();
categoryContainer.Name = $"{category}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;
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);
// 创建生产线网格 - 使用VBoxContainer实现垂直堆叠
var productionContainer = new VBoxContainer();
productionContainer.Name = $"{category}ProductionLines";
productionContainer.SizeFlagsHorizontal = Control.SizeFlags.ExpandFill;
productionContainer.AddThemeConstantOverride("separation", 8); // 垂直间距
// 添加该分类的所有生产线
AddProductionLinesToContainer(productionContainer, category);
categoryContainer.AddChild(productionContainer);
// 添加到父容器
parentContainer.AddChild(categoryContainer);
}
private void AddProductionLinesToContainer(VBoxContainer container, string category)
{
GD.Print($"为分类 '{category}' 添加生产线");
var productionLineManager = ProductionLineManager.Instance;
if (productionLineManager == null)
{
GD.PrintErr("ProductionLineManager 实例为null");
return;
}
// 获取该分类的所有生产线
var productionLines = productionLineManager.GetProductionLinesByCategory(category);
GD.Print($"获取到 {productionLines.Count} 条生产线");
foreach (var productionLine in productionLines)
{
// 创建ProductionLineItem实例
var productionLineItem = productionLineItemScene.Instantiate<ProductionLineItem>();
if (productionLineItem == null)
{
GD.PrintErr($"无法创建ProductionLineItem实例: {productionLine.Name}");
continue;
}
// 设置生产线数据
productionLineItem.SetupProductionLine(productionLine);
// 添加到容器
container.AddChild(productionLineItem);
GD.Print($"成功添加生产线: {productionLine.Name}");
}
} }
private void CreateCategoryBlock(VBoxContainer parentContainer, ResourceCategoryManager.ResourceCategory category, string tabType) private void CreateCategoryBlock(VBoxContainer parentContainer, ResourceCategoryManager.ResourceCategory category, string tabType)

View File

@ -0,0 +1,250 @@
using Godot;
public partial class ProductionLineItem : Panel
{
private Label nameLabel;
private Label productionLabel;
private Label timeLabel;
private Label powerLabel;
private Label buildingLabel;
private Label deviceLabel;
private Button addButton;
private Button removeButton;
private ColorRect progressFill;
private TextureRect iconTexture;
private ProductionLineManager.ProductionLine productionLine;
private string productionLineId;
public override void _Ready()
{
// 获取UI组件引用
nameLabel = GetNode<Label>("MarginContainer/VBoxContainer/TopRow/MiddleContainer/TopInfoRow/NameLabel");
productionLabel = GetNode<Label>("MarginContainer/VBoxContainer/TopRow/MiddleContainer/TopInfoRow/ProductionLabel");
timeLabel = GetNode<Label>("MarginContainer/VBoxContainer/TopRow/MiddleContainer/InfoRow/TimeLabel");
powerLabel = GetNode<Label>("MarginContainer/VBoxContainer/TopRow/MiddleContainer/InfoRow/PowerLabel");
buildingLabel = GetNode<Label>("MarginContainer/VBoxContainer/TopRow/MiddleContainer/InfoRow/BuildingLabel");
deviceLabel = GetNode<Label>("MarginContainer/VBoxContainer/TopRow/RightContainer/BuildingCountRow/DeviceLabel");
addButton = GetNode<Button>("MarginContainer/VBoxContainer/TopRow/RightContainer/ButtonsRow/AddButton");
removeButton = GetNode<Button>("MarginContainer/VBoxContainer/TopRow/RightContainer/ButtonsRow/RemoveButton");
progressFill = GetNode<ColorRect>("MarginContainer/VBoxContainer/ProgressContainer/ProgressFill");
iconTexture = GetNode<TextureRect>("MarginContainer/VBoxContainer/TopRow/IconTexture");
// 连接按钮信号
addButton.Pressed += OnAddButtonPressed;
removeButton.Pressed += OnRemoveButtonPressed;
// 如果生产线数据已经设置,现在应用它
if (productionLine != null)
{
ApplyProductionLineData();
}
}
public void SetupProductionLine(ProductionLineManager.ProductionLine line)
{
productionLine = line;
productionLineId = line.Id;
// 如果UI组件还没有初始化延迟设置
if (nameLabel == null)
{
GD.Print("UI组件还未初始化延迟设置生产线数据");
CallDeferred(nameof(ApplyProductionLineData));
return;
}
ApplyProductionLineData();
}
private void ApplyProductionLineData()
{
if (productionLine == null)
{
GD.PrintErr("productionLine为null无法应用数据");
return;
}
// 确保UI组件已初始化
if (nameLabel == null)
{
GD.PrintErr("nameLabel仍然为nullUI初始化可能失败");
return;
}
// 设置基本信息
nameLabel.Text = productionLine.Name;
timeLabel.Text = $"{productionLine.ProductionTime:F1}s";
powerLabel.Text = $"{productionLine.PowerConsumption}W";
// 设置建筑需求信息
if (productionLine.BuildingRequirements != null && productionLine.BuildingRequirements.Count > 0)
{
var firstRequirement = productionLine.BuildingRequirements[0];
var buildingItem = GameData.Instance?.GetItem(firstRequirement.ItemId);
string buildingName = buildingItem?.Name ?? firstRequirement.ItemId;
if (productionLine.BuildingRequirements.Count == 1)
{
buildingLabel.Text = $"需要: {firstRequirement.Quantity}x{buildingName}";
}
else
{
buildingLabel.Text = $"需要: {firstRequirement.Quantity}x{buildingName}...";
}
}
else
{
buildingLabel.Text = "无建筑需求";
}
// 尝试加载图标
LoadProductionLineIcon();
// 初始更新显示
UpdateDisplay();
GD.Print($"成功设置生产线数据: {productionLine.Name}");
}
private void LoadProductionLineIcon()
{
if (productionLine == null) return;
// 尝试加载产线专用图标,如果没有则使用建筑图标
string iconPath = $"res://assets/textures/production_lines/{productionLineId}.png";
if (!ResourceLoader.Exists(iconPath))
{
// 回退到建筑图标(使用第一个建筑需求的图标)
if (productionLine.BuildingRequirements != null && productionLine.BuildingRequirements.Count > 0)
{
var firstRequirement = productionLine.BuildingRequirements[0];
var buildingItem = GameData.Instance?.GetItem(firstRequirement.ItemId);
if (buildingItem != null && !string.IsNullOrEmpty(buildingItem.IconPath))
{
iconPath = buildingItem.IconPath;
}
}
}
if (ResourceLoader.Exists(iconPath))
{
var texture = GD.Load<Texture2D>(iconPath);
if (texture != null)
{
iconTexture.Texture = texture;
}
}
}
public override void _Process(double delta)
{
// 只有当UI组件准备好且有生产线数据时才更新显示
if (productionLine != null && nameLabel != null)
{
UpdateDisplay();
}
}
private void UpdateDisplay()
{
if (productionLine == null) return;
// 确保UI组件已初始化
if (deviceLabel == null || productionLabel == null || progressFill == null)
{
return; // UI组件还没准备好跳过更新
}
var activeLine = ProductionLineManager.Instance?.GetActiveProductionLine(productionLineId);
var status = ProductionProcessor.Instance?.GetProductionLineStatus(productionLineId);
if (activeLine != null && status != null)
{
// 更新设备数量
deviceLabel.Text = $"设备: {activeLine.BuildingCount}";
// 更新产出率
if (activeLine.IsActive && activeLine.ProductionRate > 0)
{
productionLabel.Text = $"{activeLine.ProductionRate:F1}/s";
}
else
{
productionLabel.Text = "0/s";
}
// 更新进度条
progressFill.AnchorRight = status.Progress;
// 更新按钮状态
UpdateButtonStates();
}
else
{
// 没有激活的产线
deviceLabel.Text = "设备: 0";
productionLabel.Text = "0/s";
progressFill.AnchorRight = 0;
UpdateButtonStates();
}
}
private void UpdateButtonStates()
{
if (productionLine == null) return;
// 确保按钮组件已初始化
if (addButton == null || removeButton == null)
{
return; // 按钮还没准备好,跳过更新
}
// 检查是否有足够的建筑材料来添加设备
bool canAdd = CanAddBuilding();
addButton.Disabled = !canAdd;
// 检查是否有设备可以移除
var activeLine = ProductionLineManager.Instance?.GetActiveProductionLine(productionLineId);
removeButton.Disabled = activeLine == null || activeLine.BuildingCount <= 0;
}
private bool CanAddBuilding()
{
if (productionLine?.BuildingRequirements == null) return true;
var inventoryManager = InventoryManager.Instance;
if (inventoryManager == null) return false;
// 检查是否有足够的建筑材料
foreach (var requirement in productionLine.BuildingRequirements)
{
int available = inventoryManager.GetItemQuantity(requirement.ItemId);
if (available < requirement.Quantity)
{
return false;
}
}
return true;
}
private void OnAddButtonPressed()
{
if (productionLine == null) return;
// 直接尝试添加建筑到产线材料检查和扣除在ProductionLineManager中处理
ProductionLineManager.Instance?.AddBuilding(productionLineId, 1);
}
private void OnRemoveButtonPressed()
{
if (productionLine == null) return;
// 从产线移除建筑(建筑会自动返回库存)
ProductionLineManager.Instance?.RemoveBuilding(productionLineId, 1);
GD.Print($"移除了 {productionLine.Name} 产线的一个设备");
}
}