From 53889ef2fd155b8993baa82688fd6776628ae8a4 Mon Sep 17 00:00:00 2001 From: Cold-Mint Date: Tue, 8 Oct 2024 22:04:37 +0800 Subject: [PATCH] =?UTF-8?q?Support=20split-wave=20Spawn=20monsters=20now.?= =?UTF-8?q?=20=E6=94=AF=E6=8C=81=E5=88=86=E6=B3=A2=E6=AC=A1=E5=88=B7?= =?UTF-8?q?=E5=87=BA=E6=80=AA=E7=89=A9=E4=BA=86=E3=80=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- data/levelGraphs/test.yaml | 2 +- prefab/projectile/Catapult.tscn | 36 ------- prefab/projectile/curseOfTheUndead.tscn | 4 +- prefab/roomTemplates/dungeon/utilityRoom.tscn | 16 +++- .../roomTemplates/tutorials/spellEditor.tscn | 8 +- .../tutorials/tripleShotSpell.tscn | 4 +- scripts/map/AiCharacterSpawn.cs | 42 +++++--- scripts/map/ItemSpawn.cs | 24 ++++- scripts/map/PlayerSpawn.cs | 25 ++++- scripts/map/room/ISpawnMarker.cs | 13 ++- scripts/map/room/Room.cs | 95 +++++++++++++++++-- 11 files changed, 187 insertions(+), 82 deletions(-) delete mode 100644 prefab/projectile/Catapult.tscn diff --git a/data/levelGraphs/test.yaml b/data/levelGraphs/test.yaml index 4e4b36e..3b6b659 100644 --- a/data/levelGraphs/test.yaml +++ b/data/levelGraphs/test.yaml @@ -31,7 +31,7 @@ room_node_data_list: title: 房间3 description: '' room_template_set: - - res://prefab/roomTemplates/dungeon/ + - res://prefab/roomTemplates/dungeon/utilityRoom.tscn tags: room_injection_processor_data: '' enter_room_event_handler_id: diff --git a/prefab/projectile/Catapult.tscn b/prefab/projectile/Catapult.tscn deleted file mode 100644 index 78c0088..0000000 --- a/prefab/projectile/Catapult.tscn +++ /dev/null @@ -1,36 +0,0 @@ -[gd_scene load_steps=5 format=3 uid="uid://bdxgx5vcof8em"] - -[ext_resource type="Script" path="res://scripts/projectile/Projectile.cs" id="1_ib3qh"] -[ext_resource type="Texture2D" uid="uid://b1twcink38sh0" path="res://sprites/Player.png" id="2_dxg46"] - -[sub_resource type="CircleShape2D" id="CircleShape2D_dgro2"] - -[sub_resource type="CircleShape2D" id="CircleShape2D_8117d"] -radius = 11.0 - -[node name="curseOfTheUndead" type="CharacterBody2D"] -collision_layer = 16 -collision_mask = 102 -slide_on_ceiling = false -platform_floor_layers = 4294967042 -platform_wall_layers = 32 -script = ExtResource("1_ib3qh") -Speed = 300.0 - -[node name="CollisionShape2D" type="CollisionShape2D" parent="."] -shape = SubResource("CircleShape2D_dgro2") - -[node name="CollisionDetectionArea" type="Area2D" parent="."] -collision_layer = 16 -collision_mask = 78 - -[node name="CollisionShape2D" type="CollisionShape2D" parent="CollisionDetectionArea"] -shape = SubResource("CircleShape2D_8117d") - -[node name="AudioStreamPlayer2D" type="AudioStreamPlayer2D" parent="."] -bus = &"SoundEffect" -area_mask = 16 - -[node name="Player" type="Sprite2D" parent="."] -scale = Vector2(0.3, 0.3) -texture = ExtResource("2_dxg46") diff --git a/prefab/projectile/curseOfTheUndead.tscn b/prefab/projectile/curseOfTheUndead.tscn index 3aefe50..8aee10b 100644 --- a/prefab/projectile/curseOfTheUndead.tscn +++ b/prefab/projectile/curseOfTheUndead.tscn @@ -11,8 +11,8 @@ collision_mask = 0 script = ExtResource("1_ib3qh") _life = 5000 _durability = 1.0 -_maxDamage = 10 -_minDamage = 1 +_maxDamage = 7 +_minDamage = 3 _damageType = 2 Speed = 500.0 _targetDiesDestroyProjectile = true diff --git a/prefab/roomTemplates/dungeon/utilityRoom.tscn b/prefab/roomTemplates/dungeon/utilityRoom.tscn index 4184acc..88429b6 100644 --- a/prefab/roomTemplates/dungeon/utilityRoom.tscn +++ b/prefab/roomTemplates/dungeon/utilityRoom.tscn @@ -1,7 +1,8 @@ -[gd_scene load_steps=8 format=4 uid="uid://c57cc1tyreybb"] +[gd_scene load_steps=9 format=4 uid="uid://c57cc1tyreybb"] [ext_resource type="TileSet" uid="uid://c4wpp12rr44hi" path="res://tileSets/dungeon.tres" id="1_rn2om"] [ext_resource type="Texture2D" uid="uid://drw45jlmfo0su" path="res://sprites/light/White_100.png" id="2_1ctsj"] +[ext_resource type="Script" path="res://scripts/map/AiCharacterSpawn.cs" id="3_u5h84"] [sub_resource type="RectangleShape2D" id="RectangleShape2D_kiih8"] size = Vector2(728, 509) @@ -72,7 +73,6 @@ tile_map_data = PackedByteArray("AAAAAAAAAQAAAAMAAAAAAAEAAQACAAEAAAAAAAIAAQACAAE tile_set = ExtResource("1_rn2om") [node name="Barrier" type="TileMapLayer" parent="TileMap"] -visible = false use_parent_material = true tile_map_data = PackedByteArray("AAAWAA0AAQAAAAEAAAAWAA4AAQAAAAEAAAAWAAEAAQAAAAEAAAAWAAIAAQAAAAEAAAAAAA0AAQACAAEAAAAAAA4AAQACAAEAAAA=") tile_set = ExtResource("1_rn2om") @@ -82,3 +82,15 @@ visible = false position = Vector2(367.5, 258) scale = Vector2(23.0938, 16.25) texture = ExtResource("2_1ctsj") + +[node name="AutoSpawn" type="Node2D" parent="."] + +[node name="Marker2D" type="Marker2D" parent="AutoSpawn"] +position = Vector2(121, 178) +script = ExtResource("3_u5h84") +_resPathArray = PackedStringArray("res://prefab/entitys/BlackenedAboriginalWarrior.tscn", "res://prefab/entitys/BlackenedAboriginalWarrior.tscn", "", "res://prefab/entitys/BlackenedAboriginalWarrior.tscn") + +[node name="Marker2D2" type="Marker2D" parent="AutoSpawn"] +position = Vector2(545, 438) +script = ExtResource("3_u5h84") +_resPathArray = PackedStringArray("res://prefab/entitys/BlackenedAboriginalWarrior.tscn", "", "res://prefab/entitys/BlackenedAboriginalWarrior.tscn", "") diff --git a/prefab/roomTemplates/tutorials/spellEditor.tscn b/prefab/roomTemplates/tutorials/spellEditor.tscn index b4880fc..e48ed08 100644 --- a/prefab/roomTemplates/tutorials/spellEditor.tscn +++ b/prefab/roomTemplates/tutorials/spellEditor.tscn @@ -9,7 +9,7 @@ [ext_resource type="PackedScene" uid="uid://dld3qttpsdjpe" path="res://prefab/furnitures/WoodenBox.tscn" id="7_jybe6"] [sub_resource type="RectangleShape2D" id="RectangleShape2D_kiih8"] -size = Vector2(709, 296) +size = Vector2(758, 342) [sub_resource type="RectangleShape2D" id="RectangleShape2D_jxmys"] size = Vector2(23, 54.875) @@ -25,7 +25,7 @@ source_geometry_group_name = &"navigation_polygon_source_group" [node name="RoomArea" type="Area2D" parent="."] [node name="CollisionShape2D" type="CollisionShape2D" parent="RoomArea"] -position = Vector2(383.5, 176) +position = Vector2(383, 175) shape = SubResource("RectangleShape2D_kiih8") [node name="RoomSlotList" type="Node2D" parent="."] @@ -111,9 +111,9 @@ position = Vector2(714, 122) [node name="necromancy" type="Marker2D" parent="AutoSpawn"] position = Vector2(134, 248) script = ExtResource("4_6ihp7") -ItemId = "necromancy" +_itemIdList = PackedStringArray("necromancy") [node name="staff_necromancy" type="Marker2D" parent="AutoSpawn"] position = Vector2(100, 250) script = ExtResource("4_6ihp7") -ItemId = "staff_necromancy" +_itemIdList = PackedStringArray("staff_necromancy") diff --git a/prefab/roomTemplates/tutorials/tripleShotSpell.tscn b/prefab/roomTemplates/tutorials/tripleShotSpell.tscn index db85fef..3fcf5a1 100644 --- a/prefab/roomTemplates/tutorials/tripleShotSpell.tscn +++ b/prefab/roomTemplates/tutorials/tripleShotSpell.tscn @@ -8,7 +8,7 @@ [ext_resource type="Texture2D" uid="uid://kgodvs3ilxbs" path="res://sprites/tutorials/tripleShotSpell.png" id="6_2qcf3"] [sub_resource type="RectangleShape2D" id="RectangleShape2D_kiih8"] -size = Vector2(709, 296) +size = Vector2(755, 340) [sub_resource type="RectangleShape2D" id="RectangleShape2D_jxmys"] size = Vector2(23, 54.875) @@ -130,4 +130,4 @@ texture = ExtResource("6_2qcf3") [node name="x3" type="Marker2D" parent="AutoSpawn"] position = Vector2(434, 105) script = ExtResource("4_fh50l") -ItemId = "x3" +_itemIdList = PackedStringArray("x3") diff --git a/scripts/map/AiCharacterSpawn.cs b/scripts/map/AiCharacterSpawn.cs index 3e6548d..60262b6 100644 --- a/scripts/map/AiCharacterSpawn.cs +++ b/scripts/map/AiCharacterSpawn.cs @@ -11,26 +11,33 @@ namespace ColdMint.scripts.map; /// public partial class AiCharacterSpawn : Marker2D, ISpawnMarker { - private PackedScene? _packedScene; - [Export] private string? _resPath; + [Export] private string[]? _resPathArray; - public override void _Ready() + public Node2D? Spawn(int waveNumber) { - base._Ready(); - if (!string.IsNullOrEmpty(_resPath)) - { - _packedScene = GD.Load(_resPath); - } - } - - public Node2D? Spawn() - { - if (GameSceneDepend.AiCharacterContainer == null || _packedScene == null) + if (GameSceneDepend.AiCharacterContainer == null) { return null; } - - var aiCharacter = NodeUtils.InstantiatePackedScene(_packedScene); + if (_resPathArray == null) + { + return null; + } + if (waveNumber < 0 || waveNumber >= _resPathArray.Length) + { + return null; + } + var resPath = _resPathArray[waveNumber]; + if (string.IsNullOrEmpty(resPath)) + { + return null; + } + var packedScene = GD.Load(resPath); + if (packedScene == null) + { + return null; + } + var aiCharacter = NodeUtils.InstantiatePackedScene(packedScene); if (aiCharacter == null) { return null; @@ -41,6 +48,11 @@ public partial class AiCharacterSpawn : Marker2D, ISpawnMarker return aiCharacter; } + public int GetMaxWaveNumber() + { + return _resPathArray?.Length ?? 0; + } + public bool CanQueueFree() { return true; diff --git a/scripts/map/ItemSpawn.cs b/scripts/map/ItemSpawn.cs index a99008d..db485fa 100644 --- a/scripts/map/ItemSpawn.cs +++ b/scripts/map/ItemSpawn.cs @@ -11,17 +11,26 @@ namespace ColdMint.scripts.map; /// public partial class ItemSpawn : Marker2D, ISpawnMarker { - [Export] private string? ItemId { get; set; } + [Export] private string[]? _itemIdList; - public Node2D? Spawn() + public Node2D? Spawn(int waveNumber) { - if (string.IsNullOrEmpty(ItemId)) + if (_itemIdList == null) { return null; } - var item = ItemTypeManager.CreateItem(ItemId, this); - LogCat.LogWithFormat("generated_item_is_empty", LogCat.LogLabel.ItemSpawn, true, ItemId, item == null); + if (waveNumber < 0 || waveNumber >= _itemIdList.Length) + { + return null; + } + var itemId = _itemIdList[waveNumber]; + if (string.IsNullOrEmpty(itemId)) + { + return null; + } + var item = ItemTypeManager.CreateItem(itemId, this); + LogCat.LogWithFormat("generated_item_is_empty", LogCat.LogLabel.ItemSpawn, true, itemId, item == null); if (item is not Node2D node2D) { return null; @@ -30,6 +39,11 @@ public partial class ItemSpawn : Marker2D, ISpawnMarker return node2D; } + public int GetMaxWaveNumber() + { + return _itemIdList?.Length ?? 0; + } + public bool CanQueueFree() { return true; diff --git a/scripts/map/PlayerSpawn.cs b/scripts/map/PlayerSpawn.cs index cbb76f8..e35852b 100644 --- a/scripts/map/PlayerSpawn.cs +++ b/scripts/map/PlayerSpawn.cs @@ -12,9 +12,14 @@ namespace ColdMint.scripts.map; /// PlayerSpawn /// 玩家出生点 /// -public partial class PlayerSpawn : Marker2D,ISpawnMarker +public partial class PlayerSpawn : Marker2D, ISpawnMarker { private PackedScene? _playerPackedScene; + /// + /// The player's generated wave count + /// 玩家的生成波数 + /// + private static readonly int PlayerWaveNumber = 1; public override void _Ready() { @@ -32,9 +37,9 @@ public partial class PlayerSpawn : Marker2D,ISpawnMarker GameSceneDepend.Player.GlobalPosition = GlobalPosition; return; } - Spawn(); + Spawn(PlayerWaveNumber); } - + private void MapGenerationCompleteEvent(MapGenerationCompleteEvent mapGenerationCompleteEvent) { @@ -47,7 +52,7 @@ public partial class PlayerSpawn : Marker2D,ISpawnMarker return; } - Spawn(); + Spawn(PlayerWaveNumber); } public override void _ExitTree() @@ -57,8 +62,13 @@ public partial class PlayerSpawn : Marker2D,ISpawnMarker EventBus.GameReplayEvent -= GameReplayEvent; } - public Node2D? Spawn() + + public Node2D? Spawn(int waveNumber) { + if (waveNumber != PlayerWaveNumber) + { + return null; + } if (GameSceneDepend.PlayerContainer == null) { return null; @@ -94,6 +104,11 @@ public partial class PlayerSpawn : Marker2D,ISpawnMarker return playerNode; } + public int GetMaxWaveNumber() + { + return PlayerWaveNumber; + } + public bool CanQueueFree() { return false; diff --git a/scripts/map/room/ISpawnMarker.cs b/scripts/map/room/ISpawnMarker.cs index 5950f58..f0d935e 100644 --- a/scripts/map/room/ISpawnMarker.cs +++ b/scripts/map/room/ISpawnMarker.cs @@ -12,11 +12,22 @@ public interface ISpawnMarker /// Generating entity /// 生成实体 /// + /// + ///Spawning waves + ///刷怪的波次 + /// /// ///Return the result of the generation. If null is returned, the generation fails. ///返回生成结果,为null则生成失败。 /// - Node2D? Spawn(); + Node2D? Spawn(int waveNumber); + + /// + /// GetMaxWaveNumber + /// 获取生成器支持的最大生成波数 + /// + /// + int GetMaxWaveNumber(); /// /// Can Queue Free diff --git a/scripts/map/room/Room.cs b/scripts/map/room/Room.cs index e26d383..ca88251 100644 --- a/scripts/map/room/Room.cs +++ b/scripts/map/room/Room.cs @@ -28,13 +28,27 @@ public class Room private CollisionShape2D? _collisionShape2D; private bool _hasPlayer; private readonly List _characterTemplateList = []; - + /// /// When the player first enters the room, all nodes under this node are executed /// 当玩家首次进入房间时,会执行此节点下所有节点 /// private Node2D? _autoSpawn; + /// + /// Current generated wave number + /// 当前生成波数 + /// + private int _currentWaveNumber; + + private readonly List _spawnedCharacterTemplateList = []; + + /// + /// Max generated wave number + /// 最大的生成波数 + /// + private int _maxWaveNumber; + /// /// The number of times the player visits the room /// 玩家访问房间的次数 @@ -162,6 +176,76 @@ public class Room characterTemplate.Hide(); } } + /// + /// Spawn a wave of entities + /// 生成一波实体 + /// + private void SpawnEnemyWave() + { + if (PlayerRoomVisitCount != 1 || _autoSpawn == null) + { + return; + } + if (_maxWaveNumber > 0 && _currentWaveNumber == _maxWaveNumber) + { + //Complete all waves. + //完成所有的波次。 + ClearAllMatchedBarriers(); + GameSceneDepend.MiniMap?.Show(); + return; + } + NodeUtils.ForEachNode(_autoSpawn, marker => + { + var node2D = marker.Spawn(_currentWaveNumber); + if (node2D is CharacterTemplate characterTemplate) + { + //The maximum wave number should be the maximum wave number produced by living organisms.For now, the player's condition for the next step is to kill all enemies. + //最大波数应该是生物生成的最大波数。就目前而言,玩家进入下一步的条件是杀死所有敌人。 + _maxWaveNumber = Math.Max(_maxWaveNumber, marker.GetMaxWaveNumber()); + _spawnedCharacterTemplateList.Add(characterTemplate); + characterTemplate.TreeExited += () => + { + _spawnedCharacterTemplateList.Remove(characterTemplate); + if (_spawnedCharacterTemplateList.Count == 0) + { + //All the creatures they summoned are dead. + //召唤的生物全死了。 + _currentWaveNumber++; + AddTimer(SpawnEnemyWave); + } + }; + } + return false; + }); + if (_spawnedCharacterTemplateList.Count > 0) + { + GameSceneDepend.MiniMap?.Hide(); + AddTimer(PlaceBarriersInAllSlots); + } + } + + /// + /// Add a timer node to handle some events + /// 添加定时器节点处理一些事件 + /// + /// + private void AddTimer(Action timeoutAction) + { + if (_rootNode == null) + { + return; + } + var timer = new Timer(); + timer.Autostart = true; + timer.OneShot = true; + timer.WaitTime = 0.3f; + timer.Timeout += () => + { + timeoutAction.Invoke(); + timer.QueueFree(); + }; + NodeUtils.CallDeferredAddChild(_rootNode, timer); + } /// /// When a node enters the room @@ -181,14 +265,7 @@ public class Room _characterTemplateList.Add(player); _hasPlayer = true; PlayerRoomVisitCount++; - if (PlayerRoomVisitCount == 1 && _autoSpawn != null) - { - NodeUtils.ForEachNode(_autoSpawn, marker => - { - marker.Spawn(); - return false; - }); - } + SpawnEnemyWave(); //The player enters the room, opening up their view. //玩家进入了房间,开放视野。 if (_pointLight2D != null)