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");