diff --git a/DungeonShooting_Godot/addons/dungeonShooting_plugin/Plugin.cs b/DungeonShooting_Godot/addons/dungeonShooting_plugin/Plugin.cs index af4f4ec..6e9581b 100644 --- a/DungeonShooting_Godot/addons/dungeonShooting_plugin/Plugin.cs +++ b/DungeonShooting_Godot/addons/dungeonShooting_plugin/Plugin.cs @@ -42,18 +42,12 @@ //自定义节点 private CustomTypeInfo[] _customTypeInfos = new CustomTypeInfo[] { - // new CustomTypeInfo( - // "ActivityMark", - // "Node2D", - // "res://src/framework/map/mark/ActivityMark.cs", - // "res://addons/dungeonShooting_plugin/Mark.svg" - // ), - // new CustomTypeInfo( - // "EnemyMark", - // "Node2D", - // "res://src/framework/map/mark/EnemyMark.cs", - // "res://addons/dungeonShooting_plugin/Mark.svg" - // ), + new CustomTypeInfo( + "ActivityInstance", + "Node2D", + "res://src/framework/activity/ActivityInstance.cs", + "res://addons/dungeonShooting_plugin/Mark.svg" + ), }; public override void _Process(double delta) diff --git a/DungeonShooting_Godot/scene/Hall.tscn b/DungeonShooting_Godot/scene/Hall.tscn index 0669ca8..dd62a0b 100644 --- a/DungeonShooting_Godot/scene/Hall.tscn +++ b/DungeonShooting_Godot/scene/Hall.tscn @@ -1,6 +1,6 @@ [gd_scene load_steps=10 format=3 uid="uid://c2hynqudkykxl"] -[ext_resource type="PackedScene" path="res://scene/Dungeon.tscn" id="1_31od0"] +[ext_resource type="PackedScene" uid="uid://bqf2vks5ggnsp" path="res://scene/Dungeon.tscn" id="1_31od0"] [ext_resource type="Script" path="res://src/game/hall/Hall.cs" id="2_43fdu"] [ext_resource type="Texture2D" uid="uid://b2j5mkqm3uv6w" path="res://resource/sprite/hall/HallBg.png" id="3_p8v6p"] [ext_resource type="Script" path="res://src/game/hall/DungeonEntrance.cs" id="3_t3my6"] @@ -27,10 +27,14 @@ metadata/_edit_horizontal_guides_ = [666.0, -210.0] [node name="HallBg" type="Sprite2D" parent="." index="1"] +z_index = -5 texture = ExtResource("3_p8v6p") centered = false -[node name="DungeonEntrance" type="Area2D" parent="." index="2"] +[node name="BirthMark" type="Marker2D" parent="." index="2"] +position = Vector2(553, 320) + +[node name="DungeonEntrance" type="Area2D" parent="." index="3"] position = Vector2(537, 209) collision_layer = 0 collision_mask = 8 @@ -40,14 +44,7 @@ [node name="CollisionShape2D" type="CollisionShape2D" parent="DungeonEntrance" index="0"] shape = SubResource("RectangleShape2D_ru8u4") -[node name="BirthMark" type="Marker2D" parent="." index="3"] -position = Vector2(553, 320) - -[node name="PointLight2D" type="PointLight2D" parent="." index="4"] -position = Vector2(138, 306) -texture_scale = 3.11 - -[node name="StaticBody2D" type="StaticBody2D" parent="." index="5"] +[node name="StaticBody2D" type="StaticBody2D" parent="." index="4"] collision_mask = 0 [node name="CollisionShape2D" type="CollisionShape2D" parent="StaticBody2D" index="0"] diff --git a/DungeonShooting_Godot/src/framework/activity/ActivityInstance.cs b/DungeonShooting_Godot/src/framework/activity/ActivityInstance.cs new file mode 100644 index 0000000..6deea4b --- /dev/null +++ b/DungeonShooting_Godot/src/framework/activity/ActivityInstance.cs @@ -0,0 +1,325 @@ + +using System; +using System.IO; +using Godot; + +/// +/// 用于在预制场景中创建 ActivityObject +/// +[Tool] +public partial class ActivityInstance : Node2D +{ + /// + /// 物体Id + /// + [Export] + public string Id + { + get => _id; + set + { + _id = value; + _dirty = true; + } + } + + /// + /// 默认所在层级 + /// + [Export] + public RoomLayerEnum DefaultLayer { get; set; } = RoomLayerEnum.NormalLayer; + + /// + /// 是否显示阴影 + /// + [Export] + public bool ShowSprite + { + get => _showSprite; + set + { + _showSprite = value; + if (_activityObject != null) + { + if (value) + { + _activityObject.ShowShadowSprite(); + } + else + { + _activityObject.HideShadowSprite(); + } + } + } + } + + /// + /// 阴影偏移 + /// + [Export] + public Vector2 ShowOffset + { + get => _showOffset; + set + { + _showOffset = value; + if (_activityObject != null) + { + _activityObject.ShadowOffset = value; + } + } + } + + /// + /// 初始海拔高度 + /// + [Export] + public float Altitude + { + get => _altitude; + set + { + _altitude = value; + if (_activityObject != null) + { + _activityObject.Altitude = value; + _activityObject.Collision.Position = _collPos; + _activityObject.UpdateShadowSprite((float)GetProcessDeltaTime()); + _activityObject.CalcThrowAnimatedPosition(); + } + } + } + + /// + /// 是否启用垂直运动模拟 + /// + [Export] + public bool VerticalMotion { get; private set; } = true; + + /// + /// 编辑器属性, 物体子碰撞器在编辑器中是否可见 + /// + [Export] + public bool CollisionVisible + { + get => _collisionVisible; + set + { + _collisionVisible = value; + OnChangeCollisionVisible(); + } + } + + private bool _dirty = false; + private bool _collisionVisible = true; + private string _prevId; + private string _id; + private ActivityObject _activityObject; + private Sprite2D _errorSprite; + private bool _showSprite = true; + private Vector2 _showOffset = new Vector2(0, 2); + private float _altitude; + + private Vector2 _collPos; + private bool _createFlag = false; + + private static string _jsonText; + + public override void _Ready() + { +#if TOOLS + if (!Engine.IsEditorHint()) + { +#endif + var world = World.Current; + if (world != null && world.YSortLayer != null && world.NormalLayer != null) + { + DoCreateObject(); + } +#if TOOLS + } +#endif + } + + public override void _Process(double delta) + { +#if TOOLS + if (Engine.IsEditorHint()) + { + if (_dirty || (_activityObject != null && _activityObject.GetParent() != this)) + { + _dirty = false; + + if (_prevId != _id) + { + OnChangeActivityId(_id); + } + else if (string.IsNullOrEmpty(_id)) + { + ShowErrorSprite(); + } + + OnChangeCollisionVisible(); + } + + if (_activityObject != null) + { + _activityObject.Collision.Position = _collPos; + _activityObject.UpdateShadowSprite((float)delta); + _activityObject.CalcThrowAnimatedPosition(); + } + } + else + { +#endif + var world = World.Current; + if (world != null && world.YSortLayer != null && world.NormalLayer != null) + { + DoCreateObject(); + } +#if TOOLS + } +#endif + } + + public override void _EnterTree() + { +#if TOOLS + if (Engine.IsEditorHint()) + { + var children = GetChildren(); + foreach (var child in children) + { + child.QueueFree(); + } + _dirty = true; + _activityObject = null; + _prevId = null; + } +#endif + } + + public override void _ExitTree() + { +#if TOOLS + if (Engine.IsEditorHint() && _activityObject != null) + { + _activityObject.QueueFree(); + _activityObject = null; + } +#endif + } + + private void DoCreateObject() + { + if (_createFlag) + { + return; + } + + _createFlag = true; + var activityObject = ActivityObject.Create(Id); + activityObject.Position = GlobalPosition; + activityObject.Scale = GlobalScale; + activityObject.Rotation = GlobalRotation; + activityObject.Name = Name; + activityObject.Visible = Visible; + activityObject.ShadowOffset = _showOffset; + activityObject.Altitude = _altitude; + activityObject.EnableVerticalMotion = VerticalMotion; + activityObject.PutDown(DefaultLayer, _showSprite); + QueueFree(); + } + + private void OnChangeActivityId(string id) + { + _prevId = id; + + if (_activityObject != null) + { + _activityObject.QueueFree(); + _activityObject = null; + } + + if (string.IsNullOrEmpty(id)) + { + GD.Print("删除物体"); + ShowErrorSprite(); + return; + } + + if (_jsonText == null) + { + _jsonText = File.ReadAllText("resource/config/ActivityBase.json"); + } + var str = $"\"Id\": \"{id}\","; + var index = _jsonText.IndexOf(str, StringComparison.Ordinal); + if (index > -1) + { + const string s = "\"Prefab\": \""; + var startIndex = _jsonText.IndexOf(s, index, StringComparison.Ordinal); + if (startIndex > -1) + { + var endIndex = _jsonText.IndexOf('"', startIndex + s.Length + 1); + if (endIndex > -1) + { + var prefab = _jsonText.Substring(startIndex + s.Length, endIndex - (startIndex + s.Length)); + GD.Print("创建物体: " + id); + var instance = ResourceManager.LoadAndInstantiate(prefab); + _activityObject = instance; + _collPos = instance.Collision.Position - instance.AnimatedSprite.Position - instance.AnimatedSprite.Offset; + Debug.Log("_collPos: " + _collPos); + instance.IsCustomShadowSprite = instance.ShadowSprite.Texture != null; + instance.Altitude = _altitude; + instance.ShadowOffset = _showOffset; + if (_showSprite) + { + instance.ShowShadowSprite(); + } + AddChild(instance); + HideErrorSprite(); + return; + } + } + } + GD.PrintErr($"未找到Id为'{id}'的物体!"); + ShowErrorSprite(); + } + + private void OnChangeCollisionVisible() + { + if (_activityObject != null) + { + Utils.EachNode(_activityObject, node => + { + if (node is CollisionShape2D collisionShape2D) + { + collisionShape2D.Visible = _collisionVisible; + } + else if (node is CollisionPolygon2D collisionPolygon2D) + { + collisionPolygon2D.Visible = _collisionVisible; + } + }); + } + } + + private void ShowErrorSprite() + { + if (_errorSprite == null) + { + _errorSprite = new Sprite2D(); + _errorSprite.Texture = ResourceManager.LoadTexture2D(ResourcePath.resource_sprite_ui_commonIcon_Error_mini_png); + AddChild(_errorSprite); + } + } + + private void HideErrorSprite() + { + if (_errorSprite != null) + { + _errorSprite.QueueFree(); + _errorSprite = null; + } + } +} \ No newline at end of file diff --git a/DungeonShooting_Godot/src/framework/activity/ActivityObject.cs b/DungeonShooting_Godot/src/framework/activity/ActivityObject.cs index fc03323..e5b5a58 100644 --- a/DungeonShooting_Godot/src/framework/activity/ActivityObject.cs +++ b/DungeonShooting_Godot/src/framework/activity/ActivityObject.cs @@ -245,7 +245,7 @@ /// /// 是否是自定义阴影纹理 /// - public bool IsCustomShadowSprite { get; private set; } + public bool IsCustomShadowSprite { get; set; } /// /// 记录绘制液体的笔刷上一次绘制的位置
@@ -1361,8 +1361,10 @@ ShadowSprite.GlobalPosition = new Vector2(pos.X + ShadowOffset.X, pos.Y + ShadowOffset.Y + Altitude); } - //计算位置 - private void CalcThrowAnimatedPosition() + /// + /// 计算物体精灵和阴影位置 + /// + public void CalcThrowAnimatedPosition() { if (Scale.Y < 0) { diff --git a/DungeonShooting_Godot/src/framework/common/Utils.cs b/DungeonShooting_Godot/src/framework/common/Utils.cs index be6cc8e..9b3dbd7 100644 --- a/DungeonShooting_Godot/src/framework/common/Utils.cs +++ b/DungeonShooting_Godot/src/framework/common/Utils.cs @@ -1,3 +1,4 @@ +using System; using System.Collections.Generic; using Godot; using UI.TileSetEditorCombination; @@ -554,4 +555,17 @@ } return list.ToArray(); } + + /// + /// 遍历节点树 + /// + public static void EachNode(Node node, Action action) + { + action(node); + var childCount = node.GetChildCount(); + for (var i = 0; i < childCount; i++) + { + EachNode(node.GetChild(i), action); + } + } } \ No newline at end of file diff --git a/DungeonShooting_Godot/src/game/World.cs b/DungeonShooting_Godot/src/game/World.cs index aaa8d72..421110e 100644 --- a/DungeonShooting_Godot/src/game/World.cs +++ b/DungeonShooting_Godot/src/game/World.cs @@ -11,7 +11,7 @@ /// /// 当前的游戏世界对象 /// - public static World Current => GameApplication.Instance.DungeonManager.CurrWorld; + public static World Current => GameApplication.Instance?.DungeonManager?.CurrWorld; /// /// //对象根节点