diff --git a/DungeonShooting_Godot/addons/dungeonShooting_plugin/Automation.cs b/DungeonShooting_Godot/addons/dungeonShooting_plugin/Automation.cs index da597de..576b44f 100644 --- a/DungeonShooting_Godot/addons/dungeonShooting_plugin/Automation.cs +++ b/DungeonShooting_Godot/addons/dungeonShooting_plugin/Automation.cs @@ -1,64 +1,16 @@ #if TOOLS -using System; -using System.Collections.Generic; -using System.IO; -using System.Linq; -using System.Text.Json; -using System.Text.RegularExpressions; +using Generator; using Godot; -using File = System.IO.File; [Tool] public partial class Automation : Control { - //支持后缀 - private string[] suffix = - { - ".png", ".jpg", ".txt", ".json", ".ini", ".tscn", ".tres", ".otf", ".gdshader", ".ogg", ".mp3", ".wav", ".svg" - }; - //排除第一层的文件夹 - private string[] exclude = - { - ".vscode", ".idea", ".git", ".import", ".mono", "android", "addons", ".godot" - }; - private string currDir = System.Environment.CurrentDirectory; - - private string resultStr = ""; - /// <summary> /// 更新 ResourcePath /// </summary> private void _on_Button_pressed() { - resultStr = "/// <summary>\n" + - "/// 编辑器下所有资源路径, 该类为 Automation 面板下自动生成的, 请不要手动编辑!\n" + - "/// </summary>\n" + - "public class ResourcePath\n" + - "{\n"; - - GD.Print("更新 ResourcePath..."); - - var directoryInfo = new DirectoryInfo(currDir); - - var directories = directoryInfo.GetDirectories(); - for (int i = 0; i < directories.Length; i++) - { - var directory = directories[i]; - if (!exclude.Contains(directory.Name)) - { - EachDir(directory); - } - } - - var fileInfos = directoryInfo.GetFiles(); - for (var i = 0; i < fileInfos.Length; i++) - { - HandleFile(fileInfos[i]); - } - - resultStr += "}"; - File.WriteAllText("src/game/manager/ResourcePath.cs", resultStr); - GD.Print("ResourcePath.cs 写出完成!"); + ResourcePathGenerator.Generate(); } /// <summary> @@ -66,139 +18,7 @@ /// </summary> private void _on_Button2_pressed() { - //地图路径 - var tileDir = GameConfig.RoomTileDir; - //地图描述数据路径 - var tileDataDir = GameConfig.RoomTileDataDir; - - var tileDirInfo = new DirectoryInfo(tileDir); - var tileDataDirInfo = new DirectoryInfo(tileDataDir); - - //所有地图列表 - var mapList = new HashSet<string>(); - - //收集所有名称 - var fileDataInfos = tileDataDirInfo.GetFiles(); - foreach (var fileInfo in fileDataInfos) - { - mapList.Add(RemoveExtension(fileInfo.Name)); - } - //收集所有名称 - var fileInfos = tileDirInfo.GetFiles(); - foreach (var fileInfo in fileInfos) - { - if (fileInfo.Extension == ".tscn") - { - mapList.Add(RemoveExtension(fileInfo.Name)); - } - } - - //剔除多余的 tile.json - var arrays = mapList.ToArray(); - foreach (var item in arrays) - { - if (!File.Exists(tileDir + item + ".tscn")) - { - mapList.Remove(item); - var filePath = tileDataDir + item + ".json"; - if (File.Exists(filePath)) - { - GD.Print($"未找到'{tileDir + item}.tscn', 删除配置文件: {filePath}"); - File.Delete(filePath); - } - } - } - - //手动生成缺失的 tile.json - foreach (var item in mapList) - { - if (!File.Exists(tileDataDir + item + ".json")) - { - var tscnName = tileDir + item + ".tscn"; - var packedScene = ResourceManager.Load<PackedScene>(tscnName, false); - if (packedScene != null) - { - var dungeonRoomTemplate = packedScene.Instantiate<DungeonRoomTemplate>(); - var usedRect = dungeonRoomTemplate.GetUsedRect(); - var dungeonTile = new DungeonTile(dungeonRoomTemplate); - dungeonTile.SetFloorAtlasCoords(new List<Vector2I>() { new Vector2I(0, 8) }); - //计算导航网格 - dungeonTile.GenerateNavigationPolygon(0); - var polygonData = dungeonTile.GetPolygonData(); - DungeonRoomTemplate.SaveConfig(new List<DoorAreaInfo>(), usedRect.Position, usedRect.Size, polygonData.ToList(), item); - dungeonRoomTemplate.QueueFree(); - } - } - } - - var list = new List<DungeonRoomSplit>(); - //整合操作 - foreach (var item in mapList) - { - var configPath = tileDataDir + item + ".json"; - var configText = File.ReadAllText(configPath); - var roomInfo = DungeonRoomTemplate.DeserializeDungeonRoomInfo(configText); - var split = new DungeonRoomSplit(); - split.ScenePath = ToResPath(tileDir + item + ".tscn"); - split.ConfigPath = ToResPath(configPath); - split.RoomInfo = roomInfo; - list.Add(split); - } - - //写出配置 - var config = new JsonSerializerOptions(); - config.WriteIndented = true; - var text = JsonSerializer.Serialize(list, config); - File.WriteAllText(GameConfig.RoomTileConfigFile, text); - - GD.Print("地牢房间配置, 重新打包完成!"); - } - - private void EachDir(DirectoryInfo directoryInfos) - { - 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 void HandleFile(FileInfo fileInfo) - { - if (suffix.Contains(fileInfo.Extension)) - { - var field = fileInfo.FullName.Substring(currDir.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"; - } - } - - private string ToResPath(string path) - { - var field = path.Substring(currDir.Length + 1); - field = field.Replace("\\", "/"); - return "res://" + field; - } - - private string RemoveExtension(string name) - { - var index = name.LastIndexOf(".", StringComparison.Ordinal); - if (index >= 0) - { - return name.Substring(0, index); - } - - return name; + RoomPackGenerator.Generate(); } } #endif \ No newline at end of file diff --git a/DungeonShooting_Godot/prefab/ui/RoomUI.tscn b/DungeonShooting_Godot/prefab/ui/RoomUI.tscn index 0428334..d7f5ba9 100644 --- a/DungeonShooting_Godot/prefab/ui/RoomUI.tscn +++ b/DungeonShooting_Godot/prefab/ui/RoomUI.tscn @@ -1,6 +1,6 @@ [gd_scene load_steps=11 format=3 uid="uid://bvpmtfupny8iu"] -[ext_resource type="Script" path="res://src/game/ui/RoomUI.cs" id="1"] +[ext_resource type="Script" path="res://src/game/ui/roomUI/RoomUIPanel.cs" id="1_u48k1"] [ext_resource type="Texture2D" uid="uid://k621mhhkg65f" path="res://resource/sprite/ui/mapBar.png" id="2"] [ext_resource type="PackedScene" path="res://prefab/ui/bar/ReloadBar.tscn" id="3"] [ext_resource type="Texture2D" uid="uid://u5ul7fu8wv1a" path="res://resource/sprite/ui/healthBar.png" id="4"] @@ -18,7 +18,7 @@ anchor_bottom = 1.0 grow_horizontal = 2 grow_vertical = 2 -script = ExtResource("1") +script = ExtResource("1_u48k1") [node name="Control" type="Control" parent="."] anchors_preset = 0 diff --git a/DungeonShooting_Godot/resource/theme/mainTheme.tres b/DungeonShooting_Godot/resource/theme/mainTheme.tres index 2f97beb..553bffb 100644 --- a/DungeonShooting_Godot/resource/theme/mainTheme.tres +++ b/DungeonShooting_Godot/resource/theme/mainTheme.tres @@ -352,7 +352,7 @@ [sub_resource type="ImageTexture" id="58"] -[sub_resource type="Image" id="Image_sxxms"] +[sub_resource type="Image" id="Image_xtynf"] data = { "data": PackedByteArray(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 255, 255, 0, 255, 255, 255, 1, 255, 255, 255, 39, 255, 255, 255, 67, 255, 255, 255, 67, 255, 255, 255, 39, 255, 255, 255, 1, 255, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 255, 255, 0, 255, 255, 255, 39, 255, 255, 255, 75, 255, 255, 255, 75, 255, 255, 255, 75, 255, 255, 255, 75, 255, 255, 255, 39, 255, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 255, 255, 0, 255, 255, 255, 66, 255, 255, 255, 75, 255, 255, 255, 75, 255, 255, 255, 75, 255, 255, 255, 75, 255, 255, 255, 66, 255, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 255, 255, 0, 255, 255, 255, 66, 255, 255, 255, 75, 255, 255, 255, 75, 255, 255, 255, 75, 255, 255, 255, 75, 255, 255, 255, 66, 255, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 255, 255, 0, 255, 255, 255, 39, 255, 255, 255, 75, 255, 255, 255, 75, 255, 255, 255, 75, 255, 255, 255, 75, 255, 255, 255, 39, 255, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 255, 255, 0, 255, 255, 255, 1, 255, 255, 255, 39, 255, 255, 255, 67, 255, 255, 255, 67, 255, 255, 255, 39, 255, 255, 255, 1, 255, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0), "format": "RGBA8", @@ -362,7 +362,7 @@ } [sub_resource type="ImageTexture" id="60"] -image = SubResource("Image_sxxms") +image = SubResource("Image_xtynf") [sub_resource type="StyleBoxTexture" id="61"] content_margin_left = 2.0 @@ -372,7 +372,7 @@ texture = SubResource("60") region_rect = Rect2(0, 0, 12, 12) -[sub_resource type="Image" id="Image_d4kn7"] +[sub_resource type="Image" id="Image_njets"] data = { "data": PackedByteArray(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 191, 191, 191, 0, 247, 247, 247, 0, 248, 248, 248, 0, 248, 248, 248, 0, 247, 247, 247, 0, 191, 191, 191, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 191, 191, 191, 0, 191, 191, 191, 4, 247, 247, 247, 98, 248, 248, 248, 167, 248, 248, 248, 167, 247, 247, 247, 98, 191, 191, 191, 4, 191, 191, 191, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 247, 247, 247, 0, 247, 247, 247, 97, 248, 248, 248, 186, 248, 248, 248, 186, 248, 248, 248, 186, 248, 248, 248, 186, 247, 247, 247, 97, 247, 247, 247, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 248, 248, 248, 0, 248, 248, 248, 164, 248, 248, 248, 186, 248, 248, 248, 186, 248, 248, 248, 186, 248, 248, 248, 186, 248, 248, 248, 164, 248, 248, 248, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 248, 248, 248, 0, 248, 248, 248, 164, 248, 248, 248, 186, 248, 248, 248, 186, 248, 248, 248, 186, 248, 248, 248, 186, 248, 248, 248, 164, 248, 248, 248, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 247, 247, 247, 0, 247, 247, 247, 97, 248, 248, 248, 186, 248, 248, 248, 186, 248, 248, 248, 186, 248, 248, 248, 186, 247, 247, 247, 97, 247, 247, 247, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 191, 191, 191, 0, 191, 191, 191, 4, 247, 247, 247, 98, 248, 248, 248, 167, 248, 248, 248, 167, 247, 247, 247, 98, 191, 191, 191, 4, 191, 191, 191, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 191, 191, 191, 0, 247, 247, 247, 0, 248, 248, 248, 0, 248, 248, 248, 0, 247, 247, 247, 0, 191, 191, 191, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0), "format": "RGBA8", @@ -382,7 +382,7 @@ } [sub_resource type="ImageTexture" id="63"] -image = SubResource("Image_d4kn7") +image = SubResource("Image_njets") [sub_resource type="StyleBoxTexture" id="64"] content_margin_left = 2.0 @@ -392,7 +392,7 @@ texture = SubResource("63") region_rect = Rect2(0, 0, 12, 12) -[sub_resource type="Image" id="Image_lim08"] +[sub_resource type="Image" id="Image_1em1k"] data = { "data": PackedByteArray(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 127, 127, 127, 0, 173, 173, 173, 0, 173, 173, 173, 0, 173, 173, 173, 0, 173, 173, 173, 0, 127, 127, 127, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 127, 127, 127, 0, 127, 127, 127, 4, 173, 173, 173, 97, 173, 173, 173, 166, 173, 173, 173, 166, 173, 173, 173, 97, 127, 127, 127, 4, 127, 127, 127, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 172, 172, 172, 0, 172, 172, 172, 96, 173, 173, 173, 185, 173, 173, 173, 185, 173, 173, 173, 185, 173, 173, 173, 185, 172, 172, 172, 96, 172, 172, 172, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 173, 173, 173, 0, 173, 173, 173, 163, 173, 173, 173, 185, 173, 173, 173, 185, 173, 173, 173, 185, 173, 173, 173, 185, 173, 173, 173, 163, 173, 173, 173, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 173, 173, 173, 0, 173, 173, 173, 163, 173, 173, 173, 185, 173, 173, 173, 185, 173, 173, 173, 185, 173, 173, 173, 185, 173, 173, 173, 163, 173, 173, 173, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 172, 172, 172, 0, 172, 172, 172, 96, 173, 173, 173, 185, 173, 173, 173, 185, 173, 173, 173, 185, 173, 173, 173, 185, 172, 172, 172, 96, 172, 172, 172, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 127, 127, 127, 0, 127, 127, 127, 4, 173, 173, 173, 97, 173, 173, 173, 166, 173, 173, 173, 166, 173, 173, 173, 97, 127, 127, 127, 4, 127, 127, 127, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 127, 127, 127, 0, 173, 173, 173, 0, 173, 173, 173, 0, 173, 173, 173, 0, 173, 173, 173, 0, 127, 127, 127, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0), "format": "RGBA8", @@ -402,7 +402,7 @@ } [sub_resource type="ImageTexture" id="66"] -image = SubResource("Image_lim08") +image = SubResource("Image_1em1k") [sub_resource type="StyleBoxTexture" id="67"] content_margin_left = 2.0 @@ -412,7 +412,7 @@ texture = SubResource("66") region_rect = Rect2(0, 0, 12, 12) -[sub_resource type="Image" id="Image_86mbg"] +[sub_resource type="Image" id="Image_366uy"] data = { "data": PackedByteArray(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 255, 255, 0, 255, 255, 255, 4, 255, 255, 255, 16, 255, 255, 255, 16, 255, 255, 255, 4, 255, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 255, 255, 0, 255, 255, 255, 16, 255, 255, 255, 21, 255, 255, 255, 21, 255, 255, 255, 16, 255, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 255, 255, 0, 255, 255, 255, 16, 255, 255, 255, 21, 255, 255, 255, 21, 255, 255, 255, 16, 255, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 255, 255, 0, 255, 255, 255, 4, 255, 255, 255, 16, 255, 255, 255, 16, 255, 255, 255, 4, 255, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0), "format": "RGBA8", @@ -422,7 +422,7 @@ } [sub_resource type="ImageTexture" id="69"] -image = SubResource("Image_86mbg") +image = SubResource("Image_366uy") [sub_resource type="StyleBoxTexture" id="70"] content_margin_left = 0.0 @@ -446,7 +446,7 @@ content_margin_right = 4.0 content_margin_bottom = 4.0 -[sub_resource type="Image" id="Image_4edk4"] +[sub_resource type="Image" id="Image_s1m4t"] data = { "data": PackedByteArray(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 255, 255, 0, 255, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 255, 255, 0, 255, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 255, 255, 0, 255, 255, 255, 76, 255, 255, 255, 17, 255, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 255, 255, 0, 255, 255, 255, 17, 255, 255, 255, 76, 255, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 255, 255, 0, 255, 255, 255, 76, 255, 255, 255, 228, 255, 255, 255, 188, 255, 255, 255, 17, 255, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 255, 255, 0, 255, 255, 255, 17, 255, 255, 255, 188, 255, 255, 255, 228, 255, 255, 255, 76, 255, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 255, 255, 0, 255, 255, 255, 18, 255, 255, 255, 188, 255, 255, 255, 229, 255, 255, 255, 187, 255, 255, 255, 17, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 17, 255, 255, 255, 187, 255, 255, 255, 229, 255, 255, 255, 188, 255, 255, 255, 18, 255, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 255, 255, 0, 255, 255, 255, 19, 255, 255, 255, 188, 255, 255, 255, 229, 255, 255, 255, 185, 255, 255, 255, 17, 255, 255, 255, 17, 255, 255, 255, 186, 255, 255, 255, 229, 255, 255, 255, 188, 255, 255, 255, 19, 255, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 255, 255, 0, 255, 255, 255, 19, 255, 255, 255, 190, 255, 255, 255, 229, 255, 255, 255, 185, 255, 255, 255, 185, 255, 255, 255, 229, 255, 255, 255, 189, 255, 255, 255, 19, 255, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 255, 255, 0, 255, 255, 255, 19, 255, 255, 255, 191, 255, 255, 255, 229, 255, 255, 255, 229, 255, 255, 255, 190, 255, 255, 255, 19, 255, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 255, 255, 0, 255, 255, 255, 17, 255, 255, 255, 188, 255, 255, 255, 229, 255, 255, 255, 229, 255, 255, 255, 188, 255, 255, 255, 17, 255, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 255, 255, 0, 255, 255, 255, 17, 255, 255, 255, 188, 255, 255, 255, 229, 255, 255, 255, 188, 255, 255, 255, 188, 255, 255, 255, 229, 255, 255, 255, 187, 255, 255, 255, 17, 255, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 255, 255, 0, 255, 255, 255, 17, 255, 255, 255, 187, 255, 255, 255, 229, 255, 255, 255, 188, 255, 255, 255, 18, 255, 255, 255, 19, 255, 255, 255, 188, 255, 255, 255, 229, 255, 255, 255, 186, 255, 255, 255, 17, 255, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 255, 255, 0, 255, 255, 255, 17, 255, 255, 255, 185, 255, 255, 255, 229, 255, 255, 255, 189, 255, 255, 255, 19, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 19, 255, 255, 255, 189, 255, 255, 255, 229, 255, 255, 255, 185, 255, 255, 255, 17, 255, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 255, 255, 0, 255, 255, 255, 76, 255, 255, 255, 229, 255, 255, 255, 190, 255, 255, 255, 19, 255, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 255, 255, 0, 255, 255, 255, 19, 255, 255, 255, 190, 255, 255, 255, 229, 255, 255, 255, 76, 255, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 255, 255, 0, 255, 255, 255, 77, 255, 255, 255, 19, 255, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 255, 255, 0, 255, 255, 255, 19, 255, 255, 255, 77, 255, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 255, 255, 0, 255, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 255, 255, 0, 255, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0), "format": "RGBA8", @@ -456,7 +456,7 @@ } [sub_resource type="ImageTexture" id="56"] -image = SubResource("Image_4edk4") +image = SubResource("Image_s1m4t") [sub_resource type="StyleBoxFlat" id="57"] content_margin_left = 6.0 diff --git a/DungeonShooting_Godot/src/framework/generator/ResourcePathGenerator.cs b/DungeonShooting_Godot/src/framework/generator/ResourcePathGenerator.cs new file mode 100644 index 0000000..0958ed4 --- /dev/null +++ b/DungeonShooting_Godot/src/framework/generator/ResourcePathGenerator.cs @@ -0,0 +1,96 @@ + +using System.IO; +using System.Linq; +using System.Text.RegularExpressions; +using Godot; + +namespace Generator; + +/// <summary> +/// ResourcePath 类文件生成器 +/// </summary> +public static class ResourcePathGenerator +{ + //支持后缀 + private static string[] suffix = + { + ".png", ".jpg", ".txt", ".json", ".ini", ".tscn", ".tres", ".otf", ".gdshader", ".ogg", ".mp3", ".wav", ".svg" + }; + //排除第一层的文件夹 + private static string[] exclude = + { + ".vscode", ".idea", ".git", ".import", ".mono", "android", "addons", ".godot" + }; + private static string currDir = System.Environment.CurrentDirectory; + + private static string resultStr = ""; + + //保存路径 + public static string savePath = "src/game/manager/ResourcePath.cs"; + + /// <summary> + /// 执行生成操作 + /// </summary> + public static void Generate() + { + resultStr = "/// <summary>\n" + + "/// 编辑器下所有资源路径, 该类为 Automation 面板下自动生成的, 请不要手动编辑!\n" + + "/// </summary>\n" + + "public class ResourcePath\n" + + "{\n"; + + GD.Print("更新 ResourcePath..."); + + var directoryInfo = new DirectoryInfo(currDir); + + var directories = directoryInfo.GetDirectories(); + for (int i = 0; i < directories.Length; i++) + { + var directory = directories[i]; + if (!exclude.Contains(directory.Name)) + { + EachDir(directory); + } + } + + var fileInfos = directoryInfo.GetFiles(); + for (var i = 0; i < fileInfos.Length; i++) + { + HandleFile(fileInfos[i]); + } + + resultStr += "}"; + File.WriteAllText(savePath, resultStr); + GD.Print("ResourcePath.cs 写出完成!"); + } + + private static void EachDir(DirectoryInfo directoryInfos) + { + 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(currDir.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"; + } + } + +} \ No newline at end of file diff --git a/DungeonShooting_Godot/src/framework/generator/RoomPackGenerator.cs b/DungeonShooting_Godot/src/framework/generator/RoomPackGenerator.cs new file mode 100644 index 0000000..046b4ff --- /dev/null +++ b/DungeonShooting_Godot/src/framework/generator/RoomPackGenerator.cs @@ -0,0 +1,128 @@ + +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Text.Json; +using Godot; + +namespace Generator; + +/// <summary> +/// 预制房间数据生成器 +/// </summary> +public static class RoomPackGenerator +{ + private static string currDir = System.Environment.CurrentDirectory; + + /// <summary> + /// 执行生成操作 + /// </summary> + public static void Generate() + { + //地图路径 + var tileDir = DungeonRoomTemplate.RoomTileDir; + //地图描述数据路径 + var tileDataDir = DungeonRoomTemplate.RoomTileDataDir; + + var tileDirInfo = new DirectoryInfo(tileDir); + var tileDataDirInfo = new DirectoryInfo(tileDataDir); + + //所有地图列表 + var mapList = new HashSet<string>(); + + //收集所有名称 + var fileDataInfos = tileDataDirInfo.GetFiles(); + foreach (var fileInfo in fileDataInfos) + { + mapList.Add(RemoveExtension(fileInfo.Name)); + } + //收集所有名称 + var fileInfos = tileDirInfo.GetFiles(); + foreach (var fileInfo in fileInfos) + { + if (fileInfo.Extension == ".tscn") + { + mapList.Add(RemoveExtension(fileInfo.Name)); + } + } + + //剔除多余的 tile.json + var arrays = mapList.ToArray(); + foreach (var item in arrays) + { + if (!File.Exists(tileDir + item + ".tscn")) + { + mapList.Remove(item); + var filePath = tileDataDir + item + ".json"; + if (File.Exists(filePath)) + { + GD.Print($"未找到'{tileDir + item}.tscn', 删除配置文件: {filePath}"); + File.Delete(filePath); + } + } + } + + //手动生成缺失的 tile.json + foreach (var item in mapList) + { + if (!File.Exists(tileDataDir + item + ".json")) + { + var tscnName = tileDir + item + ".tscn"; + var packedScene = ResourceManager.Load<PackedScene>(tscnName, false); + if (packedScene != null) + { + var dungeonRoomTemplate = packedScene.Instantiate<DungeonRoomTemplate>(); + var usedRect = dungeonRoomTemplate.GetUsedRect(); + var dungeonTile = new DungeonTile(dungeonRoomTemplate); + dungeonTile.SetFloorAtlasCoords(new List<Vector2I>() { new Vector2I(0, 8) }); + //计算导航网格 + dungeonTile.GenerateNavigationPolygon(0); + var polygonData = dungeonTile.GetPolygonData(); + DungeonRoomTemplate.SaveConfig(new List<DoorAreaInfo>(), usedRect.Position, usedRect.Size, polygonData.ToList(), item); + dungeonRoomTemplate.QueueFree(); + } + } + } + + var list = new List<DungeonRoomSplit>(); + //整合操作 + foreach (var item in mapList) + { + var configPath = tileDataDir + item + ".json"; + var configText = File.ReadAllText(configPath); + var roomInfo = DungeonRoomTemplate.DeserializeDungeonRoomInfo(configText); + var split = new DungeonRoomSplit(); + split.ScenePath = ToResPath(tileDir + item + ".tscn"); + split.ConfigPath = ToResPath(configPath); + split.RoomInfo = roomInfo; + list.Add(split); + } + + //写出配置 + var config = new JsonSerializerOptions(); + config.WriteIndented = true; + var text = JsonSerializer.Serialize(list, config); + File.WriteAllText(DungeonRoomTemplate.RoomTileConfigFile, text); + + GD.Print("地牢房间配置, 重新打包完成!"); + } + + private static string ToResPath(string path) + { + var field = path.Substring(currDir.Length + 1); + field = field.Replace("\\", "/"); + return "res://" + field; + } + + private static string RemoveExtension(string name) + { + var index = name.LastIndexOf(".", StringComparison.Ordinal); + if (index >= 0) + { + return name.Substring(0, index); + } + + return name; + } +} \ No newline at end of file diff --git a/DungeonShooting_Godot/src/framework/generator/UiGenerator.cs b/DungeonShooting_Godot/src/framework/generator/UiGenerator.cs new file mode 100644 index 0000000..fd72026 --- /dev/null +++ b/DungeonShooting_Godot/src/framework/generator/UiGenerator.cs @@ -0,0 +1,136 @@ + +using System.Collections.Generic; +using System.Text.RegularExpressions; +using Godot; + +namespace Generator; + +public static class UiGenerator +{ + private static int _nodeIndex = 0; + + public static void GenerateUi(Control control) + { + _nodeIndex = 0; + var uiNode = EachNode(control); + var code = GenerateClassCode(uiNode); + GD.Print("code: \n" + code); + } + + private static string GenerateClassCode(UiNode uiNode) + { + return $"namespace UI;\n\n" + + $"public abstract partial class {uiNode.Name} : UiBase\n" + + $"{{\n" + + GeneratePropertyListClassCode("", uiNode.Name + ".", uiNode, " ") + + $"\n\n" + + GenerateAllChildrenClassCode(uiNode.Name + ".", uiNode, " ") + + $"}}\n"; + } + + private static string GenerateAllChildrenClassCode(string parent, UiNode uiNode, string retraction) + { + var str = ""; + if (uiNode.Children != null) + { + for (var i = 0; i < uiNode.Children.Count; i++) + { + var item = uiNode.Children[i]; + str += GenerateAllChildrenClassCode(parent + item.Name + ".", item, retraction); + str += GenerateChildrenClassCode(parent, item, retraction); + } + } + + return str; + } + + private static string GenerateChildrenClassCode(string parent, UiNode uiNode, string retraction) + { + return retraction + $"/// <summary>\n" + + retraction + $"/// 类型: <see cref=\"{uiNode.TypeName}\"/>, 路径: {parent}{uiNode.Name}\n" + + retraction + $"/// </summary>\n" + + retraction + $"public class {uiNode.ClassName}\n" + + retraction + $"{{\n" + + retraction + $" /// <summary>\n" + + retraction + $" /// Ui节点实例, 节点类型: <see cref=\"{uiNode.TypeName}\"/>, 节点路径: {parent}{uiNode.Name}\n" + + retraction + $" /// </summary>\n" + + retraction + $" public {uiNode.TypeName} Instance {{ get; }}\n\n" + + GeneratePropertyListClassCode("Instance.", parent, uiNode, retraction + " ") + + retraction + $" public {uiNode.ClassName}({uiNode.TypeName} node) => Instance = node;\n" + + retraction + $" public {uiNode.ClassName} Clone() => new (({uiNode.TypeName})Instance.Duplicate());\n" + + retraction + $"}}\n\n"; + } + + private static string GeneratePropertyListClassCode(string target, string parent, UiNode uiNode, string retraction) + { + var str = ""; + if (uiNode.Children != null) + { + for (var i = 0; i < uiNode.Children.Count; i++) + { + var item = uiNode.Children[i]; + str += GeneratePropertyCode(target, parent, item, retraction); + } + } + + return str; + } + + private static string GeneratePropertyCode(string target, string parent, UiNode uiNode, string retraction) + { + return retraction + $"/// <summary>\n" + + retraction + $"/// 使用 Instance 属性获取当前节点实例对象, 节点类型: <see cref=\"{uiNode.TypeName}\"/>, 节点路径: {parent}{uiNode.Name}\n" + + retraction + $"/// </summary>\n" + + retraction + $"public {uiNode.ClassName} {uiNode.Name}\n" + + retraction + $"{{\n" + + retraction + $" get\n" + + retraction + $" {{\n" + + retraction + $" if (_{uiNode.Name} == null) _{uiNode.Name} = new {uiNode.ClassName}({target}GetNode<{uiNode.TypeName}>(\"{uiNode.Name}\"));\n" + + retraction + $" return _{uiNode.Name};\n" + + retraction + $" }}\n" + + retraction + $"}}\n" + + retraction + $"private {uiNode.ClassName} _{uiNode.Name};\n\n"; + } + + private static UiNode EachNode(Control control) + { + var name = Regex.Replace(control.Name, "[^\\w_]", ""); + var uiNode = new UiNode(name, "UiNode" + (_nodeIndex++) + "_" + name, control.GetType().FullName); + + var childCount = control.GetChildCount(); + if (childCount > 0) + { + for (var i = 0; i < childCount; i++) + { + var children = control.GetChildOrNull<Control>(i); + if (children != null) + { + if (uiNode.Children == null) + { + uiNode.Children = new List<UiNode>(); + } + + uiNode.Children.Add(EachNode(children)); + } + } + } + + return uiNode; + } + + private class UiNode + { + public string Name; + public string ClassName; + public string TypeName; + public List<UiNode> Children; + + public UiNode(string name, string className, string typeName) + { + Name = name; + ClassName = className; + TypeName = typeName; + } + } + +} \ No newline at end of file diff --git a/DungeonShooting_Godot/src/framework/ui/UiBase.cs b/DungeonShooting_Godot/src/framework/ui/UiBase.cs new file mode 100644 index 0000000..d3e50ef --- /dev/null +++ b/DungeonShooting_Godot/src/framework/ui/UiBase.cs @@ -0,0 +1,50 @@ + +using Godot; + +/// <summary> +/// Ui 基类 +/// </summary> +public abstract partial class UiBase : Control +{ + /// <summary> + /// 当前 UI 所属层级 + /// </summary> + [Export] + public UiLayer Layer = UiLayer.Middle; + + /// <summary> + /// Ui 模式 + /// </summary> + [Export] + public UiMode Mode = UiMode.Normal; + + /// <summary> + /// 阻止下层 Ui 点击 + /// </summary> + [Export] + public bool KeepOut = false; + + /// <summary> + /// 创建当前ui时调用 + /// </summary> + public virtual void OnCreate() + { + } + + /// <summary> + /// 当前ui打开时调用,并接收参数 + /// </summary> + public abstract void OnOpen(params object[] args); + + /// <summary> + /// 当前ui关闭时调用 + /// </summary> + public abstract void OnClose(); + + /// <summary> + /// 销毁当前ui时调用 + /// </summary> + public virtual void OnDispose() + { + } +} \ No newline at end of file diff --git a/DungeonShooting_Godot/src/framework/ui/UiLayer.cs b/DungeonShooting_Godot/src/framework/ui/UiLayer.cs new file mode 100644 index 0000000..4a7002e --- /dev/null +++ b/DungeonShooting_Godot/src/framework/ui/UiLayer.cs @@ -0,0 +1,20 @@ + +public enum UiLayer +{ + /// <summary> + /// 最底层 + /// </summary> + Bottom, + /// <summary> + /// 中间层 + /// </summary> + Middle, + /// <summary> + /// 较高层 + /// </summary> + Height, + /// <summary> + /// 最顶层 + /// </summary> + Pop, +} \ No newline at end of file diff --git a/DungeonShooting_Godot/src/framework/ui/UiManager.cs b/DungeonShooting_Godot/src/framework/ui/UiManager.cs new file mode 100644 index 0000000..289a729 --- /dev/null +++ b/DungeonShooting_Godot/src/framework/ui/UiManager.cs @@ -0,0 +1,27 @@ + +using Godot; + +public static partial class UiManager +{ + private static bool _init = false; + + public static void Init() + { + if (_init) + { + return; + } + + _init = true; + } + + public static UiBase OpenUi(string resourcePath) + { + return null; + } + + public static T OpenUi<T>(string resourcePath) where T : UiBase + { + return (T)OpenUi(resourcePath); + } +} \ No newline at end of file diff --git a/DungeonShooting_Godot/src/framework/ui/UiMode.cs b/DungeonShooting_Godot/src/framework/ui/UiMode.cs new file mode 100644 index 0000000..d4d9ccb --- /dev/null +++ b/DungeonShooting_Godot/src/framework/ui/UiMode.cs @@ -0,0 +1,12 @@ + +public enum UiMode +{ + /// <summary> + /// 正常模式,可以开多个相同的 Ui + /// </summary> + Normal, + /// <summary> + /// 单例模式, 只能同时打开一个相同的 Ui + /// </summary> + Singleton, +} \ No newline at end of file diff --git a/DungeonShooting_Godot/src/game/GameApplication.cs b/DungeonShooting_Godot/src/game/GameApplication.cs index 4fbf5a0..9e7f69d 100644 --- a/DungeonShooting_Godot/src/game/GameApplication.cs +++ b/DungeonShooting_Godot/src/game/GameApplication.cs @@ -2,6 +2,7 @@ using System.Collections.Generic; using System.Text.Json; using Godot; +using UI; public partial class GameApplication : Node2D { @@ -49,7 +50,7 @@ /// <summary> /// 游戏ui对象 /// </summary> - public RoomUI Ui { get; private set; } + public RoomUIPanel Ui { get; private set; } /// <summary> /// 全局根节点 @@ -81,6 +82,9 @@ ActivityObject.IsDebug = Debug; //Engine.TimeScale = 0.3f; + //初始化ui + UiManager.Init(); + GlobalNodeRoot = GetNode<Node2D>(GlobalNodeRootPath); // 初始化鼠标 Input.MouseMode = Input.MouseModeEnum.Hidden; @@ -89,7 +93,7 @@ RoomManager = GetNode<RoomManager>(RoomPath); SubViewport = GetNode<SubViewport>(ViewportPath); SubViewportContainer = GetNode<SubViewportContainer>(ViewportContainerPath); - Ui = GetNode<RoomUI>(UiPath); + Ui = GetNode<RoomUIPanel>(UiPath); Ui.AddChild(Cursor); } diff --git a/DungeonShooting_Godot/src/game/ui/ReloadBar.cs b/DungeonShooting_Godot/src/game/ui/ReloadBar.cs index 2f4a7ba..697e3e0 100644 --- a/DungeonShooting_Godot/src/game/ui/ReloadBar.cs +++ b/DungeonShooting_Godot/src/game/ui/ReloadBar.cs @@ -35,7 +35,7 @@ public void ShowBar(Vector2 position, float progress) { Visible = true; - GlobalPosition = position; + GlobalPosition = position.Round(); progress = Mathf.Clamp(progress, 0, 1); block.Position = new Vector2(startX + (width - 3) * progress, 0); } diff --git a/DungeonShooting_Godot/src/game/ui/RoomUI.cs b/DungeonShooting_Godot/src/game/ui/RoomUI.cs deleted file mode 100644 index 2f25757..0000000 --- a/DungeonShooting_Godot/src/game/ui/RoomUI.cs +++ /dev/null @@ -1,179 +0,0 @@ -using Godot; - -/// <summary> -/// 房间中的ui -/// </summary> -public partial class RoomUI : Control -{ - //public static RoomUI Current { get; private set; } - - /// <summary> - /// 当前血量 - /// </summary> - public int Hp { get; private set; } - /// <summary> - /// 最大血量 - /// </summary> - public int MaxHp { get; private set; } - /// <summary> - /// 当前护盾值 - /// </summary> - public int Shield { get; private set; } - /// <summary> - /// 最大护盾值 - /// </summary> - public int MaxShield { get; private set; } - /// <summary> - /// 互动提示组件 - /// </summary> - public InteractiveTipBar InteractiveTipBar { get; private set; } - /// <summary> - /// 换弹进度组件 - /// </summary> - public ReloadBar ReloadBar { get; private set; } - - private NinePatchRect hpSlot; - private NinePatchRect shieldSlot; - private TextureRect hpBar; - private TextureRect shieldBar; - private Label bulletText; - private TextureRect gunSprite; - - public override void _EnterTree() - { - hpSlot = GetNode<NinePatchRect>("Control/HealthBar/HpSlot"); - shieldSlot = GetNode<NinePatchRect>("Control/HealthBar/ShieldSlot"); - hpBar = GetNode<TextureRect>("Control/HealthBar/HpSlot/HpBar"); - shieldBar = GetNode<TextureRect>("Control/HealthBar/ShieldSlot/ShieldBar"); - - bulletText = GetNode<Label>("Control/GunBar/BulletText"); - gunSprite = GetNode<TextureRect>("Control/GunBar/GunSprite"); - - InteractiveTipBar = GetNode<InteractiveTipBar>("ViewNode/InteractiveTipBar"); - InteractiveTipBar.Visible = false; - - ReloadBar = GetNode<ReloadBar>("ViewNode/ReloadBar"); - ReloadBar.Visible = false; - } - - public override void _Ready() - { - //将 GlobalNode 节点下的 ui 节点放入全局坐标中 - var globalNode = GetNode("GlobalNode"); - var root = GameApplication.Instance.GlobalNodeRoot; - var count = globalNode.GetChildCount(); - for (int i = count - 1; i >= 0; i--) - { - var node = globalNode.GetChild(i); - globalNode.RemoveChild(node); - root.CallDeferred("add_child", node); - } - globalNode.CallDeferred("queue_free"); - - //将 ViewNode 节点放到 SubViewport 下 - var viewNode = GetNode("ViewNode"); - var viewport = GameApplication.Instance.SubViewport; - count = viewNode.GetChildCount(); - for (int i = count - 1; i >= 0; i--) - { - var node = viewNode.GetChild(i); - viewNode.RemoveChild(node); - viewport.CallDeferred("add_child", node); - } - viewNode.CallDeferred("queue_free"); - } - - public override void _Process(double delta) - { - - } - - public override void _PhysicsProcess(double delta) - { - // var colorRect = GetNode<ColorRect>("ColorRect"); - // var pos = GameApplication.Instance.ViewToGlobalPosition(GameApplication.Instance.Node3D.Player.GlobalPosition); - // colorRect.SetGlobalPosition(pos); - //GD.Print("pos: " + pos + ", " + colorRect.GlobalPosition); - } - - /// <summary> - /// 设置最大血量 - /// </summary> - public void SetMaxHp(int maxHp) - { - MaxHp = Mathf.Max(maxHp, 0); - hpSlot.Size = new Vector2(maxHp + 3, hpSlot.Size.Y); - if (Hp > maxHp) - { - SetHp(maxHp); - } - } - - /// <summary> - /// 设置最大护盾值 - /// </summary> - public void SetMaxShield(int maxShield) - { - MaxShield = Mathf.Max(maxShield, 0); ; - shieldSlot.Size = new Vector2(maxShield + 2, shieldSlot.Size.Y); - if (Shield > MaxShield) - { - SetShield(maxShield); - } - } - - /// <summary> - /// 设置当前血量 - /// </summary> - public void SetHp(int hp) - { - Hp = Mathf.Clamp(hp, 0, MaxHp); - hpBar.Size = new Vector2(hp, hpBar.Size.Y); - } - - /// <summary> - /// 设置护盾值 - /// </summary> - public void SetShield(int shield) - { - Shield = Mathf.Clamp(shield, 0, MaxShield); - shieldBar.Size = new Vector2(shield, shieldBar.Size.Y); - } - - /// <summary> - /// 玩家受到伤害 - /// </summary> - public void Hit(int num) - { - - } - - /// <summary> - /// 设置显示在 ui 上的枪的纹理 - /// </summary> - /// <param name="gun">纹理</param> - public void SetGunTexture(Texture2D gun) - { - if (gun != null) - { - gunSprite.Texture = gun; - gunSprite.Visible = true; - bulletText.Visible = true; - } - else - { - gunSprite.Visible = false; - bulletText.Visible = false; - } - } - - /// <summary> - /// 设置弹药数据 - /// </summary> - /// <param name="curr">当前弹夹弹药量</param> - /// <param name="total">剩余弹药总数</param> - public void SetAmmunition(int curr, int total) - { - bulletText.Text = curr + " / " + total; - } -} \ No newline at end of file diff --git a/DungeonShooting_Godot/src/game/ui/roomUI/RoomUI.cs b/DungeonShooting_Godot/src/game/ui/roomUI/RoomUI.cs new file mode 100644 index 0000000..0a9ac2e --- /dev/null +++ b/DungeonShooting_Godot/src/game/ui/roomUI/RoomUI.cs @@ -0,0 +1,277 @@ +namespace UI; + +public abstract partial class RoomUI : UiBase +{ + /// <summary> + /// 使用 Instance 属性获取当前节点实例对象, 节点类型: <see cref="Godot.Control"/>, 节点路径: RoomUI.Control + /// </summary> + public UiNode1_Control Control + { + get + { + if (_Control == null) _Control = new UiNode1_Control(GetNode<Godot.Control>("Control")); + return _Control; + } + } + private UiNode1_Control _Control; + + + + /// <summary> + /// 类型: <see cref="Godot.TextureRect"/>, 路径: RoomUI.Control.HealthBar.HpSlot.HpBar + /// </summary> + public class UiNode4_HpBar + { + /// <summary> + /// Ui节点实例, 节点类型: <see cref="Godot.TextureRect"/>, 节点路径: RoomUI.Control.HealthBar.HpSlot.HpBar + /// </summary> + public Godot.TextureRect Instance { get; } + + public UiNode4_HpBar(Godot.TextureRect node) => Instance = node; + public UiNode4_HpBar Clone() => new ((Godot.TextureRect)Instance.Duplicate()); + } + + /// <summary> + /// 类型: <see cref="Godot.NinePatchRect"/>, 路径: RoomUI.Control.HealthBar.HpSlot + /// </summary> + public class UiNode3_HpSlot + { + /// <summary> + /// Ui节点实例, 节点类型: <see cref="Godot.NinePatchRect"/>, 节点路径: RoomUI.Control.HealthBar.HpSlot + /// </summary> + public Godot.NinePatchRect Instance { get; } + + /// <summary> + /// 使用 Instance 属性获取当前节点实例对象, 节点类型: <see cref="Godot.TextureRect"/>, 节点路径: RoomUI.Control.HealthBar.HpBar + /// </summary> + public UiNode4_HpBar HpBar + { + get + { + if (_HpBar == null) _HpBar = new UiNode4_HpBar(Instance.GetNode<Godot.TextureRect>("HpBar")); + return _HpBar; + } + } + private UiNode4_HpBar _HpBar; + + public UiNode3_HpSlot(Godot.NinePatchRect node) => Instance = node; + public UiNode3_HpSlot Clone() => new ((Godot.NinePatchRect)Instance.Duplicate()); + } + + /// <summary> + /// 类型: <see cref="Godot.TextureRect"/>, 路径: RoomUI.Control.HealthBar.ShieldSlot.ShieldBar + /// </summary> + public class UiNode6_ShieldBar + { + /// <summary> + /// Ui节点实例, 节点类型: <see cref="Godot.TextureRect"/>, 节点路径: RoomUI.Control.HealthBar.ShieldSlot.ShieldBar + /// </summary> + public Godot.TextureRect Instance { get; } + + public UiNode6_ShieldBar(Godot.TextureRect node) => Instance = node; + public UiNode6_ShieldBar Clone() => new ((Godot.TextureRect)Instance.Duplicate()); + } + + /// <summary> + /// 类型: <see cref="Godot.NinePatchRect"/>, 路径: RoomUI.Control.HealthBar.ShieldSlot + /// </summary> + public class UiNode5_ShieldSlot + { + /// <summary> + /// Ui节点实例, 节点类型: <see cref="Godot.NinePatchRect"/>, 节点路径: RoomUI.Control.HealthBar.ShieldSlot + /// </summary> + public Godot.NinePatchRect Instance { get; } + + /// <summary> + /// 使用 Instance 属性获取当前节点实例对象, 节点类型: <see cref="Godot.TextureRect"/>, 节点路径: RoomUI.Control.HealthBar.ShieldBar + /// </summary> + public UiNode6_ShieldBar ShieldBar + { + get + { + if (_ShieldBar == null) _ShieldBar = new UiNode6_ShieldBar(Instance.GetNode<Godot.TextureRect>("ShieldBar")); + return _ShieldBar; + } + } + private UiNode6_ShieldBar _ShieldBar; + + public UiNode5_ShieldSlot(Godot.NinePatchRect node) => Instance = node; + public UiNode5_ShieldSlot Clone() => new ((Godot.NinePatchRect)Instance.Duplicate()); + } + + /// <summary> + /// 类型: <see cref="Godot.TextureRect"/>, 路径: RoomUI.Control.HealthBar + /// </summary> + public class UiNode2_HealthBar + { + /// <summary> + /// Ui节点实例, 节点类型: <see cref="Godot.TextureRect"/>, 节点路径: RoomUI.Control.HealthBar + /// </summary> + public Godot.TextureRect Instance { get; } + + /// <summary> + /// 使用 Instance 属性获取当前节点实例对象, 节点类型: <see cref="Godot.NinePatchRect"/>, 节点路径: RoomUI.Control.HpSlot + /// </summary> + public UiNode3_HpSlot HpSlot + { + get + { + if (_HpSlot == null) _HpSlot = new UiNode3_HpSlot(Instance.GetNode<Godot.NinePatchRect>("HpSlot")); + return _HpSlot; + } + } + private UiNode3_HpSlot _HpSlot; + + /// <summary> + /// 使用 Instance 属性获取当前节点实例对象, 节点类型: <see cref="Godot.NinePatchRect"/>, 节点路径: RoomUI.Control.ShieldSlot + /// </summary> + public UiNode5_ShieldSlot ShieldSlot + { + get + { + if (_ShieldSlot == null) _ShieldSlot = new UiNode5_ShieldSlot(Instance.GetNode<Godot.NinePatchRect>("ShieldSlot")); + return _ShieldSlot; + } + } + private UiNode5_ShieldSlot _ShieldSlot; + + public UiNode2_HealthBar(Godot.TextureRect node) => Instance = node; + public UiNode2_HealthBar Clone() => new ((Godot.TextureRect)Instance.Duplicate()); + } + + /// <summary> + /// 类型: <see cref="Godot.TextureRect"/>, 路径: RoomUI.Control.MapBar + /// </summary> + public class UiNode7_MapBar + { + /// <summary> + /// Ui节点实例, 节点类型: <see cref="Godot.TextureRect"/>, 节点路径: RoomUI.Control.MapBar + /// </summary> + public Godot.TextureRect Instance { get; } + + public UiNode7_MapBar(Godot.TextureRect node) => Instance = node; + public UiNode7_MapBar Clone() => new ((Godot.TextureRect)Instance.Duplicate()); + } + + /// <summary> + /// 类型: <see cref="Godot.TextureRect"/>, 路径: RoomUI.Control.GunBar.GunSprite + /// </summary> + public class UiNode9_GunSprite + { + /// <summary> + /// Ui节点实例, 节点类型: <see cref="Godot.TextureRect"/>, 节点路径: RoomUI.Control.GunBar.GunSprite + /// </summary> + public Godot.TextureRect Instance { get; } + + public UiNode9_GunSprite(Godot.TextureRect node) => Instance = node; + public UiNode9_GunSprite Clone() => new ((Godot.TextureRect)Instance.Duplicate()); + } + + /// <summary> + /// 类型: <see cref="Godot.Label"/>, 路径: RoomUI.Control.GunBar.BulletText + /// </summary> + public class UiNode10_BulletText + { + /// <summary> + /// Ui节点实例, 节点类型: <see cref="Godot.Label"/>, 节点路径: RoomUI.Control.GunBar.BulletText + /// </summary> + public Godot.Label Instance { get; } + + public UiNode10_BulletText(Godot.Label node) => Instance = node; + public UiNode10_BulletText Clone() => new ((Godot.Label)Instance.Duplicate()); + } + + /// <summary> + /// 类型: <see cref="Godot.Control"/>, 路径: RoomUI.Control.GunBar + /// </summary> + public class UiNode8_GunBar + { + /// <summary> + /// Ui节点实例, 节点类型: <see cref="Godot.Control"/>, 节点路径: RoomUI.Control.GunBar + /// </summary> + public Godot.Control Instance { get; } + + /// <summary> + /// 使用 Instance 属性获取当前节点实例对象, 节点类型: <see cref="Godot.TextureRect"/>, 节点路径: RoomUI.Control.GunSprite + /// </summary> + public UiNode9_GunSprite GunSprite + { + get + { + if (_GunSprite == null) _GunSprite = new UiNode9_GunSprite(Instance.GetNode<Godot.TextureRect>("GunSprite")); + return _GunSprite; + } + } + private UiNode9_GunSprite _GunSprite; + + /// <summary> + /// 使用 Instance 属性获取当前节点实例对象, 节点类型: <see cref="Godot.Label"/>, 节点路径: RoomUI.Control.BulletText + /// </summary> + public UiNode10_BulletText BulletText + { + get + { + if (_BulletText == null) _BulletText = new UiNode10_BulletText(Instance.GetNode<Godot.Label>("BulletText")); + return _BulletText; + } + } + private UiNode10_BulletText _BulletText; + + public UiNode8_GunBar(Godot.Control node) => Instance = node; + public UiNode8_GunBar Clone() => new ((Godot.Control)Instance.Duplicate()); + } + + /// <summary> + /// 类型: <see cref="Godot.Control"/>, 路径: RoomUI.Control + /// </summary> + public class UiNode1_Control + { + /// <summary> + /// Ui节点实例, 节点类型: <see cref="Godot.Control"/>, 节点路径: RoomUI.Control + /// </summary> + public Godot.Control Instance { get; } + + /// <summary> + /// 使用 Instance 属性获取当前节点实例对象, 节点类型: <see cref="Godot.TextureRect"/>, 节点路径: RoomUI.HealthBar + /// </summary> + public UiNode2_HealthBar HealthBar + { + get + { + if (_HealthBar == null) _HealthBar = new UiNode2_HealthBar(Instance.GetNode<Godot.TextureRect>("HealthBar")); + return _HealthBar; + } + } + private UiNode2_HealthBar _HealthBar; + + /// <summary> + /// 使用 Instance 属性获取当前节点实例对象, 节点类型: <see cref="Godot.TextureRect"/>, 节点路径: RoomUI.MapBar + /// </summary> + public UiNode7_MapBar MapBar + { + get + { + if (_MapBar == null) _MapBar = new UiNode7_MapBar(Instance.GetNode<Godot.TextureRect>("MapBar")); + return _MapBar; + } + } + private UiNode7_MapBar _MapBar; + + /// <summary> + /// 使用 Instance 属性获取当前节点实例对象, 节点类型: <see cref="Godot.Control"/>, 节点路径: RoomUI.GunBar + /// </summary> + public UiNode8_GunBar GunBar + { + get + { + if (_GunBar == null) _GunBar = new UiNode8_GunBar(Instance.GetNode<Godot.Control>("GunBar")); + return _GunBar; + } + } + private UiNode8_GunBar _GunBar; + + public UiNode1_Control(Godot.Control node) => Instance = node; + public UiNode1_Control Clone() => new ((Godot.Control)Instance.Duplicate()); + } + +} diff --git a/DungeonShooting_Godot/src/game/ui/roomUI/RoomUIPanel.cs b/DungeonShooting_Godot/src/game/ui/roomUI/RoomUIPanel.cs new file mode 100644 index 0000000..143b8a5 --- /dev/null +++ b/DungeonShooting_Godot/src/game/ui/roomUI/RoomUIPanel.cs @@ -0,0 +1,163 @@ +using Godot; + +namespace UI; + +/// <summary> +/// 房间中的ui +/// </summary> +public partial class RoomUIPanel : RoomUI +{ + /// <summary> + /// 当前血量 + /// </summary> + public int Hp { get; private set; } + /// <summary> + /// 最大血量 + /// </summary> + public int MaxHp { get; private set; } + /// <summary> + /// 当前护盾值 + /// </summary> + public int Shield { get; private set; } + /// <summary> + /// 最大护盾值 + /// </summary> + public int MaxShield { get; private set; } + + /// <summary> + /// 互动提示组件 + /// </summary> + public InteractiveTipBar InteractiveTipBar { get; private set; } + /// <summary> + /// 换弹进度组件 + /// </summary> + public ReloadBar ReloadBar { get; private set; } + + public override void OnOpen(params object[] args) + { + + } + + public override void OnClose() + { + + } + + public override void _EnterTree() + { + InteractiveTipBar = GetNode<InteractiveTipBar>("ViewNode/InteractiveTipBar"); + InteractiveTipBar.Visible = false; + + ReloadBar = GetNode<ReloadBar>("ViewNode/ReloadBar"); + ReloadBar.Visible = false; + } + + public override void _Ready() + { + //将 GlobalNode 节点下的 ui 节点放入全局坐标中 + var globalNode = GetNode("GlobalNode"); + var root = GameApplication.Instance.GlobalNodeRoot; + var count = globalNode.GetChildCount(); + for (int i = count - 1; i >= 0; i--) + { + var node = globalNode.GetChild(i); + globalNode.RemoveChild(node); + root.CallDeferred("add_child", node); + } + globalNode.CallDeferred("queue_free"); + + //将 ViewNode 节点放到 SubViewport 下 + var viewNode = GetNode("ViewNode"); + var viewport = GameApplication.Instance.SubViewport; + count = viewNode.GetChildCount(); + for (int i = count - 1; i >= 0; i--) + { + var node = viewNode.GetChild(i); + viewNode.RemoveChild(node); + viewport.CallDeferred("add_child", node); + } + viewNode.CallDeferred("queue_free"); + } + + /// <summary> + /// 设置最大血量 + /// </summary> + public void SetMaxHp(int maxHp) + { + MaxHp = Mathf.Max(maxHp, 0); + Control.HealthBar.HpSlot.Instance.Size = new Vector2(maxHp + 3, Control.HealthBar.HpSlot.Instance.Size.Y); + if (Hp > maxHp) + { + SetHp(maxHp); + } + } + + /// <summary> + /// 设置最大护盾值 + /// </summary> + public void SetMaxShield(int maxShield) + { + MaxShield = Mathf.Max(maxShield, 0); ; + Control.HealthBar.ShieldSlot.Instance.Size = new Vector2(maxShield + 2, Control.HealthBar.ShieldSlot.Instance.Size.Y); + if (Shield > MaxShield) + { + SetShield(maxShield); + } + } + + /// <summary> + /// 设置当前血量 + /// </summary> + public void SetHp(int hp) + { + Hp = Mathf.Clamp(hp, 0, MaxHp); + Control.HealthBar.HpSlot.Instance.Size = new Vector2(hp, Control.HealthBar.HpSlot.Instance.Size.Y); + } + + /// <summary> + /// 设置护盾值 + /// </summary> + public void SetShield(int shield) + { + Shield = Mathf.Clamp(shield, 0, MaxShield); + Control.HealthBar.ShieldSlot.Instance.Size = new Vector2(shield, Control.HealthBar.ShieldSlot.Instance.Size.Y); + } + + /// <summary> + /// 玩家受到伤害 + /// </summary> + public void Hit(int num) + { + + } + + /// <summary> + /// 设置显示在 ui 上的枪的纹理 + /// </summary> + /// <param name="gun">纹理</param> + public void SetGunTexture(Texture2D gun) + { + if (gun != null) + { + Control.GunBar.GunSprite.Instance.Texture = gun; + Control.GunBar.GunSprite.Instance.Visible = true; + Control.GunBar.BulletText.Instance.Visible = true; + } + else + { + Control.GunBar.GunSprite.Instance.Visible = false; + Control.GunBar.BulletText.Instance.Visible = false; + } + } + + /// <summary> + /// 设置弹药数据 + /// </summary> + /// <param name="curr">当前弹夹弹药量</param> + /// <param name="total">剩余弹药总数</param> + public void SetAmmunition(int curr, int total) + { + Control.GunBar.BulletText.Instance.Text = curr + " / " + total; + } + +} \ No newline at end of file diff --git a/DungeonShooting_Godot/src/test/TestUi/Test.cs b/DungeonShooting_Godot/src/test/TestUi/Test.cs new file mode 100644 index 0000000..d577cb9 --- /dev/null +++ b/DungeonShooting_Godot/src/test/TestUi/Test.cs @@ -0,0 +1,88 @@ +using Godot; + +namespace UI; + +/* + Test + c1 + c11 + c2 + */ +public abstract partial class Test : UiBase +{ + public UiNode2_c1 c1 + { + get + { + if (_c1 == null) _c1 = new UiNode2_c1(GetNode<Control>("c1")); + return _c1; + } + } + public UiNode3_c2 c2 + { + get + { + if (_c2 == null) _c2 = new UiNode3_c2(GetNode<Control>("c2")); + return _c2; + } + } + + private UiNode2_c1 _c1; + private UiNode3_c2 _c2; + + public class UiNode1_c11 + { + public Control Instance { get; } + + public UiNode1_c11(Control node) + { + Instance = node; + } + + public UiNode1_c11 Clone() + { + return new UiNode1_c11((Control)Instance.Duplicate()); + } + } + + public class UiNode2_c1 + { + public Control Instance { get; } + + public UiNode1_c11 c11 + { + get + { + if (_c11 == null) _c11 = new UiNode1_c11(Instance.GetNode<Control>("c11")); + return _c11; + } + } + + private UiNode1_c11 _c11; + + public UiNode2_c1(Control node) + { + Instance = node; + } + + public UiNode2_c1 Clone() + { + return new UiNode2_c1((Control)Instance.Duplicate()); + } + } + + public class UiNode3_c2 + { + public Control Instance { get; } + + public UiNode3_c2(Control node) + { + Instance = node; + } + + public UiNode3_c2 Clone() + { + return new UiNode3_c2((Control)Instance.Duplicate()); + } + } +} \ No newline at end of file diff --git a/DungeonShooting_Godot/src/test/TestUi/TestPanel.cs b/DungeonShooting_Godot/src/test/TestUi/TestPanel.cs new file mode 100644 index 0000000..a65c268 --- /dev/null +++ b/DungeonShooting_Godot/src/test/TestUi/TestPanel.cs @@ -0,0 +1,14 @@ +namespace UI; + +public partial class TestPanel : Test +{ + public override void OnOpen(params object[] args) + { + + } + + public override void OnClose() + { + + } +} \ No newline at end of file