diff --git "a/DungeonShooting_Document/\346\226\207\346\241\243\350\265\204\346\272\220/2023-03-26_030144.png" "b/DungeonShooting_Document/\346\226\207\346\241\243\350\265\204\346\272\220/2023-03-26_030144.png" deleted file mode 100644 index 2db4357..0000000 --- "a/DungeonShooting_Document/\346\226\207\346\241\243\350\265\204\346\272\220/2023-03-26_030144.png" +++ /dev/null Binary files differ diff --git "a/DungeonShooting_Document/\346\226\207\346\241\243\350\265\204\346\272\220/gif_1.gif" "b/DungeonShooting_Document/\346\226\207\346\241\243\350\265\204\346\272\220/gif_1.gif" deleted file mode 100644 index cad3ad3..0000000 --- "a/DungeonShooting_Document/\346\226\207\346\241\243\350\265\204\346\272\220/gif_1.gif" +++ /dev/null Binary files differ diff --git "a/DungeonShooting_Document/\346\226\207\346\241\243\350\265\204\346\272\220/gif_2.gif" "b/DungeonShooting_Document/\346\226\207\346\241\243\350\265\204\346\272\220/gif_2.gif" deleted file mode 100644 index fd8194e..0000000 --- "a/DungeonShooting_Document/\346\226\207\346\241\243\350\265\204\346\272\220/gif_2.gif" +++ /dev/null Binary files differ diff --git "a/DungeonShooting_Document/\346\226\207\346\241\243\350\265\204\346\272\220/gif_3.gif" "b/DungeonShooting_Document/\346\226\207\346\241\243\350\265\204\346\272\220/gif_3.gif" deleted file mode 100644 index 245744f..0000000 --- "a/DungeonShooting_Document/\346\226\207\346\241\243\350\265\204\346\272\220/gif_3.gif" +++ /dev/null Binary files differ diff --git "a/DungeonShooting_Document/\346\226\207\346\241\243\350\265\204\346\272\220/gif_4.gif" "b/DungeonShooting_Document/\346\226\207\346\241\243\350\265\204\346\272\220/gif_4.gif" deleted file mode 100644 index a087451..0000000 --- "a/DungeonShooting_Document/\346\226\207\346\241\243\350\265\204\346\272\220/gif_4.gif" +++ /dev/null Binary files differ diff --git "a/DungeonShooting_Document/\346\226\207\346\241\243\350\265\204\346\272\220/image_10.png" "b/DungeonShooting_Document/\346\226\207\346\241\243\350\265\204\346\272\220/image_10.png" deleted file mode 100644 index 37aee41..0000000 --- "a/DungeonShooting_Document/\346\226\207\346\241\243\350\265\204\346\272\220/image_10.png" +++ /dev/null Binary files differ diff --git "a/DungeonShooting_Document/\346\226\207\346\241\243\350\265\204\346\272\220/image_11.png" "b/DungeonShooting_Document/\346\226\207\346\241\243\350\265\204\346\272\220/image_11.png" deleted file mode 100644 index 046e766..0000000 --- "a/DungeonShooting_Document/\346\226\207\346\241\243\350\265\204\346\272\220/image_11.png" +++ /dev/null Binary files differ diff --git "a/DungeonShooting_Document/\346\226\207\346\241\243\350\265\204\346\272\220/image_12.png" "b/DungeonShooting_Document/\346\226\207\346\241\243\350\265\204\346\272\220/image_12.png" deleted file mode 100644 index 0bbfdaf..0000000 --- "a/DungeonShooting_Document/\346\226\207\346\241\243\350\265\204\346\272\220/image_12.png" +++ /dev/null Binary files differ diff --git "a/DungeonShooting_Document/\346\226\207\346\241\243\350\265\204\346\272\220/image_13.png" "b/DungeonShooting_Document/\346\226\207\346\241\243\350\265\204\346\272\220/image_13.png" deleted file mode 100644 index a7d7727..0000000 --- "a/DungeonShooting_Document/\346\226\207\346\241\243\350\265\204\346\272\220/image_13.png" +++ /dev/null Binary files differ diff --git "a/DungeonShooting_Document/\346\226\207\346\241\243\350\265\204\346\272\220/image_14.png" "b/DungeonShooting_Document/\346\226\207\346\241\243\350\265\204\346\272\220/image_14.png" deleted file mode 100644 index a5181fc..0000000 --- "a/DungeonShooting_Document/\346\226\207\346\241\243\350\265\204\346\272\220/image_14.png" +++ /dev/null Binary files differ diff --git "a/DungeonShooting_Document/\346\226\207\346\241\243\350\265\204\346\272\220/image_15.png" "b/DungeonShooting_Document/\346\226\207\346\241\243\350\265\204\346\272\220/image_15.png" deleted file mode 100644 index 94ad6d2..0000000 --- "a/DungeonShooting_Document/\346\226\207\346\241\243\350\265\204\346\272\220/image_15.png" +++ /dev/null Binary files differ diff --git "a/DungeonShooting_Document/\346\226\207\346\241\243\350\265\204\346\272\220/image_16.png" "b/DungeonShooting_Document/\346\226\207\346\241\243\350\265\204\346\272\220/image_16.png" deleted file mode 100644 index d87de83..0000000 --- "a/DungeonShooting_Document/\346\226\207\346\241\243\350\265\204\346\272\220/image_16.png" +++ /dev/null Binary files differ diff --git "a/DungeonShooting_Document/\346\226\207\346\241\243\350\265\204\346\272\220/image_17.png" "b/DungeonShooting_Document/\346\226\207\346\241\243\350\265\204\346\272\220/image_17.png" deleted file mode 100644 index 2ec7c41..0000000 --- "a/DungeonShooting_Document/\346\226\207\346\241\243\350\265\204\346\272\220/image_17.png" +++ /dev/null Binary files differ diff --git "a/DungeonShooting_Document/\346\226\207\346\241\243\350\265\204\346\272\220/image_18.png" "b/DungeonShooting_Document/\346\226\207\346\241\243\350\265\204\346\272\220/image_18.png" deleted file mode 100644 index a8e6e2e..0000000 --- "a/DungeonShooting_Document/\346\226\207\346\241\243\350\265\204\346\272\220/image_18.png" +++ /dev/null Binary files differ diff --git "a/DungeonShooting_Document/\346\226\207\346\241\243\350\265\204\346\272\220/image_19.png" "b/DungeonShooting_Document/\346\226\207\346\241\243\350\265\204\346\272\220/image_19.png" deleted file mode 100644 index 9ad2347..0000000 --- "a/DungeonShooting_Document/\346\226\207\346\241\243\350\265\204\346\272\220/image_19.png" +++ /dev/null Binary files differ diff --git "a/DungeonShooting_Document/\346\226\207\346\241\243\350\265\204\346\272\220/image_4.png" "b/DungeonShooting_Document/\346\226\207\346\241\243\350\265\204\346\272\220/image_4.png" deleted file mode 100644 index c1c2d7a..0000000 --- "a/DungeonShooting_Document/\346\226\207\346\241\243\350\265\204\346\272\220/image_4.png" +++ /dev/null Binary files differ diff --git "a/DungeonShooting_Document/\346\226\207\346\241\243\350\265\204\346\272\220/image_5.png" "b/DungeonShooting_Document/\346\226\207\346\241\243\350\265\204\346\272\220/image_5.png" deleted file mode 100644 index 246ce43..0000000 --- "a/DungeonShooting_Document/\346\226\207\346\241\243\350\265\204\346\272\220/image_5.png" +++ /dev/null Binary files differ diff --git "a/DungeonShooting_Document/\346\226\207\346\241\243\350\265\204\346\272\220/image_6.png" "b/DungeonShooting_Document/\346\226\207\346\241\243\350\265\204\346\272\220/image_6.png" deleted file mode 100644 index 78a85d7..0000000 --- "a/DungeonShooting_Document/\346\226\207\346\241\243\350\265\204\346\272\220/image_6.png" +++ /dev/null Binary files differ diff --git "a/DungeonShooting_Document/\346\226\207\346\241\243\350\265\204\346\272\220/image_7.png" "b/DungeonShooting_Document/\346\226\207\346\241\243\350\265\204\346\272\220/image_7.png" deleted file mode 100644 index 516e32a..0000000 --- "a/DungeonShooting_Document/\346\226\207\346\241\243\350\265\204\346\272\220/image_7.png" +++ /dev/null Binary files differ diff --git "a/DungeonShooting_Document/\346\226\207\346\241\243\350\265\204\346\272\220/image_8.png" "b/DungeonShooting_Document/\346\226\207\346\241\243\350\265\204\346\272\220/image_8.png" deleted file mode 100644 index 6d9c19a..0000000 --- "a/DungeonShooting_Document/\346\226\207\346\241\243\350\265\204\346\272\220/image_8.png" +++ /dev/null Binary files differ diff --git "a/DungeonShooting_Document/\346\226\207\346\241\243\350\265\204\346\272\220/image_9.png" "b/DungeonShooting_Document/\346\226\207\346\241\243\350\265\204\346\272\220/image_9.png" deleted file mode 100644 index fcd1381..0000000 --- "a/DungeonShooting_Document/\346\226\207\346\241\243\350\265\204\346\272\220/image_9.png" +++ /dev/null Binary files differ diff --git "a/DungeonShooting_Document/\351\241\271\347\233\256\345\270\256\345\212\251\346\226\207\346\241\243.md" "b/DungeonShooting_Document/\351\241\271\347\233\256\345\270\256\345\212\251\346\226\207\346\241\243.md" deleted file mode 100644 index 39bdd3a..0000000 --- "a/DungeonShooting_Document/\351\241\271\347\233\256\345\270\256\345\212\251\346\226\207\346\241\243.md" +++ /dev/null @@ -1,347 +0,0 @@ - -前言: 该文档仅针对`DungeonShooting_Godot`目录下的Godot工程 - -**注意:** 新版文档编写中... - -目录: - ---- -## 1.启动项目 -**Godot版本:** Godot4x -**.net版本:** .net6.0 -使用Godot打开`project.godot`, 如果是第一次打开项目会弹出一个找不到资源的提示, 这是因为项目没有编译过, 点击Godot右上角`build`, 然后打`开项目设置`, 在`插件`这一个页签下启用`DungeonShooting_plugin`这个插件, 然后项目就可以正常运行了 - ---- -## 2.项目资源 - -### 2.1.目录结构 -所有资源严格划分类别, 并放入指定的文件夹 -**项目目录结构如下:** -* ./addons: 项目插件目录 -* ./prefab: 预制体资源目录 -* ./resource 美术,音乐,配置文件等资源放置路径 -* ./scene 场景资源 -* ./src 代码资源 - -### 2.2.脚本获取资源 -为了方便代码获取资源以及排除代码中引用丢失资源的情况, 项目中使用`ResourcePath`类来放置所有资源路径, 该类常量值即代表资源路径, 使用`ResourceManager.Load()`来加载资源 -举个例子, 某资源在编辑器中的路径为: -```text -res://resource/theme/mainTheme.tres -``` -那么在`ResourcePath`中的代码就为: -```csharp -public const string resource_theme_mainTheme_tres = "res://resource/theme/mainTheme.tres"; -``` -加载该资源的代码为: -```csharp -var resource = ResourceManager.Load(ResourcePath.resource_theme_mainTheme_tres); -``` - -### 2.3.重新生成ResourcePath -如果项目中有资源变动, 则可以使用`Tools`页签下的`重新生成ResourcePath.cs文件` -![](文档资源/image_6.png) - ---- -## 3.游戏框架 -### 3.1.简述 -游戏框架分为三部分: -1. 游戏核心系统 -2. UI模块系统 -3. 代码生成系统 - -**游戏核心系统**: 以游戏玩法为中心的逻辑代码, 包括玩家, 敌人, 武器, 被动, 道具, 地牢生成, 房间规则, 存档逻辑等 -**UI模块系统**: 用户操作界面的逻辑代码 -**代码生成系统**: 自动生成便于开发的资源的逻辑代码 -**编辑器系统**: 用于用于自定义游戏内容 - -### 3.2.游戏核心系统 - -在`Main/ViewCanvas/SubViewportContainer/SubViewport`的子节点将开启4倍缩放, 并且启用完美像素 -该节点放置除UI以外的任何节点 - -#### 3.2.1.什么是ActivityObject -定义: 游戏内所有可活动物体的基类叫做`ActivityObject` -源代码: [ActivityObject.cs](../DungeonShooting_Godot/src/framework/activity/ActivityObject.cs) - -`ActivityObject`的意由来: 为了方便统一管理物体, 并且减少子类代码沉积, 因此将所有活动物体都需要用到的逻辑抽到一个统一的类中, 并命名为`ActivityObject`, 所有的活动物体都需要继承该类 - -`ActivityObject`提供的基础功能: -* `Component`组件管理 -* 协程功能 -* 外力控制运动 -* 纵轴运动模拟 (自由落体, 投抛物体等) -* 数据标记 -* 对象归属区域 -* 互动逻辑接口 - -通过下面这张图可以了解游戏中的物体与`ActivityObject`的关系 (注意: 该图为早期开发版本的继承关系图, 后面开发可能会有修改) -![](文档资源/2023-03-26_030144.png) - - -#### 3.2.2.ActivityObject常用功能 - -##### 自定义组件 -这个功能类似于`Unity`的`MonoBehaviour`, 组件必须继承`Component`类, 组件的作用是拆分功能代码, 开发者可以将相同功能的代码放入同一个组件中, 与`Godot`的`Node`不同的是, 挂载到`ActivityObject`上的组件并不会生成一个`Node`节点, 它相比于`Node`更加轻量 - -自定义组件代码: -```csharp -public class MyComponent : Component -{ - -} -``` -调用`ActivityObject.AddComponent()`添加组件: -```csharp -var component = activityInstance.AddComponent(); -``` -注意: 一个`ActivityObject`上不允许挂载多个相同的组件 - -##### 运动控制 -`ActivityObject`的移动由自身的`MoveController`组件控制, 非特殊情况下不要直接修改`ActivityObject`的位置, 而是使用`MoveController.AddConstantForce()`函数来添加外力 -```csharp -//添加一个向右的外力, 速度为100 -var force = activityInstance.MoveController.AddConstantForce("ForceName"); //外力必须起名称, 而且在运动控制器中必须唯一 -force.Velocity = new Vector2(0, 100); -//以下为精简写法 -var force = activityInstance.MoveController.AddConstantForce(new Vector2(0, 100), 0); //创建匿名外力, 但是与上面不同的是当速率变为 0 时自动销毁 -``` -物体的运动方向就是所有外力总和的方向, 通过`MoveController.Velocity`可以获取当前运动速度 - -##### 垂直方向运动 -当游戏中需要制作飞行物体或者模拟投抛运动时, 就需要控制物体纵轴所处高度, `ActivityObject`中提供了一系列控制纵轴方向运动的属性和函数, 以下列举几个关键属性和函数: -```csharp -/// -/// 当前物体的海拔高度, 如果大于0, 则会做自由落体运动, 也就是执行投抛代码 -/// -public float Altitude { get; set; } = 0; - -/// -/// 物体纵轴移动速度, 如果设置大于0, 就可以营造向上投抛物体的效果, 该值会随着重力加速度衰减 -/// -public float VerticalSpeed { get; set; } = 0; - -/// -/// 物体下坠回弹的强度 -/// -public float BounceStrength { get; set; } = 0.5f; - -/// -/// 物体下坠回弹后的运动速度衰减量 -/// -public float BounceSpeed { get; set; } = 0.75f; - -/// -/// 是否启用垂直方向上的运动模拟, 默认开启, 如果禁用, 那么下落和投抛效果, 同样 Throw() 函数也将失效 -/// -public bool EnableVerticalMotion { get; set; } = true; -``` -垂直运动也提供了一些可供重写的虚函数: -```csharp -/// -/// 开始投抛该物体时调用 -/// -protected virtual void OnThrowStart() -{ -} - -/// -/// 投抛该物体达到最高点时调用 -/// -protected virtual void OnThrowMaxHeight(float height) -{ -} - -/// -/// 投抛状态下第一次接触地面时调用, 之后的回弹落地将不会调用该函数 -/// -protected virtual void OnFirstFallToGround() -{ -} - -/// -/// 投抛状态下每次接触地面时调用 -/// -protected virtual void OnFallToGround() -{ -} - -/// -/// 投抛结束时调用 -/// -protected virtual void OnThrowOver() -{ -} -``` -如果需要模拟飞行效果则需要设置`Altitude`值大于0, 并且将`EnableVerticalMotion`设置为`false` -如果需要自由落体, 则直接设置`Altitude`值大于0 -如果需要上抛运动, 则直接设置`VerticalSpeed`值大于0 -如果值`BounceStrength`和`BounceSpeed`设置成1, 则投抛的物体在地上会一直朝一个方向弹跳 -如果需要投抛物体不需要每个关键值都设置一遍信息, 只需要调用`ActivityObject.Throw()`函数即可: -```csharp -/// -/// 将该节点投抛出去 -/// -/// 初始高度 -/// 旋转速度 -/// 移动速率 -/// 纵轴速度 -public void Throw(float altitude, float verticalSpeed, Vector2 velocity, float rotate); -``` -调用示例, 模拟弹壳投抛落在地上弹跳的过程 -```csharp -var startPos = GlobalPosition; -var startHeight = 6; -var direction = GlobalRotationDegrees + Utils.RandomRangeInt(-30, 30) + 180; -var verticalSpeed = Utils.RandomRangeInt(60, 120); -var velocity = new Vector2(Utils.RandomRangeInt(20, 60), 0).Rotated(direction * Mathf.Pi / 180); -var rotate = Utils.RandomRangeInt(-720, 720); -var shell = ActivityObject.Create(ActivityIdPrefix.Shell + "0001"); -shell.Throw(startPos, startHeight, verticalSpeed, velocity, rotate); -``` - -##### 协程 -该功能与`Unity`的协程功能类似, 在协程函数中通过`yield`关键字暂停执行后面的代码, 并将控制权返还给`ActivityObject`, 协程常被用在动画处理和资源异步加载 -`ActivityObject`中协程相关函数: -```csharp -/// -/// 开启一个协程, 返回协程 id, 协程是在普通帧执行的, 支持: 协程嵌套, WaitForSeconds, WaitForFixedProcess -/// -public long StartCoroutine(IEnumerator able); - -/// -/// 根据协程 id 停止协程 -/// -public void StopCoroutine(long coroutineId); - -/// -/// 停止所有协程 -/// -public void StopAllCoroutine(); -``` -协程`yield return`返回特殊值类型如下: -* **WaitForSeconds**: 当前协程等待秒数 -* **WaitForFixedProcess**: 当前协程等待帧数 -* **IEnumerator**: 嵌套执行子协程, 等子协程执行完毕后才会继续执行后面的代码 - -协程`yield return`如果返回除以上数据类型以外的数据, 将忽略返回值 - -调用实例, 以下代码在`ActivityInstance`初始化时执行协程`StartRotation`, 协程在60帧内让物体每帧角度加1 -```csharp -public override void OnInit() -{ - StartCoroutine(StartRotation()); -} - -private IEnumerator StartRotation() -{ - for (int i = 0; i < 60; i++) - { - RotationDegrees += 1; - //结束这一帧, 返回0会被忽略返回值 - yield return 0; - } -} -``` - -### 3.3.地牢 -#### 3.3.1.地牢概述 -游戏中的地牢由若干层组成, 每一层地牢又由数个小房间随机拼接而成, 由起始房间开始, 成树状连接; 每一层地牢有一个起始房间, 和至少一个通向另一层的结束房间, 房间与房间之间由过道连接, 过道不会交叉和重叠 - -房间有以下类别 (目前代码还未完成区分类型的功能): -* **起始房间**: 由上一层地牢的结束房间进入该房间, 每层包含一个起始房间 -* **结束房间**: 进入另一层地牢, 每层只是包含一个结束房间 -* **普通战斗房间**: 进入该房间时会关上门, 并刷出若干波敌人, 消灭所有敌人后开门 -* **boss战房间**: 进入房间时会关上没, 刷出boss, 消灭boss后开门 -* **奖励房间**: 给予玩家武器或者道具奖励的房间 -* **商店**: 玩家买卖道具装备的房间 -* **事件房间**: 触发剧情或者解锁NPC的房间 - - - -### 3.4.UI系统 -#### 3.4.1.UI系统概述 -游戏内的物体, 例如`ActivityObject`等都是在`Main/ViewCanvas/SubViewportContainer/SubViewport`节点下, 并且启用了完美像素, 但是UI恰恰相反,它们直接位于`Main`节点下, 既没有4倍缩放也没有完美像素 -游戏中的UI分为4个层级, 分别为 -* Bottom: 最底层, 层级为5 -* Middle: 中间层, 层级为15 -* Height: 较高层, 层级为25 -* Pop: 最顶层, 层级为35 - -UI场景根节点必须继承`UiBase`类, 并且生命周期由`UiManager`控制 -UI代码放置位置: `src/game/ui/**/**.cs` -UI场景资源放置位置: `prefab/ui/**.tscn` -源代码: [UiBase.cs](../DungeonShooting_Godot/src/framework/ui/UiBase.cs), [UiManager.cs](../DungeonShooting_Godot/src/framework/ui/UiManager.cs) -打开指定UI: -```csharp -var ui = UiManager.OpenUi("UI名称"); -``` -关闭Ui -```csharp -UiManager.DisposeUi(ui); -``` - -#### 3.4.2.UI代码生器 -为了减低开发者制作UI的复杂程度, 避免手写获取UI节点的代码, 我们设计了一套自动生成UI层级代码的功能, 该功能在编辑器中会监听开发者对于UI场景的修改, 并及时生成相应的UI代码, 并且开发者的UI逻辑类继承生成的UI类, 即可方便的获取UI节点, 可以节省大量时间, 因为代码是实时生成的, 因此一旦有节点改名或者移动位置, 重新生成UI代码后, 引用该节点的代码就会出现编译错误, 方便开发者修改 - -##### 创建UI -在`Tools`页签下找到`创建游戏UI`, 输入UI名称即可点击创建UI -![](文档资源/image_14.png) -创建完毕后编辑器会离开打开该UI场景 -观察文件系统可以注意到, 编辑器为我创建并保存了场景和代码, 并且还生成了一个`MyUiPanel.cs`的文件, 该文件就是我们写UI逻辑代码的地方, 并且命名方式为`UI名称`+`Panel`, 这个Panel类继承了自动生成出来的UI类 -![](文档资源/image_15.png) -![](文档资源/image_16.png) - -动态生成的UI代码的节点对象由`IUiNode`包裹, 为了子节点与内助属性区分方便, 生成出来的代码会为每一层的名称加上前缀`L_`, 同理如果需要获取子节点则直接寻找以`L_`开始的属性 -例如节点在编辑器的路径为`Group/Button`, 那么在代码里就是`L_Group.L_Button` -源代码: [IUiNode.cs](../DungeonShooting_Godot/src/framework/ui/IUiNode.cs) - -通过以下这个gif就可以直观感受到该功能的便捷之处 -![](文档资源/gif_4.gif) - -##### 打开UI -创建完成UI后, 编辑器也会在`UiManager`中生成打开该UI和获取UI实例的Api -![](文档资源/image_17.png) -那么可以直接调用`UiManager`中的函数打开该UI -```csharp -UiManager.Open_MyUi(); -``` - -#### 3.4.3.常用功能 - -##### 生命周期 -`UiBase`包含4个生命周期函数: -```csharp -/// -/// 创建当前ui时调用 -/// -public virtual void OnCreateUi() -{ -} - -/// -/// 当前ui显示时调用 -/// -public virtual void OnShowUi() -{ -} - -/// -/// 当前ui隐藏时调用 -/// -public virtual void OnHideUi() -{ -} - -/// -/// 销毁当前ui时调用 -/// -public virtual void OnDestroy() -{ -} -``` - -#### 包裹UI节点的IUiNode -获取`Node`实例: 使用例如`L_Group.L_Button`的代码获取的节点并不是`Godot`节点对象, 而是包裹对象, 需要从`Instance`属性中获取原生`Node`对象 -克隆节点: 使用`IUiNode.Clone()`可以完整的克隆当前节点以及子节点 -嵌套UI: 使用`IUiNode.OpenNestedUi()`即可以当前节点为根节点打开子级UI diff --git a/DungeonShooting_ExcelTool/DungeonShooting_ExcelTool.csproj b/DungeonShooting_ExcelTool/DungeonShooting_ExcelTool.csproj deleted file mode 100644 index d171c69..0000000 --- a/DungeonShooting_ExcelTool/DungeonShooting_ExcelTool.csproj +++ /dev/null @@ -1,23 +0,0 @@ - - - - Exe - net7.0 - enable - enable - - - - - - - - - PreserveNewest - - - PreserveNewest - - - - diff --git a/DungeonShooting_ExcelTool/DungeonShooting_ExcelTool.sln b/DungeonShooting_ExcelTool/DungeonShooting_ExcelTool.sln deleted file mode 100644 index e3d1576..0000000 --- a/DungeonShooting_ExcelTool/DungeonShooting_ExcelTool.sln +++ /dev/null @@ -1,16 +0,0 @@ - -Microsoft Visual Studio Solution File, Format Version 12.00 -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DungeonShooting_ExcelTool", "DungeonShooting_ExcelTool.csproj", "{F6A26370-A918-40F0-8D78-414213011172}" -EndProject -Global - GlobalSection(SolutionConfigurationPlatforms) = preSolution - Debug|Any CPU = Debug|Any CPU - Release|Any CPU = Release|Any CPU - EndGlobalSection - GlobalSection(ProjectConfigurationPlatforms) = postSolution - {F6A26370-A918-40F0-8D78-414213011172}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {F6A26370-A918-40F0-8D78-414213011172}.Debug|Any CPU.Build.0 = Debug|Any CPU - {F6A26370-A918-40F0-8D78-414213011172}.Release|Any CPU.ActiveCfg = Release|Any CPU - {F6A26370-A918-40F0-8D78-414213011172}.Release|Any CPU.Build.0 = Release|Any CPU - EndGlobalSection -EndGlobal diff --git a/DungeonShooting_ExcelTool/DungeonShooting_ExcelTool.sln.DotSettings.user b/DungeonShooting_ExcelTool/DungeonShooting_ExcelTool.sln.DotSettings.user deleted file mode 100644 index 5ef2d60..0000000 --- a/DungeonShooting_ExcelTool/DungeonShooting_ExcelTool.sln.DotSettings.user +++ /dev/null @@ -1,2 +0,0 @@ - - WARNING \ No newline at end of file diff --git a/DungeonShooting_ExcelTool/ExcelGenerator.cs b/DungeonShooting_ExcelTool/ExcelGenerator.cs deleted file mode 100644 index d76af05..0000000 --- a/DungeonShooting_ExcelTool/ExcelGenerator.cs +++ /dev/null @@ -1,748 +0,0 @@ -using System.Text.Json; -using System.Text.RegularExpressions; -using NPOI.SS.UserModel; -using NPOI.XSSF.UserModel; - -public static class ExcelGenerator -{ - private const string CodeOutPath = "src/config/"; - private const string JsonOutPath = "resource/config/"; - private const string ExcelFilePath = "excelFile"; - - private static HashSet _excelNames = new HashSet(); - - - private enum CollectionsType - { - None, - Array, - Map - } - - private class MappingData - { - - public string TypeStr; - public string TypeName; - public CollectionsType CollectionsType; - - public bool IsRefExcel; - public string RefTypeStr; - public string RefTypeName; - - public MappingData(string typeStr, string typeName, CollectionsType collectionsType) - { - TypeStr = typeStr; - TypeName = typeName; - CollectionsType = collectionsType; - IsRefExcel = false; - } - - public MappingData(string typeStr, string typeName, CollectionsType collectionsType, string refTypeStr, string refTypeName) - { - TypeStr = typeStr; - TypeName = typeName; - CollectionsType = collectionsType; - IsRefExcel = true; - RefTypeStr = refTypeStr; - RefTypeName = refTypeName; - } - } - - private class ExcelData - { - public string TableName; - public string OutCode; - public List ColumnNames = new List(); - public Dictionary ColumnMappingData = new Dictionary(); - public Dictionary ColumnType = new Dictionary(); - public List> DataList = new List>(); - } - - public static bool ExportExcel() - { - return ExportExcel(ExcelFilePath, JsonOutPath, CodeOutPath); - } - - public static bool ExportExcel(string excelFilePath, string jsonOutPath, string codeOutPath) - { - Console.WriteLine("当前路径: " + Environment.CurrentDirectory); - Console.WriteLine("excel路径: " + excelFilePath); - Console.WriteLine("json输出路径: " + jsonOutPath); - Console.WriteLine("cs代码输出路径: " + codeOutPath); - try - { - var excelDataList = new List(); - - var directoryInfo = new DirectoryInfo(excelFilePath); - if (directoryInfo.Exists) - { - var fileInfos = directoryInfo.GetFiles(); - //记录文件 - foreach (var fileInfo in fileInfos) - { - var fileName = Path.GetFileNameWithoutExtension(fileInfo.Name).FirstToUpper(); - _excelNames.Add(fileName); - } - //读取配置文件 - foreach (var fileInfo in fileInfos) - { - if (fileInfo.Extension == ".xlsx") - { - if (fileInfo.Name == "ExcelConfig.xlsx") - { - throw new Exception("excel表文件名称不允许叫'ExcelConfig.xlsx'!"); - } - Console.WriteLine("excel表: " + fileInfo.FullName); - excelDataList.Add(ReadExcel(fileInfo.FullName)); - } - } - } - - Console.WriteLine($"一共检测到excel表共{excelDataList.Count}张."); - if (excelDataList.Count == 0) - { - return true; - } - - if (Directory.Exists(codeOutPath)) - { - Directory.Delete(codeOutPath, true); - } - if (Directory.Exists(jsonOutPath)) - { - Directory.Delete(jsonOutPath, true); - } - Directory.CreateDirectory(codeOutPath); - Directory.CreateDirectory(jsonOutPath); - - //保存配置和代码 - foreach (var excelData in excelDataList) - { - File.WriteAllText(codeOutPath + "ExcelConfig_" + excelData.TableName + ".cs", excelData.OutCode); - var config = new JsonSerializerOptions(); - config.WriteIndented = true; - File.WriteAllText(jsonOutPath + excelData.TableName + ".json", JsonSerializer.Serialize(excelData.DataList, config)); - } - - //生成加载代码 - var code = GeneratorInitCode(excelDataList); - File.WriteAllText(codeOutPath + "ExcelConfig.cs", code); - } - catch (Exception e) - { - PrintError(e.ToString()); - return false; - } - - return true; - } - - private static string GeneratorInitCode(List excelList) - { - var code = $"using System;\n"; - code += $"using System.Collections.Generic;\n"; - code += $"using System.Text.Json;\n"; - code += $"using Godot;\n"; - code += $"\n"; - code += $"namespace Config;\n"; - code += $"\n"; - code += $"public static partial class ExcelConfig\n"; - code += $"{{\n"; - - var fieldCode = ""; - var callFuncCode = ""; - var callInitRefFuncCode = ""; - var funcCode = ""; - var initRefFuncCode = ""; - - foreach (var excelData in excelList) - { - var idName = excelData.ColumnNames[0]; - var idTypeStr = excelData.ColumnMappingData[idName].TypeStr; - - //---------------------------- 引用其他表处理 ---------------------------- - var hasRefColumn = false; - var refColumnNoneCode = ""; - foreach (var columnName in excelData.ColumnNames) - { - var mappingData = excelData.ColumnMappingData[columnName]; - if (mappingData.IsRefExcel) - { - hasRefColumn = true; - if (mappingData.CollectionsType == CollectionsType.None) - { - refColumnNoneCode += $" if (!string.IsNullOrEmpty(item.__{columnName}))\n"; - refColumnNoneCode += $" {{\n"; - refColumnNoneCode += $" item.{columnName} = {mappingData.RefTypeName}_Map[item.__{columnName}];\n"; - refColumnNoneCode += $" }}\n"; - } - else if (mappingData.CollectionsType == CollectionsType.Array) - { - refColumnNoneCode += $" if (item.__{columnName} != null)\n"; - refColumnNoneCode += $" {{\n"; - refColumnNoneCode += $" item.{columnName} = new {mappingData.RefTypeName}[item.__{columnName}.Length];\n"; - refColumnNoneCode += $" for (var i = 0; i < item.__{columnName}.Length; i++)\n"; - refColumnNoneCode += $" {{\n"; - refColumnNoneCode += $" item.{columnName}[i] = {mappingData.RefTypeName}_Map[item.__{columnName}[i]];\n"; - refColumnNoneCode += $" }}\n"; - refColumnNoneCode += $" }}\n"; - } - else - { - refColumnNoneCode += $" if (item.__{columnName} != null)\n"; - refColumnNoneCode += $" {{\n"; - refColumnNoneCode += $" item.{columnName} = new {mappingData.RefTypeStr}();\n"; - refColumnNoneCode += $" foreach (var pair in item.__{columnName})\n"; - refColumnNoneCode += $" {{\n"; - refColumnNoneCode += $" item.{columnName}.Add(pair.Key, {mappingData.RefTypeName}_Map[pair.Value]);\n"; - refColumnNoneCode += $" }}\n"; - refColumnNoneCode += $" }}\n"; - } - refColumnNoneCode += $"\n"; - } - } - - //----------------------------- 数据集合 ------------------------------------ - fieldCode += $" /// \n"; - fieldCode += $" /// {excelData.TableName}.xlsx表数据集合, 以 List 形式存储, 数据顺序与 Excel 表相同\n"; - fieldCode += $" /// \n"; - fieldCode += $" public static List<{excelData.TableName}> {excelData.TableName}_List {{ get; private set; }}\n"; - fieldCode += $" /// \n"; - fieldCode += $" /// {excelData.TableName}.xlsx表数据集合, 里 Map 形式存储, key 为 {idName}\n"; - fieldCode += $" /// \n"; - fieldCode += $" public static Dictionary<{idTypeStr}, {excelData.TableName}> {excelData.TableName}_Map {{ get; private set; }}\n"; - fieldCode += $"\n"; - - //------------------------------- 初始化函数 ------------------------------------- - callFuncCode += $" _Init{excelData.TableName}Config();\n"; - - funcCode += $" private static void _Init{excelData.TableName}Config()\n"; - funcCode += $" {{\n"; - funcCode += $" try\n"; - funcCode += $" {{\n"; - funcCode += $" var text = _ReadConfigAsText(\"res://resource/config/{excelData.TableName}.json\");\n"; - if (hasRefColumn) //存在引用列 - { - funcCode += $" {excelData.TableName}_List = new List<{excelData.TableName}>(JsonSerializer.Deserialize>(text));\n"; - } - else - { - funcCode += $" {excelData.TableName}_List = JsonSerializer.Deserialize>(text);\n"; - } - funcCode += $" {excelData.TableName}_Map = new Dictionary<{idTypeStr}, {excelData.TableName}>();\n"; - funcCode += $" foreach (var item in {excelData.TableName}_List)\n"; - funcCode += $" {{\n"; - funcCode += $" {excelData.TableName}_Map.Add(item.{idName}, item);\n"; - funcCode += $" }}\n"; - funcCode += $" }}\n"; - funcCode += $" catch (Exception e)\n"; - funcCode += $" {{\n"; - funcCode += $" GD.PrintErr(e.ToString());\n"; - funcCode += $" throw new Exception(\"初始化表'{excelData.TableName}'失败!\");\n"; - funcCode += $" }}\n"; - funcCode += $" }}\n"; - - - //------------------------------- 初始化引用 --------------------------------- - if (hasRefColumn) - { - callInitRefFuncCode += $" _Init{excelData.TableName}Ref();\n"; - - initRefFuncCode += $" private static void _Init{excelData.TableName}Ref()\n"; - initRefFuncCode += $" {{\n"; - initRefFuncCode += $" foreach (Ref_{excelData.TableName} item in {excelData.TableName}_List)\n"; - initRefFuncCode += $" {{\n"; - initRefFuncCode += $" try\n"; - initRefFuncCode += $" {{\n"; - initRefFuncCode += refColumnNoneCode; - initRefFuncCode += $" }}\n"; - initRefFuncCode += $" catch (Exception e)\n"; - initRefFuncCode += $" {{\n"; - initRefFuncCode += $" GD.PrintErr(e.ToString());\n"; - initRefFuncCode += $" throw new Exception(\"初始化'{excelData.TableName}'引用其他表数据失败, 当前行id: \" + item.Id);\n"; - initRefFuncCode += $" }}\n"; - initRefFuncCode += $" }}\n"; - initRefFuncCode += $" }}\n"; - } - } - - code += fieldCode; - code += $"\n"; - code += $" private static bool _init = false;\n"; - code += $" /// \n"; - code += $" /// 初始化所有配置表数据\n"; - code += $" /// \n"; - code += $" public static void Init()\n"; - code += $" {{\n"; - code += $" if (_init) return;\n"; - code += $" _init = true;\n"; - code += $"\n"; - code += callFuncCode; - code += $"\n"; - code += callInitRefFuncCode; - code += $" }}\n"; - code += funcCode; - code += $"\n"; - code += initRefFuncCode; - code += $" private static string _ReadConfigAsText(string path)\n"; - code += $" {{\n"; - code += $" var file = FileAccess.Open(path, FileAccess.ModeFlags.Read);\n"; - code += $" var asText = file.GetAsText();\n"; - code += $" file.Dispose();\n"; - code += $" return asText;\n"; - code += $" }}\n"; - code += $"}}"; - return code; - } - - private static ExcelData ReadExcel(string excelPath) - { - var excelData = new ExcelData(); - //文件名称 - var fileName = Path.GetFileNameWithoutExtension(excelPath).FirstToUpper(); - excelData.TableName = fileName; - //输出代码 - var outStr = $"using System.Text.Json.Serialization;\n"; - outStr += $"using System.Collections.Generic;\n\n"; - outStr += $"namespace Config;\n\n"; - outStr += $"public static partial class ExcelConfig\n{{\n"; - outStr += $" public class {fileName}\n"; - outStr += $" {{\n"; - //继承的带有引用其他表的类代码 - var outRefStr = ""; - - var cloneFuncStr = $" /// \n"; - cloneFuncStr += $" /// 返回浅拷贝出的新对象\n"; - cloneFuncStr += $" /// \n"; - cloneFuncStr += $" public {fileName} Clone()\n"; - cloneFuncStr += $" {{\n"; - cloneFuncStr += $" var inst = new {fileName}();\n"; - - var sourceFile = excelPath; - - //行数 - var rowCount = -1; - //列数 - var columnCount = -1; - - //加载表数据 - var workbook = new XSSFWorkbook(sourceFile); - using (workbook) - { - var sheet1 = workbook.GetSheet("Sheet1"); - rowCount = sheet1.LastRowNum; - //先解析表中的列名, 注释, 类型 - var names = sheet1.GetRow(0); - var descriptions = sheet1.GetRow(1); - var types = sheet1.GetRow(2); - columnCount = names.LastCellNum; - foreach (var cell in names) - { - //字段名称 - var field = GetCellStringValue(cell); - if (string.IsNullOrEmpty(field)) - { - if (cell.ColumnIndex == 0) - { - throw new Exception($"表'{fileName}'的列数为0!"); - } - //到达最后一列了 - columnCount = cell.ColumnIndex; - break; - } - field = field.FirstToUpper(); - excelData.ColumnNames.Add(field); - if (field == "Clone") - { - throw new Exception($"表'{fileName}'中不允许有'Clone'字段!"); - } - - var descriptionCell = descriptions.GetCell(cell.ColumnIndex); - //描述 - string description; - if (descriptionCell != null) - { - description = GetCellStringValue(descriptionCell).Replace("\n", "
\n /// "); - } - else - { - description = ""; - } - //类型 - var typeString = GetCellStringValue(types.GetCell(cell.ColumnIndex)); - if (string.IsNullOrEmpty(typeString)) - { - throw new Exception($"表'{fileName}'中'{field}'这一列类型为空!"); - } - - //尝试解析类型 - MappingData mappingData; - try - { - mappingData = ConvertToType(typeString.Replace(" ", "")); - } - catch (Exception e) - { - PrintError(e.ToString()); - throw new Exception($"表'{fileName}'中'{field}'这一列类型描述语法错误: {typeString}"); - } - - if (!excelData.ColumnMappingData.TryAdd(field, mappingData)) - { - throw new Exception($"表'{fileName}'中存在相同名称的列: '{field}'!"); - } - outStr += $" /// \n"; - outStr += $" /// {description}\n"; - outStr += $" /// \n"; - if (!mappingData.IsRefExcel) //没有引用其他表 - { - outStr += $" [JsonInclude]\n"; - outStr += $" public {mappingData.TypeStr} {field};\n\n"; - } - else - { - outStr += $" public {mappingData.RefTypeStr} {field};\n\n"; - } - - if (mappingData.IsRefExcel) //引用其他表 - { - if (string.IsNullOrEmpty(outRefStr)) - { - outRefStr += $" private class Ref_{fileName} : {fileName}\n"; - outRefStr += $" {{\n"; - } - outRefStr += $" [JsonInclude]\n"; - outRefStr += $" public {mappingData.TypeStr} __{field};\n\n"; - } - - cloneFuncStr += $" inst.{field} = {field};\n"; - } - - cloneFuncStr += " return inst;\n"; - cloneFuncStr += " }\n"; - outStr += cloneFuncStr; - outStr += " }\n"; - - if (!string.IsNullOrEmpty(outRefStr)) - { - outRefStr += " }\n"; - outStr += outRefStr; - } - - outStr += "}"; - - //解析字段类型 - foreach (var kv in excelData.ColumnMappingData) - { - var typeName = kv.Value.TypeName; - var type = Type.GetType(typeName); - if (type == null) - { - throw new Exception($"表'{fileName}'中'{kv.Key}'这一列类型未知! " + kv.Value.TypeStr); - } - excelData.ColumnType.Add(kv.Key, type); - } - - //解析数据 - for (int i = 3; i <= rowCount; i++) - { - Dictionary data = null; - var row = sheet1.GetRow(i); - if (row == null) - { - continue; - } - for (int j = 0; j < columnCount; j++) - { - var cell = row.GetCell(j); - var strValue = GetCellStringValue(cell); - //如果这一行的第一列数据为空, 则跳过这一行 - if (j == 0 && string.IsNullOrEmpty(strValue)) - { - break; - } - else if (data == null) - { - data = new Dictionary(); - excelData.DataList.Add(data); - } - - var fieldName = excelData.ColumnNames[j]; - var mappingData = excelData.ColumnMappingData[fieldName]; - var field = mappingData.IsRefExcel ? "__" + fieldName : fieldName; - try - { - switch (mappingData.TypeStr) - { - case "bool": - case "boolean": - data.Add(field, GetCellBooleanValue(cell)); - break; - case "byte": - data.Add(field, Convert.ToByte(GetCellNumberValue(cell))); - break; - case "sbyte": - data.Add(field, Convert.ToSByte(GetCellNumberValue(cell))); - break; - case "short": - data.Add(field, Convert.ToInt16(GetCellNumberValue(cell))); - break; - case "ushort": - data.Add(field, Convert.ToUInt16(GetCellNumberValue(cell))); - break; - case "int": - data.Add(field, Convert.ToInt32(GetCellNumberValue(cell))); - break; - case "uint": - data.Add(field, Convert.ToUInt32(GetCellNumberValue(cell))); - break; - case "long": - data.Add(field, Convert.ToInt64(GetCellNumberValue(cell))); - break; - case "ulong": - data.Add(field, Convert.ToUInt64(GetCellNumberValue(cell))); - break; - case "float": - data.Add(field, Convert.ToSingle(GetCellNumberValue(cell))); - break; - case "double": - data.Add(field, GetCellNumberValue(cell)); - break; - case "string": - data.Add(field, GetCellStringValue(cell)); - break; - default: - { - var cellStringValue = GetCellStringValue(cell); - if (cellStringValue.Length == 0) - { - data.Add(field, null); - } - else - { - data.Add(field, JsonSerializer.Deserialize(cellStringValue, excelData.ColumnType[fieldName])); - } - } - break; - } - } - catch (Exception e) - { - PrintError(e.ToString()); - throw new Exception($"解析表'{fileName}'第'{i + 1}'行第'{j + 1}'列数据时发生异常"); - } - } - } - } - - excelData.OutCode = outStr; - return excelData; - } - - private static string GetCellStringValue(ICell cell) - { - if (cell == null) - { - return ""; - } - switch (cell.CellType) - { - case CellType.Numeric: - return cell.NumericCellValue.ToString(); - case CellType.String: - return cell.StringCellValue; - case CellType.Formula: - return cell.CellFormula; - case CellType.Boolean: - return cell.BooleanCellValue ? "true" : "false"; - } - - return ""; - } - - private static double GetCellNumberValue(ICell cell) - { - if (cell == null) - { - return 0; - } - - return cell.NumericCellValue; - } - - private static bool GetCellBooleanValue(ICell cell) - { - if (cell == null) - { - return false; - } - - if (cell.CellType == CellType.Boolean) - { - return cell.BooleanCellValue; - } - - var value = cell.StringCellValue; - if (string.IsNullOrWhiteSpace(value)) - { - return false; - } - - return bool.Parse(value); - } - - private static MappingData ConvertToType(string str, int depth = 0) - { - if (Regex.IsMatch(str, "^\\w+$")) - { - var typeStr = TypeStrMapping(str); - var typeName = TypeNameMapping(str); - return new MappingData(typeStr, typeName, CollectionsType.None); - } - else if (Regex.IsMatch(str, "^\\$\\w+$")) //引用其他表 - { - var realName = str.Substring(1); - if (!_excelNames.Contains(realName)) - { - throw new Exception($"引用表数据失败, 未找到表: {realName}!"); - } - - if (depth > 1) - { - throw new Exception("引用表数据失败, 引用表数据仅支持放入第一层的数组和字典!"); - } - - return new MappingData(TypeStrMapping("string"), TypeNameMapping("string"), CollectionsType.None, realName, realName); - } - else if (str.StartsWith('{')) //字典 - { - var tempStr = str.Substring(1, str.Length - 2); - var index = tempStr.IndexOf(':'); - if (index == -1) - { - throw new Exception("类型描述语法错误!"); - } - - var keyStr = tempStr.Substring(0, index); - if (!IsBaseType(keyStr)) - { - throw new Exception($"字典key类型必须是基础类型!"); - } - - var type1 = ConvertToType(keyStr, depth + 1); - var type2 = ConvertToType(tempStr.Substring(index + 1), depth + 1); - - var typeStr = $"Dictionary<{type1.TypeStr}, {type2.TypeStr}>"; - var typeName = $"System.Collections.Generic.Dictionary`2[[{type1.TypeName}],[{type2.TypeName}]]"; - - if (type2.IsRefExcel) //引用过其他表 - { - var refTypeStr = $"Dictionary<{type1.TypeStr}, {type2.RefTypeStr}>"; - return new MappingData(typeStr, typeName, CollectionsType.Map, refTypeStr, type2.RefTypeName); - } - - return new MappingData(typeStr, typeName, CollectionsType.Map); - } - else if (str.StartsWith('[')) //数组 - { - var tempStr = str.Substring(1, str.Length - 2); - var typeData = ConvertToType(tempStr, depth + 1); - var typeStr = typeData.TypeStr + "[]"; - var typeName = typeData.TypeName + "[]"; - - if (typeData.IsRefExcel) //引用过其他表 - { - var refTypeStr = typeData.RefTypeStr + "[]"; - return new MappingData(typeStr, typeName, CollectionsType.Array, refTypeStr, typeData.RefTypeName); - } - - return new MappingData(typeStr, typeName, CollectionsType.Array); - } - throw new Exception("类型描述语法错误!"); - } - - private static string TypeStrMapping(string typeName) - { - switch (typeName) - { - case "boolean": return "bool"; - case "vector2": return "SerializeVector2"; - case "vector3": return "SerializeVector3"; - case "color": return "SerializeColor"; - } - - return typeName; - } - - private static string TypeNameMapping(string typeName) - { - switch (typeName) - { - case "bool": - case "boolean": return typeof(bool).FullName; - case "byte": return typeof(byte).FullName; - case "sbyte": return typeof(sbyte).FullName; - case "short": return typeof(short).FullName; - case "ushort": return typeof(ushort).FullName; - case "int": return typeof(int).FullName; - case "uint": return typeof(uint).FullName; - case "long": return typeof(long).FullName; - case "ulong": return typeof(ulong).FullName; - case "string": return typeof(string).FullName; - case "float": return typeof(float).FullName; - case "double": return typeof(double).FullName; - case "vector2": return "SerializeVector2"; - case "vector3": return "SerializeVector3"; - case "color": return "SerializeColor"; - } - - return typeName; - } - - private static bool IsBaseType(string typeName) - { - switch (typeName) - { - case "bool": - case "boolean": - case "byte": - case "sbyte": - case "short": - case "ushort": - case "int": - case "uint": - case "long": - case "ulong": - case "string": - case "float": - case "double": - return true; - } - - return false; - } - - private static void PrintError(string message) - { - Console.ForegroundColor = ConsoleColor.Red; - Console.WriteLine(message); - Console.ResetColor(); - } - - /// - /// 字符串首字母小写 - /// - public static string FirstToLower(this string str) - { - 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_ExcelTool/Program.cs b/DungeonShooting_ExcelTool/Program.cs deleted file mode 100644 index d6384c0..0000000 --- a/DungeonShooting_ExcelTool/Program.cs +++ /dev/null @@ -1,26 +0,0 @@ - -public class Program -{ - public static void Main(string[] args) - { - Console.WriteLine("准备导出excel表..."); - bool success; - if (args.Length >= 3) - { - success = ExcelGenerator.ExportExcel(args[0], args[1], args[2]); - } - else - { - success = ExcelGenerator.ExportExcel(); - } - - if (success) - { - Console.WriteLine("excel表导出成功!"); - } - else - { - Console.WriteLine("excel表导出失败!"); - } - } -} \ No newline at end of file diff --git a/DungeonShooting_ExcelTool/excelFile/ActivityObject.xlsx b/DungeonShooting_ExcelTool/excelFile/ActivityObject.xlsx deleted file mode 100644 index 286ad1d..0000000 --- a/DungeonShooting_ExcelTool/excelFile/ActivityObject.xlsx +++ /dev/null Binary files differ diff --git a/DungeonShooting_ExcelTool/excelFile/Sound.xlsx b/DungeonShooting_ExcelTool/excelFile/Sound.xlsx deleted file mode 100644 index 4a5986a..0000000 --- a/DungeonShooting_ExcelTool/excelFile/Sound.xlsx +++ /dev/null Binary files differ diff --git a/DungeonShooting_ExcelTool/excelFile/Test.xlsx b/DungeonShooting_ExcelTool/excelFile/Test.xlsx deleted file mode 100644 index 3699e31..0000000 --- a/DungeonShooting_ExcelTool/excelFile/Test.xlsx +++ /dev/null Binary files differ diff --git a/DungeonShooting_ExcelTool/excelFile/Weapon.xlsx b/DungeonShooting_ExcelTool/excelFile/Weapon.xlsx deleted file mode 100644 index 8e77d9c..0000000 --- a/DungeonShooting_ExcelTool/excelFile/Weapon.xlsx +++ /dev/null Binary files differ diff --git a/DungeonShooting_ExcelTool/serialize/SerializeColor.cs b/DungeonShooting_ExcelTool/serialize/SerializeColor.cs deleted file mode 100644 index c1f6c1e..0000000 --- a/DungeonShooting_ExcelTool/serialize/SerializeColor.cs +++ /dev/null @@ -1,31 +0,0 @@ - - -using System.Text.Json.Serialization; - -/// -/// 可序列化的 Color 对象 -/// -public class SerializeColor -{ - public SerializeColor(float r, float g, float b, float a) - { - R = r; - G = g; - B = b; - A = a; - } - - public SerializeColor() - { - } - - [JsonInclude] - public float R { get; private set; } - [JsonInclude] - public float G { get; private set; } - [JsonInclude] - public float B { get; private set; } - [JsonInclude] - public float A { get; private set; } - -} \ No newline at end of file diff --git a/DungeonShooting_ExcelTool/serialize/SerializeVector2.cs b/DungeonShooting_ExcelTool/serialize/SerializeVector2.cs deleted file mode 100644 index f3051d1..0000000 --- a/DungeonShooting_ExcelTool/serialize/SerializeVector2.cs +++ /dev/null @@ -1,30 +0,0 @@ - -using System.Text.Json.Serialization; - -/// -/// 可序列化的 Vector2 对象 -/// -public class SerializeVector2 -{ - public SerializeVector2(float x, float y) - { - X = x; - Y = y; - } - - public SerializeVector2(SerializeVector2 v) - { - X = v.X; - Y = v.Y; - } - - public SerializeVector2() - { - - } - - [JsonInclude] - public float X { get; private set; } - [JsonInclude] - public float Y { get; private set; } -} \ No newline at end of file diff --git a/DungeonShooting_ExcelTool/serialize/SerializeVector3.cs b/DungeonShooting_ExcelTool/serialize/SerializeVector3.cs deleted file mode 100644 index 60f74e8..0000000 --- a/DungeonShooting_ExcelTool/serialize/SerializeVector3.cs +++ /dev/null @@ -1,32 +0,0 @@ -using System.Text.Json.Serialization; - -/// -/// 可序列化的 Vector3 对象 -/// -public class SerializeVector3 -{ - public SerializeVector3(float x, float y, float z) - { - X = x; - Y = y; - Z = z; - } - - public SerializeVector3(SerializeVector3 v) - { - X = v.X; - Y = v.Y; - } - - public SerializeVector3() - { - } - - [JsonInclude] - public float X { get; private set; } - [JsonInclude] - public float Y { get; private set; } - [JsonInclude] - public float Z { get; private set; } - -} \ No newline at end of file diff --git a/DungeonShooting_Godot/addons/dungeonShooting_plugin/generator/ExcelGenerator.cs b/DungeonShooting_Godot/addons/dungeonShooting_plugin/generator/ExcelGenerator.cs new file mode 100644 index 0000000..0915274 --- /dev/null +++ b/DungeonShooting_Godot/addons/dungeonShooting_plugin/generator/ExcelGenerator.cs @@ -0,0 +1,789 @@ +#if TOOLS + +using System; +using System.Collections.Generic; +using System.IO; +using System.Text.Json; +using System.Text.RegularExpressions; +using Config; +using Godot; +using NPOI.SS.UserModel; +using NPOI.XSSF.UserModel; +using Array = Godot.Collections.Array; +using Environment = System.Environment; + +namespace Generator; + +public static class ExcelGenerator +{ + private static HashSet _excelNames = new HashSet(); + + private enum CollectionsType + { + None, + Array, + Map + } + + private class MappingData + { + public string TypeStr; + public string TypeName; + public CollectionsType CollectionsType; + + public bool IsRefExcel; + public string RefTypeStr; + public string RefTypeName; + + public MappingData(string typeStr, string typeName, CollectionsType collectionsType) + { + TypeStr = typeStr; + TypeName = typeName; + CollectionsType = collectionsType; + IsRefExcel = false; + } + + public MappingData(string typeStr, string typeName, CollectionsType collectionsType, string refTypeStr, string refTypeName) + { + TypeStr = typeStr; + TypeName = typeName; + CollectionsType = collectionsType; + IsRefExcel = true; + RefTypeStr = refTypeStr; + RefTypeName = refTypeName; + } + } + + private class ExcelData + { + public string TableName; + public string OutCode; + public List ColumnNames = new List(); + public Dictionary ColumnMappingData = new Dictionary(); + public Dictionary ColumnType = new Dictionary(); + public List> DataList = new List>(); + } + + /// + /// 导出 Excel 表 + /// + public static void ExportExcel() + { + var excelPath = "excel/"; + var jsonPath = "resource/config/"; + var codePath = "src/config/"; + ExportExcel(excelPath, jsonPath, codePath); + } + + /// + /// 导出 Excel 表 + /// + /// excel文件路径 + /// json配置输出路径 + /// 代码输出路径 + public static bool ExportExcel(string excelFilePath, string jsonOutPath, string codeOutPath) + { + _excelNames.Clear(); + Debug.Log("当前路径: " + Environment.CurrentDirectory); + Debug.Log("excel路径: " + excelFilePath); + Debug.Log("json输出路径: " + jsonOutPath); + Debug.Log("cs代码输出路径: " + codeOutPath); + try + { + var excelDataList = new List(); + + var directoryInfo = new DirectoryInfo(excelFilePath); + if (directoryInfo.Exists) + { + var fileInfos = directoryInfo.GetFiles(); + //记录文件 + foreach (var fileInfo in fileInfos) + { + var fileName = Path.GetFileNameWithoutExtension(fileInfo.Name).FirstToUpper(); + _excelNames.Add(fileName); + } + //读取配置文件 + foreach (var fileInfo in fileInfos) + { + if (fileInfo.Extension == ".xlsx") + { + if (fileInfo.Name == "ExcelConfig.xlsx") + { + throw new Exception("excel表文件名称不允许叫'ExcelConfig.xlsx'!"); + } + Debug.Log("excel表: " + fileInfo.FullName); + excelDataList.Add(ReadExcel(fileInfo.FullName)); + } + } + } + + Debug.Log($"一共检测到excel表共{excelDataList.Count}张."); + if (excelDataList.Count == 0) + { + return true; + } + + if (Directory.Exists(codeOutPath)) + { + Directory.Delete(codeOutPath, true); + } + if (Directory.Exists(jsonOutPath)) + { + Directory.Delete(jsonOutPath, true); + } + Directory.CreateDirectory(codeOutPath); + Directory.CreateDirectory(jsonOutPath); + + //保存配置和代码 + foreach (var excelData in excelDataList) + { + if (excelData.TableName == "ActivityBase") + { + //生成初始化 ActivityObject 代码 + GeneratorActivityObjectInit(excelData); + } + File.WriteAllText(codeOutPath + "ExcelConfig_" + excelData.TableName + ".cs", excelData.OutCode); + var config = new JsonSerializerOptions(); + config.WriteIndented = true; + File.WriteAllText(jsonOutPath + excelData.TableName + ".json", JsonSerializer.Serialize(excelData.DataList, config)); + } + + //生成加载代码 + var code = GeneratorInitCode(excelDataList); + File.WriteAllText(codeOutPath + "ExcelConfig.cs", code); + } + catch (Exception e) + { + PrintError(e.ToString()); + return false; + } + + return true; + } + + private static string GeneratorInitCode(List excelList) + { + var code = $"using System;\n"; + code += $"using System.Collections.Generic;\n"; + code += $"using System.Text.Json;\n"; + code += $"using Godot;\n"; + code += $"\n"; + code += $"namespace Config;\n"; + code += $"\n"; + code += $"public static partial class ExcelConfig\n"; + code += $"{{\n"; + + var fieldCode = ""; + var callFuncCode = ""; + var callInitRefFuncCode = ""; + var funcCode = ""; + var initRefFuncCode = ""; + + foreach (var excelData in excelList) + { + var idName = excelData.ColumnNames[0]; + var idTypeStr = excelData.ColumnMappingData[idName].TypeStr; + + //---------------------------- 引用其他表处理 ---------------------------- + var hasRefColumn = false; + var refColumnNoneCode = ""; + foreach (var columnName in excelData.ColumnNames) + { + var mappingData = excelData.ColumnMappingData[columnName]; + if (mappingData.IsRefExcel) + { + hasRefColumn = true; + if (mappingData.CollectionsType == CollectionsType.None) + { + refColumnNoneCode += $" if (!string.IsNullOrEmpty(item.__{columnName}))\n"; + refColumnNoneCode += $" {{\n"; + refColumnNoneCode += $" item.{columnName} = {mappingData.RefTypeName}_Map[item.__{columnName}];\n"; + refColumnNoneCode += $" }}\n"; + } + else if (mappingData.CollectionsType == CollectionsType.Array) + { + refColumnNoneCode += $" if (item.__{columnName} != null)\n"; + refColumnNoneCode += $" {{\n"; + refColumnNoneCode += $" item.{columnName} = new {mappingData.RefTypeName}[item.__{columnName}.Length];\n"; + refColumnNoneCode += $" for (var i = 0; i < item.__{columnName}.Length; i++)\n"; + refColumnNoneCode += $" {{\n"; + refColumnNoneCode += $" item.{columnName}[i] = {mappingData.RefTypeName}_Map[item.__{columnName}[i]];\n"; + refColumnNoneCode += $" }}\n"; + refColumnNoneCode += $" }}\n"; + } + else + { + refColumnNoneCode += $" if (item.__{columnName} != null)\n"; + refColumnNoneCode += $" {{\n"; + refColumnNoneCode += $" item.{columnName} = new {mappingData.RefTypeStr}();\n"; + refColumnNoneCode += $" foreach (var pair in item.__{columnName})\n"; + refColumnNoneCode += $" {{\n"; + refColumnNoneCode += $" item.{columnName}.Add(pair.Key, {mappingData.RefTypeName}_Map[pair.Value]);\n"; + refColumnNoneCode += $" }}\n"; + refColumnNoneCode += $" }}\n"; + } + refColumnNoneCode += $"\n"; + } + } + + //----------------------------- 数据集合 ------------------------------------ + fieldCode += $" /// \n"; + fieldCode += $" /// {excelData.TableName}.xlsx表数据集合, 以 List 形式存储, 数据顺序与 Excel 表相同\n"; + fieldCode += $" /// \n"; + fieldCode += $" public static List<{excelData.TableName}> {excelData.TableName}_List {{ get; private set; }}\n"; + fieldCode += $" /// \n"; + fieldCode += $" /// {excelData.TableName}.xlsx表数据集合, 里 Map 形式存储, key 为 {idName}\n"; + fieldCode += $" /// \n"; + fieldCode += $" public static Dictionary<{idTypeStr}, {excelData.TableName}> {excelData.TableName}_Map {{ get; private set; }}\n"; + fieldCode += $"\n"; + + //------------------------------- 初始化函数 ------------------------------------- + callFuncCode += $" _Init{excelData.TableName}Config();\n"; + + funcCode += $" private static void _Init{excelData.TableName}Config()\n"; + funcCode += $" {{\n"; + funcCode += $" try\n"; + funcCode += $" {{\n"; + funcCode += $" var text = _ReadConfigAsText(\"res://resource/config/{excelData.TableName}.json\");\n"; + if (hasRefColumn) //存在引用列 + { + funcCode += $" {excelData.TableName}_List = new List<{excelData.TableName}>(JsonSerializer.Deserialize>(text));\n"; + } + else + { + funcCode += $" {excelData.TableName}_List = JsonSerializer.Deserialize>(text);\n"; + } + funcCode += $" {excelData.TableName}_Map = new Dictionary<{idTypeStr}, {excelData.TableName}>();\n"; + funcCode += $" foreach (var item in {excelData.TableName}_List)\n"; + funcCode += $" {{\n"; + funcCode += $" {excelData.TableName}_Map.Add(item.{idName}, item);\n"; + funcCode += $" }}\n"; + funcCode += $" }}\n"; + funcCode += $" catch (Exception e)\n"; + funcCode += $" {{\n"; + funcCode += $" GD.PrintErr(e.ToString());\n"; + funcCode += $" throw new Exception(\"初始化表'{excelData.TableName}'失败!\");\n"; + funcCode += $" }}\n"; + funcCode += $" }}\n"; + + + //------------------------------- 初始化引用 --------------------------------- + if (hasRefColumn) + { + callInitRefFuncCode += $" _Init{excelData.TableName}Ref();\n"; + + initRefFuncCode += $" private static void _Init{excelData.TableName}Ref()\n"; + initRefFuncCode += $" {{\n"; + initRefFuncCode += $" foreach (Ref_{excelData.TableName} item in {excelData.TableName}_List)\n"; + initRefFuncCode += $" {{\n"; + initRefFuncCode += $" try\n"; + initRefFuncCode += $" {{\n"; + initRefFuncCode += refColumnNoneCode; + initRefFuncCode += $" }}\n"; + initRefFuncCode += $" catch (Exception e)\n"; + initRefFuncCode += $" {{\n"; + initRefFuncCode += $" GD.PrintErr(e.ToString());\n"; + initRefFuncCode += $" throw new Exception(\"初始化'{excelData.TableName}'引用其他表数据失败, 当前行id: \" + item.Id);\n"; + initRefFuncCode += $" }}\n"; + initRefFuncCode += $" }}\n"; + initRefFuncCode += $" }}\n"; + } + } + + code += fieldCode; + code += $"\n"; + code += $" private static bool _init = false;\n"; + code += $" /// \n"; + code += $" /// 初始化所有配置表数据\n"; + code += $" /// \n"; + code += $" public static void Init()\n"; + code += $" {{\n"; + code += $" if (_init) return;\n"; + code += $" _init = true;\n"; + code += $"\n"; + code += callFuncCode; + code += $"\n"; + code += callInitRefFuncCode; + code += $" }}\n"; + code += funcCode; + code += $"\n"; + code += initRefFuncCode; + code += $" private static string _ReadConfigAsText(string path)\n"; + code += $" {{\n"; + code += $" var file = FileAccess.Open(path, FileAccess.ModeFlags.Read);\n"; + code += $" var asText = file.GetAsText();\n"; + code += $" file.Dispose();\n"; + code += $" return asText;\n"; + code += $" }}\n"; + code += $"}}"; + return code; + } + + private static ExcelData ReadExcel(string excelPath) + { + var excelData = new ExcelData(); + //文件名称 + var fileName = Path.GetFileNameWithoutExtension(excelPath).FirstToUpper(); + excelData.TableName = fileName; + //输出代码 + var outStr = $"using System.Text.Json.Serialization;\n"; + outStr += $"using System.Collections.Generic;\n\n"; + outStr += $"namespace Config;\n\n"; + outStr += $"public static partial class ExcelConfig\n{{\n"; + outStr += $" public class {fileName}\n"; + outStr += $" {{\n"; + //继承的带有引用其他表的类代码 + var outRefStr = ""; + + var cloneFuncStr = $" /// \n"; + cloneFuncStr += $" /// 返回浅拷贝出的新对象\n"; + cloneFuncStr += $" /// \n"; + cloneFuncStr += $" public {fileName} Clone()\n"; + cloneFuncStr += $" {{\n"; + cloneFuncStr += $" var inst = new {fileName}();\n"; + + var sourceFile = excelPath; + + //行数 + var rowCount = -1; + //列数 + var columnCount = -1; + + //加载表数据 + var workbook = new XSSFWorkbook(sourceFile); + using (workbook) + { + var sheet1 = workbook.GetSheet("Sheet1"); + rowCount = sheet1.LastRowNum; + //先解析表中的列名, 注释, 类型 + var names = sheet1.GetRow(0); + var descriptions = sheet1.GetRow(1); + var types = sheet1.GetRow(2); + columnCount = names.LastCellNum; + foreach (var cell in names) + { + //字段名称 + var field = GetCellStringValue(cell); + if (string.IsNullOrEmpty(field)) + { + if (cell.ColumnIndex == 0) + { + throw new Exception($"表'{fileName}'的列数为0!"); + } + //到达最后一列了 + columnCount = cell.ColumnIndex; + break; + } + field = field.FirstToUpper(); + excelData.ColumnNames.Add(field); + if (field == "Clone") + { + throw new Exception($"表'{fileName}'中不允许有'Clone'字段!"); + } + + var descriptionCell = descriptions.GetCell(cell.ColumnIndex); + //描述 + string description; + if (descriptionCell != null) + { + description = GetCellStringValue(descriptionCell).Replace("\n", "
\n /// "); + } + else + { + description = ""; + } + //类型 + var typeString = GetCellStringValue(types.GetCell(cell.ColumnIndex)); + if (string.IsNullOrEmpty(typeString)) + { + throw new Exception($"表'{fileName}'中'{field}'这一列类型为空!"); + } + + //尝试解析类型 + MappingData mappingData; + try + { + mappingData = ConvertToType(typeString.Replace(" ", "")); + } + catch (Exception e) + { + PrintError(e.ToString()); + throw new Exception($"表'{fileName}'中'{field}'这一列类型描述语法错误: {typeString}"); + } + + if (!excelData.ColumnMappingData.TryAdd(field, mappingData)) + { + throw new Exception($"表'{fileName}'中存在相同名称的列: '{field}'!"); + } + outStr += $" /// \n"; + outStr += $" /// {description}\n"; + outStr += $" /// \n"; + if (!mappingData.IsRefExcel) //没有引用其他表 + { + outStr += $" [JsonInclude]\n"; + outStr += $" public {mappingData.TypeStr} {field};\n\n"; + } + else + { + outStr += $" public {mappingData.RefTypeStr} {field};\n\n"; + } + + if (mappingData.IsRefExcel) //引用其他表 + { + if (string.IsNullOrEmpty(outRefStr)) + { + outRefStr += $" private class Ref_{fileName} : {fileName}\n"; + outRefStr += $" {{\n"; + } + outRefStr += $" [JsonInclude]\n"; + outRefStr += $" public {mappingData.TypeStr} __{field};\n\n"; + } + + cloneFuncStr += $" inst.{field} = {field};\n"; + } + + cloneFuncStr += " return inst;\n"; + cloneFuncStr += " }\n"; + outStr += cloneFuncStr; + outStr += " }\n"; + + if (!string.IsNullOrEmpty(outRefStr)) + { + outRefStr += " }\n"; + outStr += outRefStr; + } + + outStr += "}"; + + //解析字段类型 + foreach (var kv in excelData.ColumnMappingData) + { + var typeName = kv.Value.TypeName; + var type = Type.GetType(typeName); + if (type == null) + { + throw new Exception($"表'{fileName}'中'{kv.Key}'这一列类型未知! " + kv.Value.TypeStr); + } + excelData.ColumnType.Add(kv.Key, type); + } + + //解析数据 + for (int i = 3; i <= rowCount; i++) + { + Dictionary data = null; + var row = sheet1.GetRow(i); + if (row == null) + { + continue; + } + for (int j = 0; j < columnCount; j++) + { + var cell = row.GetCell(j); + var strValue = GetCellStringValue(cell); + //如果这一行的第一列数据为空, 则跳过这一行 + if (j == 0 && string.IsNullOrEmpty(strValue)) + { + break; + } + else if (data == null) + { + data = new Dictionary(); + excelData.DataList.Add(data); + } + + var fieldName = excelData.ColumnNames[j]; + var mappingData = excelData.ColumnMappingData[fieldName]; + var field = mappingData.IsRefExcel ? "__" + fieldName : fieldName; + try + { + switch (mappingData.TypeStr) + { + case "bool": + case "boolean": + data.Add(field, GetCellBooleanValue(cell)); + break; + case "byte": + data.Add(field, Convert.ToByte(GetCellNumberValue(cell))); + break; + case "sbyte": + data.Add(field, Convert.ToSByte(GetCellNumberValue(cell))); + break; + case "short": + data.Add(field, Convert.ToInt16(GetCellNumberValue(cell))); + break; + case "ushort": + data.Add(field, Convert.ToUInt16(GetCellNumberValue(cell))); + break; + case "int": + data.Add(field, Convert.ToInt32(GetCellNumberValue(cell))); + break; + case "uint": + data.Add(field, Convert.ToUInt32(GetCellNumberValue(cell))); + break; + case "long": + data.Add(field, Convert.ToInt64(GetCellNumberValue(cell))); + break; + case "ulong": + data.Add(field, Convert.ToUInt64(GetCellNumberValue(cell))); + break; + case "float": + data.Add(field, Convert.ToSingle(GetCellNumberValue(cell))); + break; + case "double": + data.Add(field, GetCellNumberValue(cell)); + break; + case "string": + data.Add(field, GetCellStringValue(cell)); + break; + default: + { + var cellStringValue = GetCellStringValue(cell); + if (cellStringValue.Length == 0) + { + data.Add(field, null); + } + else + { + data.Add(field, JsonSerializer.Deserialize(cellStringValue, excelData.ColumnType[fieldName])); + } + } + break; + } + } + catch (Exception e) + { + PrintError(e.ToString()); + throw new Exception($"解析表'{fileName}'第'{i + 1}'行第'{j + 1}'列数据时发生异常"); + } + } + } + } + + excelData.OutCode = outStr; + return excelData; + } + + private static string GetCellStringValue(ICell cell) + { + if (cell == null) + { + return ""; + } + switch (cell.CellType) + { + case CellType.Numeric: + return cell.NumericCellValue.ToString(); + case CellType.String: + return cell.StringCellValue; + case CellType.Formula: + return cell.CellFormula; + case CellType.Boolean: + return cell.BooleanCellValue ? "true" : "false"; + } + + return ""; + } + + private static double GetCellNumberValue(ICell cell) + { + if (cell == null) + { + return 0; + } + + return cell.NumericCellValue; + } + + private static bool GetCellBooleanValue(ICell cell) + { + if (cell == null) + { + return false; + } + + if (cell.CellType == CellType.Boolean) + { + return cell.BooleanCellValue; + } + + var value = cell.StringCellValue; + if (string.IsNullOrWhiteSpace(value)) + { + return false; + } + + return bool.Parse(value); + } + + private static MappingData ConvertToType(string str, int depth = 0) + { + if (Regex.IsMatch(str, "^\\w+$")) + { + var typeStr = TypeStrMapping(str); + var typeName = TypeNameMapping(str); + return new MappingData(typeStr, typeName, CollectionsType.None); + } + else if (Regex.IsMatch(str, "^\\$\\w+$")) //引用其他表 + { + var realName = str.Substring(1); + if (!_excelNames.Contains(realName)) + { + throw new Exception($"引用表数据失败, 未找到表: {realName}!"); + } + + if (depth > 1) + { + throw new Exception("引用表数据失败, 引用表数据仅支持放入第一层的数组和字典!"); + } + + return new MappingData(TypeStrMapping("string"), TypeNameMapping("string"), CollectionsType.None, realName, realName); + } + else if (str.StartsWith('{')) //字典 + { + var tempStr = str.Substring(1, str.Length - 2); + var index = tempStr.IndexOf(':'); + if (index == -1) + { + throw new Exception("类型描述语法错误!"); + } + + var keyStr = tempStr.Substring(0, index); + if (!IsBaseType(keyStr)) + { + throw new Exception($"字典key类型必须是基础类型!"); + } + + var type1 = ConvertToType(keyStr, depth + 1); + var type2 = ConvertToType(tempStr.Substring(index + 1), depth + 1); + + var typeStr = $"Dictionary<{type1.TypeStr}, {type2.TypeStr}>"; + var typeName = $"System.Collections.Generic.Dictionary`2[[{type1.TypeName}],[{type2.TypeName}]]"; + + if (type2.IsRefExcel) //引用过其他表 + { + var refTypeStr = $"Dictionary<{type1.TypeStr}, {type2.RefTypeStr}>"; + return new MappingData(typeStr, typeName, CollectionsType.Map, refTypeStr, type2.RefTypeName); + } + + return new MappingData(typeStr, typeName, CollectionsType.Map); + } + else if (str.StartsWith('[')) //数组 + { + var tempStr = str.Substring(1, str.Length - 2); + var typeData = ConvertToType(tempStr, depth + 1); + var typeStr = typeData.TypeStr + "[]"; + var typeName = typeData.TypeName + "[]"; + + if (typeData.IsRefExcel) //引用过其他表 + { + var refTypeStr = typeData.RefTypeStr + "[]"; + return new MappingData(typeStr, typeName, CollectionsType.Array, refTypeStr, typeData.RefTypeName); + } + + return new MappingData(typeStr, typeName, CollectionsType.Array); + } + throw new Exception("类型描述语法错误!"); + } + + private static string TypeStrMapping(string typeName) + { + switch (typeName) + { + case "boolean": return "bool"; + case "vector2": return "SerializeVector2"; + case "vector3": return "SerializeVector3"; + case "color": return "SerializeColor"; + } + + return typeName; + } + + private static string TypeNameMapping(string typeName) + { + switch (typeName) + { + case "bool": + case "boolean": return typeof(bool).FullName; + case "byte": return typeof(byte).FullName; + case "sbyte": return typeof(sbyte).FullName; + case "short": return typeof(short).FullName; + case "ushort": return typeof(ushort).FullName; + case "int": return typeof(int).FullName; + case "uint": return typeof(uint).FullName; + case "long": return typeof(long).FullName; + case "ulong": return typeof(ulong).FullName; + case "string": return typeof(string).FullName; + case "float": return typeof(float).FullName; + case "double": return typeof(double).FullName; + case "vector2": return "SerializeVector2"; + case "vector3": return "SerializeVector3"; + case "color": return "SerializeColor"; + } + + return typeName; + } + + private static bool IsBaseType(string typeName) + { + switch (typeName) + { + case "bool": + case "boolean": + case "byte": + case "sbyte": + case "short": + case "ushort": + case "int": + case "uint": + case "long": + case "ulong": + case "string": + case "float": + case "double": + return true; + } + + return false; + } + + private static void PrintError(string message) + { + Debug.LogError(message); + } + + //生成 ActivityObject.Ids 代码 + private static void GeneratorActivityObjectInit(ExcelData activityExcelData) + { + var code1 = ""; + foreach (var item in activityExcelData.DataList) + { + var id = item["Id"]; + var name = item["Name"] + ""; + var intro = item["Intro"] + ""; + code1 += $" /// \n"; + code1 += $" /// 名称: {name}
\n"; + code1 += $" /// 简介: {intro.Replace("\n", "
\n /// ")}\n"; + code1 += $" ///
\n"; + code1 += $" public const string Id_{id} = \"{id}\";\n"; + } + + var str = $"using Config;\n\n"; + str += $"// 根据配置表注册物体, 该类是自动生成的, 请不要手动编辑!\n"; + str += $"public partial class ActivityObject\n"; + str += $"{{\n"; + + str += $" /// \n"; + str += $" /// 存放所有在表中注册的物体的id\n"; + str += $" /// \n"; + str += $" public static class Ids\n"; + str += $" {{\n"; + str += code1; + str += $" }}\n"; + + str += $"}}\n"; + + File.WriteAllText("src/framework/activity/ActivityObject_Init.cs", str); + } +} + +#endif \ No newline at end of file diff --git a/DungeonShooting_Godot/addons/dungeonShooting_plugin/generator/ResourcePathGenerator.cs b/DungeonShooting_Godot/addons/dungeonShooting_plugin/generator/ResourcePathGenerator.cs new file mode 100644 index 0000000..c8f4479 --- /dev/null +++ b/DungeonShooting_Godot/addons/dungeonShooting_plugin/generator/ResourcePathGenerator.cs @@ -0,0 +1,128 @@ +#if TOOLS + +using System; +using System.IO; +using System.Linq; +using System.Text.RegularExpressions; + +namespace Generator; + +/// +/// ResourcePath 类文件生成器 +/// +public static class ResourcePathGenerator +{ + //支持后缀 + private static string[] suffix = + { + ".png", + ".jpg", + ".txt", + ".json", + ".ini", + ".tscn", + ".tres", + ".otf", + ".gdshader", + ".ogg", + ".mp3", + ".wav", + ".svg", + ".ttf", + ".otf" + }; + //排除的文件夹, 斜杠用: / + private static string[] exclude = + { + ".vscode", + ".idea", + ".git", + ".import", + ".mono", + "android", + "addons", + ".godot", + ".vs", + "resource/map/tiledata", + "resource/map/tileMaps" + }; + + private static string resultStr = ""; + + //保存路径 + private static string savePath = "src/game/manager/ResourcePath.cs"; + + /// + /// 执行生成操作, 返回是否执行成功 + /// + public static bool Generate() + { + try + { + resultStr = "/// \n" + + "/// 编辑器下所有资源路径, 该类为 Tools 面板下自动生成的, 请不要手动编辑!\n" + + "/// \n" + + "public class ResourcePath\n" + + "{\n"; + + Debug.Log("更新 ResourcePath..."); + + var directoryInfo = new DirectoryInfo(System.Environment.CurrentDirectory); + EachDir(directoryInfo); + + resultStr += "}"; + File.WriteAllText(savePath, resultStr); + Debug.Log("ResourcePath.cs 写出完成!"); + } + catch (Exception e) + { + Debug.LogError(e.ToString()); + return false; + } + + return true; + } + + private static void EachDir(DirectoryInfo directoryInfos) + { + if (directoryInfos.FullName.Length > System.Environment.CurrentDirectory.Length) + { + var path = directoryInfos.FullName.Substring(System.Environment.CurrentDirectory.Length + 1); + path = path.Replace('\\', '/'); + if (exclude.Contains(path)) + { + Debug.Log("扫描排除路径: " + path); + return; + } + } + + var fileInfos = directoryInfos.GetFiles(); + for (var i = 0; i < fileInfos.Length; i++) + { + HandleFile(fileInfos[i]); + } + + var directories = directoryInfos.GetDirectories(); + for (var i = 0; i < directories.Length; i++) + { + EachDir(directories[i]); + } + } + + private static void HandleFile(FileInfo fileInfo) + { + if (suffix.Contains(fileInfo.Extension)) + { + var field = fileInfo.FullName.Substring(System.Environment.CurrentDirectory.Length + 1); + field = field.Replace("\\", "/"); + var resPath = "res://" + field; + field = field.Replace(".", "_"); + field = field.Replace("/", "_"); + field = Regex.Replace(field, "[^\\w]", ""); + resultStr += $" public const string {field} = \"{resPath}\";\n"; + } + } + +} + +#endif \ No newline at end of file diff --git a/DungeonShooting_Godot/addons/dungeonShooting_plugin/generator/UiGenerator.cs b/DungeonShooting_Godot/addons/dungeonShooting_plugin/generator/UiGenerator.cs new file mode 100644 index 0000000..3a84f2a --- /dev/null +++ b/DungeonShooting_Godot/addons/dungeonShooting_plugin/generator/UiGenerator.cs @@ -0,0 +1,509 @@ +#if TOOLS + +using System; +using System.Collections.Generic; +using System.IO; +using System.Text.RegularExpressions; +using Godot; + +namespace Generator; + +/// +/// Ui类生成器 +/// +public static class UiGenerator +{ + private static Dictionary _nodeNameMap = new Dictionary(); + private static int _nestedIndex = 1; + + /// + /// 根据名称在编辑器中创建Ui, open 表示创建完成后是否在编辑器中打开这个ui + /// + public static bool CreateUi(string uiName, bool open = false) + { + try + { + //创建脚本代码 + var scriptPath = GameConfig.UiCodeDir + uiName.FirstToLower(); + var scriptFile = scriptPath + "/" + uiName + "Panel.cs"; + var scriptCode = $"using Godot;\n" + + $"\n" + + $"namespace UI.{uiName};\n" + + $"\n" + + $"public partial class {uiName}Panel : {uiName}\n" + + $"{{\n" + + $"\n" + + $" public override void OnCreateUi()\n" + + $" {{\n" + + $" \n" + + $" }}\n" + + $"\n" + + $" public override void OnDestroyUi()\n" + + $" {{\n" + + $" \n" + + $" }}\n" + + $"\n" + + $"}}\n"; + if (!Directory.Exists(scriptPath)) + { + Directory.CreateDirectory(scriptPath); + } + File.WriteAllText(scriptFile, scriptCode); + + //加载脚本资源 + var scriptRes = GD.Load("res://" + scriptFile); + + //创建场景资源 + var prefabFile = GameConfig.UiPrefabDir + uiName + ".tscn"; + var prefabResPath = "res://" + prefabFile; + if (!Directory.Exists(GameConfig.UiPrefabDir)) + { + Directory.CreateDirectory(GameConfig.UiPrefabDir); + } + var uiNode = new Control(); + uiNode.Name = uiName; + uiNode.SetAnchorsPreset(Control.LayoutPreset.FullRect, true); + uiNode.SetScript(scriptRes); + var scene = new PackedScene(); + scene.Pack(uiNode); + ResourceSaver.Save(scene, prefabResPath); + + //生成Ui结构代码 + GenerateUiCode(uiNode, scriptPath + "/" + uiName + ".cs"); + + //生成 ResourcePath.cs 代码 + ResourcePathGenerator.Generate(); + + //生成 UiManager_Methods.cs 代码 + UiManagerMethodsGenerator.Generate(); + + //打开ui + if (open) + { + Plugin.Plugin.Instance.GetEditorInterface().OpenSceneFromPath(prefabResPath); + } + + } + catch (Exception e) + { + Debug.LogError(e.ToString()); + return false; + } + + return true; + } + + /// + /// 根据指定ui节点生成相应的Ui类, 并保存到指定路径下 + /// + public static void GenerateUiCode(Node control, string path) + { + _nodeNameMap.Clear(); + _nestedIndex = 1; + var uiNode = EachNodeFromEditor(control.Name, control); + var code = GenerateClassCode(uiNode); + File.WriteAllText(path, code); + } + + /// + /// 从编辑器中生成ui代码 + /// + public static bool GenerateUiCodeFromEditor(Node control) + { + try + { + _nodeNameMap.Clear(); + _nestedIndex = 1; + + var uiName = control.Name.ToString(); + var path = GameConfig.UiCodeDir + uiName.FirstToLower() + "/" + uiName + ".cs"; + Debug.Log("重新生成ui代码: " + path); + + var uiNode = EachNodeFromEditor(control.Name, control); + var code = GenerateClassCode(uiNode); + + foreach (var pair in _nodeNameMap) + { + if (pair.Value > 1) + { + Debug.Log($"检测到同名节点: '{pair.Key}', 使用该名称的节点将无法生成唯一节点属性!"); + } + } + + File.WriteAllText(path, code); + } + catch (Exception e) + { + Debug.LogError(e.ToString()); + return false; + } + + return true; + } + + private static string GenerateClassCode(UiNodeInfo uiNodeInfo) + { + var retraction = " "; + return $"namespace UI.{uiNodeInfo.OriginName};\n\n" + + $"/// \n" + + $"/// Ui代码, 该类是根据ui场景自动生成的, 请不要手动编辑该类, 以免造成代码丢失\n" + + $"/// \n" + + $"public abstract partial class {uiNodeInfo.OriginName} : UiBase\n" + + $"{{\n" + + GeneratePropertyListClassCode("", uiNodeInfo.OriginName + ".", uiNodeInfo, retraction) + + $"\n" + + $" public {uiNodeInfo.OriginName}() : base(nameof({uiNodeInfo.OriginName}))\n" + + $" {{\n" + + $" }}\n" + + $"\n" + + $" public sealed override void OnInitNestedUi()\n" + + $" {{\n" + + GenerateUiScriptCode("", uiNodeInfo, retraction) + + $"\n" + + GenerateInitNestedUi("", uiNodeInfo, retraction) + + $" }}\n" + + $"\n" + + GenerateAllChildrenClassCode(uiNodeInfo.OriginName + ".", uiNodeInfo, retraction) + + $"\n" + + GenerateSoleLayerCode(uiNodeInfo, "", uiNodeInfo.OriginName, retraction) + + $"}}\n"; + } + + private static string GenerateUiScriptCode(string parent, UiNodeInfo uiNodeInfo, string retraction) + { + var str = ""; + var node = parent + (string.IsNullOrEmpty(parent) ? "" : ".") + uiNodeInfo.Name; + if (uiNodeInfo.IsNodeScript) + { + str += retraction + $" _ = {node};\n"; + } + else + { + if (uiNodeInfo.Children != null) + { + for (var i = 0; i < uiNodeInfo.Children.Count; i++) + { + var item = uiNodeInfo.Children[i]; + if (uiNodeInfo.OriginName == uiNodeInfo.UiRootName) + { + str += GenerateUiScriptCode("", item, retraction); + } + else + { + str += GenerateUiScriptCode(node, item, retraction); + } + } + } + } + + return str; + } + + private static string GenerateInitNestedUi(string parent, UiNodeInfo uiNodeInfo, string retraction) + { + var str = ""; + if (uiNodeInfo.IsRefUi) + { + var parentUi = "inst" + _nestedIndex++; + var uiNode = $"{parentUi}.{uiNodeInfo.Name}.Instance"; + var parentNode = string.IsNullOrEmpty(parent) ? "this" : parent; + var parentNode2 = string.IsNullOrEmpty(parent) ? "null" : parentUi; + str += retraction + $" var {parentUi} = {parentNode};\n"; + str += retraction + $" RecordNestedUi({uiNode}, {parentNode2}, UiManager.RecordType.Open);\n"; + str += retraction + $" {uiNode}.OnCreateUi();\n"; + str += retraction + $" {uiNode}.OnInitNestedUi();\n\n"; + } + else + { + if (uiNodeInfo.Children != null) + { + for (var i = 0; i < uiNodeInfo.Children.Count; i++) + { + var item = uiNodeInfo.Children[i]; + if (uiNodeInfo.OriginName == uiNodeInfo.UiRootName) + { + str += GenerateInitNestedUi("", item, retraction); + } + else + { + str += GenerateInitNestedUi(parent + (string.IsNullOrEmpty(parent)? "" : ".") + uiNodeInfo.Name, item, retraction); + } + } + } + } + + return str; + } + + private static string GenerateAllChildrenClassCode(string parent, UiNodeInfo uiNodeInfo, string retraction) + { + var str = ""; + if (uiNodeInfo.Children != null) + { + for (var i = 0; i < uiNodeInfo.Children.Count; i++) + { + var item = uiNodeInfo.Children[i]; + str += GenerateAllChildrenClassCode(parent + item.OriginName + ".", item, retraction); + str += GenerateChildrenClassCode(parent, item, retraction); + } + } + + return str; + } + + private static string GenerateChildrenClassCode(string parent, UiNodeInfo uiNodeInfo, string retraction) + { + string cloneCode; + + if (uiNodeInfo.IsRefUi) + { + cloneCode = retraction + $" public override {uiNodeInfo.ClassName} Clone()\n"; + cloneCode += retraction + $" {{\n"; + cloneCode += retraction + $" var uiNode = new {uiNodeInfo.ClassName}(UiPanel, ({uiNodeInfo.NodeTypeName})Instance.Duplicate());\n"; + cloneCode += retraction + $" UiPanel.RecordNestedUi(uiNode.Instance, this, UiManager.RecordType.Open);\n"; + cloneCode += retraction + $" uiNode.Instance.OnCreateUi();\n"; + cloneCode += retraction + $" uiNode.Instance.OnInitNestedUi();\n"; + cloneCode += retraction + $" return uiNode;\n"; + cloneCode += retraction + $" }}\n"; + } + else + { + cloneCode = retraction + $" public override {uiNodeInfo.ClassName} Clone() => new (UiPanel, ({uiNodeInfo.NodeTypeName})Instance.Duplicate());\n"; + } + + return retraction + $"/// \n" + + retraction + $"/// 类型: , 路径: {parent}{uiNodeInfo.OriginName}\n" + + retraction + $"/// \n" + + retraction + $"public class {uiNodeInfo.ClassName} : UiNode<{uiNodeInfo.UiRootName}Panel, {uiNodeInfo.NodeTypeName}, {uiNodeInfo.ClassName}>\n" + + retraction + $"{{\n" + + GeneratePropertyListClassCode("Instance.", parent, uiNodeInfo, retraction + " ") + + retraction + $" public {uiNodeInfo.ClassName}({uiNodeInfo.UiRootName}Panel uiPanel, {uiNodeInfo.NodeTypeName} node) : base(uiPanel, node) {{ }}\n" + + cloneCode + + retraction + $"}}\n\n"; + } + + private static string GeneratePropertyListClassCode(string target, string parent, UiNodeInfo uiNodeInfo, string retraction) + { + var str = ""; + if (uiNodeInfo.Children != null) + { + for (var i = 0; i < uiNodeInfo.Children.Count; i++) + { + var item = uiNodeInfo.Children[i]; + str += GeneratePropertyCode(target, parent, item, retraction); + } + } + + return str; + } + + private static string GeneratePropertyCode(string target, string parent, UiNodeInfo uiNodeInfo, string retraction) + { + string uiPanel; + if (string.IsNullOrEmpty(target)) + { + uiPanel = $"({uiNodeInfo.UiRootName}Panel)this"; + } + else + { + uiPanel = "UiPanel"; + } + return retraction + $"/// \n" + + retraction + $"/// 使用 Instance 属性获取当前节点实例对象, 节点类型: , 节点路径: {parent}{uiNodeInfo.OriginName}\n" + + retraction + $"/// \n" + + retraction + $"public {uiNodeInfo.ClassName} {uiNodeInfo.Name}\n" + + retraction + $"{{\n" + + retraction + $" get\n" + + retraction + $" {{\n" + + retraction + $" if (_{uiNodeInfo.Name} == null) _{uiNodeInfo.Name} = new {uiNodeInfo.ClassName}({uiPanel}, {target}GetNode<{uiNodeInfo.NodeTypeName}>(\"{uiNodeInfo.OriginName}\"));\n" + + retraction + $" return _{uiNodeInfo.Name};\n" + + retraction + $" }}\n" + + retraction + $"}}\n" + + retraction + $"private {uiNodeInfo.ClassName} _{uiNodeInfo.Name};\n\n"; + } + + private static string GenerateSoleLayerCode(UiNodeInfo uiNodeInfo, string layerName, string parent, string retraction) + { + var str = ""; + if (uiNodeInfo.Children != null) + { + foreach (var nodeInfo in uiNodeInfo.Children) + { + var layer = layerName; + if (layerName.Length > 0) + { + layer += "."; + } + + layer += nodeInfo.Name; + var path = parent + "." + nodeInfo.OriginName; + str += GenerateSoleLayerCode(nodeInfo, layer, path, retraction); + if (IsSoleNameNode(nodeInfo)) + { + str += $"{retraction}/// \n"; + str += $"{retraction}/// 场景中唯一名称的节点, 节点类型: , 节点路径: {path}\n"; + str += $"{retraction}/// \n"; + str += $"{retraction}public {nodeInfo.ClassName} S_{nodeInfo.OriginName} => {layer};\n\n"; + } + } + } + return str; + } + + //返回指定节点在当前场景中是否是唯一名称的节点 + private static bool IsSoleNameNode(UiNodeInfo uiNodeInfo) + { + if (!_nodeNameMap.TryGetValue(uiNodeInfo.OriginName, out var count)) + { + return true; + } + + return count <= 1; + } + + /// + /// 在编辑器下递归解析节点, 由于编辑器下绑定用户脚本的节点无法直接判断节点类型, 那么就只能获取节点的脚本然后解析名称和命名空间 + /// + private static UiNodeInfo EachNodeFromEditor(string uiRootName, Node node) + { + UiNodeInfo uiNode; + //原名称 + var originName = Regex.Replace(node.Name, "[^\\w]", ""); + //字段名称 + var fieldName = "L_" + originName; + //类定义该图层的类名 + string className; + if (_nodeNameMap.ContainsKey(originName)) //有同名图层, 为了防止类名冲突, 需要在 UiNode 后面加上索引 + { + var count = _nodeNameMap[originName]; + className = originName + "_" + count; + _nodeNameMap[originName] = count + 1; + } + else + { + className = originName; + _nodeNameMap.Add(originName, 1); + } + + var script = node.GetScript().As(); + if (script == null) //无脚本, 说明是内置节点 + { + uiNode = new UiNodeInfo(uiRootName, fieldName, originName, className, node.GetType().FullName, false); + } + else //存在脚本 + { + var index = script.ResourcePath.LastIndexOf("/", StringComparison.Ordinal); + //文件名称 + var fileName = script.ResourcePath.Substring(index + 1, script.ResourcePath.Length - index - 3 - 1); + //在源代码中寻找命名空间 + var match = Regex.Match(script.SourceCode, "(?<=namespace\\s+)[\\w\\.]+"); + bool isNodeScript; + if (match.Success) //存在命名空间 + { + isNodeScript = IsNodeScript(match.Value + "." + fileName); + uiNode = new UiNodeInfo(uiRootName, fieldName, originName, className, match.Value + "." + fileName, isNodeScript); + } + else //不存在命名空间 + { + isNodeScript = IsNodeScript(fileName); + uiNode = new UiNodeInfo(uiRootName, fieldName, originName, className, fileName, isNodeScript); + } + //检测是否是引用Ui + if (fileName.EndsWith("Panel")) + { + var childUiName = fileName.Substring(0, fileName.Length - 5); + if (childUiName != uiRootName && File.Exists(GameConfig.UiPrefabDir + childUiName + ".tscn")) + { + //是引用Ui + uiNode.IsRefUi = true; + } + } + } + + //如果是引用Ui, 就没有必要递归子节点了 + if (uiNode.IsRefUi) + { + return uiNode; + } + + var childCount = node.GetChildCount(); + if (childCount > 0) + { + for (var i = 0; i < childCount; i++) + { + var children = node.GetChild(i); + if (children != null) + { + if (uiNode.Children == null) + { + uiNode.Children = new List(); + } + + uiNode.Children.Add(EachNodeFromEditor(uiRootName, children)); + } + } + } + + return uiNode; + } + + private static bool IsNodeScript(string typeName) + { + var type = typeof(UiGenerator).Assembly.GetType(typeName); + if (type == null) + { + return false; + } + + return type.IsAssignableTo(typeof(IUiNodeScript)); + } + + private class UiNodeInfo + { + /// + /// 层级名称 + /// + public string Name; + /// + /// 层级原名称 + /// + public string OriginName; + /// + /// 层级类名 + /// + public string ClassName; + /// + /// Godot节点类型名称 + /// + public string NodeTypeName; + /// + /// 子节点 + /// + public List Children; + /// + /// Ui根节点名称 + /// + public string UiRootName; + /// + /// 是否实现了 IUiNodeScript 接口 + /// + public bool IsNodeScript; + /// + /// 是否是引用Ui + /// + public bool IsRefUi; + + public UiNodeInfo(string uiRootName, string name, string originName, string className, string nodeTypeName, bool isNodeScript) + { + UiRootName = uiRootName; + Name = name; + OriginName = originName; + ClassName = className; + NodeTypeName = nodeTypeName; + IsNodeScript = isNodeScript; + } + } + +} + +#endif \ No newline at end of file diff --git a/DungeonShooting_Godot/addons/dungeonShooting_plugin/generator/UiManagerMethodsGenerator.cs b/DungeonShooting_Godot/addons/dungeonShooting_plugin/generator/UiManagerMethodsGenerator.cs new file mode 100644 index 0000000..d005c2b --- /dev/null +++ b/DungeonShooting_Godot/addons/dungeonShooting_plugin/generator/UiManagerMethodsGenerator.cs @@ -0,0 +1,115 @@ +#if TOOLS + +using System; +using System.IO; + +namespace Generator; + +/// +/// 生成 UiManager 中打开Ui相关的函数代码 +/// +public static class UiManagerMethodsGenerator +{ + private static string savePath = "src/game/manager/UiManager_Methods.cs"; + + /// + /// 执行生成操作, 并返回执行结果 + /// + public static bool Generate() + { + //扫描所有ui + if (!Directory.Exists(GameConfig.UiPrefabDir)) + { + return true; + } + + try + { + var directoryInfo = new DirectoryInfo(GameConfig.UiPrefabDir); + var fileInfos = directoryInfo.GetFiles(); + + var code = $"\n// 该类为自动生成的, 请不要手动编辑, 以免造成代码丢失\n" + + $"public static partial class UiManager\n" + + $"{{\n" + + $"\n"; + + var uiNameClass = $" public static class UiNames\n" + + $" {{\n"; + var methodClass = ""; + + foreach (var fileInfo in fileInfos) + { + if (fileInfo.Extension == ".tscn") + { + var uiName = fileInfo.Name.Substring(0, fileInfo.Name.Length - 5); + uiNameClass += $" public const string {uiName} = \"{uiName}\";\n"; + + methodClass += $" /// \n" + + $" /// 创建 {uiName}, 并返回UI实例, 该函数不会打开 Ui\n" + + $" /// \n" + + $" public static UI.{uiName}.{uiName}Panel Create_{uiName}()\n" + + $" {{\n" + + $" return CreateUi(UiNames.{uiName});\n" + + $" }}\n" + + $"\n" + + $" /// \n" + + $" /// 打开 {uiName}, 并返回UI实例\n" + + $" /// \n" + + $" public static UI.{uiName}.{uiName}Panel Open_{uiName}()\n" + + $" {{\n" + + $" return OpenUi(UiNames.{uiName});\n" + + $" }}\n" + + $"\n" + + $" /// \n" + + $" /// 隐藏 {uiName} 的所有实例\n" + + $" /// \n" + + $" public static void Hide_{uiName}()\n" + + $" {{\n" + + $" var uiInstance = Get_{uiName}_Instance();\n" + + $" foreach (var uiPanel in uiInstance)\n" + + $" {{\n" + + $" uiPanel.HideUi();\n" + + $" }}\n" + + $" }}\n" + + $"\n" + + $" /// \n" + + $" /// 销毁 {uiName} 的所有实例\n" + + $" /// \n" + + $" public static void Destroy_{uiName}()\n" + + $" {{\n" + + $" var uiInstance = Get_{uiName}_Instance();\n" + + $" foreach (var uiPanel in uiInstance)\n" + + $" {{\n" + + $" uiPanel.Destroy();\n" + + $" }}\n" + + $" }}\n" + + $"\n" + + $" /// \n" + + $" /// 获取所有 {uiName} 的实例, 如果没有实例, 则返回一个空数组\n" + + $" /// \n" + + $" public static UI.{uiName}.{uiName}Panel[] Get_{uiName}_Instance()\n" + + $" {{\n" + + $" return GetUiInstance(nameof(UI.{uiName}.{uiName}));\n" + + $" }}\n" + + $"\n"; + } + } + uiNameClass += $" }}\n\n"; + + code += uiNameClass; + code += methodClass; + code += $"}}\n"; + + File.WriteAllText(savePath, code); + } + catch (Exception e) + { + Debug.LogError(e.ToString()); + return false; + } + + return true; + } +} + +#endif \ No newline at end of file diff --git a/DungeonShooting_Godot/excel/ActivityBase.xlsx b/DungeonShooting_Godot/excel/ActivityBase.xlsx new file mode 100644 index 0000000..560af91 --- /dev/null +++ b/DungeonShooting_Godot/excel/ActivityBase.xlsx Binary files differ diff --git a/DungeonShooting_Godot/excel/ActivityMaterial.xlsx b/DungeonShooting_Godot/excel/ActivityMaterial.xlsx new file mode 100644 index 0000000..b23fc4c --- /dev/null +++ b/DungeonShooting_Godot/excel/ActivityMaterial.xlsx Binary files differ diff --git a/DungeonShooting_Godot/excel/AiAttackAttr.xlsx b/DungeonShooting_Godot/excel/AiAttackAttr.xlsx new file mode 100644 index 0000000..8d3cdf5 --- /dev/null +++ b/DungeonShooting_Godot/excel/AiAttackAttr.xlsx Binary files differ diff --git a/DungeonShooting_Godot/excel/BouncyCastle.Crypto.dll b/DungeonShooting_Godot/excel/BouncyCastle.Crypto.dll deleted file mode 100644 index b811138..0000000 --- a/DungeonShooting_Godot/excel/BouncyCastle.Crypto.dll +++ /dev/null Binary files differ diff --git a/DungeonShooting_Godot/excel/BulletBase.xlsx b/DungeonShooting_Godot/excel/BulletBase.xlsx new file mode 100644 index 0000000..6ee6491 --- /dev/null +++ b/DungeonShooting_Godot/excel/BulletBase.xlsx Binary files differ diff --git a/DungeonShooting_Godot/excel/DungeonShooting_ExcelTool.deps.json b/DungeonShooting_Godot/excel/DungeonShooting_ExcelTool.deps.json deleted file mode 100644 index 98c2130..0000000 --- a/DungeonShooting_Godot/excel/DungeonShooting_ExcelTool.deps.json +++ /dev/null @@ -1,352 +0,0 @@ -{ - "runtimeTarget": { - "name": ".NETCoreApp,Version=v7.0/win-x64", - "signature": "" - }, - "compilationOptions": {}, - "targets": { - ".NETCoreApp,Version=v7.0": {}, - ".NETCoreApp,Version=v7.0/win-x64": { - "DungeonShooting_ExcelTool/1.0.0": { - "dependencies": { - "NPOI": "2.6.0" - }, - "runtime": { - "DungeonShooting_ExcelTool.dll": {} - } - }, - "Enums.NET/4.0.0": { - "runtime": { - "lib/netcoreapp3.0/Enums.NET.dll": { - "assemblyVersion": "4.0.0.0", - "fileVersion": "4.0.0.0" - } - } - }, - "MathNet.Numerics.Signed/4.15.0": { - "runtime": { - "lib/netstandard2.0/MathNet.Numerics.dll": { - "assemblyVersion": "4.15.0.0", - "fileVersion": "4.15.0.0" - } - } - }, - "Microsoft.IO.RecyclableMemoryStream/2.2.0": { - "runtime": { - "lib/net5.0/Microsoft.IO.RecyclableMemoryStream.dll": { - "assemblyVersion": "2.2.0.0", - "fileVersion": "2.2.0.0" - } - } - }, - "Microsoft.Win32.SystemEvents/6.0.0": { - "runtime": { - "runtimes/win/lib/net6.0/Microsoft.Win32.SystemEvents.dll": { - "assemblyVersion": "6.0.0.0", - "fileVersion": "6.0.21.52210" - } - } - }, - "NPOI/2.6.0": { - "dependencies": { - "Enums.NET": "4.0.0", - "MathNet.Numerics.Signed": "4.15.0", - "Microsoft.IO.RecyclableMemoryStream": "2.2.0", - "Portable.BouncyCastle": "1.9.0", - "SharpZipLib": "1.3.3", - "SixLabors.Fonts": "1.0.0-beta18", - "SixLabors.ImageSharp": "2.1.3", - "System.Configuration.ConfigurationManager": "6.0.0", - "System.Security.Cryptography.Xml": "6.0.1", - "System.Text.Encoding.CodePages": "6.0.0" - }, - "runtime": { - "lib/net6.0/NPOI.OOXML.dll": { - "assemblyVersion": "2.6.0.0", - "fileVersion": "2.6.0.0" - }, - "lib/net6.0/NPOI.OpenXml4Net.dll": { - "assemblyVersion": "2.6.0.0", - "fileVersion": "2.6.0.0" - }, - "lib/net6.0/NPOI.OpenXmlFormats.dll": { - "assemblyVersion": "2.6.0.0", - "fileVersion": "2.6.0.0" - }, - "lib/net6.0/NPOI.dll": { - "assemblyVersion": "2.6.0.0", - "fileVersion": "2.6.0.0" - } - } - }, - "Portable.BouncyCastle/1.9.0": { - "runtime": { - "lib/netstandard2.0/BouncyCastle.Crypto.dll": { - "assemblyVersion": "1.9.0.0", - "fileVersion": "1.9.0.1" - } - } - }, - "SharpZipLib/1.3.3": { - "runtime": { - "lib/netstandard2.1/ICSharpCode.SharpZipLib.dll": { - "assemblyVersion": "1.3.3.11", - "fileVersion": "1.3.3.11" - } - } - }, - "SixLabors.Fonts/1.0.0-beta18": { - "runtime": { - "lib/netcoreapp3.1/SixLabors.Fonts.dll": { - "assemblyVersion": "1.0.0.0", - "fileVersion": "1.0.0.0" - } - } - }, - "SixLabors.ImageSharp/2.1.3": { - "dependencies": { - "System.Runtime.CompilerServices.Unsafe": "6.0.0", - "System.Text.Encoding.CodePages": "6.0.0" - }, - "runtime": { - "lib/netcoreapp3.1/SixLabors.ImageSharp.dll": { - "assemblyVersion": "2.0.0.0", - "fileVersion": "2.1.3.0" - } - } - }, - "System.Configuration.ConfigurationManager/6.0.0": { - "dependencies": { - "System.Security.Cryptography.ProtectedData": "6.0.0", - "System.Security.Permissions": "6.0.0" - }, - "runtime": { - "lib/net6.0/System.Configuration.ConfigurationManager.dll": { - "assemblyVersion": "6.0.0.0", - "fileVersion": "6.0.21.52210" - } - } - }, - "System.Drawing.Common/6.0.0": { - "dependencies": { - "Microsoft.Win32.SystemEvents": "6.0.0" - }, - "runtime": { - "runtimes/win/lib/net6.0/System.Drawing.Common.dll": { - "assemblyVersion": "6.0.0.0", - "fileVersion": "6.0.21.52210" - } - } - }, - "System.Formats.Asn1/6.0.0": {}, - "System.Runtime.CompilerServices.Unsafe/6.0.0": {}, - "System.Security.AccessControl/6.0.0": {}, - "System.Security.Cryptography.Pkcs/6.0.1": { - "dependencies": { - "System.Formats.Asn1": "6.0.0" - }, - "runtime": { - "runtimes/win/lib/net6.0/System.Security.Cryptography.Pkcs.dll": { - "assemblyVersion": "6.0.0.0", - "fileVersion": "6.0.522.21309" - } - } - }, - "System.Security.Cryptography.ProtectedData/6.0.0": { - "runtime": { - "runtimes/win/lib/net6.0/System.Security.Cryptography.ProtectedData.dll": { - "assemblyVersion": "6.0.0.0", - "fileVersion": "6.0.21.52210" - } - } - }, - "System.Security.Cryptography.Xml/6.0.1": { - "dependencies": { - "System.Security.AccessControl": "6.0.0", - "System.Security.Cryptography.Pkcs": "6.0.1" - }, - "runtime": { - "lib/net6.0/System.Security.Cryptography.Xml.dll": { - "assemblyVersion": "6.0.0.0", - "fileVersion": "6.0.822.36306" - } - } - }, - "System.Security.Permissions/6.0.0": { - "dependencies": { - "System.Security.AccessControl": "6.0.0", - "System.Windows.Extensions": "6.0.0" - }, - "runtime": { - "lib/net6.0/System.Security.Permissions.dll": { - "assemblyVersion": "6.0.0.0", - "fileVersion": "6.0.21.52210" - } - } - }, - "System.Text.Encoding.CodePages/6.0.0": { - "dependencies": { - "System.Runtime.CompilerServices.Unsafe": "6.0.0" - } - }, - "System.Windows.Extensions/6.0.0": { - "dependencies": { - "System.Drawing.Common": "6.0.0" - }, - "runtime": { - "runtimes/win/lib/net6.0/System.Windows.Extensions.dll": { - "assemblyVersion": "6.0.0.0", - "fileVersion": "6.0.21.52210" - } - } - } - } - }, - "libraries": { - "DungeonShooting_ExcelTool/1.0.0": { - "type": "project", - "serviceable": false, - "sha512": "" - }, - "Enums.NET/4.0.0": { - "type": "package", - "serviceable": true, - "sha512": "sha512-d47SgeuGxKpalKhYoHqFkDPmO9SoE3amSwVNDoUdy4d675/tX7bLyZFHdjfo3Tobth9Y80VnjfasQ/PD4LqUuA==", - "path": "enums.net/4.0.0", - "hashPath": "enums.net.4.0.0.nupkg.sha512" - }, - "MathNet.Numerics.Signed/4.15.0": { - "type": "package", - "serviceable": true, - "sha512": "sha512-LFjukMRatkg9dgRM7U/gM4uKgaWAX7E0lt3fsVDTPdtBIVuh7uPlksDie290br1/tv1a4Ar/Bz9ywCPSL8PhHg==", - "path": "mathnet.numerics.signed/4.15.0", - "hashPath": "mathnet.numerics.signed.4.15.0.nupkg.sha512" - }, - "Microsoft.IO.RecyclableMemoryStream/2.2.0": { - "type": "package", - "serviceable": true, - "sha512": "sha512-uyjY/cqomw1irT4L7lDeg4sJ36MsjHg3wKqpGrBAdzvZaxo85yMF+sAA9RIzTV92fDxuUzjqksMqA0+SNMkMgA==", - "path": "microsoft.io.recyclablememorystream/2.2.0", - "hashPath": "microsoft.io.recyclablememorystream.2.2.0.nupkg.sha512" - }, - "Microsoft.Win32.SystemEvents/6.0.0": { - "type": "package", - "serviceable": true, - "sha512": "sha512-hqTM5628jSsQiv+HGpiq3WKBl2c8v1KZfby2J6Pr7pEPlK9waPdgEO6b8A/+/xn/yZ9ulv8HuqK71ONy2tg67A==", - "path": "microsoft.win32.systemevents/6.0.0", - "hashPath": "microsoft.win32.systemevents.6.0.0.nupkg.sha512" - }, - "NPOI/2.6.0": { - "type": "package", - "serviceable": true, - "sha512": "sha512-Pwjo65CUH3MiRnBEbVo8ff31ZrDGdGyyFJyAEncmbTQ0/gYgDkBUnGKm20aLpdwCpPNLzvapZm8v5tx4S6qAWg==", - "path": "npoi/2.6.0", - "hashPath": "npoi.2.6.0.nupkg.sha512" - }, - "Portable.BouncyCastle/1.9.0": { - "type": "package", - "serviceable": true, - "sha512": "sha512-eZZBCABzVOek+id9Xy04HhmgykF0wZg9wpByzrWN7q8qEI0Qen9b7tfd7w8VA3dOeesumMG7C5ZPy0jk7PSRHw==", - "path": "portable.bouncycastle/1.9.0", - "hashPath": "portable.bouncycastle.1.9.0.nupkg.sha512" - }, - "SharpZipLib/1.3.3": { - "type": "package", - "serviceable": true, - "sha512": "sha512-N8+hwhsKZm25tDJfWpBSW7EGhH/R7EMuiX+KJ4C4u+fCWVc1lJ5zg1u3S1RPPVYgTqhx/C3hxrqUpi6RwK5+Tg==", - "path": "sharpziplib/1.3.3", - "hashPath": "sharpziplib.1.3.3.nupkg.sha512" - }, - "SixLabors.Fonts/1.0.0-beta18": { - "type": "package", - "serviceable": true, - "sha512": "sha512-evykNmy/kEE9EAEKgZm3MNUYXuMHFfmcLUNPw7Ho5q7OI96GFkkIxBm+QaKOTPBKw+L0AjKOs+ArVg8P40Ac9g==", - "path": "sixlabors.fonts/1.0.0-beta18", - "hashPath": "sixlabors.fonts.1.0.0-beta18.nupkg.sha512" - }, - "SixLabors.ImageSharp/2.1.3": { - "type": "package", - "serviceable": true, - "sha512": "sha512-8yonNRWX3vUE9k29ta0Hbfa0AEc0hbDjSH/nZ3vOTJEXmY6hLnGsjDKoz96Z+AgOsrdkAu6PdL/Ebaf70aitzw==", - "path": "sixlabors.imagesharp/2.1.3", - "hashPath": "sixlabors.imagesharp.2.1.3.nupkg.sha512" - }, - "System.Configuration.ConfigurationManager/6.0.0": { - "type": "package", - "serviceable": true, - "sha512": "sha512-7T+m0kDSlIPTHIkPMIu6m6tV6qsMqJpvQWW2jIc2qi7sn40qxFo0q+7mEQAhMPXZHMKnWrnv47ntGlM/ejvw3g==", - "path": "system.configuration.configurationmanager/6.0.0", - "hashPath": "system.configuration.configurationmanager.6.0.0.nupkg.sha512" - }, - "System.Drawing.Common/6.0.0": { - "type": "package", - "serviceable": true, - "sha512": "sha512-NfuoKUiP2nUWwKZN6twGqXioIe1zVD0RIj2t976A+czLHr2nY454RwwXs6JU9Htc6mwqL6Dn/nEL3dpVf2jOhg==", - "path": "system.drawing.common/6.0.0", - "hashPath": "system.drawing.common.6.0.0.nupkg.sha512" - }, - "System.Formats.Asn1/6.0.0": { - "type": "package", - "serviceable": true, - "sha512": "sha512-T6fD00dQ3NTbPDy31m4eQUwKW84s03z0N2C8HpOklyeaDgaJPa/TexP4/SkORMSOwc7WhKifnA6Ya33AkzmafA==", - "path": "system.formats.asn1/6.0.0", - "hashPath": "system.formats.asn1.6.0.0.nupkg.sha512" - }, - "System.Runtime.CompilerServices.Unsafe/6.0.0": { - "type": "package", - "serviceable": true, - "sha512": "sha512-/iUeP3tq1S0XdNNoMz5C9twLSrM/TH+qElHkXWaPvuNOt+99G75NrV0OS2EqHx5wMN7popYjpc8oTjC1y16DLg==", - "path": "system.runtime.compilerservices.unsafe/6.0.0", - "hashPath": "system.runtime.compilerservices.unsafe.6.0.0.nupkg.sha512" - }, - "System.Security.AccessControl/6.0.0": { - "type": "package", - "serviceable": true, - "sha512": "sha512-AUADIc0LIEQe7MzC+I0cl0rAT8RrTAKFHl53yHjEUzNVIaUlhFY11vc2ebiVJzVBuOzun6F7FBA+8KAbGTTedQ==", - "path": "system.security.accesscontrol/6.0.0", - "hashPath": "system.security.accesscontrol.6.0.0.nupkg.sha512" - }, - "System.Security.Cryptography.Pkcs/6.0.1": { - "type": "package", - "serviceable": true, - "sha512": "sha512-ynmbW2GjIGg9K1wXmVIRs4IlyDolf0JXNpzFQ8JCVgwM+myUC2JeUggl2PwQig2PNVMegKmN1aAx7WPQ8tI3vA==", - "path": "system.security.cryptography.pkcs/6.0.1", - "hashPath": "system.security.cryptography.pkcs.6.0.1.nupkg.sha512" - }, - "System.Security.Cryptography.ProtectedData/6.0.0": { - "type": "package", - "serviceable": true, - "sha512": "sha512-rp1gMNEZpvx9vP0JW0oHLxlf8oSiQgtno77Y4PLUBjSiDYoD77Y8uXHr1Ea5XG4/pIKhqAdxZ8v8OTUtqo9PeQ==", - "path": "system.security.cryptography.protecteddata/6.0.0", - "hashPath": "system.security.cryptography.protecteddata.6.0.0.nupkg.sha512" - }, - "System.Security.Cryptography.Xml/6.0.1": { - "type": "package", - "serviceable": true, - "sha512": "sha512-5e5bI28T0x73AwTsbuFP4qSRzthmU2C0Gqgg3AZ3KTxmSyA+Uhk31puA3srdaeWaacVnHhLdJywCzqOiEpbO/w==", - "path": "system.security.cryptography.xml/6.0.1", - "hashPath": "system.security.cryptography.xml.6.0.1.nupkg.sha512" - }, - "System.Security.Permissions/6.0.0": { - "type": "package", - "serviceable": true, - "sha512": "sha512-T/uuc7AklkDoxmcJ7LGkyX1CcSviZuLCa4jg3PekfJ7SU0niF0IVTXwUiNVP9DSpzou2PpxJ+eNY2IfDM90ZCg==", - "path": "system.security.permissions/6.0.0", - "hashPath": "system.security.permissions.6.0.0.nupkg.sha512" - }, - "System.Text.Encoding.CodePages/6.0.0": { - "type": "package", - "serviceable": true, - "sha512": "sha512-ZFCILZuOvtKPauZ/j/swhvw68ZRi9ATCfvGbk1QfydmcXBkIWecWKn/250UH7rahZ5OoDBaiAudJtPvLwzw85A==", - "path": "system.text.encoding.codepages/6.0.0", - "hashPath": "system.text.encoding.codepages.6.0.0.nupkg.sha512" - }, - "System.Windows.Extensions/6.0.0": { - "type": "package", - "serviceable": true, - "sha512": "sha512-IXoJOXIqc39AIe+CIR7koBtRGMiCt/LPM3lI+PELtDIy9XdyeSrwXFdWV9dzJ2Awl0paLWUaknLxFQ5HpHZUog==", - "path": "system.windows.extensions/6.0.0", - "hashPath": "system.windows.extensions.6.0.0.nupkg.sha512" - } - } -} \ No newline at end of file diff --git a/DungeonShooting_Godot/excel/DungeonShooting_ExcelTool.dll b/DungeonShooting_Godot/excel/DungeonShooting_ExcelTool.dll deleted file mode 100644 index f91239a..0000000 --- a/DungeonShooting_Godot/excel/DungeonShooting_ExcelTool.dll +++ /dev/null Binary files differ diff --git a/DungeonShooting_Godot/excel/DungeonShooting_ExcelTool.exe b/DungeonShooting_Godot/excel/DungeonShooting_ExcelTool.exe deleted file mode 100644 index 9c2c323..0000000 --- a/DungeonShooting_Godot/excel/DungeonShooting_ExcelTool.exe +++ /dev/null Binary files differ diff --git a/DungeonShooting_Godot/excel/DungeonShooting_ExcelTool.pdb b/DungeonShooting_Godot/excel/DungeonShooting_ExcelTool.pdb deleted file mode 100644 index 86422eb..0000000 --- a/DungeonShooting_Godot/excel/DungeonShooting_ExcelTool.pdb +++ /dev/null Binary files differ diff --git a/DungeonShooting_Godot/excel/DungeonShooting_ExcelTool.runtimeconfig.json b/DungeonShooting_Godot/excel/DungeonShooting_ExcelTool.runtimeconfig.json deleted file mode 100644 index 398903e..0000000 --- a/DungeonShooting_Godot/excel/DungeonShooting_ExcelTool.runtimeconfig.json +++ /dev/null @@ -1,12 +0,0 @@ -{ - "runtimeOptions": { - "tfm": "net7.0", - "framework": { - "name": "Microsoft.NETCore.App", - "version": "7.0.0" - }, - "configProperties": { - "System.Reflection.Metadata.MetadataUpdater.IsSupported": false - } - } -} \ No newline at end of file diff --git a/DungeonShooting_Godot/excel/EnemyBase.xlsx b/DungeonShooting_Godot/excel/EnemyBase.xlsx new file mode 100644 index 0000000..cec7fac --- /dev/null +++ b/DungeonShooting_Godot/excel/EnemyBase.xlsx Binary files differ diff --git a/DungeonShooting_Godot/excel/Enums.NET.dll b/DungeonShooting_Godot/excel/Enums.NET.dll deleted file mode 100644 index 1979743..0000000 --- a/DungeonShooting_Godot/excel/Enums.NET.dll +++ /dev/null Binary files differ diff --git a/DungeonShooting_Godot/excel/ICSharpCode.SharpZipLib.dll b/DungeonShooting_Godot/excel/ICSharpCode.SharpZipLib.dll deleted file mode 100644 index 8a74343..0000000 --- a/DungeonShooting_Godot/excel/ICSharpCode.SharpZipLib.dll +++ /dev/null Binary files differ diff --git a/DungeonShooting_Godot/excel/LiquidMaterial.xlsx b/DungeonShooting_Godot/excel/LiquidMaterial.xlsx new file mode 100644 index 0000000..560d63f --- /dev/null +++ b/DungeonShooting_Godot/excel/LiquidMaterial.xlsx Binary files differ diff --git a/DungeonShooting_Godot/excel/MathNet.Numerics.dll b/DungeonShooting_Godot/excel/MathNet.Numerics.dll deleted file mode 100644 index 71d6b4c..0000000 --- a/DungeonShooting_Godot/excel/MathNet.Numerics.dll +++ /dev/null Binary files differ diff --git a/DungeonShooting_Godot/excel/Microsoft.IO.RecyclableMemoryStream.dll b/DungeonShooting_Godot/excel/Microsoft.IO.RecyclableMemoryStream.dll deleted file mode 100644 index c19ee7f..0000000 --- a/DungeonShooting_Godot/excel/Microsoft.IO.RecyclableMemoryStream.dll +++ /dev/null Binary files differ diff --git a/DungeonShooting_Godot/excel/Microsoft.Win32.SystemEvents.dll b/DungeonShooting_Godot/excel/Microsoft.Win32.SystemEvents.dll deleted file mode 100644 index 66af198..0000000 --- a/DungeonShooting_Godot/excel/Microsoft.Win32.SystemEvents.dll +++ /dev/null Binary files differ diff --git a/DungeonShooting_Godot/excel/NPOI.OOXML.dll b/DungeonShooting_Godot/excel/NPOI.OOXML.dll deleted file mode 100644 index b476bdc..0000000 --- a/DungeonShooting_Godot/excel/NPOI.OOXML.dll +++ /dev/null Binary files differ diff --git a/DungeonShooting_Godot/excel/NPOI.OpenXml4Net.dll b/DungeonShooting_Godot/excel/NPOI.OpenXml4Net.dll deleted file mode 100644 index bbdf16b..0000000 --- a/DungeonShooting_Godot/excel/NPOI.OpenXml4Net.dll +++ /dev/null Binary files differ diff --git a/DungeonShooting_Godot/excel/NPOI.OpenXmlFormats.dll b/DungeonShooting_Godot/excel/NPOI.OpenXmlFormats.dll deleted file mode 100644 index a968c09..0000000 --- a/DungeonShooting_Godot/excel/NPOI.OpenXmlFormats.dll +++ /dev/null Binary files differ diff --git a/DungeonShooting_Godot/excel/NPOI.dll b/DungeonShooting_Godot/excel/NPOI.dll deleted file mode 100644 index 2b08549..0000000 --- a/DungeonShooting_Godot/excel/NPOI.dll +++ /dev/null Binary files differ diff --git a/DungeonShooting_Godot/excel/SixLabors.Fonts.dll b/DungeonShooting_Godot/excel/SixLabors.Fonts.dll deleted file mode 100644 index 5780135..0000000 --- a/DungeonShooting_Godot/excel/SixLabors.Fonts.dll +++ /dev/null Binary files differ diff --git a/DungeonShooting_Godot/excel/SixLabors.ImageSharp.dll b/DungeonShooting_Godot/excel/SixLabors.ImageSharp.dll deleted file mode 100644 index dd87091..0000000 --- a/DungeonShooting_Godot/excel/SixLabors.ImageSharp.dll +++ /dev/null Binary files differ diff --git a/DungeonShooting_Godot/excel/Sound.xlsx b/DungeonShooting_Godot/excel/Sound.xlsx new file mode 100644 index 0000000..ff7944e --- /dev/null +++ b/DungeonShooting_Godot/excel/Sound.xlsx Binary files differ diff --git a/DungeonShooting_Godot/excel/System.Configuration.ConfigurationManager.dll b/DungeonShooting_Godot/excel/System.Configuration.ConfigurationManager.dll deleted file mode 100644 index d67c8a8..0000000 --- a/DungeonShooting_Godot/excel/System.Configuration.ConfigurationManager.dll +++ /dev/null Binary files differ diff --git a/DungeonShooting_Godot/excel/System.Drawing.Common.dll b/DungeonShooting_Godot/excel/System.Drawing.Common.dll deleted file mode 100644 index 7c9e87b..0000000 --- a/DungeonShooting_Godot/excel/System.Drawing.Common.dll +++ /dev/null Binary files differ diff --git a/DungeonShooting_Godot/excel/System.Security.Cryptography.Pkcs.dll b/DungeonShooting_Godot/excel/System.Security.Cryptography.Pkcs.dll deleted file mode 100644 index 6cbb734..0000000 --- a/DungeonShooting_Godot/excel/System.Security.Cryptography.Pkcs.dll +++ /dev/null Binary files differ diff --git a/DungeonShooting_Godot/excel/System.Security.Cryptography.ProtectedData.dll b/DungeonShooting_Godot/excel/System.Security.Cryptography.ProtectedData.dll deleted file mode 100644 index 332dbfa..0000000 --- a/DungeonShooting_Godot/excel/System.Security.Cryptography.ProtectedData.dll +++ /dev/null Binary files differ diff --git a/DungeonShooting_Godot/excel/System.Security.Cryptography.Xml.dll b/DungeonShooting_Godot/excel/System.Security.Cryptography.Xml.dll deleted file mode 100644 index b43ece0..0000000 --- a/DungeonShooting_Godot/excel/System.Security.Cryptography.Xml.dll +++ /dev/null Binary files differ diff --git a/DungeonShooting_Godot/excel/System.Security.Permissions.dll b/DungeonShooting_Godot/excel/System.Security.Permissions.dll deleted file mode 100644 index 39dd4df..0000000 --- a/DungeonShooting_Godot/excel/System.Security.Permissions.dll +++ /dev/null Binary files differ diff --git a/DungeonShooting_Godot/excel/System.Windows.Extensions.dll b/DungeonShooting_Godot/excel/System.Windows.Extensions.dll deleted file mode 100644 index 69f0d1b..0000000 --- a/DungeonShooting_Godot/excel/System.Windows.Extensions.dll +++ /dev/null Binary files differ diff --git a/DungeonShooting_Godot/excel/WeaponBase.xlsx b/DungeonShooting_Godot/excel/WeaponBase.xlsx new file mode 100644 index 0000000..e3c81e8 --- /dev/null +++ b/DungeonShooting_Godot/excel/WeaponBase.xlsx Binary files differ diff --git a/DungeonShooting_Godot/excel/excelFile/ActivityBase.xlsx b/DungeonShooting_Godot/excel/excelFile/ActivityBase.xlsx deleted file mode 100644 index 0dc50ce..0000000 --- a/DungeonShooting_Godot/excel/excelFile/ActivityBase.xlsx +++ /dev/null Binary files differ diff --git a/DungeonShooting_Godot/excel/excelFile/ActivityMaterial.xlsx b/DungeonShooting_Godot/excel/excelFile/ActivityMaterial.xlsx deleted file mode 100644 index 9f2979b..0000000 --- a/DungeonShooting_Godot/excel/excelFile/ActivityMaterial.xlsx +++ /dev/null Binary files differ diff --git a/DungeonShooting_Godot/excel/excelFile/AiAttackAttr.xlsx b/DungeonShooting_Godot/excel/excelFile/AiAttackAttr.xlsx deleted file mode 100644 index 693f907..0000000 --- a/DungeonShooting_Godot/excel/excelFile/AiAttackAttr.xlsx +++ /dev/null Binary files differ diff --git a/DungeonShooting_Godot/excel/excelFile/BulletBase.xlsx b/DungeonShooting_Godot/excel/excelFile/BulletBase.xlsx deleted file mode 100644 index d7c0d11..0000000 --- a/DungeonShooting_Godot/excel/excelFile/BulletBase.xlsx +++ /dev/null Binary files differ diff --git a/DungeonShooting_Godot/excel/excelFile/EnemyBase.xlsx b/DungeonShooting_Godot/excel/excelFile/EnemyBase.xlsx deleted file mode 100644 index 4a59086..0000000 --- a/DungeonShooting_Godot/excel/excelFile/EnemyBase.xlsx +++ /dev/null Binary files differ diff --git a/DungeonShooting_Godot/excel/excelFile/LiquidMaterial.xlsx b/DungeonShooting_Godot/excel/excelFile/LiquidMaterial.xlsx deleted file mode 100644 index 0b20dc6..0000000 --- a/DungeonShooting_Godot/excel/excelFile/LiquidMaterial.xlsx +++ /dev/null Binary files differ diff --git a/DungeonShooting_Godot/excel/excelFile/Sound.xlsx b/DungeonShooting_Godot/excel/excelFile/Sound.xlsx deleted file mode 100644 index 6b4a890..0000000 --- a/DungeonShooting_Godot/excel/excelFile/Sound.xlsx +++ /dev/null Binary files differ diff --git a/DungeonShooting_Godot/excel/excelFile/WeaponBase.xlsx b/DungeonShooting_Godot/excel/excelFile/WeaponBase.xlsx deleted file mode 100644 index a669ff0..0000000 --- a/DungeonShooting_Godot/excel/excelFile/WeaponBase.xlsx +++ /dev/null Binary files differ diff --git a/DungeonShooting_Godot/export_presets.cfg b/DungeonShooting_Godot/export_presets.cfg index dec7e9c..e026db4 100644 --- a/DungeonShooting_Godot/export_presets.cfg +++ b/DungeonShooting_Godot/export_presets.cfg @@ -7,7 +7,7 @@ custom_features="" export_filter="all_resources" include_filter="" -exclude_filter="build/*" +exclude_filter="excel/*,build/*" export_path="build/android/build.apk" encryption_include_filters="" encryption_exclude_filters="" @@ -215,8 +215,8 @@ custom_features="" export_filter="all_resources" include_filter="" -exclude_filter="resource/map/tileMaps/*" -export_path="../../DungeonShooting_Export/windows/game.exe" +exclude_filter="resource/map/tileMaps/*,excel/*,build/*" +export_path="build/windows/game.exe" encryption_include_filters="" encryption_exclude_filters="" encrypt_pck=false diff --git a/DungeonShooting_Godot/prefab/ui/Setting.tscn b/DungeonShooting_Godot/prefab/ui/Setting.tscn index 85242df..d0eb890 100644 --- a/DungeonShooting_Godot/prefab/ui/Setting.tscn +++ b/DungeonShooting_Godot/prefab/ui/Setting.tscn @@ -1,7 +1,7 @@ [gd_scene load_steps=3 format=3 uid="uid://bnwweusrc44xy"] [ext_resource type="Script" path="res://src/game/ui/setting/SettingPanel.cs" id="1_ff0oi"] -[ext_resource type="Texture2D" uid="uid://cajcnlimvoxk" path="res://resource/sprite/ui/commonIcon/Back.png" id="2_vgl60"] +[ext_resource type="Texture2D" uid="uid://bd0kpqji660ta" path="res://resource/sprite/ui/commonIcon/Back.png" id="2_vgl60"] [node name="Setting" type="Control"] layout_mode = 3 @@ -302,6 +302,21 @@ layout_mode = 2 text = "空格" +[node name="Key14" type="HBoxContainer" parent="ScrollContainer/KeySetting"] +custom_minimum_size = Vector2(600, 0) +layout_mode = 2 +size_flags_horizontal = 4 +size_flags_vertical = 0 + +[node name="Name" type="Label" parent="ScrollContainer/KeySetting/Key14"] +layout_mode = 2 +size_flags_horizontal = 3 +text = "展开小地图" + +[node name="Value" type="Label" parent="ScrollContainer/KeySetting/Key14"] +layout_mode = 2 +text = "Ctrl" + [node name="Back" type="Button" parent="ScrollContainer/KeySetting"] layout_mode = 2 size_flags_horizontal = 4 diff --git a/DungeonShooting_Godot/resource/map/tileMaps/TestGroup1/inlet/Start1/Preinstall.json b/DungeonShooting_Godot/resource/map/tileMaps/TestGroup1/inlet/Start1/Preinstall.json index f5139d6..87b9dd1 100644 --- a/DungeonShooting_Godot/resource/map/tileMaps/TestGroup1/inlet/Start1/Preinstall.json +++ b/DungeonShooting_Godot/resource/map/tileMaps/TestGroup1/inlet/Start1/Preinstall.json @@ -1 +1 @@ -[{"Name":"test1","Weight":100,"Remark":"","WaveList":[[{"Position":{"X":0,"Y":0},"Size":{"X":14,"Y":16},"SpecialMarkType":1,"DelayTime":0,"MarkList":[]},{"Position":{"X":35,"Y":-27},"Size":{"X":30,"Y":12},"SpecialMarkType":0,"DelayTime":0,"MarkList":[{"Id":"weapon0001","Weight":100,"Attr":{"CurrAmmon":"30","ResidueAmmo":"210"},"Altitude":8,"VerticalSpeed":0}]},{"Position":{"X":8,"Y":32},"Size":{"X":16,"Y":16},"SpecialMarkType":0,"DelayTime":0,"MarkList":[{"Id":"weapon0002","Weight":100,"Attr":{"CurrAmmon":"7","ResidueAmmo":"70"},"Altitude":8,"VerticalSpeed":0}]},{"Position":{"X":-50,"Y":7},"Size":{"X":16,"Y":16},"SpecialMarkType":0,"DelayTime":0,"MarkList":[{"Id":"weapon0004","Weight":100,"Attr":{"CurrAmmon":"180","ResidueAmmo":"90"},"Altitude":8,"VerticalSpeed":0}]},{"Position":{"X":-63,"Y":-18},"Size":{"X":16,"Y":16},"SpecialMarkType":0,"DelayTime":0,"MarkList":[{"Id":"weapon0005","Weight":100,"Attr":{"CurrAmmon":"10","ResidueAmmo":"40"},"Altitude":8,"VerticalSpeed":0}]},{"Position":{"X":-31,"Y":-16},"Size":{"X":16,"Y":16},"SpecialMarkType":0,"DelayTime":0,"MarkList":[{"Id":"weapon0003","Weight":100,"Attr":{"CurrAmmon":"12","ResidueAmmo":"90"},"Altitude":8,"VerticalSpeed":0}]},{"Position":{"X":-54,"Y":33},"Size":{"X":16,"Y":16},"SpecialMarkType":0,"DelayTime":0,"MarkList":[{"Id":"weapon0006","Weight":100,"Attr":{"CurrAmmon":"20","ResidueAmmo":"300"},"Altitude":8,"VerticalSpeed":0}]},{"Position":{"X":2,"Y":-25},"Size":{"X":16,"Y":16},"SpecialMarkType":0,"DelayTime":0,"MarkList":[{"Id":"weapon0007","Weight":100,"Attr":{"CurrAmmon":"60","ResidueAmmo":"300"},"Altitude":8,"VerticalSpeed":0}]},{"Position":{"X":-76,"Y":21},"Size":{"X":16,"Y":16},"SpecialMarkType":0,"DelayTime":0,"MarkList":[{"Id":"weapon0008","Weight":100,"Attr":{"CurrAmmon":"10","ResidueAmmo":"120"},"Altitude":8,"VerticalSpeed":0}]},{"Position":{"X":-87,"Y":46},"Size":{"X":16,"Y":16},"SpecialMarkType":0,"DelayTime":0,"MarkList":[{"Id":"weapon0009","Weight":100,"Attr":{"CurrAmmon":"1","ResidueAmmo":"25"},"Altitude":8,"VerticalSpeed":0}]},{"Position":{"X":34,"Y":-1},"Size":{"X":24,"Y":16},"SpecialMarkType":0,"DelayTime":0,"MarkList":[{"Id":"prop0011","Weight":100,"Attr":null,"Altitude":8,"VerticalSpeed":0}]},{"Position":{"X":45,"Y":55},"Size":{"X":16,"Y":16},"SpecialMarkType":0,"DelayTime":0,"MarkList":[{"Id":"prop0012","Weight":100,"Attr":null,"Altitude":8,"VerticalSpeed":0}]},{"Position":{"X":-90,"Y":-26},"Size":{"X":13,"Y":16},"SpecialMarkType":0,"DelayTime":0,"MarkList":[{"Id":"prop0013","Weight":100,"Attr":null,"Altitude":8,"VerticalSpeed":0}]},{"Position":{"X":-91,"Y":-6},"Size":{"X":14,"Y":13},"SpecialMarkType":0,"DelayTime":0,"MarkList":[{"Id":"prop0014","Weight":100,"Attr":null,"Altitude":8,"VerticalSpeed":0}]},{"Position":{"X":-73,"Y":66},"Size":{"X":14,"Y":14},"SpecialMarkType":0,"DelayTime":0,"MarkList":[{"Id":"prop5001","Weight":100,"Attr":null,"Altitude":8,"VerticalSpeed":0}]}],[{"Position":{"X":72,"Y":62},"Size":{"X":16,"Y":16},"SpecialMarkType":0,"DelayTime":0,"MarkList":[{"Id":"prop0003","Weight":100,"Attr":null,"Altitude":8,"VerticalSpeed":0}]},{"Position":{"X":67,"Y":28},"Size":{"X":16,"Y":17},"SpecialMarkType":0,"DelayTime":0.5,"MarkList":[{"Id":"prop5000","Weight":100,"Attr":null,"Altitude":8,"VerticalSpeed":0}]},{"Position":{"X":67,"Y":-12},"Size":{"X":16,"Y":16},"SpecialMarkType":0,"DelayTime":1,"MarkList":[{"Id":"prop5001","Weight":100,"Attr":null,"Altitude":8,"VerticalSpeed":0}]},{"Position":{"X":36,"Y":25},"Size":{"X":16,"Y":16},"SpecialMarkType":0,"DelayTime":1.5,"MarkList":[{"Id":"prop0002","Weight":100,"Attr":null,"Altitude":8,"VerticalSpeed":0}]},{"Position":{"X":-24,"Y":8},"Size":{"X":18,"Y":16},"SpecialMarkType":0,"DelayTime":0,"MarkList":[{"Id":"prop0010","Weight":100,"Attr":null,"Altitude":8,"VerticalSpeed":0}]},{"Position":{"X":-20,"Y":34},"Size":{"X":16,"Y":16},"SpecialMarkType":0,"DelayTime":0,"MarkList":[{"Id":"prop0010","Weight":100,"Attr":null,"Altitude":8,"VerticalSpeed":0},{"Id":"prop0006","Weight":100,"Attr":null,"Altitude":8,"VerticalSpeed":0}]}]]},{"Name":"test2","Weight":100,"Remark":"","WaveList":[[{"Position":{"X":0,"Y":0},"Size":{"X":0,"Y":0},"SpecialMarkType":1,"DelayTime":0,"MarkList":[]}]]}] \ No newline at end of file +[{"Name":"test1","Weight":100,"Remark":"","WaveList":[[{"Position":{"X":0,"Y":0},"Size":{"X":14,"Y":16},"SpecialMarkType":1,"DelayTime":0,"MarkList":[]},{"Position":{"X":35,"Y":-27},"Size":{"X":30,"Y":12},"SpecialMarkType":0,"DelayTime":0,"MarkList":[{"Id":"weapon0001","Weight":100,"Attr":{"CurrAmmon":"30","ResidueAmmo":"210"},"Altitude":8,"VerticalSpeed":0}]},{"Position":{"X":8,"Y":32},"Size":{"X":16,"Y":16},"SpecialMarkType":0,"DelayTime":0,"MarkList":[{"Id":"weapon0002","Weight":100,"Attr":{"CurrAmmon":"7","ResidueAmmo":"70"},"Altitude":8,"VerticalSpeed":0}]},{"Position":{"X":-50,"Y":7},"Size":{"X":16,"Y":16},"SpecialMarkType":0,"DelayTime":0,"MarkList":[{"Id":"weapon0004","Weight":100,"Attr":{"CurrAmmon":"180","ResidueAmmo":"90"},"Altitude":8,"VerticalSpeed":0}]},{"Position":{"X":-63,"Y":-18},"Size":{"X":16,"Y":16},"SpecialMarkType":0,"DelayTime":0,"MarkList":[{"Id":"weapon0005","Weight":100,"Attr":{"CurrAmmon":"10","ResidueAmmo":"40"},"Altitude":8,"VerticalSpeed":0}]},{"Position":{"X":-31,"Y":-16},"Size":{"X":16,"Y":16},"SpecialMarkType":0,"DelayTime":0,"MarkList":[{"Id":"weapon0003","Weight":100,"Attr":{"CurrAmmon":"12","ResidueAmmo":"90"},"Altitude":8,"VerticalSpeed":0}]},{"Position":{"X":-54,"Y":33},"Size":{"X":16,"Y":16},"SpecialMarkType":0,"DelayTime":0,"MarkList":[{"Id":"weapon0006","Weight":100,"Attr":{"CurrAmmon":"20","ResidueAmmo":"300"},"Altitude":8,"VerticalSpeed":0}]},{"Position":{"X":2,"Y":-25},"Size":{"X":16,"Y":16},"SpecialMarkType":0,"DelayTime":0,"MarkList":[{"Id":"weapon0007","Weight":100,"Attr":{"CurrAmmon":"60","ResidueAmmo":"300"},"Altitude":8,"VerticalSpeed":0}]},{"Position":{"X":-76,"Y":21},"Size":{"X":16,"Y":16},"SpecialMarkType":0,"DelayTime":0,"MarkList":[{"Id":"weapon0008","Weight":100,"Attr":{"CurrAmmon":"10","ResidueAmmo":"120"},"Altitude":8,"VerticalSpeed":0}]},{"Position":{"X":-87,"Y":46},"Size":{"X":16,"Y":16},"SpecialMarkType":0,"DelayTime":0,"MarkList":[{"Id":"weapon0009","Weight":100,"Attr":{"CurrAmmon":"1","ResidueAmmo":"25"},"Altitude":8,"VerticalSpeed":0}]},{"Position":{"X":34,"Y":-1},"Size":{"X":24,"Y":16},"SpecialMarkType":0,"DelayTime":0,"MarkList":[{"Id":"prop0011","Weight":100,"Attr":null,"Altitude":8,"VerticalSpeed":0}]},{"Position":{"X":45,"Y":55},"Size":{"X":16,"Y":16},"SpecialMarkType":0,"DelayTime":0,"MarkList":[{"Id":"prop0012","Weight":100,"Attr":null,"Altitude":8,"VerticalSpeed":0}]},{"Position":{"X":-90,"Y":-26},"Size":{"X":13,"Y":16},"SpecialMarkType":0,"DelayTime":0,"MarkList":[{"Id":"prop0013","Weight":100,"Attr":null,"Altitude":8,"VerticalSpeed":0}]},{"Position":{"X":-91,"Y":-6},"Size":{"X":14,"Y":13},"SpecialMarkType":0,"DelayTime":0,"MarkList":[{"Id":"prop0014","Weight":100,"Attr":null,"Altitude":8,"VerticalSpeed":0}]},{"Position":{"X":-73,"Y":66},"Size":{"X":14,"Y":14},"SpecialMarkType":0,"DelayTime":0,"MarkList":[{"Id":"prop5001","Weight":100,"Attr":null,"Altitude":8,"VerticalSpeed":0}]}],[{"Position":{"X":72,"Y":62},"Size":{"X":16,"Y":16},"SpecialMarkType":0,"DelayTime":0,"MarkList":[{"Id":"prop0003","Weight":100,"Attr":null,"Altitude":8,"VerticalSpeed":0}]},{"Position":{"X":67,"Y":28},"Size":{"X":16,"Y":17},"SpecialMarkType":0,"DelayTime":0.5,"MarkList":[{"Id":"prop5000","Weight":100,"Attr":null,"Altitude":8,"VerticalSpeed":0}]},{"Position":{"X":67,"Y":-12},"Size":{"X":16,"Y":16},"SpecialMarkType":0,"DelayTime":1,"MarkList":[{"Id":"prop5001","Weight":100,"Attr":null,"Altitude":8,"VerticalSpeed":0}]},{"Position":{"X":36,"Y":25},"Size":{"X":16,"Y":16},"SpecialMarkType":0,"DelayTime":1.5,"MarkList":[{"Id":"prop0002","Weight":100,"Attr":null,"Altitude":8,"VerticalSpeed":0}]},{"Position":{"X":-24,"Y":8},"Size":{"X":18,"Y":16},"SpecialMarkType":0,"DelayTime":0,"MarkList":[{"Id":"prop0010","Weight":100,"Attr":null,"Altitude":8,"VerticalSpeed":0}]},{"Position":{"X":-20,"Y":34},"Size":{"X":16,"Y":16},"SpecialMarkType":0,"DelayTime":0,"MarkList":[{"Id":"prop0010","Weight":100,"Attr":null,"Altitude":8,"VerticalSpeed":0},{"Id":"prop0006","Weight":100,"Attr":null,"Altitude":8,"VerticalSpeed":0}]}]]}] \ No newline at end of file diff --git a/DungeonShooting_Godot/resource/theme/mainTheme.tres b/DungeonShooting_Godot/resource/theme/mainTheme.tres index 4c042ce..d37dfbb 100644 --- a/DungeonShooting_Godot/resource/theme/mainTheme.tres +++ b/DungeonShooting_Godot/resource/theme/mainTheme.tres @@ -1,6 +1,6 @@ [gd_resource type="Theme" load_steps=61 format=3 uid="uid://ds668te2rph30"] -[ext_resource type="FontFile" uid="uid://cad0in7dtweo5" path="res://resource/font/VonwaonBitmap-16px.ttf" id="1_1e6k7"] +[ext_resource type="FontFile" uid="uid://l2h5n3elepgp" path="res://resource/font/VonwaonBitmap-16px.ttf" id="1_1e6k7"] [sub_resource type="StyleBoxFlat" id="2"] content_margin_left = 6.0 diff --git a/DungeonShooting_Godot/src/framework/generator/DungeonRoomGenerator.cs b/DungeonShooting_Godot/src/framework/generator/DungeonRoomGenerator.cs deleted file mode 100644 index 28229bc..0000000 --- a/DungeonShooting_Godot/src/framework/generator/DungeonRoomGenerator.cs +++ /dev/null @@ -1,255 +0,0 @@ - -#if TOOLS - -using System; -using System.Collections.Generic; -using System.IO; -using System.Linq; -using System.Text.Json; -using Godot; - -namespace Generator; - -/// -/// 地牢房间数据生成器 -/// -public static class DungeonRoomGenerator -{ - /// - /// 根据名称在编辑器中创建地牢的预制房间, open 表示创建完成后是否在编辑器中打开这个房间 - /// - public static bool CreateDungeonRoom(string groupName, string roomType, string roomName, bool open = false) - { - try - { - var path = GameConfig.RoomTileDir + groupName + "/" + roomType; - if (!Directory.Exists(path)) - { - Directory.CreateDirectory(path); - } - //创建场景资源 - var prefabFile = path + "/" + roomName + ".tscn"; - var prefabResPath = "res://" + prefabFile; - if (!Directory.Exists(GameConfig.RoomTileDir)) - { - Directory.CreateDirectory(GameConfig.RoomTileDir); - } - - //加载脚本资源 - - // 这段代码在 Godot4.0.1rc1中会报错, 应该是个bug - // var scriptRes = GD.Load("res://src/framework/map/DungeonRoomTemplate.cs"); - // var tileMap = new TileMap(); - // tileMap.Name = roomName; - // tileMap.SetScript(scriptRes); - // var scene = new PackedScene(); - // scene.Pack(tileMap); //报错在这一行, 报的是访问了被销毁的资源 scriptRes - // ResourceSaver.Save(scene, prefabResPath); - - //临时处理 - { - var tscnCode = $"[gd_scene load_steps=2 format=3]\n" + - $"\n" + - $"[ext_resource type=\"Script\" path=\"res://src/framework/map/DungeonRoomTemplate.cs\" id=\"dungeonRoomTemplate\"]\n" + - $"\n" + - $"[node name=\"{roomName}\" type=\"TileMap\"]\n" + - $"format = 2\n" + - $"script = ExtResource(\"dungeonRoomTemplate\")\n"; - File.WriteAllText(prefabFile, tscnCode); - //重新保存一遍, 以让编辑器生成资源Id - var scene = GD.Load(prefabResPath); - ResourceSaver.Save(scene, prefabResPath); - } - - //打包房间配置 - GenerateRoomConfig(); - - //生成 UiManager_Methods.cs 代码 - UiManagerMethodsGenerator.Generate(); - //打开房间 - if (open) - { - Plugin.Plugin.Instance.GetEditorInterface().OpenSceneFromPath(prefabResPath); - } - } - catch (Exception e) - { - Debug.LogError(e.ToString()); - return false; - } - - return true; - } - - /// - /// 执行生成 RoomConfig.json 操作, 返回是否执行成功 - /// - public static bool GenerateRoomConfig() - { - Debug.Log("生成RoomConfig.json流程得改"); - // try - // { - // //地图路径 - // var tileDir = GameConfig.RoomTileDir; - // //地图描述数据路径 - // var tileDataDir = GameConfig.RoomTileDataDir; - // - // var tileGroup = new DirectoryInfo(tileDir).GetDirectories(); - // var tileDataGroup = new DirectoryInfo(tileDataDir).GetDirectories(); - // - // //所有地图列表 - // var map = new Dictionary(); - // - // //地图场景 - // foreach (var groupDir in tileGroup) - // { - // var groupName = groupDir.Name; - // var typeDirArray = groupDir.GetDirectories(); - // //遍历枚举, 获取指定路径文件 - // foreach (DungeonRoomType roomType in Enum.GetValues(typeof(DungeonRoomType))) - // { - // var typeName = DungeonManager.DungeonRoomTypeToString(roomType); - // - // //收集所有文件名称 - // var tempFileDataInfos = typeDirArray.FirstOrDefault(dirInfo => dirInfo.Name == typeName); - // if (tempFileDataInfos != null) - // { - // foreach (var fileInfo in tempFileDataInfos.GetFiles()) - // { - // if (fileInfo.Extension == ".tscn") - // { - // var pathInfo = new FileInfo(groupName, roomType, typeName, ResourceManager.RemoveExtension(fileInfo.Name)); - // map.TryAdd(pathInfo.GetPath(), pathInfo); - // } - // } - // } - // } - // } - // - // //地图配置数据 - // foreach (var groupDir in tileDataGroup) - // { - // var groupName = groupDir.Name; - // var typeDirArray = groupDir.GetDirectories(); - // //遍历枚举, 获取指定路径文件 - // foreach (DungeonRoomType roomType in Enum.GetValues(typeof(DungeonRoomType))) - // { - // var typeName = DungeonManager.DungeonRoomTypeToString(roomType); - // - // //收集所有文件名称 - // var tempFileDataInfos = typeDirArray.FirstOrDefault(dirInfo => dirInfo.Name == typeName); - // if (tempFileDataInfos != null) - // { - // foreach (var fileInfo in tempFileDataInfos.GetFiles()) - // { - // if (fileInfo.Extension == ".json") - // { - // var pathInfo = new FileInfo(groupName, roomType, typeName, ResourceManager.RemoveExtension(fileInfo.Name)); - // map.TryAdd(pathInfo.GetPath(), pathInfo); - // } - // } - // } - // } - // } - // - // //剔除多余的 tile.json - // foreach (var item in map) - // { - // var path = item.Key; - // if (!File.Exists(tileDir + path + ".tscn")) - // { - // map.Remove(path); - // var filePath = tileDataDir + path + ".json"; - // if (File.Exists(filePath)) - // { - // Debug.Log($"未找到'{tileDir + path}.tscn', 删除配置文件: {filePath}"); - // File.Delete(filePath); - // } - // } - // } - // - // //手动生成缺失的 tile.json - // foreach (var item in map) - // { - // if (!File.Exists(tileDataDir + item.Key + ".json")) - // { - // var tscnName = tileDir + item.Key + ".tscn"; - // var packedScene = ResourceManager.Load(tscnName, false); - // if (packedScene != null) - // { - // var dungeonRoomTemplate = packedScene.Instantiate(); - // var usedRect = dungeonRoomTemplate.GetUsedRect(); - // var dungeonTile = new DungeonTileMap(dungeonRoomTemplate); - // dungeonTile.SetFloorAtlasCoords(new List() { new Vector2I(0, 8) }); - // //计算导航网格 - // dungeonTile.GenerateNavigationPolygon(0); - // - // DungeonRoomInfo.SaveConfig(new List(), usedRect.Position, usedRect.Size, - // item.Value.GroupName, item.Value.RoomType, item.Value.FileName, dungeonRoomTemplate.Weight); - // dungeonRoomTemplate.QueueFree(); - // } - // } - // } - // - // var roomGroupMap = new Dictionary(); - // //var list = new List(); - // //整合操作 - // foreach (var item in map) - // { - // var path = item.Key; - // var configPath = tileDataDir + path + ".json"; - // var split = new DungeonRoomSplit(); - // split.ScenePath = ResourceManager.ToResPath(tileDir + path + ".tscn"); - // split.RoomPath = ResourceManager.ToResPath(configPath); - // - // if (!roomGroupMap.TryGetValue(item.Value.GroupName, out var group)) - // { - // group = new DungeonRoomGroup(); - // group.GroupName = item.Value.GroupName; - // roomGroupMap.Add(group.GroupName, group); - // } - // - // group.GetRoomList(item.Value.RoomType).Add(split); - // } - // - // //写出配置 - // var config = new JsonSerializerOptions(); - // config.WriteIndented = true; - // var text = JsonSerializer.Serialize(roomGroupMap, config); - // File.WriteAllText(GameConfig.RoomTileConfigFile, text); - // - // Debug.Log("地牢房间配置, 重新打包完成!"); - // } - // catch (Exception e) - // { - // Debug.LogError(e.ToString()); - // return false; - // } - - return true; - } - - private class FileInfo - { - public FileInfo(string groupName, DungeonRoomType roomType, string typeName, string fileName) - { - GroupName = groupName; - RoomType = roomType; - TypeName = typeName; - FileName = fileName; - } - - public string GroupName; - public DungeonRoomType RoomType; - public string TypeName; - public string FileName; - - public string GetPath() - { - return GroupName + "/" + TypeName + "/" + FileName; - } - } -} - - -#endif \ No newline at end of file diff --git a/DungeonShooting_Godot/src/framework/generator/ExcelGenerator.cs b/DungeonShooting_Godot/src/framework/generator/ExcelGenerator.cs deleted file mode 100644 index 86bfa6d..0000000 --- a/DungeonShooting_Godot/src/framework/generator/ExcelGenerator.cs +++ /dev/null @@ -1,76 +0,0 @@ -#if TOOLS - -using System; -using System.IO; -using System.Text.Json; -using Config; -using Godot; -using Array = Godot.Collections.Array; - -namespace Generator; - -public static class ExcelGenerator -{ - public static void ExportExcel() - { - var arr = new Array(); - var excelPath = "excel/excelFile/"; - var jsonPath = "resource/config/"; - var codePath = "src/config/"; - OS.Execute("excel/DungeonShooting_ExcelTool.exe", new string[] { excelPath, jsonPath, codePath }, arr); - foreach (var message in arr) - { - Debug.Log(message); - } - - try - { - GeneratorActivityObjectInit(); - Debug.Log("生成'src/framework/activity/ActivityObject_Init.cs'成功!"); - } - catch (Exception e) - { - Debug.LogError(e.ToString()); - } - } - - //生成初始化 ActivityObject 代码 - private static void GeneratorActivityObjectInit() - { - var text = File.ReadAllText($"resource/config/{nameof(ExcelConfig.ActivityBase)}.json"); - var array = JsonSerializer.Deserialize[]>(text); - - var code1 = ""; - - foreach (var item in array) - { - var id = item["Id"]; - var name = item["Name"] + ""; - var intro = item["Intro"] + ""; - code1 += $" /// \n"; - code1 += $" /// 名称: {name}
\n"; - code1 += $" /// 简介: {intro.Replace("\n", "
\n /// ")}\n"; - code1 += $" ///
\n"; - code1 += $" public const string Id_{id} = \"{id}\";\n"; - } - - var str = $"using Config;\n\n"; - str += $"// 根据配置表注册物体, 该类是自动生成的, 请不要手动编辑!\n"; - str += $"public partial class ActivityObject\n"; - str += $"{{\n"; - - str += $" /// \n"; - str += $" /// 存放所有在表中注册的物体的id\n"; - str += $" /// \n"; - str += $" public static class Ids\n"; - str += $" {{\n"; - str += code1; - str += $" }}\n"; - - str += $"}}\n"; - - File.WriteAllText("src/framework/activity/ActivityObject_Init.cs", str); - } -} - -#endif \ No newline at end of file diff --git a/DungeonShooting_Godot/src/framework/generator/ResourcePathGenerator.cs b/DungeonShooting_Godot/src/framework/generator/ResourcePathGenerator.cs deleted file mode 100644 index 739d9da..0000000 --- a/DungeonShooting_Godot/src/framework/generator/ResourcePathGenerator.cs +++ /dev/null @@ -1,129 +0,0 @@ -#if TOOLS - -using System; -using System.IO; -using System.Linq; -using System.Text.RegularExpressions; -using Godot; - -namespace Generator; - -/// -/// ResourcePath 类文件生成器 -/// -public static class ResourcePathGenerator -{ - //支持后缀 - private static string[] suffix = - { - ".png", - ".jpg", - ".txt", - ".json", - ".ini", - ".tscn", - ".tres", - ".otf", - ".gdshader", - ".ogg", - ".mp3", - ".wav", - ".svg", - ".ttf", - ".otf" - }; - //排除的文件夹, 斜杠用: / - private static string[] exclude = - { - ".vscode", - ".idea", - ".git", - ".import", - ".mono", - "android", - "addons", - ".godot", - ".vs", - "resource/map/tiledata", - "resource/map/tileMaps" - }; - - private static string resultStr = ""; - - //保存路径 - private static string savePath = "src/game/manager/ResourcePath.cs"; - - /// - /// 执行生成操作, 返回是否执行成功 - /// - public static bool Generate() - { - try - { - resultStr = "/// \n" + - "/// 编辑器下所有资源路径, 该类为 Tools 面板下自动生成的, 请不要手动编辑!\n" + - "/// \n" + - "public class ResourcePath\n" + - "{\n"; - - Debug.Log("更新 ResourcePath..."); - - var directoryInfo = new DirectoryInfo(System.Environment.CurrentDirectory); - EachDir(directoryInfo); - - resultStr += "}"; - File.WriteAllText(savePath, resultStr); - Debug.Log("ResourcePath.cs 写出完成!"); - } - catch (Exception e) - { - Debug.LogError(e.ToString()); - return false; - } - - return true; - } - - private static void EachDir(DirectoryInfo directoryInfos) - { - if (directoryInfos.FullName.Length > System.Environment.CurrentDirectory.Length) - { - var path = directoryInfos.FullName.Substring(System.Environment.CurrentDirectory.Length + 1); - path = path.Replace('\\', '/'); - if (exclude.Contains(path)) - { - Debug.Log("扫描排除路径: " + path); - return; - } - } - - var fileInfos = directoryInfos.GetFiles(); - for (var i = 0; i < fileInfos.Length; i++) - { - HandleFile(fileInfos[i]); - } - - var directories = directoryInfos.GetDirectories(); - for (var i = 0; i < directories.Length; i++) - { - EachDir(directories[i]); - } - } - - private static void HandleFile(FileInfo fileInfo) - { - if (suffix.Contains(fileInfo.Extension)) - { - var field = fileInfo.FullName.Substring(System.Environment.CurrentDirectory.Length + 1); - field = field.Replace("\\", "/"); - var resPath = "res://" + field; - field = field.Replace(".", "_"); - field = field.Replace("/", "_"); - field = Regex.Replace(field, "[^\\w]", ""); - resultStr += $" public const string {field} = \"{resPath}\";\n"; - } - } - -} - -#endif \ No newline at end of file diff --git a/DungeonShooting_Godot/src/framework/generator/UiGenerator.cs b/DungeonShooting_Godot/src/framework/generator/UiGenerator.cs deleted file mode 100644 index 3a84f2a..0000000 --- a/DungeonShooting_Godot/src/framework/generator/UiGenerator.cs +++ /dev/null @@ -1,509 +0,0 @@ -#if TOOLS - -using System; -using System.Collections.Generic; -using System.IO; -using System.Text.RegularExpressions; -using Godot; - -namespace Generator; - -/// -/// Ui类生成器 -/// -public static class UiGenerator -{ - private static Dictionary _nodeNameMap = new Dictionary(); - private static int _nestedIndex = 1; - - /// - /// 根据名称在编辑器中创建Ui, open 表示创建完成后是否在编辑器中打开这个ui - /// - public static bool CreateUi(string uiName, bool open = false) - { - try - { - //创建脚本代码 - var scriptPath = GameConfig.UiCodeDir + uiName.FirstToLower(); - var scriptFile = scriptPath + "/" + uiName + "Panel.cs"; - var scriptCode = $"using Godot;\n" + - $"\n" + - $"namespace UI.{uiName};\n" + - $"\n" + - $"public partial class {uiName}Panel : {uiName}\n" + - $"{{\n" + - $"\n" + - $" public override void OnCreateUi()\n" + - $" {{\n" + - $" \n" + - $" }}\n" + - $"\n" + - $" public override void OnDestroyUi()\n" + - $" {{\n" + - $" \n" + - $" }}\n" + - $"\n" + - $"}}\n"; - if (!Directory.Exists(scriptPath)) - { - Directory.CreateDirectory(scriptPath); - } - File.WriteAllText(scriptFile, scriptCode); - - //加载脚本资源 - var scriptRes = GD.Load("res://" + scriptFile); - - //创建场景资源 - var prefabFile = GameConfig.UiPrefabDir + uiName + ".tscn"; - var prefabResPath = "res://" + prefabFile; - if (!Directory.Exists(GameConfig.UiPrefabDir)) - { - Directory.CreateDirectory(GameConfig.UiPrefabDir); - } - var uiNode = new Control(); - uiNode.Name = uiName; - uiNode.SetAnchorsPreset(Control.LayoutPreset.FullRect, true); - uiNode.SetScript(scriptRes); - var scene = new PackedScene(); - scene.Pack(uiNode); - ResourceSaver.Save(scene, prefabResPath); - - //生成Ui结构代码 - GenerateUiCode(uiNode, scriptPath + "/" + uiName + ".cs"); - - //生成 ResourcePath.cs 代码 - ResourcePathGenerator.Generate(); - - //生成 UiManager_Methods.cs 代码 - UiManagerMethodsGenerator.Generate(); - - //打开ui - if (open) - { - Plugin.Plugin.Instance.GetEditorInterface().OpenSceneFromPath(prefabResPath); - } - - } - catch (Exception e) - { - Debug.LogError(e.ToString()); - return false; - } - - return true; - } - - /// - /// 根据指定ui节点生成相应的Ui类, 并保存到指定路径下 - /// - public static void GenerateUiCode(Node control, string path) - { - _nodeNameMap.Clear(); - _nestedIndex = 1; - var uiNode = EachNodeFromEditor(control.Name, control); - var code = GenerateClassCode(uiNode); - File.WriteAllText(path, code); - } - - /// - /// 从编辑器中生成ui代码 - /// - public static bool GenerateUiCodeFromEditor(Node control) - { - try - { - _nodeNameMap.Clear(); - _nestedIndex = 1; - - var uiName = control.Name.ToString(); - var path = GameConfig.UiCodeDir + uiName.FirstToLower() + "/" + uiName + ".cs"; - Debug.Log("重新生成ui代码: " + path); - - var uiNode = EachNodeFromEditor(control.Name, control); - var code = GenerateClassCode(uiNode); - - foreach (var pair in _nodeNameMap) - { - if (pair.Value > 1) - { - Debug.Log($"检测到同名节点: '{pair.Key}', 使用该名称的节点将无法生成唯一节点属性!"); - } - } - - File.WriteAllText(path, code); - } - catch (Exception e) - { - Debug.LogError(e.ToString()); - return false; - } - - return true; - } - - private static string GenerateClassCode(UiNodeInfo uiNodeInfo) - { - var retraction = " "; - return $"namespace UI.{uiNodeInfo.OriginName};\n\n" + - $"/// \n" + - $"/// Ui代码, 该类是根据ui场景自动生成的, 请不要手动编辑该类, 以免造成代码丢失\n" + - $"/// \n" + - $"public abstract partial class {uiNodeInfo.OriginName} : UiBase\n" + - $"{{\n" + - GeneratePropertyListClassCode("", uiNodeInfo.OriginName + ".", uiNodeInfo, retraction) + - $"\n" + - $" public {uiNodeInfo.OriginName}() : base(nameof({uiNodeInfo.OriginName}))\n" + - $" {{\n" + - $" }}\n" + - $"\n" + - $" public sealed override void OnInitNestedUi()\n" + - $" {{\n" + - GenerateUiScriptCode("", uiNodeInfo, retraction) + - $"\n" + - GenerateInitNestedUi("", uiNodeInfo, retraction) + - $" }}\n" + - $"\n" + - GenerateAllChildrenClassCode(uiNodeInfo.OriginName + ".", uiNodeInfo, retraction) + - $"\n" + - GenerateSoleLayerCode(uiNodeInfo, "", uiNodeInfo.OriginName, retraction) + - $"}}\n"; - } - - private static string GenerateUiScriptCode(string parent, UiNodeInfo uiNodeInfo, string retraction) - { - var str = ""; - var node = parent + (string.IsNullOrEmpty(parent) ? "" : ".") + uiNodeInfo.Name; - if (uiNodeInfo.IsNodeScript) - { - str += retraction + $" _ = {node};\n"; - } - else - { - if (uiNodeInfo.Children != null) - { - for (var i = 0; i < uiNodeInfo.Children.Count; i++) - { - var item = uiNodeInfo.Children[i]; - if (uiNodeInfo.OriginName == uiNodeInfo.UiRootName) - { - str += GenerateUiScriptCode("", item, retraction); - } - else - { - str += GenerateUiScriptCode(node, item, retraction); - } - } - } - } - - return str; - } - - private static string GenerateInitNestedUi(string parent, UiNodeInfo uiNodeInfo, string retraction) - { - var str = ""; - if (uiNodeInfo.IsRefUi) - { - var parentUi = "inst" + _nestedIndex++; - var uiNode = $"{parentUi}.{uiNodeInfo.Name}.Instance"; - var parentNode = string.IsNullOrEmpty(parent) ? "this" : parent; - var parentNode2 = string.IsNullOrEmpty(parent) ? "null" : parentUi; - str += retraction + $" var {parentUi} = {parentNode};\n"; - str += retraction + $" RecordNestedUi({uiNode}, {parentNode2}, UiManager.RecordType.Open);\n"; - str += retraction + $" {uiNode}.OnCreateUi();\n"; - str += retraction + $" {uiNode}.OnInitNestedUi();\n\n"; - } - else - { - if (uiNodeInfo.Children != null) - { - for (var i = 0; i < uiNodeInfo.Children.Count; i++) - { - var item = uiNodeInfo.Children[i]; - if (uiNodeInfo.OriginName == uiNodeInfo.UiRootName) - { - str += GenerateInitNestedUi("", item, retraction); - } - else - { - str += GenerateInitNestedUi(parent + (string.IsNullOrEmpty(parent)? "" : ".") + uiNodeInfo.Name, item, retraction); - } - } - } - } - - return str; - } - - private static string GenerateAllChildrenClassCode(string parent, UiNodeInfo uiNodeInfo, string retraction) - { - var str = ""; - if (uiNodeInfo.Children != null) - { - for (var i = 0; i < uiNodeInfo.Children.Count; i++) - { - var item = uiNodeInfo.Children[i]; - str += GenerateAllChildrenClassCode(parent + item.OriginName + ".", item, retraction); - str += GenerateChildrenClassCode(parent, item, retraction); - } - } - - return str; - } - - private static string GenerateChildrenClassCode(string parent, UiNodeInfo uiNodeInfo, string retraction) - { - string cloneCode; - - if (uiNodeInfo.IsRefUi) - { - cloneCode = retraction + $" public override {uiNodeInfo.ClassName} Clone()\n"; - cloneCode += retraction + $" {{\n"; - cloneCode += retraction + $" var uiNode = new {uiNodeInfo.ClassName}(UiPanel, ({uiNodeInfo.NodeTypeName})Instance.Duplicate());\n"; - cloneCode += retraction + $" UiPanel.RecordNestedUi(uiNode.Instance, this, UiManager.RecordType.Open);\n"; - cloneCode += retraction + $" uiNode.Instance.OnCreateUi();\n"; - cloneCode += retraction + $" uiNode.Instance.OnInitNestedUi();\n"; - cloneCode += retraction + $" return uiNode;\n"; - cloneCode += retraction + $" }}\n"; - } - else - { - cloneCode = retraction + $" public override {uiNodeInfo.ClassName} Clone() => new (UiPanel, ({uiNodeInfo.NodeTypeName})Instance.Duplicate());\n"; - } - - return retraction + $"/// \n" + - retraction + $"/// 类型: , 路径: {parent}{uiNodeInfo.OriginName}\n" + - retraction + $"/// \n" + - retraction + $"public class {uiNodeInfo.ClassName} : UiNode<{uiNodeInfo.UiRootName}Panel, {uiNodeInfo.NodeTypeName}, {uiNodeInfo.ClassName}>\n" + - retraction + $"{{\n" + - GeneratePropertyListClassCode("Instance.", parent, uiNodeInfo, retraction + " ") + - retraction + $" public {uiNodeInfo.ClassName}({uiNodeInfo.UiRootName}Panel uiPanel, {uiNodeInfo.NodeTypeName} node) : base(uiPanel, node) {{ }}\n" + - cloneCode + - retraction + $"}}\n\n"; - } - - private static string GeneratePropertyListClassCode(string target, string parent, UiNodeInfo uiNodeInfo, string retraction) - { - var str = ""; - if (uiNodeInfo.Children != null) - { - for (var i = 0; i < uiNodeInfo.Children.Count; i++) - { - var item = uiNodeInfo.Children[i]; - str += GeneratePropertyCode(target, parent, item, retraction); - } - } - - return str; - } - - private static string GeneratePropertyCode(string target, string parent, UiNodeInfo uiNodeInfo, string retraction) - { - string uiPanel; - if (string.IsNullOrEmpty(target)) - { - uiPanel = $"({uiNodeInfo.UiRootName}Panel)this"; - } - else - { - uiPanel = "UiPanel"; - } - return retraction + $"/// \n" + - retraction + $"/// 使用 Instance 属性获取当前节点实例对象, 节点类型: , 节点路径: {parent}{uiNodeInfo.OriginName}\n" + - retraction + $"/// \n" + - retraction + $"public {uiNodeInfo.ClassName} {uiNodeInfo.Name}\n" + - retraction + $"{{\n" + - retraction + $" get\n" + - retraction + $" {{\n" + - retraction + $" if (_{uiNodeInfo.Name} == null) _{uiNodeInfo.Name} = new {uiNodeInfo.ClassName}({uiPanel}, {target}GetNode<{uiNodeInfo.NodeTypeName}>(\"{uiNodeInfo.OriginName}\"));\n" + - retraction + $" return _{uiNodeInfo.Name};\n" + - retraction + $" }}\n" + - retraction + $"}}\n" + - retraction + $"private {uiNodeInfo.ClassName} _{uiNodeInfo.Name};\n\n"; - } - - private static string GenerateSoleLayerCode(UiNodeInfo uiNodeInfo, string layerName, string parent, string retraction) - { - var str = ""; - if (uiNodeInfo.Children != null) - { - foreach (var nodeInfo in uiNodeInfo.Children) - { - var layer = layerName; - if (layerName.Length > 0) - { - layer += "."; - } - - layer += nodeInfo.Name; - var path = parent + "." + nodeInfo.OriginName; - str += GenerateSoleLayerCode(nodeInfo, layer, path, retraction); - if (IsSoleNameNode(nodeInfo)) - { - str += $"{retraction}/// \n"; - str += $"{retraction}/// 场景中唯一名称的节点, 节点类型: , 节点路径: {path}\n"; - str += $"{retraction}/// \n"; - str += $"{retraction}public {nodeInfo.ClassName} S_{nodeInfo.OriginName} => {layer};\n\n"; - } - } - } - return str; - } - - //返回指定节点在当前场景中是否是唯一名称的节点 - private static bool IsSoleNameNode(UiNodeInfo uiNodeInfo) - { - if (!_nodeNameMap.TryGetValue(uiNodeInfo.OriginName, out var count)) - { - return true; - } - - return count <= 1; - } - - /// - /// 在编辑器下递归解析节点, 由于编辑器下绑定用户脚本的节点无法直接判断节点类型, 那么就只能获取节点的脚本然后解析名称和命名空间 - /// - private static UiNodeInfo EachNodeFromEditor(string uiRootName, Node node) - { - UiNodeInfo uiNode; - //原名称 - var originName = Regex.Replace(node.Name, "[^\\w]", ""); - //字段名称 - var fieldName = "L_" + originName; - //类定义该图层的类名 - string className; - if (_nodeNameMap.ContainsKey(originName)) //有同名图层, 为了防止类名冲突, 需要在 UiNode 后面加上索引 - { - var count = _nodeNameMap[originName]; - className = originName + "_" + count; - _nodeNameMap[originName] = count + 1; - } - else - { - className = originName; - _nodeNameMap.Add(originName, 1); - } - - var script = node.GetScript().As(); - if (script == null) //无脚本, 说明是内置节点 - { - uiNode = new UiNodeInfo(uiRootName, fieldName, originName, className, node.GetType().FullName, false); - } - else //存在脚本 - { - var index = script.ResourcePath.LastIndexOf("/", StringComparison.Ordinal); - //文件名称 - var fileName = script.ResourcePath.Substring(index + 1, script.ResourcePath.Length - index - 3 - 1); - //在源代码中寻找命名空间 - var match = Regex.Match(script.SourceCode, "(?<=namespace\\s+)[\\w\\.]+"); - bool isNodeScript; - if (match.Success) //存在命名空间 - { - isNodeScript = IsNodeScript(match.Value + "." + fileName); - uiNode = new UiNodeInfo(uiRootName, fieldName, originName, className, match.Value + "." + fileName, isNodeScript); - } - else //不存在命名空间 - { - isNodeScript = IsNodeScript(fileName); - uiNode = new UiNodeInfo(uiRootName, fieldName, originName, className, fileName, isNodeScript); - } - //检测是否是引用Ui - if (fileName.EndsWith("Panel")) - { - var childUiName = fileName.Substring(0, fileName.Length - 5); - if (childUiName != uiRootName && File.Exists(GameConfig.UiPrefabDir + childUiName + ".tscn")) - { - //是引用Ui - uiNode.IsRefUi = true; - } - } - } - - //如果是引用Ui, 就没有必要递归子节点了 - if (uiNode.IsRefUi) - { - return uiNode; - } - - var childCount = node.GetChildCount(); - if (childCount > 0) - { - for (var i = 0; i < childCount; i++) - { - var children = node.GetChild(i); - if (children != null) - { - if (uiNode.Children == null) - { - uiNode.Children = new List(); - } - - uiNode.Children.Add(EachNodeFromEditor(uiRootName, children)); - } - } - } - - return uiNode; - } - - private static bool IsNodeScript(string typeName) - { - var type = typeof(UiGenerator).Assembly.GetType(typeName); - if (type == null) - { - return false; - } - - return type.IsAssignableTo(typeof(IUiNodeScript)); - } - - private class UiNodeInfo - { - /// - /// 层级名称 - /// - public string Name; - /// - /// 层级原名称 - /// - public string OriginName; - /// - /// 层级类名 - /// - public string ClassName; - /// - /// Godot节点类型名称 - /// - public string NodeTypeName; - /// - /// 子节点 - /// - public List Children; - /// - /// Ui根节点名称 - /// - public string UiRootName; - /// - /// 是否实现了 IUiNodeScript 接口 - /// - public bool IsNodeScript; - /// - /// 是否是引用Ui - /// - public bool IsRefUi; - - public UiNodeInfo(string uiRootName, string name, string originName, string className, string nodeTypeName, bool isNodeScript) - { - UiRootName = uiRootName; - Name = name; - OriginName = originName; - ClassName = className; - NodeTypeName = nodeTypeName; - IsNodeScript = isNodeScript; - } - } - -} - -#endif \ No newline at end of file diff --git a/DungeonShooting_Godot/src/framework/generator/UiManagerMethodsGenerator.cs b/DungeonShooting_Godot/src/framework/generator/UiManagerMethodsGenerator.cs deleted file mode 100644 index cc33ef6..0000000 --- a/DungeonShooting_Godot/src/framework/generator/UiManagerMethodsGenerator.cs +++ /dev/null @@ -1,117 +0,0 @@ -#if TOOLS - -using System; -using System.IO; -using System.Text.RegularExpressions; -using Godot; - -namespace Generator; - -/// -/// 生成 UiManager 中打开Ui相关的函数代码 -/// -public static class UiManagerMethodsGenerator -{ - private static string savePath = "src/game/manager/UiManager_Methods.cs"; - - /// - /// 执行生成操作, 并返回执行结果 - /// - public static bool Generate() - { - //扫描所有ui - if (!Directory.Exists(GameConfig.UiPrefabDir)) - { - return true; - } - - try - { - var directoryInfo = new DirectoryInfo(GameConfig.UiPrefabDir); - var fileInfos = directoryInfo.GetFiles(); - - var code = $"\n// 该类为自动生成的, 请不要手动编辑, 以免造成代码丢失\n" + - $"public static partial class UiManager\n" + - $"{{\n" + - $"\n"; - - var uiNameClass = $" public static class UiNames\n" + - $" {{\n"; - var methodClass = ""; - - foreach (var fileInfo in fileInfos) - { - if (fileInfo.Extension == ".tscn") - { - var uiName = fileInfo.Name.Substring(0, fileInfo.Name.Length - 5); - uiNameClass += $" public const string {uiName} = \"{uiName}\";\n"; - - methodClass += $" /// \n" + - $" /// 创建 {uiName}, 并返回UI实例, 该函数不会打开 Ui\n" + - $" /// \n" + - $" public static UI.{uiName}.{uiName}Panel Create_{uiName}()\n" + - $" {{\n" + - $" return CreateUi(UiNames.{uiName});\n" + - $" }}\n" + - $"\n" + - $" /// \n" + - $" /// 打开 {uiName}, 并返回UI实例\n" + - $" /// \n" + - $" public static UI.{uiName}.{uiName}Panel Open_{uiName}()\n" + - $" {{\n" + - $" return OpenUi(UiNames.{uiName});\n" + - $" }}\n" + - $"\n" + - $" /// \n" + - $" /// 隐藏 {uiName} 的所有实例\n" + - $" /// \n" + - $" public static void Hide_{uiName}()\n" + - $" {{\n" + - $" var uiInstance = Get_{uiName}_Instance();\n" + - $" foreach (var uiPanel in uiInstance)\n" + - $" {{\n" + - $" uiPanel.HideUi();\n" + - $" }}\n" + - $" }}\n" + - $"\n" + - $" /// \n" + - $" /// 销毁 {uiName} 的所有实例\n" + - $" /// \n" + - $" public static void Destroy_{uiName}()\n" + - $" {{\n" + - $" var uiInstance = Get_{uiName}_Instance();\n" + - $" foreach (var uiPanel in uiInstance)\n" + - $" {{\n" + - $" uiPanel.Destroy();\n" + - $" }}\n" + - $" }}\n" + - $"\n" + - $" /// \n" + - $" /// 获取所有 {uiName} 的实例, 如果没有实例, 则返回一个空数组\n" + - $" /// \n" + - $" public static UI.{uiName}.{uiName}Panel[] Get_{uiName}_Instance()\n" + - $" {{\n" + - $" return GetUiInstance(nameof(UI.{uiName}.{uiName}));\n" + - $" }}\n" + - $"\n"; - } - } - uiNameClass += $" }}\n\n"; - - code += uiNameClass; - code += methodClass; - code += $"}}\n"; - - File.WriteAllText(savePath, code); - } - catch (Exception e) - { - Debug.LogError(e.ToString()); - return false; - } - - return true; - } -} - -#endif \ No newline at end of file diff --git a/DungeonShooting_Godot/src/game/activity/role/player/Player.cs b/DungeonShooting_Godot/src/game/activity/role/player/Player.cs index 53909ad..fc93bb3 100644 --- a/DungeonShooting_Godot/src/game/activity/role/player/Player.cs +++ b/DungeonShooting_Godot/src/game/activity/role/player/Player.cs @@ -239,7 +239,7 @@ protected override void OnAffiliationChange(AffiliationArea prevArea) { - //BrushPrevPosition = null; + BrushPrevPosition = null; base.OnAffiliationChange(prevArea); } diff --git a/DungeonShooting_Godot/src/game/activity/weapon/knife/Knife.cs b/DungeonShooting_Godot/src/game/activity/weapon/knife/Knife.cs index 4cc5b3c..3d386d0 100644 --- a/DungeonShooting_Godot/src/game/activity/weapon/knife/Knife.cs +++ b/DungeonShooting_Godot/src/game/activity/weapon/knife/Knife.cs @@ -84,7 +84,7 @@ //播放挥刀特效 SpecialEffectManager.Play( Master, - ResourcePath.resource_sprite_weapon_weapon0004_KnifeHit1_png, "default", + ResourcePath.resource_spriteFrames_weapon_Weapon0004_hit_tres, "default", Master.MountPoint.Position, Master.MountPoint.Rotation + Mathf.DegToRad(Attribute.UpliftAngle + 60), AnimatedSprite.Scale, diff --git a/DungeonShooting_Godot/src/game/room/DungeonManager.cs b/DungeonShooting_Godot/src/game/room/DungeonManager.cs index 9ddf478..6444ff1 100644 --- a/DungeonShooting_Godot/src/game/room/DungeonManager.cs +++ b/DungeonShooting_Godot/src/game/room/DungeonManager.cs @@ -201,7 +201,7 @@ World = GameApplication.Instance.CreateNewWorld(); yield return 0; //生成地牢房间 - var random = new SeedRandom(); + var random = new SeedRandom(205371406); _dungeonGenerator = new DungeonGenerator(CurrConfig, random); _dungeonGenerator.Generate(); yield return 0; diff --git a/DungeonShooting_Godot/src/game/ui/editorTools/EditorToolsPanel.cs b/DungeonShooting_Godot/src/game/ui/editorTools/EditorToolsPanel.cs index 864e2a4..0f808aa 100644 --- a/DungeonShooting_Godot/src/game/ui/editorTools/EditorToolsPanel.cs +++ b/DungeonShooting_Godot/src/game/ui/editorTools/EditorToolsPanel.cs @@ -303,7 +303,7 @@ /// private void OpenExportExcelFolder() { - var path = Environment.CurrentDirectory + "\\excel\\excelFile"; + var path = Environment.CurrentDirectory + "\\excel"; System.Diagnostics.Process.Start("explorer.exe", path); } diff --git a/DungeonShooting_Godot/src/game/ui/setting/Setting.cs b/DungeonShooting_Godot/src/game/ui/setting/Setting.cs index c3726ec..141775f 100644 --- a/DungeonShooting_Godot/src/game/ui/setting/Setting.cs +++ b/DungeonShooting_Godot/src/game/ui/setting/Setting.cs @@ -943,6 +943,59 @@ } /// + /// 类型: , 路径: Setting.ScrollContainer.KeySetting.Key14.Name + /// + public class Name_14 : UiNode + { + public Name_14(SettingPanel uiPanel, Godot.Label node) : base(uiPanel, node) { } + public override Name_14 Clone() => new (UiPanel, (Godot.Label)Instance.Duplicate()); + } + + /// + /// 类型: , 路径: Setting.ScrollContainer.KeySetting.Key14.Value + /// + public class Value_13 : UiNode + { + public Value_13(SettingPanel uiPanel, Godot.Label node) : base(uiPanel, node) { } + public override Value_13 Clone() => new (UiPanel, (Godot.Label)Instance.Duplicate()); + } + + /// + /// 类型: , 路径: Setting.ScrollContainer.KeySetting.Key14 + /// + public class Key14 : UiNode + { + /// + /// 使用 Instance 属性获取当前节点实例对象, 节点类型: , 节点路径: Setting.ScrollContainer.KeySetting.Name + /// + public Name_14 L_Name + { + get + { + if (_L_Name == null) _L_Name = new Name_14(UiPanel, Instance.GetNode("Name")); + return _L_Name; + } + } + private Name_14 _L_Name; + + /// + /// 使用 Instance 属性获取当前节点实例对象, 节点类型: , 节点路径: Setting.ScrollContainer.KeySetting.Value + /// + public Value_13 L_Value + { + get + { + if (_L_Value == null) _L_Value = new Value_13(UiPanel, Instance.GetNode("Value")); + return _L_Value; + } + } + private Value_13 _L_Value; + + public Key14(SettingPanel uiPanel, Godot.HBoxContainer node) : base(uiPanel, node) { } + public override Key14 Clone() => new (UiPanel, (Godot.HBoxContainer)Instance.Duplicate()); + } + + /// /// 类型: , 路径: Setting.ScrollContainer.KeySetting.Back /// public class Back_2 : UiNode @@ -1139,6 +1192,19 @@ private Key13 _L_Key13; /// + /// 使用 Instance 属性获取当前节点实例对象, 节点类型: , 节点路径: Setting.ScrollContainer.Key14 + /// + public Key14 L_Key14 + { + get + { + if (_L_Key14 == null) _L_Key14 = new Key14(UiPanel, Instance.GetNode("Key14")); + return _L_Key14; + } + } + private Key14 _L_Key14; + + /// /// 使用 Instance 属性获取当前节点实例对象, 节点类型: , 节点路径: Setting.ScrollContainer.Back /// public Back_2 L_Back @@ -1315,6 +1381,11 @@ public Key13 S_Key13 => L_ScrollContainer.L_KeySetting.L_Key13; /// + /// 场景中唯一名称的节点, 节点类型: , 节点路径: Setting.ScrollContainer.KeySetting.Key14 + /// + public Key14 S_Key14 => L_ScrollContainer.L_KeySetting.L_Key14; + + /// /// 场景中唯一名称的节点, 节点类型: , 节点路径: Setting.ScrollContainer.KeySetting /// public KeySetting S_KeySetting => L_ScrollContainer.L_KeySetting; diff --git a/README.md b/README.md index ddf21a1..579c8da 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,8 @@ -一款由Godot开发的地牢射击类型的游戏, 脚本语言使用的是C#, 当前项目使用的Godot版本: Godot_v4.2 +## 一款由Godot开发的地牢射击类型的游戏 + +**Godot版本:** `4.2.1 mono` +**.Net版本:** `8.0` --- ### 游戏定义 @@ -9,24 +12,24 @@ **游戏类型:** Roguelite, 俯视角, 地牢探索, 双摇杆射击 **参考游戏:** 挺进地牢, 元气骑士, 废土之王 **核心简介:** 游戏整体流程由数层地牢组成, 每层又由数个房间组成, 每个房间有一堵门隔开, 玩家每进入一个房间, 需要清理房间内所有的敌人, 方可离开和进入下一个房间, -玩家需要在这些房间中探索, 战斗, 收集掉落的道具和被动, 一步步成长, 击败boss, 进入下一层, 如此往复, 直到击败最后一层boss即可通关. +玩家需要在这些房间中探索, 战斗, 收集掉落的道具和被动, 一步步成长, 击败boss, 进入下一层, 如此往复, 直到击败最后一层boss即可通关. 但本作与市面上常规地牢射击游戏不同的是, 玩家与敌人共用武器资源, 玩家击败敌人便可拾起敌人的武器, 并且更加注重环境互动要素 **游戏背景:** 构思中 ![gif](DungeonShooting_Document/文档资源/preview_gif.gif) --- - ### 启动项目 + git仓库的目录结构如下 -> ├ DungeonShooting_Document (项目帮助文档, 更新日志相关的目录) -> ├ DungeonShooting_ExcelTool (项目excel配置表导出工具源代码) +> ├ DungeonShooting_Document (更新日志相关的目录) > └ DungeonShooting_Godot (Godot工程目录) -下载好指定的Godot版本, 注意使用的是Godot_Mono版, 使用Godot打开`DungeonShooting_Godot/project.godot`, 如果是第一次打开项目会弹出一个找不到资源的提示, 这是因为项目没有编译过, 点击Godot右上角`build`, 然后打`开项目设置`, 在`插件`这一个页签下启用`DungeonShooting_plugin`这个插件, 然后项目就可以正常运行了 +使用GodotMono版打开`DungeonShooting_Godot/project.godot`, 如果是第一次打开项目会弹出一个找不到资源的提示, 这是因为项目没有编译过, 点击Godot右上角`build`, 然后打`开项目设置`, 在`插件`这一个页签下启用`DungeonShooting_plugin`这个插件, 然后项目就可以正常运行了 --- ### 其他 + **开发日志:** [开发日志.md](DungeonShooting_Document/开发日志.md) **哔哩哔哩:** https://space.bilibili.com/259437820 **项目Ui插件:** https://github.com/xlljc/Ds_Ui \ No newline at end of file