From fa3805ecfe3b23c38dfdf968ad9ce15896eea2c1 Mon Sep 17 00:00:00 2001 From: Marco Date: Sun, 8 Jun 2025 16:33:38 +0200 Subject: [PATCH] Bullets pooling --- Resources/Debug/DebugLevels.tres | 41 +++--- Scenes/Barrel.cs | 7 +- Scenes/Maps/PlayerFSMTest.tscn | 2 +- Scenes/Utils/pooling_manager.tscn | 9 ++ Scripts/Bullet.cs | 54 +++++++- Scripts/Components/BulletSpawner.cs | 8 +- Scripts/Components/FSM/Player/FreezeModule.cs | 50 +++---- .../FSM/Player/PlayerGrazingModule.cs | 3 +- Scripts/Controllers/PoolingManager.cs | 131 ++++++++++++++++++ Scripts/Controllers/PoolingManager.cs.uid | 1 + Scripts/Enemy.cs | 1 + Scripts/GameManager.cs | 12 +- Scripts/Interactables/HitButton.cs | 1 + Scripts/PlayerMovement.cs | 10 +- .../ItemEffects/SpiderbombEffectResource.cs | 7 +- Scripts/UI/DebugMenu.cs | 5 +- Scripts/Weapon.cs | 6 +- project.godot | 1 + 18 files changed, 280 insertions(+), 69 deletions(-) create mode 100644 Scenes/Utils/pooling_manager.tscn create mode 100644 Scripts/Controllers/PoolingManager.cs create mode 100644 Scripts/Controllers/PoolingManager.cs.uid diff --git a/Resources/Debug/DebugLevels.tres b/Resources/Debug/DebugLevels.tres index 83bc6d0d..1c0f296e 100644 --- a/Resources/Debug/DebugLevels.tres +++ b/Resources/Debug/DebugLevels.tres @@ -1,4 +1,4 @@ -[gd_resource type="Resource" script_class="DebugMapSelectData" load_steps=40 format=3 uid="uid://d1lc8lhq1b05p"] +[gd_resource type="Resource" script_class="DebugMapSelectData" load_steps=42 format=3 uid="uid://d1lc8lhq1b05p"] [ext_resource type="Script" uid="uid://durmwwyw3dnm6" path="res://Scripts/Resources/DebugMenu/DebugMapSelectData.cs" id="1_6kwth"] [ext_resource type="Script" uid="uid://mja0rk7n2kln" path="res://Scripts/Resources/MapStartDataResource.cs" id="1_ov731"] @@ -11,6 +11,7 @@ [ext_resource type="Resource" uid="uid://cs3ihltcn2166" path="res://Resources/Items/IcicleGun.tres" id="7_b3oo5"] [ext_resource type="Resource" uid="uid://6ek4lmtuij4t" path="res://Resources/Maps/Roguelite.tres" id="9_ognca"] [ext_resource type="Resource" uid="uid://cn8tu4jct04rp" path="res://Resources/StartData/Pistol_Start.tres" id="10_olpjo"] +[ext_resource type="Resource" uid="uid://d1rd3eep3b0jj" path="res://Resources/Maps/ReimuTest.tres" id="11_olpjo"] [sub_resource type="Resource" id="Resource_qnbi6"] script = ExtResource("2_tnajf") @@ -21,8 +22,8 @@ _name = "Intro" [sub_resource type="Resource" id="Resource_cfhv5"] script = ExtResource("1_ov731") EggIndex = 0 -StartingEquipment = Array[ExtResource("2_bkci5")]([]) -RemoveEquipment = Array[ExtResource("2_bkci5")]([]) +StartingEquipment = [] +RemoveEquipment = [] [sub_resource type="Resource" id="Resource_0k62o"] script = ExtResource("2_tnajf") @@ -34,8 +35,8 @@ StartData = SubResource("Resource_cfhv5") [sub_resource type="Resource" id="Resource_tpb7s"] script = ExtResource("1_ov731") EggIndex = 0 -StartingEquipment = Array[ExtResource("2_bkci5")]([]) -RemoveEquipment = Array[ExtResource("2_bkci5")]([]) +StartingEquipment = [] +RemoveEquipment = [] [sub_resource type="Resource" id="Resource_edoov"] script = ExtResource("2_tnajf") @@ -47,8 +48,8 @@ StartData = SubResource("Resource_tpb7s") [sub_resource type="Resource" id="Resource_1sw5g"] script = ExtResource("1_ov731") EggIndex = 255 -StartingEquipment = Array[ExtResource("2_bkci5")]([]) -RemoveEquipment = Array[ExtResource("2_bkci5")]([]) +StartingEquipment = [] +RemoveEquipment = [] [sub_resource type="Resource" id="Resource_47bot"] script = ExtResource("2_tnajf") @@ -61,7 +62,7 @@ StartData = SubResource("Resource_1sw5g") script = ExtResource("1_ov731") EggIndex = 2 StartingEquipment = Array[ExtResource("2_bkci5")]([ExtResource("3_fydgr"), ExtResource("4_38yta"), ExtResource("5_em757"), ExtResource("6_sdmg8")]) -RemoveEquipment = Array[ExtResource("2_bkci5")]([]) +RemoveEquipment = [] [sub_resource type="Resource" id="Resource_mgdm6"] script = ExtResource("2_tnajf") @@ -79,8 +80,8 @@ _name = "Rebel Base" [sub_resource type="Resource" id="Resource_maxpt"] script = ExtResource("1_ov731") EggIndex = 0 -StartingEquipment = Array[ExtResource("2_bkci5")]([]) -RemoveEquipment = Array[ExtResource("2_bkci5")]([]) +StartingEquipment = [] +RemoveEquipment = [] [sub_resource type="Resource" id="Resource_pein5"] script = ExtResource("2_tnajf") @@ -117,7 +118,7 @@ _name = "Default Scene" script = ExtResource("1_ov731") EggIndex = 0 StartingEquipment = Array[ExtResource("2_bkci5")]([ExtResource("7_b3oo5")]) -RemoveEquipment = Array[ExtResource("2_bkci5")]([]) +RemoveEquipment = [] [sub_resource type="Resource" id="Resource_6ijnv"] script = ExtResource("2_tnajf") @@ -136,8 +137,8 @@ metadata/_custom_type_script = "uid://dnthdjrx78u6m" [sub_resource type="Resource" id="Resource_7sue8"] script = ExtResource("1_ov731") EggIndex = 255 -StartingEquipment = Array[ExtResource("2_bkci5")]([]) -RemoveEquipment = Array[ExtResource("2_bkci5")]([]) +StartingEquipment = [] +RemoveEquipment = [] metadata/_custom_type_script = "uid://mja0rk7n2kln" [sub_resource type="Resource" id="Resource_ognca"] @@ -151,8 +152,8 @@ metadata/_custom_type_script = "uid://dnthdjrx78u6m" [sub_resource type="Resource" id="Resource_olpjo"] script = ExtResource("1_ov731") EggIndex = 0 -StartingEquipment = Array[ExtResource("2_bkci5")]([]) -RemoveEquipment = Array[ExtResource("2_bkci5")]([]) +StartingEquipment = [] +RemoveEquipment = [] metadata/_custom_type_script = "uid://mja0rk7n2kln" [sub_resource type="Resource" id="Resource_nbnej"] @@ -200,6 +201,14 @@ _name = "Roguelite" StartData = ExtResource("10_olpjo") metadata/_custom_type_script = "uid://dnthdjrx78u6m" +[sub_resource type="Resource" id="Resource_c3ldk"] +script = ExtResource("2_tnajf") +Enabled = true +Map = ExtResource("11_olpjo") +Path = "" +_name = "Reimu Test" +metadata/_custom_type_script = "uid://dnthdjrx78u6m" + [resource] script = ExtResource("1_6kwth") -Maps = Array[Object]([SubResource("Resource_qnbi6"), SubResource("Resource_0k62o"), SubResource("Resource_edoov"), SubResource("Resource_47bot"), SubResource("Resource_mgdm6"), SubResource("Resource_v2as6"), SubResource("Resource_pein5"), SubResource("Resource_6wrc7"), SubResource("Resource_x3w7w"), SubResource("Resource_ajht5"), SubResource("Resource_7vmdn"), SubResource("Resource_6ijnv"), SubResource("Resource_bkci5"), SubResource("Resource_ognca"), SubResource("Resource_nbnej"), SubResource("Resource_w7lsm"), SubResource("Resource_vq1um"), SubResource("Resource_hougo"), SubResource("Resource_xhgge"), SubResource("Resource_gkp3t")]) +Maps = Array[Object]([SubResource("Resource_qnbi6"), SubResource("Resource_0k62o"), SubResource("Resource_edoov"), SubResource("Resource_47bot"), SubResource("Resource_mgdm6"), SubResource("Resource_v2as6"), SubResource("Resource_pein5"), SubResource("Resource_6wrc7"), SubResource("Resource_x3w7w"), SubResource("Resource_ajht5"), SubResource("Resource_7vmdn"), SubResource("Resource_6ijnv"), SubResource("Resource_bkci5"), SubResource("Resource_ognca"), SubResource("Resource_nbnej"), SubResource("Resource_w7lsm"), SubResource("Resource_vq1um"), SubResource("Resource_hougo"), SubResource("Resource_xhgge"), SubResource("Resource_gkp3t"), SubResource("Resource_c3ldk")]) diff --git a/Scenes/Barrel.cs b/Scenes/Barrel.cs index 3672a3ee..23ca349d 100644 --- a/Scenes/Barrel.cs +++ b/Scenes/Barrel.cs @@ -3,6 +3,7 @@ using System; using System.Diagnostics; using System.Linq; using Cirno.Scripts; +using Cirno.Scripts.Controllers; using Cirno.Scripts.Resources; using Godot.Collections; @@ -78,7 +79,11 @@ public partial class Barrel : Area2D, IDestructible { if (ExplosionData == null) return; - var explosion = this.CreateSibling(ExplosionData.BulletScene); + + var explosion = PoolingManager.Instance.SpawnBullet(ExplosionData); + explosion.GlobalPosition = this.GlobalPosition; + + //var explosion = this.CreateSibling(ExplosionData.BulletScene); explosion.Speed = 0; explosion.Initialize(ExplosionData.MakeBullet(this.GlobalPosition), _gameManager); diff --git a/Scenes/Maps/PlayerFSMTest.tscn b/Scenes/Maps/PlayerFSMTest.tscn index 8cbe68b4..9fded423 100644 --- a/Scenes/Maps/PlayerFSMTest.tscn +++ b/Scenes/Maps/PlayerFSMTest.tscn @@ -86,7 +86,7 @@ script = ExtResource("4_u1i8n") EggIndex = 0 StartingEquipment = Array[ExtResource("2_g20dv")]([ExtResource("3_6314l")]) -RemoveEquipment = Array[ExtResource("2_g20dv")]([]) +RemoveEquipment = [] metadata/_custom_type_script = "uid://mja0rk7n2kln" [sub_resource type="Resource" id="Resource_1tvdd"] diff --git a/Scenes/Utils/pooling_manager.tscn b/Scenes/Utils/pooling_manager.tscn new file mode 100644 index 00000000..b3f2e081 --- /dev/null +++ b/Scenes/Utils/pooling_manager.tscn @@ -0,0 +1,9 @@ +[gd_scene load_steps=2 format=3 uid="uid://c3t8rhwwdo5cl"] + +[ext_resource type="Script" uid="uid://k1pdoan4wie2" path="res://Scripts/Controllers/PoolingManager.cs" id="1_ji88p"] + +[node name="PoolingManager" type="Node2D"] +z_index = 1 +script = ExtResource("1_ji88p") +PoolOnStart = Array[Resource]([]) +DebugView = true diff --git a/Scripts/Bullet.cs b/Scripts/Bullet.cs index 21b6c8ee..6861bc42 100644 --- a/Scripts/Bullet.cs +++ b/Scripts/Bullet.cs @@ -5,6 +5,7 @@ using System.Diagnostics; using System.Linq; using Cirno.Scripts; using Cirno.Scripts.Components; +using Cirno.Scripts.Controllers; using Cirno.Scripts.Resources; public partial class Bullet : Area2D @@ -31,16 +32,21 @@ public partial class Bullet : Area2D public bool IsGrazed { get; set; } = false; public bool IsFrozen { get; private set; } = false; - + public bool Enabled { get; private set; } = false; + [Signal] public delegate void OnDestroyEventHandler(); private AudioStreamPlayer2D _grazeSound; private GpuParticles2D _grazeParticles; + private CollisionShape2D _collisionShape2D; + public override void _Ready() { _grazeSound = GetNodeOrNull("AudioStreamPlayer2D"); _grazeParticles = GetNodeOrNull("GrazeParticles"); + + _collisionShape2D = GetNode("CollisionShape2D"); } public void Initialize(BulletInfo bulletInfo, GameManager gameManager) @@ -64,8 +70,43 @@ public partial class Bullet : Area2D _modifiers = _bulletInfo.TimeModifiers.Select(x => x.Wrap()).ToList(); } + /// + /// Enables the bullet, shows the sprite and activates collisions + /// + public void Enable() + { + Enabled = true; + Show(); + if (this._collisionShape2D is null) + { + _collisionShape2D = GetNode("CollisionShape2D"); + } + + _collisionShape2D.SetDeferred(CollisionShape2D.PropertyName.Disabled, false); + + } + + /// + /// Disables the bullet, hides the sprite and disables collisions + /// + public void Disable(bool hideSprite = true) + { + Enabled = false; + if (hideSprite) + { + Hide(); + } + if (this._collisionShape2D is null) + { + _collisionShape2D = GetNode("CollisionShape2D"); + } + + _collisionShape2D.SetDeferred(CollisionShape2D.PropertyName.Disabled, true); + } + public void Graze() { + if (!Enabled) return; _grazeSound?.Play(); if (_grazeParticles is not null) { @@ -172,6 +213,7 @@ public partial class Bullet : Area2D // Called every frame. 'delta' is the elapsed time since the previous frame. public override void _Process(double delta) { + if (!Enabled) return; _elapsedTime += delta; if (_elapsedTime >= _bulletInfo.LifeTime) @@ -182,6 +224,7 @@ public partial class Bullet : Area2D public override void _PhysicsProcess(double delta) { + if (!Enabled) return; if (_bulletInfo != null) { ApplyTimeModifiers(delta); @@ -197,6 +240,7 @@ public partial class Bullet : Area2D private void ControlBullet(double delta) { + if (!Enabled) return; var axis = Input.GetAxis("left", "right"); if (axis != 0) @@ -208,6 +252,7 @@ public partial class Bullet : Area2D private void _on_visible_on_screen_notifier_2d_screen_exited() { + if (!Enabled) return; //Debug.WriteLine("Destroy bullet out of screen"); Destroy(); } @@ -259,6 +304,7 @@ public partial class Bullet : Area2D public void RequestCollisionDestruction() { + if (!Enabled) return; if (_bulletInfo.DestroyOnCollision) { Destroy(); @@ -274,14 +320,16 @@ public partial class Bullet : Area2D //particle.Init(); } EmitSignal(SignalName.OnDestroy); - QueueFree(); + //QueueFree(); + PoolingManager.Instance.DisableBullet(this); } public void Freeze() { IsFrozen = true; EmitSignal(SignalName.OnDestroy); - QueueFree(); + //QueueFree(); + PoolingManager.Instance.DisableBullet(this); } } diff --git a/Scripts/Components/BulletSpawner.cs b/Scripts/Components/BulletSpawner.cs index 4fdac929..8c9b13a1 100644 --- a/Scripts/Components/BulletSpawner.cs +++ b/Scripts/Components/BulletSpawner.cs @@ -1,4 +1,5 @@ using System; +using Cirno.Scripts.Controllers; using Cirno.Scripts.Weapons; using Godot; using Godot.Collections; @@ -22,10 +23,9 @@ public partial class BulletSpawner : Node2D for (int i = 0; i < bulletInfo.BulletCount; i++) { - if (bulletInfo.IsLaser) - bullet = this.CreateChildOf(_gameManager.BulletsContainer, bulletScene, bulletInfo.Position); - else - bullet = this.CreateChildOf(_gameManager.BulletsContainer, bulletScene, bulletInfo.Position); + // bullet = this.CreateChildOf(_gameManager.BulletsContainer, bulletScene, bulletInfo.Position); + bullet = PoolingManager.Instance.SpawnBullet(bulletInfo.OriginalBulletResource); + bullet.GlobalPosition = bulletInfo.Position; // var bullet = this.CreateChildOf(_gameManager.BulletsContainer, bulletInfo.BulletScene ?? BulletScene, bulletInfo.Position); diff --git a/Scripts/Components/FSM/Player/FreezeModule.cs b/Scripts/Components/FSM/Player/FreezeModule.cs index 54614b48..a15e11bb 100644 --- a/Scripts/Components/FSM/Player/FreezeModule.cs +++ b/Scripts/Components/FSM/Player/FreezeModule.cs @@ -1,6 +1,8 @@ using System.Collections.Generic; +using System.Linq; using Cirno.Scripts.Actors; using Cirno.Scripts.Components.Actors; +using Cirno.Scripts.Controllers; using Godot; namespace Cirno.Scripts.Components.FSM.Player; @@ -13,18 +15,15 @@ public partial class FreezeModule : ModuleBase [Export] public double Cooldown { get; private set; } = 0.5f; [Export] public double IceLife { get; private set; } = 4f; [Export] public PackedScene IceScene { get; private set; } - - [ExportGroup("Providers")] - [Export] - public ActorResourceProvider Shield { get; private set; } - - [Export] - public InputProvider InputProvider { get; private set; } - + + [ExportGroup("Providers")] [Export] public ActorResourceProvider Shield { get; private set; } + + [Export] public InputProvider InputProvider { get; private set; } + public bool Enabled { get; set; } = false; - + private double _cooldownTimer = 0; - + public override void EnterState(PlayerState state) { Enabled = true; @@ -37,7 +36,6 @@ public partial class FreezeModule : ModuleBase public override void Init(IStateMachine machine) { - } public override void Process(double delta) @@ -68,31 +66,19 @@ public partial class FreezeModule : ModuleBase var ice = bullet.CreateSibling(IceScene); ice.Life = IceLife; ice.FreezeModule = this; - } } private List GetNearbyBullets() { - var nearbyBullets = new List(); - - foreach (var child in GameManager.Instance.BulletsContainer.GetChildren()) - { - if (child is not Bullet bullet) continue; - if (bullet.BulletOwner is BulletOwner.Player) - { - continue; - } - if (bullet.IsFrozen) continue; - if (!bullet.BulletInfo.Freezable) continue; - - var distance = GlobalPosition.DistanceTo(bullet.GlobalPosition); - if (distance <= FreezeRadius) - { - nearbyBullets.Add(bullet); - } - } - - return nearbyBullets; + return (from child in PoolingManager.Instance.GetAllActiveBullets() + where child is not null + where child.Enabled // Could be redundant but better check in case of errors + where child.BulletOwner is not BulletOwner.Player + where !child.IsFrozen + where child.BulletInfo.Freezable + let distance = GlobalPosition.DistanceTo(child.GlobalPosition) + where distance <= FreezeRadius + select child).ToList(); } } \ No newline at end of file diff --git a/Scripts/Components/FSM/Player/PlayerGrazingModule.cs b/Scripts/Components/FSM/Player/PlayerGrazingModule.cs index 5efe0325..f29236d9 100644 --- a/Scripts/Components/FSM/Player/PlayerGrazingModule.cs +++ b/Scripts/Components/FSM/Player/PlayerGrazingModule.cs @@ -33,12 +33,11 @@ public partial class PlayerGrazingModule : PlayerArea2DModule if (!Enabled) return; if (area is Bullet bullet) { + if (!bullet.Enabled) return; if (bullet.IsGrazed) return; if (!bullet.BulletInfo.Grazeable) return; if (bullet.BulletOwner is BulletOwner.Player) return; - GD.Print("Grazed"); - bullet.Graze(); //bullet.IsGrazed = true; var baseGrazeValue = bullet.BulletInfo.GrazeValue; diff --git a/Scripts/Controllers/PoolingManager.cs b/Scripts/Controllers/PoolingManager.cs new file mode 100644 index 00000000..567a14ef --- /dev/null +++ b/Scripts/Controllers/PoolingManager.cs @@ -0,0 +1,131 @@ +using System.Collections.Generic; +using System.Collections.Immutable; +using System.Linq; +using Cirno.Scripts.Resources; +using Godot; +using Godot.Collections; + +namespace Cirno.Scripts.Controllers; + +public partial class PoolingManager : Node2D +{ + public static PoolingManager Instance { get; private set; } + + [Export] public Array PoolOnStart { get; private set; } + + [Export] public bool DebugView { get; private set; } = false; + + private readonly System.Collections.Generic.Dictionary> + _activeBullets = new(); + + private readonly System.Collections.Generic.Dictionary> + _inactiveBullets = new(); + + public override void _Ready() + { + Instance = this; + } + + public Bullet SpawnBullet(BulletResource bulletResource, bool active = true) + { + // Look for bullet among the inactive ones + // If present move it to active, set it as active and return it + // Otherwise spawn it and add it to active and return it + + var activeBullets = GetActiveBulletsList(bulletResource); + var inactiveBullets = GetInactiveBulletsList(bulletResource); + + var bullet = inactiveBullets.Count > 0 ? inactiveBullets.First() : InstantiateBullet(bulletResource); + + if (active) + { + inactiveBullets.Remove(bullet); + activeBullets.Add(bullet); + bullet.Enable(); + } + else + { + activeBullets.Add(bullet); + inactiveBullets.Remove(bullet); + bullet.Disable(); + } + + return bullet; + } + + public IEnumerable GetAllActiveBullets() + { + return _activeBullets.Values.SelectMany(list => list); + } + + public IEnumerable GetAllInActiveBullets() + { + return _activeBullets.Values.SelectMany(list => list); + } + + public List GetActiveBulletsList(BulletResource resource) + { + return GetOrCreateList(_activeBullets, resource); + } + + private List GetInactiveBulletsList(BulletResource resource) + { + return GetOrCreateList(_inactiveBullets, resource); + } + + public void DisableBullet(Bullet bullet) + { + var activeBulletsList = GetActiveBulletsList(bullet.BulletInfo.OriginalBulletResource); + + var inactiveBulletsList = GetInactiveBulletsList(bullet.BulletInfo.OriginalBulletResource); + + bullet.Disable(!DebugView); + + activeBulletsList.Remove(bullet); + + inactiveBulletsList.Add(bullet); + } + + public void DisableAllBullets() + { + var allActiveBullets = GetAllActiveBullets().ToImmutableList(); + + foreach (var bullet in allActiveBullets) + { + var inactiveBulletsList = GetInactiveBulletsList(bullet.BulletInfo.OriginalBulletResource); + + bullet.Disable(!DebugView); + + inactiveBulletsList.Add(bullet); + } + + foreach (var activeBulletsList in _activeBullets) + { + activeBulletsList.Value.Clear(); + } + + } + + private List GetOrCreateList(System.Collections.Generic.Dictionary> dict, BulletResource resource) + { + if (dict.TryGetValue(resource, out var list)) return list; + list = []; + dict[resource] = list; + return list; + } + + + + private Bullet InstantiateBullet(BulletResource bulletData) + { + var bullet = this.CreateChild(bulletData.BulletScene); + return bullet; + } + +} + +public partial class PooledBulletInfo : Resource +{ + public BulletResource Bullet { get; private set; } + public int Amount { get; private set; } +} \ No newline at end of file diff --git a/Scripts/Controllers/PoolingManager.cs.uid b/Scripts/Controllers/PoolingManager.cs.uid new file mode 100644 index 00000000..97757cae --- /dev/null +++ b/Scripts/Controllers/PoolingManager.cs.uid @@ -0,0 +1 @@ +uid://k1pdoan4wie2 diff --git a/Scripts/Enemy.cs b/Scripts/Enemy.cs index 6f9d551a..440e4e55 100644 --- a/Scripts/Enemy.cs +++ b/Scripts/Enemy.cs @@ -250,6 +250,7 @@ public partial class Enemy : CharacterBody2D private void _on_damage_hitbox_area_entered(Area2D area) { if (area is not Bullet bullet) return; + if (!bullet.Enabled) return; if (_invulnerable) return; if (bullet.BulletInfo.Owner == BulletOwner.Enemy) return; diff --git a/Scripts/GameManager.cs b/Scripts/GameManager.cs index d512da98..48c8705c 100644 --- a/Scripts/GameManager.cs +++ b/Scripts/GameManager.cs @@ -4,6 +4,7 @@ using System.Linq; using System.Threading.Tasks; using Cirno.Scripts; using Cirno.Scripts.Components.FSM; +using Cirno.Scripts.Controllers; using Cirno.Scripts.Enums; using Cirno.Scripts.Misc; using Cirno.Scripts.Resources; @@ -389,11 +390,12 @@ public partial class GameManager : Node2D public void ClearBullets() { - if (_bulletsContainer is null) return; - foreach (var node in _bulletsContainer.GetChildren()) - { - node.QueueFree(); - } + PoolingManager.Instance.DisableAllBullets(); + // if (_bulletsContainer is null) return; + // foreach (var node in _bulletsContainer.GetChildren()) + // { + // node.QueueFree(); + // } } public void RecalculateTilemap(Vector2 position) diff --git a/Scripts/Interactables/HitButton.cs b/Scripts/Interactables/HitButton.cs index 45be721f..6f496ec9 100644 --- a/Scripts/Interactables/HitButton.cs +++ b/Scripts/Interactables/HitButton.cs @@ -13,6 +13,7 @@ public partial class HitButton : Switch private void OnAreaEntered(Area2D area) { if (area is not Bullet bullet) return; + if (!bullet.Enabled) return; this.Activate(this.ActivationType); diff --git a/Scripts/PlayerMovement.cs b/Scripts/PlayerMovement.cs index fa66de07..74530771 100644 --- a/Scripts/PlayerMovement.cs +++ b/Scripts/PlayerMovement.cs @@ -8,6 +8,7 @@ using Cirno.Scripts.Components.Actors; using Cirno.Scripts.Resources; using Godot.Collections; using System.Threading.Tasks; +using Cirno.Scripts.Controllers; public partial class PlayerMovement : CharacterBody2D, IDestructible { @@ -229,10 +230,14 @@ public partial class PlayerMovement : CharacterBody2D, IDestructible _inventoryManager.RemoveItem(item.ItemKey, 1); // emit projectile - var bullet = this.CreateChildOf(_gameManager.BulletsContainer, item.WeaponData.BulletData.BulletScene, this.GlobalPosition); - var bulletData = item.WeaponData.MakeBullet(this.GlobalPosition); + var bullet = PoolingManager.Instance.SpawnBullet(bulletData.OriginalBulletResource); + + bullet.GlobalPosition = this.GlobalPosition; + + //var bullet = this.CreateChildOf(_gameManager.BulletsContainer, item.WeaponData.BulletData.BulletScene, this.GlobalPosition); + bullet.Initialize(bulletData, _gameManager); //bullet.SetDirection(ShootDirection); @@ -572,6 +577,7 @@ public partial class PlayerMovement : CharacterBody2D, IDestructible if (!_canMove) return; if (area is Bullet bullet && bullet.BulletOwner != BulletGroup) { + if (!bullet.Enabled) return; this.Hit(bullet.Damage, bullet.DamageType); bullet.RequestCollisionDestruction(); } diff --git a/Scripts/Resources/ItemEffects/SpiderbombEffectResource.cs b/Scripts/Resources/ItemEffects/SpiderbombEffectResource.cs index 45895865..3f08b150 100644 --- a/Scripts/Resources/ItemEffects/SpiderbombEffectResource.cs +++ b/Scripts/Resources/ItemEffects/SpiderbombEffectResource.cs @@ -1,4 +1,5 @@ using Cirno.Scripts.Components.FSM.Player; +using Cirno.Scripts.Controllers; using Godot; namespace Cirno.Scripts.Resources.ItemEffects; @@ -16,7 +17,11 @@ public partial class SpiderbombEffectResource : ItemEffectResource { public IITemEffectMachine Execute() { - var bullet = parent.CreateChildOf(GameManager.Instance.BulletsContainer, item.WeaponData.BulletData.BulletScene, parent.GlobalPosition); + + var bullet = PoolingManager.Instance.SpawnBullet(item.WeaponData.BulletData); + bullet.GlobalPosition = parent.GlobalPosition; + + //var bullet = parent.CreateChildOf(GameManager.Instance.BulletsContainer, item.WeaponData.BulletData.BulletScene, parent.GlobalPosition); var bulletData = item.WeaponData.MakeBullet(parent.GlobalPosition); diff --git a/Scripts/UI/DebugMenu.cs b/Scripts/UI/DebugMenu.cs index c704e02c..2f68a01b 100644 --- a/Scripts/UI/DebugMenu.cs +++ b/Scripts/UI/DebugMenu.cs @@ -25,7 +25,10 @@ public partial class DebugMenu : MenuBase // Called when the node enters the scene tree for the first time. public override void _Ready() { - GameManager.Instance.GameStateChange += OnGameStateChange; + if (GameManager.Instance is not null) + { + GameManager.Instance.GameStateChange += OnGameStateChange; + } DefaultSelectedButton.GrabFocus(); diff --git a/Scripts/Weapon.cs b/Scripts/Weapon.cs index 43fd292a..0e1a3678 100644 --- a/Scripts/Weapon.cs +++ b/Scripts/Weapon.cs @@ -3,6 +3,7 @@ using System; using System.Diagnostics; using Cirno.Scripts; using Cirno.Scripts.Components; +using Cirno.Scripts.Controllers; using Cirno.Scripts.Resources; using Cirno.Scripts.Utils; @@ -163,8 +164,11 @@ public partial class Weapon : Node2D // Rotate the ShootDirection by the spread angle Vector2 spreadDirection = ShootDirection.Rotated(Mathf.DegToRad(spreadOffset)); + + var bullet = PoolingManager.Instance.SpawnBullet(WeaponData.BulletData); + bullet.GlobalPosition = _muzzle.GlobalPosition; - var bullet = this.CreateChildOf(_gameManager.BulletsContainer, WeaponData.BulletData.BulletScene, _muzzle.GlobalPosition); + //var bullet = this.CreateChildOf(_gameManager.BulletsContainer, WeaponData.BulletData.BulletScene, _muzzle.GlobalPosition); if (bullet == null) { diff --git a/project.godot b/project.godot index 829c64ca..9ababf29 100644 --- a/project.godot +++ b/project.godot @@ -49,6 +49,7 @@ Dialogic="*res://addons/dialogic/Core/DialogicGameHandler.gd" GlobalState="*res://Scripts/GlobalState.cs" GodotGTweensContextNode="*res://GTweensGodot/Godot/Source/Contexts/GodotGTweensContextNode.cs" CyclopsAutoload="*res://addons/cyclops_level_builder/cyclops_global_scene.tscn" +PoolingManager="*res://Scenes/Utils/pooling_manager.tscn" [dialogic]