diff --git a/DungeonShooting_Godot/prefab/role/Player0001.tscn b/DungeonShooting_Godot/prefab/role/Player0001.tscn
new file mode 100644
index 0000000..dc986d2
--- /dev/null
+++ b/DungeonShooting_Godot/prefab/role/Player0001.tscn
@@ -0,0 +1,33 @@
+[gd_scene load_steps=5 format=3 uid="uid://dhvpoolrlrbq7"]
+
+[ext_resource type="Script" path="res://src/game/role/Player.cs" id="1_dl8pn"]
+[ext_resource type="Shader" path="res://resource/material/Blend.gdshader" id="2_ispp0"]
+
+[sub_resource type="ShaderMaterial" id="ShaderMaterial_4wbfd"]
+resource_local_to_scene = true
+shader = ExtResource("2_ispp0")
+shader_parameter/blend = Color(0, 0, 0, 0.470588)
+shader_parameter/schedule = 1
+
+[sub_resource type="ShaderMaterial" id="ShaderMaterial_mr55t"]
+resource_local_to_scene = true
+shader = ExtResource("2_ispp0")
+shader_parameter/blend = Color(1, 1, 1, 1)
+shader_parameter/schedule = 0
+
+[node name="Player0001" type="CharacterBody2D" node_paths=PackedStringArray("ShadowSprite", "AnimatedSprite", "Collision")]
+script = ExtResource("1_dl8pn")
+ShadowSprite = NodePath("CanvasGroup/ShadowSprite")
+AnimatedSprite = NodePath("CanvasGroup/AnimatedSprite")
+Collision = NodePath("Collision")
+
+[node name="CanvasGroup" type="CanvasGroup" parent="."]
+
+[node name="ShadowSprite" type="Sprite2D" parent="CanvasGroup"]
+z_index = -1
+material = SubResource("ShaderMaterial_4wbfd")
+
+[node name="AnimatedSprite" type="AnimatedSprite2D" parent="CanvasGroup"]
+material = SubResource("ShaderMaterial_mr55t")
+
+[node name="Collision" type="CollisionShape2D" parent="."]
diff --git a/DungeonShooting_Godot/src/framework/activity/ActivityObject.cs b/DungeonShooting_Godot/src/framework/activity/ActivityObject.cs
index acb7a15..50cf1dc 100644
--- a/DungeonShooting_Godot/src/framework/activity/ActivityObject.cs
+++ b/DungeonShooting_Godot/src/framework/activity/ActivityObject.cs
@@ -26,21 +26,24 @@
/// 是否是静态物体, 如果为true, 则会禁用移动处理
///
public bool IsStatic { get; set; }
-
- ///
- /// 当前物体显示的精灵图像, 节点名称必须叫 "AnimatedSprite2D", 类型为 AnimatedSprite2D
- ///
- public AnimatedSprite2D AnimatedSprite { get; private set; }
///
/// 当前物体显示的阴影图像, 节点名称必须叫 "ShadowSprite", 类型为 Sprite2D
///
- public Sprite2D ShadowSprite { get; private set; }
+ [Export, ExportFillNode]
+ public Sprite2D ShadowSprite { get; set; }
+
+ ///
+ /// 当前物体显示的精灵图像, 节点名称必须叫 "AnimatedSprite2D", 类型为 AnimatedSprite2D
+ ///
+ [Export, ExportFillNode]
+ public AnimatedSprite2D AnimatedSprite { get; set; }
///
/// 当前物体碰撞器节点, 节点名称必须叫 "Collision", 类型为 CollisionShape2D
///
- public CollisionShape2D Collision { get; private set; }
+ [Export, ExportFillNode]
+ public CollisionShape2D Collision { get; set; }
///
/// 是否调用过 Destroy() 函数
@@ -62,8 +65,22 @@
///
public Vector2 BasisVelocity
{
- get => MoveController.BasisVelocity;
- set => MoveController.BasisVelocity = value;
+ get
+ {
+ if (MoveController != null)
+ {
+ return MoveController.BasisVelocity;
+ }
+
+ return Vector2.Zero;
+ }
+ set
+ {
+ if (MoveController != null)
+ {
+ MoveController.BasisVelocity = value;
+ }
+ }
}
///
@@ -244,16 +261,25 @@
//初始化节点
private void _InitNode(string itemId, World world)
{
+#if TOOLS
+ if (!Engine.IsEditorHint())
+ {
+ if (GetType().GetCustomAttributes(typeof(ToolAttribute), false).Length == 0)
+ {
+ throw new Exception($"ActivityObject子类'{GetType().FullName}'没有加[Tool]标记!");
+ }
+ }
+#endif
World = world;
ItemId = itemId;
Name = GetType().Name + (_instanceIndex++);
- AnimatedSprite = GetNode("AnimatedSprite");
+ //AnimatedSprite = GetNode("AnimatedSprite");
_blendShaderMaterial = AnimatedSprite.Material as ShaderMaterial;
- ShadowSprite = GetNode("ShadowSprite");
+ //ShadowSprite = GetNode("ShadowSprite");
ShadowSprite.Visible = false;
- Collision = GetNode("Collision");
+ //Collision = GetNode("Collision");
MotionMode = MotionModeEnum.Floating;
MoveController = AddComponent();
@@ -266,6 +292,14 @@
///
public sealed override void _Ready()
{
+
+ }
+
+ ///
+ /// 子类需要重写 _EnterTree() 函数, 请重写 EnterTree()
+ ///
+ public sealed override void _EnterTree()
+ {
#if TOOLS
// 在工具模式下创建的 template 节点自动创建对应的必要子节点
if (Engine.IsEditorHint())
@@ -274,6 +308,14 @@
}
#endif
}
+
+ ///
+ /// 子类需要重写 _ExitTree() 函数, 请重写 ExitTree()
+ ///
+ public sealed override void _ExitTree()
+ {
+
+ }
///
/// 显示阴影
@@ -361,6 +403,22 @@
public virtual void OnInit()
{
}
+
+ ///
+ /// 进入场景树时调用
+ ///
+ public virtual void EnterTree()
+ {
+
+ }
+
+ ///
+ /// 离开场景树时调用
+ ///
+ public virtual void ExitTree()
+ {
+
+ }
///
/// 返回是否能与其他ActivityObject互动
diff --git a/DungeonShooting_Godot/src/framework/activity/ActivityObject_EditorTool.cs b/DungeonShooting_Godot/src/framework/activity/ActivityObject_EditorTool.cs
index dbed5a4..7564fb1 100644
--- a/DungeonShooting_Godot/src/framework/activity/ActivityObject_EditorTool.cs
+++ b/DungeonShooting_Godot/src/framework/activity/ActivityObject_EditorTool.cs
@@ -1,9 +1,51 @@
+using System;
+using System.Collections.Generic;
+using System.Reflection;
using Godot;
+using UI.EditorTools;
public partial class ActivityObject
{
+ ///
+ /// 该函数只会在编辑器中调用, 用于自定义处理被 [ExportFill] 标记后自动创建的节点
+ ///
+ /// 属性名称
+ /// 节点实例
+ protected virtual void OnExportFillNode(string propertyName, Node node)
+ {
+ switch (propertyName)
+ {
+ case "ShadowSprite":
+ {
+ var sprite = (Sprite2D)node;
+ sprite.ZIndex = -1;
+ var material =
+ ResourceManager.Load(ResourcePath.resource_material_Blend_tres, false);
+ material.SetShaderParameter("blend", new Color(0, 0, 0, 0.47058824F));
+ material.SetShaderParameter("schedule", 1);
+ sprite.Material = material;
+ }
+ break;
+ case "AnimatedSprite":
+ {
+ var animatedSprite = (AnimatedSprite2D)node;
+ var material =
+ ResourceManager.Load(ResourcePath.resource_material_Blend_tres, false);
+ material.SetShaderParameter("blend", new Color(1, 1, 1, 1));
+ material.SetShaderParameter("schedule", 0);
+ animatedSprite.Material = material;
+ }
+ break;
+ case "Collision":
+ {
+
+ }
+ break;
+ }
+ }
+
private void _InitNodeInEditor()
{
var parent = GetParent();
@@ -24,66 +66,48 @@
owner = parent;
}
- var sprite = GetNodeOrNull("ShadowSprite");
- //创建Shadow
- if (sprite == null)
+ var type = GetType();
+ var propertyInfos = type.GetProperties(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
+ var propertyInfoList = new List();
+ foreach (var propertyInfo in propertyInfos)
{
- sprite = new Sprite2D();
- sprite.Name = "ShadowSprite";
- sprite.ZIndex = -1;
- var material =
- ResourceManager.Load(ResourcePath.resource_material_Blend_tres, false);
- material.SetShaderParameter("blend", new Color(0, 0, 0, 0.47058824F));
- material.SetShaderParameter("schedule", 1);
- sprite.Material = material;
- AddChild(sprite);
- sprite.Owner = owner;
- }
- else if (sprite.Material == null)
- {
- var material =
- ResourceManager.Load(ResourcePath.resource_material_Blend_tres, false);
- material.SetShaderParameter("blend", new Color(0, 0, 0, 0.47058824F));
- material.SetShaderParameter("schedule", 1);
- sprite.Material = material;
- }
+ if (propertyInfo.GetCustomAttributes(typeof(ExportFillNodeAttribute), false).Length > 0)
+ {
+ if (propertyInfo.GetCustomAttributes(typeof(ExportAttribute), false).Length == 0)
+ {
+ EditorToolsPanel.ShowConfirmInEditor("警告", $"'{type.FullName}'中字段'{propertyInfo.Name}'使用了[ExportAutoFill],\n但是并没有加上[Export], 请补上!");
+ return;
+ }
- var animatedSprite = GetNodeOrNull("AnimatedSprite");
- //创建 Sprite2D
- if (animatedSprite == null)
- {
- animatedSprite = new AnimatedSprite2D();
- animatedSprite.Name = "AnimatedSprite";
- var material =
- ResourceManager.Load(ResourcePath.resource_material_Blend_tres, false);
- material.SetShaderParameter("blend", new Color(1, 1, 1, 1));
- material.SetShaderParameter("schedule", 0);
- animatedSprite.Material = material;
- AddChild(animatedSprite);
- animatedSprite.Owner = owner;
+ if (propertyInfo.PropertyType.IsAssignableTo(typeof(Node)))
+ {
+ if (propertyInfo.SetMethod == null)
+ {
+ EditorToolsPanel.ShowConfirmInEditor("警告", $"请为'{type.FullName}'中的'{propertyInfo.Name}'属性设置set访问器, 或者将set服务器设置成public!");
+ return;
+ }
+ propertyInfoList.Add(propertyInfo);
+ }
+ }
}
- else if (animatedSprite.Material == null)
+ foreach (var propertyInfo in propertyInfoList)
{
- var material =
- ResourceManager.Load(ResourcePath.resource_material_Blend_tres, false);
- material.SetShaderParameter("blend", new Color(1, 1, 1, 1));
- material.SetShaderParameter("schedule", 0);
- animatedSprite.Material = material;
- }
-
- //创建Collision
- if (GetNodeOrNull("Collision") == null)
- {
- var co = new CollisionShape2D();
- co.Name = "Collision";
- AddChild(co);
- co.Owner = owner;
+ var value = propertyInfo.GetValue(this);
+ if (value == null || ((Node)value).GetParent() == null)
+ {
+ var node = GetNodeOrNull(propertyInfo.Name);
+ if (node == null)
+ {
+ node = (Node)Activator.CreateInstance(propertyInfo.PropertyType);
+ AddChild(node);
+ node.Name = propertyInfo.Name;
+ node.Owner = owner;
+ //自定义处理导出的节点
+ OnExportFillNode(propertyInfo.Name, node);
+ }
+ propertyInfo.SetValue(this, node);
+ }
}
}
}
-
- private Node GetOwnerInEditor()
- {
- return null;
- }
}
\ No newline at end of file
diff --git a/DungeonShooting_Godot/src/framework/activity/ExportFillNodeAttribute.cs b/DungeonShooting_Godot/src/framework/activity/ExportFillNodeAttribute.cs
new file mode 100644
index 0000000..0616e34
--- /dev/null
+++ b/DungeonShooting_Godot/src/framework/activity/ExportFillNodeAttribute.cs
@@ -0,0 +1,10 @@
+
+using System;
+
+///
+/// 标记类型为Node的属性, 表示当前属性如果没有赋值, 则在编辑器中自动创建子节点, 必须搭配 [Export] 使用!
+///
+[AttributeUsage(AttributeTargets.Field | AttributeTargets.Property)]
+public class ExportFillNodeAttribute : Attribute
+{
+}
\ No newline at end of file
diff --git a/DungeonShooting_Godot/src/framework/map/mark/ActivityExpression.cs b/DungeonShooting_Godot/src/framework/map/mark/ActivityExpression.cs
deleted file mode 100644
index 040dd1d..0000000
--- a/DungeonShooting_Godot/src/framework/map/mark/ActivityExpression.cs
+++ /dev/null
@@ -1,10 +0,0 @@
-using System;
-
-///
-/// 用于 ActivityMark 字段上, 表示当前字段是一个表达式字段
-///
-[AttributeUsage(AttributeTargets.Field)]
-public class ActivityExpression : Attribute
-{
-
-}
\ No newline at end of file
diff --git a/DungeonShooting_Godot/src/framework/map/mark/ActivityExpressionAttribute.cs b/DungeonShooting_Godot/src/framework/map/mark/ActivityExpressionAttribute.cs
new file mode 100644
index 0000000..dc0ee12
--- /dev/null
+++ b/DungeonShooting_Godot/src/framework/map/mark/ActivityExpressionAttribute.cs
@@ -0,0 +1,10 @@
+using System;
+
+///
+/// 用于 ActivityMark 字段上, 表示当前字段是一个表达式字段
+///
+[AttributeUsage(AttributeTargets.Field)]
+public class ActivityExpressionAttribute : Attribute
+{
+
+}
\ No newline at end of file
diff --git a/DungeonShooting_Godot/src/framework/map/mark/ActivityMark.cs b/DungeonShooting_Godot/src/framework/map/mark/ActivityMark.cs
index ec4c0a5..9c91cdd 100644
--- a/DungeonShooting_Godot/src/framework/map/mark/ActivityMark.cs
+++ b/DungeonShooting_Godot/src/framework/map/mark/ActivityMark.cs
@@ -104,7 +104,7 @@
var tempList = type.GetFields(BindingFlags.Instance | BindingFlags.Public);
foreach (var s in tempList)
{
- if (s.GetCustomAttribute() != null)
+ if (s.GetCustomAttribute() != null)
{
fieldInfos.Add(s.Name);
}
diff --git a/DungeonShooting_Godot/src/game/item/weapon/Weapon.cs b/DungeonShooting_Godot/src/game/item/weapon/Weapon.cs
index ad92d9f..1aceed4 100644
--- a/DungeonShooting_Godot/src/game/item/weapon/Weapon.cs
+++ b/DungeonShooting_Godot/src/game/item/weapon/Weapon.cs
@@ -280,10 +280,9 @@
return 1;
}
- public override void _EnterTree()
+ public override void EnterTree()
{
- base._EnterTree();
-
+ base.EnterTree();
//收集落在地上的武器
if (IsInGround())
{
@@ -291,10 +290,9 @@
}
}
- public override void _ExitTree()
+ public override void ExitTree()
{
- base._ExitTree();
-
+ base.ExitTree();
World.Weapon_UnclaimedWeapons.Remove(this);
}
diff --git a/DungeonShooting_Godot/src/game/role/enemy/Enemy.cs b/DungeonShooting_Godot/src/game/role/enemy/Enemy.cs
index 85b45af..b52fa59 100644
--- a/DungeonShooting_Godot/src/game/role/enemy/Enemy.cs
+++ b/DungeonShooting_Godot/src/game/role/enemy/Enemy.cs
@@ -16,6 +16,7 @@
///
/// 基础敌人
///
+[Tool, GlobalClass]
public partial class Enemy : Role
{
///
@@ -92,17 +93,18 @@
StateController.ChangeStateInstant(AiStateEnum.AiNormal);
}
- public override void _EnterTree()
+ public override void EnterTree()
{
+ base.EnterTree();
if (!World.Enemy_InstanceList.Contains(this))
{
World.Enemy_InstanceList.Add(this);
}
}
- public override void _ExitTree()
+ public override void ExitTree()
{
- base._ExitTree();
+ base.ExitTree();
World.Enemy_InstanceList.Remove(this);
}
diff --git a/DungeonShooting_Godot/src/game/ui/editorTools/EditorToolsPanel.cs b/DungeonShooting_Godot/src/game/ui/editorTools/EditorToolsPanel.cs
index 9571f29..0589080 100644
--- a/DungeonShooting_Godot/src/game/ui/editorTools/EditorToolsPanel.cs
+++ b/DungeonShooting_Godot/src/game/ui/editorTools/EditorToolsPanel.cs
@@ -393,4 +393,28 @@
ExcelGenerator.ExportExcel();
ShowTips("提示", "已启动导表程序, 注意查看控制台信息!");
}
+
+ ///
+ /// 在编辑器中打开一个提示窗口
+ ///
+ public static void ShowTipsInEditor(string title, string message, Action onClose)
+ {
+ var editorToolsInstance = UiManager.Get_EditorTools_Instance();
+ if (editorToolsInstance.Length > 0)
+ {
+ editorToolsInstance[0].ShowTips(title, message, onClose);
+ }
+ }
+
+ ///
+ /// 在编辑器中打开一个询问窗口
+ ///
+ public static void ShowConfirmInEditor(string title, string message, Action onClose = null)
+ {
+ var editorToolsInstance = UiManager.Get_EditorTools_Instance();
+ if (editorToolsInstance.Length > 0)
+ {
+ editorToolsInstance[0].ShowConfirm(title, message, onClose);
+ }
+ }
}