diff --git a/DungeonShooting_Godot/DungeonShooting.csproj b/DungeonShooting_Godot/DungeonShooting.csproj index 41ef16c..0f2f332 100644 --- a/DungeonShooting_Godot/DungeonShooting.csproj +++ b/DungeonShooting_Godot/DungeonShooting.csproj @@ -6,6 +6,7 @@ + diff --git a/DungeonShooting_Godot/config/Role.xlsx b/DungeonShooting_Godot/config/Role.xlsx deleted file mode 100644 index 7b0f585..0000000 --- a/DungeonShooting_Godot/config/Role.xlsx +++ /dev/null Binary files differ diff --git a/DungeonShooting_Godot/config/Weapon.xlsx b/DungeonShooting_Godot/config/Weapon.xlsx deleted file mode 100644 index 3791f6e..0000000 --- a/DungeonShooting_Godot/config/Weapon.xlsx +++ /dev/null Binary files differ diff --git a/DungeonShooting_Godot/excel/Role.xlsx b/DungeonShooting_Godot/excel/Role.xlsx new file mode 100644 index 0000000..07a0d37 --- /dev/null +++ b/DungeonShooting_Godot/excel/Role.xlsx Binary files differ diff --git a/DungeonShooting_Godot/excel/Weapon.xlsx b/DungeonShooting_Godot/excel/Weapon.xlsx new file mode 100644 index 0000000..2c52486 --- /dev/null +++ b/DungeonShooting_Godot/excel/Weapon.xlsx Binary files differ diff --git a/DungeonShooting_Godot/prefab/ui/EditorTools.tscn b/DungeonShooting_Godot/prefab/ui/EditorTools.tscn index ea25f16..b231ae5 100644 --- a/DungeonShooting_Godot/prefab/ui/EditorTools.tscn +++ b/DungeonShooting_Godot/prefab/ui/EditorTools.tscn @@ -1,6 +1,6 @@ [gd_scene load_steps=2 format=3 uid="uid://kw3o772vpne"] -[ext_resource type="Script" path="res://src/game/ui/editorTools/EditorToolsPanel.cs" id="1_pav1q"] +[ext_resource type="Script" path="res://src/game/ui/editorTools/EditorToolsPanel.cs" id="1_hkoia"] [node name="EditorTools" type="Control"] layout_mode = 3 @@ -11,7 +11,7 @@ grow_vertical = 2 size_flags_horizontal = 3 size_flags_vertical = 3 -script = ExtResource("1_pav1q") +script = ExtResource("1_hkoia") [node name="ScrollContainer" type="ScrollContainer" parent="."] layout_mode = 0 @@ -107,6 +107,10 @@ [node name="RoomGroupSelect" type="OptionButton" parent="ScrollContainer/MarginContainer/VBoxContainer/HBoxContainer6"] layout_mode = 2 +item_count = 1 +selected = 0 +popup/item_0/text = "testGroup" +popup/item_0/id = 0 [node name="Label3" type="Label" parent="ScrollContainer/MarginContainer/VBoxContainer/HBoxContainer6"] layout_mode = 2 @@ -114,6 +118,22 @@ [node name="RoomTypeSelect" type="OptionButton" parent="ScrollContainer/MarginContainer/VBoxContainer/HBoxContainer6"] layout_mode = 2 +item_count = 7 +selected = 0 +popup/item_0/text = "battle (战斗房间)" +popup/item_0/id = 0 +popup/item_1/text = "inlet (起始房间)" +popup/item_1/id = 1 +popup/item_2/text = "outlet (结束房间)" +popup/item_2/id = 2 +popup/item_3/text = "boss (boss战房间)" +popup/item_3/id = 3 +popup/item_4/text = "reward (奖励房间)" +popup/item_4/id = 4 +popup/item_5/text = "shop (商店房间)" +popup/item_5/id = 5 +popup/item_6/text = "event (事件房间)" +popup/item_6/id = 6 [node name="Button" type="Button" parent="ScrollContainer/MarginContainer/VBoxContainer/HBoxContainer6"] layout_mode = 2 @@ -132,6 +152,18 @@ layout_mode = 2 text = "运行" +[node name="HBoxContainer7" type="HBoxContainer" parent="ScrollContainer/MarginContainer/VBoxContainer"] +layout_mode = 2 +theme_override_constants/separation = 5 + +[node name="Label" type="Label" parent="ScrollContainer/MarginContainer/VBoxContainer/HBoxContainer7"] +layout_mode = 2 +text = "导出Excel表" + +[node name="Button" type="Button" parent="ScrollContainer/MarginContainer/VBoxContainer/HBoxContainer7"] +layout_mode = 2 +text = "运行" + [node name="Confirm" type="ConfirmationDialog" parent="."] initial_position = 1 size = Vector2i(200, 124) diff --git a/DungeonShooting_Godot/scene/test/TestReadExcel.tscn b/DungeonShooting_Godot/scene/test/TestReadExcel.tscn index 78be4ee..12d2893 100644 --- a/DungeonShooting_Godot/scene/test/TestReadExcel.tscn +++ b/DungeonShooting_Godot/scene/test/TestReadExcel.tscn @@ -1,6 +1,6 @@ [gd_scene load_steps=2 format=3 uid="uid://deq562id5sngp"] -[ext_resource type="Script" path="res://src/test/TestReadExcel.cs" id="1_8sptd"] +[ext_resource type="Script" path="res://src/test/TestReadExcel.cs" id="1_4ctg1"] [node name="TestReadExcel" type="Node2D"] -script = ExtResource("1_8sptd") +script = ExtResource("1_4ctg1") diff --git a/DungeonShooting_Godot/src/config/Role.cs b/DungeonShooting_Godot/src/config/Role.cs new file mode 100644 index 0000000..964df76 --- /dev/null +++ b/DungeonShooting_Godot/src/config/Role.cs @@ -0,0 +1,11 @@ +namespace Config; + +public class Role +{ + /// + /// 物体唯一id
+ /// 不需要添加类型前缀 + ///
+ public string Id; + +} \ No newline at end of file diff --git a/DungeonShooting_Godot/src/config/Weapon.cs b/DungeonShooting_Godot/src/config/Weapon.cs new file mode 100644 index 0000000..7a48e08 --- /dev/null +++ b/DungeonShooting_Godot/src/config/Weapon.cs @@ -0,0 +1,214 @@ +namespace Config; + +public class Weapon +{ + /// + /// 物体唯一id
+ /// 不需要添加类型前缀 + ///
+ public string Id; + + /// + /// 武器 Prefab, 必须继承场景 "res://prefab/weapon/Weapon.tscn" + /// + public string Prefab; + + /// + /// 重量 + /// + public float Weight; + + /// + /// 武器显示的名称 + /// + public string Name; + + /// + /// 武器的图标 + /// + public string Icon; + + /// + /// 武器类型:
+ /// 1.副武器
+ /// 2.主武器
+ /// 3.重型武器 + ///
+ public byte WeightType; + + /// + /// 是否连续发射, 如果为false, 则每次发射都需要扣动扳机 + /// + public bool ContinuousShoot; + + /// + /// 弹夹容量 + /// + public int AmmoCapacity; + + /// + /// 弹药容量上限 + /// + public int MaxAmmoCapacity; + + /// + /// 起始备用弹药数量 + /// + public int StandbyAmmoCapacity; + + /// + /// 装弹时间, 单位: 秒 + /// + public float ReloadTime; + + /// + /// 每粒子弹是否是单独装填, 如果是, 那么每上一发子弹的时间就是 ReloadTime, 可以做霰弹武器装填效果 + /// + public bool AloneReload; + + /// + /// 单独装填时每次装填子弹数量, 必须要将 'AloneReload' 属性设置为 true + /// + public int AloneReloadCount; + + /// + /// 单独装填的子弹时可以立即射击, 必须要将 'AloneReload' 属性设置为 true + /// + public bool AloneReloadCanShoot; + + /// + /// 是否为松发开火, 也就是松开扳机才开火, 若要启用该属性, 必须将 'ContinuousShoot' 设置为 false + /// + public bool LooseShoot; + + /// + /// 最少需要蓄力多久才能开火, 必须将 'LooseShoot' 设置为 true + /// + public float MinChargeTime; + + /// + /// 连续发射最小次数, 仅当 ContinuousShoot 为 false 时生效 + /// + public int MinContinuousCount; + + /// + /// 连续发射最大次数, 仅当 ContinuousShoot 为 false 时生效 + /// + public int MaxContinuousCount; + + /// + /// 按下一次扳机后需要多长时间才能再次感应按下 + /// + public float TriggerInterval; + + /// + /// 初始射速, 初始每分钟能开火次数 + /// + public float StartFiringSpeed; + + /// + /// 最终射速, 最终每分钟能开火次数, 仅当 ContinuousShoot 为 true 时生效 + /// + public float FinalFiringSpeed; + + /// + /// 按下扳机并开火后射速增加速率 + /// + public float FiringSpeedAddSpeed; + + /// + /// 松开扳机后射速消散速率 + /// + public float FiringSpeedBackSpeed; + + /// + /// 单次开火发射子弹最小数量 + /// + public int MinFireBulletCount; + + /// + /// 单次开火发射子弹最大数量 + /// + public int MaxFireBulletCount; + + /// + /// 开火前延时 + /// + public float DelayedTime; + + /// + /// 初始散射半径 + /// + public float StartScatteringRange; + + /// + /// 最终散射半径 + /// + public float FinalScatteringRange; + + /// + /// 每次发射后散射增加值 + /// + public float ScatteringRangeAddValue; + + /// + /// 松开扳机后散射销退速率 + /// + public float ScatteringRangeBackSpeed; + + /// + /// 松开扳机多久后开始销退散射值 (单位: 秒) + /// + public float ScatteringRangeBackTime; + + /// + /// 子弹飞行最大距离 + /// + public float MaxDistance; + + /// + /// 子弹飞行最小距离 + /// + public float MinDistance; + + /// + /// 最大后坐力 (仅用于开火后武器身抖动) + /// + public float MaxBacklash; + + /// + /// 最小后坐力 (仅用于开火后武器身抖动) + /// + public float MinBacklash; + + /// + /// 后坐力偏移回归回归速度 + /// + public float BacklashRegressionSpeed; + + /// + /// 开火后武器口上抬角度 + /// + public float UpliftAngle; + + /// + /// 武器默认上抬角度 + /// + public float DefaultAngle; + + /// + /// 开火后武器口角度恢复速度倍数 + /// + public float UpliftAngleRestore; + + /// + /// 默认射出的子弹id + /// + public string BulletId; + + /// + /// 投抛状态下物体碰撞器大小 + /// + public Godot.Vector2 ThrowCollisionSize; + +} \ No newline at end of file diff --git a/DungeonShooting_Godot/src/framework/common/Utils.cs b/DungeonShooting_Godot/src/framework/common/Utils.cs index 5a29fce..02e17d1 100644 --- a/DungeonShooting_Godot/src/framework/common/Utils.cs +++ b/DungeonShooting_Godot/src/framework/common/Utils.cs @@ -177,4 +177,12 @@ { return str.Substring(0, 1).ToLower() + str.Substring(1); } + + /// + /// 字符串首字母大写 + /// + public static string FirstToUpper(this string str) + { + return str.Substring(0, 1).ToUpper() + str.Substring(1); + } } \ No newline at end of file diff --git a/DungeonShooting_Godot/src/framework/generator/ExcelGenerator.cs b/DungeonShooting_Godot/src/framework/generator/ExcelGenerator.cs index d11049e..da65dab 100644 --- a/DungeonShooting_Godot/src/framework/generator/ExcelGenerator.cs +++ b/DungeonShooting_Godot/src/framework/generator/ExcelGenerator.cs @@ -1,8 +1,101 @@ -using System; +using System.Data; +using System.IO; +using Godot; +using NPOI.XSSF.UserModel; namespace Generator; -public class ExcelGenerator +public static class ExcelGenerator { + // private class ExcelTableData + // { + // public string[] ColumnName; + // public string[] TypeName; + // public string[][] Data; + // } + + public static bool ExportExcel() + { + GD.Print("准备导出excel表..."); + var directoryInfo = new DirectoryInfo(GameConfig.ExcelFilePath); + if (directoryInfo.Exists) + { + var fileInfos = directoryInfo.GetFiles(); + foreach (var fileInfo in fileInfos) + { + if (fileInfo.Extension == ".xlsx") + { + GD.Print("excel表: " + fileInfo.FullName); + ReadExcel(fileInfo.FullName); + } + } + } + return true; + } + + private static void ReadExcel(string excelPath) + { + var fileName = Path.GetFileNameWithoutExtension(excelPath).FirstToUpper(); + var outStr = "namespace Config;\n\n"; + outStr += $"public class {fileName} \n{{\n"; + var sourceFile = excelPath; + + //加载表数据 + var workbook = new XSSFWorkbook(sourceFile); + var sheet1 = workbook.GetSheet("Sheet1"); + + //解析表 + var rowCount = sheet1.LastRowNum; + + //先解析表中的列名, 注释, 类型 + var columnCount = -1; + var names = sheet1.GetRow(0); + var descriptions = sheet1.GetRow(1); + var types = sheet1.GetRow(2); + foreach (var cell in names) + { + var value = cell.StringCellValue; + if (string.IsNullOrEmpty(value)) + { + columnCount = cell.ColumnIndex; + break; + } + + value = value.FirstToUpper(); + + outStr += $" /// \n"; + var descriptionCell = descriptions.GetCell(cell.ColumnIndex); + var description = descriptionCell.StringCellValue.Replace("\n", "
\n /// "); + var type = TypeMapping(types.GetCell(cell.ColumnIndex).StringCellValue); + outStr += $" /// {description}\n"; + outStr += $" ///
\n"; + outStr += $" public {type} {value};\n\n"; + } + + outStr += "}"; + workbook.Close(); + + if (!Directory.Exists("src/config")) + { + Directory.CreateDirectory("src/config"); + } + File.WriteAllText("src/config/" + fileName + ".cs", outStr); + } + + private static string TypeMapping(string typeName) + { + switch (typeName) + { + case "boolean": return "bool"; + case "boolean[]": return "bool[]"; + case "vector2": return "Godot.Vector2"; + case "vector2[]": return "Godot.Vector2[]"; + case "vector3": return "Godot.Vector3"; + case "vector3[]": return "Godot.Vector3[]"; + case "color[]": return "Godot.Color[]"; + } + + return typeName; + } } \ No newline at end of file diff --git a/DungeonShooting_Godot/src/game/GameConfig.cs b/DungeonShooting_Godot/src/game/GameConfig.cs index 0591a7d..e63310e 100644 --- a/DungeonShooting_Godot/src/game/GameConfig.cs +++ b/DungeonShooting_Godot/src/game/GameConfig.cs @@ -72,4 +72,9 @@ /// 配置层级的自定义数据名称 /// public const string CustomTileLayerName = "TileLayer"; + + /// + /// excel配置文件存放路径 + /// + public const string ExcelFilePath = "excel/"; } \ No newline at end of file diff --git a/DungeonShooting_Godot/src/game/ui/editorTools/EditorTools.cs b/DungeonShooting_Godot/src/game/ui/editorTools/EditorTools.cs index a33e0f6..99124ab 100644 --- a/DungeonShooting_Godot/src/game/ui/editorTools/EditorTools.cs +++ b/DungeonShooting_Godot/src/game/ui/editorTools/EditorTools.cs @@ -500,6 +500,59 @@ } /// + /// 类型: , 路径: EditorTools.ScrollContainer.MarginContainer.VBoxContainer.HBoxContainer7.Label + /// + public class UiNode6_Label : IUiNode + { + public UiNode6_Label(Godot.Label node) : base(node) { } + public override UiNode6_Label Clone() => new ((Godot.Label)Instance.Duplicate()); + } + + /// + /// 类型: , 路径: EditorTools.ScrollContainer.MarginContainer.VBoxContainer.HBoxContainer7.Button + /// + public class UiNode6_Button : IUiNode + { + public UiNode6_Button(Godot.Button node) : base(node) { } + public override UiNode6_Button Clone() => new ((Godot.Button)Instance.Duplicate()); + } + + /// + /// 类型: , 路径: EditorTools.ScrollContainer.MarginContainer.VBoxContainer.HBoxContainer7 + /// + public class UiNode_HBoxContainer7 : IUiNode + { + /// + /// 使用 Instance 属性获取当前节点实例对象, 节点类型: , 节点路径: EditorTools.ScrollContainer.MarginContainer.VBoxContainer.Label + /// + public UiNode6_Label L_Label + { + get + { + if (_L_Label == null) _L_Label = new UiNode6_Label(Instance.GetNodeOrNull("Label")); + return _L_Label; + } + } + private UiNode6_Label _L_Label; + + /// + /// 使用 Instance 属性获取当前节点实例对象, 节点类型: , 节点路径: EditorTools.ScrollContainer.MarginContainer.VBoxContainer.Button + /// + public UiNode6_Button L_Button + { + get + { + if (_L_Button == null) _L_Button = new UiNode6_Button(Instance.GetNodeOrNull("Button")); + return _L_Button; + } + } + private UiNode6_Button _L_Button; + + public UiNode_HBoxContainer7(Godot.HBoxContainer node) : base(node) { } + public override UiNode_HBoxContainer7 Clone() => new ((Godot.HBoxContainer)Instance.Duplicate()); + } + + /// /// 类型: , 路径: EditorTools.ScrollContainer.MarginContainer.VBoxContainer /// public class UiNode_VBoxContainer : IUiNode @@ -582,6 +635,19 @@ } private UiNode_HBoxContainer2 _L_HBoxContainer2; + /// + /// 使用 Instance 属性获取当前节点实例对象, 节点类型: , 节点路径: EditorTools.ScrollContainer.MarginContainer.HBoxContainer7 + /// + public UiNode_HBoxContainer7 L_HBoxContainer7 + { + get + { + if (_L_HBoxContainer7 == null) _L_HBoxContainer7 = new UiNode_HBoxContainer7(Instance.GetNodeOrNull("HBoxContainer7")); + return _L_HBoxContainer7; + } + } + private UiNode_HBoxContainer7 _L_HBoxContainer7; + public UiNode_VBoxContainer(Godot.VBoxContainer node) : base(node) { } public override UiNode_VBoxContainer Clone() => new ((Godot.VBoxContainer)Instance.Duplicate()); } diff --git a/DungeonShooting_Godot/src/game/ui/editorTools/EditorToolsPanel.cs b/DungeonShooting_Godot/src/game/ui/editorTools/EditorToolsPanel.cs index 5cf3487..98d01b9 100644 --- a/DungeonShooting_Godot/src/game/ui/editorTools/EditorToolsPanel.cs +++ b/DungeonShooting_Godot/src/game/ui/editorTools/EditorToolsPanel.cs @@ -54,6 +54,8 @@ container.L_HBoxContainer5.L_Button.Instance.Pressed += GenerateUiManagerMethods; //创建地牢房间 container.L_HBoxContainer6.L_Button.Instance.Pressed += GenerateDungeonRoom; + //导出excel表 + container.L_HBoxContainer7.L_Button.Instance.Pressed += ExportExcel; } public override void OnHideUi() @@ -73,6 +75,7 @@ container.L_HBoxContainer3.L_Button.Instance.Pressed -= OnCreateUI; container.L_HBoxContainer5.L_Button.Instance.Pressed -= GenerateUiManagerMethods; container.L_HBoxContainer6.L_Button.Instance.Pressed -= GenerateDungeonRoom; + container.L_HBoxContainer7.L_Button.Instance.Pressed -= ExportExcel; } public override void Process(float delta) @@ -381,4 +384,21 @@ } }); } + + /// + /// 导出excel表 + /// + private void ExportExcel() + { + if (ExcelGenerator.ExportExcel()) + { + ShowTips("提示", "导出Excel表执行完成!"); + } + else + { + ShowTips("错误", "导出Excel表执行失败! 前往控制台查看错误日志!"); + } + + ; + } } diff --git a/DungeonShooting_Godot/src/test/TestReadExcel.cs b/DungeonShooting_Godot/src/test/TestReadExcel.cs index fdf4724..706c0e1 100644 --- a/DungeonShooting_Godot/src/test/TestReadExcel.cs +++ b/DungeonShooting_Godot/src/test/TestReadExcel.cs @@ -8,7 +8,7 @@ { public override void _Ready() { - string sourceFile = @"config/Weapon.xlsx"; + string sourceFile = @"excel/Weapon.xlsx"; IWorkbook workbook = new XSSFWorkbook(sourceFile); ISheet sheet1 = workbook.GetSheet("Sheet1");