using System; using Cirno.Scripts.Components; using Cirno.Scripts.Resources; using Godot; namespace Cirno.Scripts.Activables; public partial class BulletEmitter : Node2D, IActivable { [Export] public BulletResource BulletResource { get; set; } [Export] public bool EmitOnStart { get; set; } = false; [Export] public bool InvertSignal { get; private set; } = false; [Export] public float EmitCoolDown { get; private set; } = 0.2f; [Export] public float BurstCoolDown { get; private set; } = 2f; [Export] public float Spread { get; set; } = 0f; [Export] public int Count { get; set; } = 1; [Export] public float EmissionRotation { get; set; } = 0f; [Export] public float RotationSpeed { get; private set; } = 0f; [Export] public int BulletsPerBurst { get; private set; } = 1; [Signal] public delegate void StateChangedEventHandler(bool isEmitting); private BulletSpawner _bulletSpawner; protected bool IsEmitting = false; private double _emitTimer = 0f; private double _reloadTimer = 0f; private float _currentEmissionRotation = 0f; private int _currentBullets = 0; private bool _isReloading = false; public override void _Ready() { _bulletSpawner = GetNode("BulletSpawner"); _currentEmissionRotation = EmissionRotation; _currentBullets = BulletsPerBurst; if (EmitOnStart) { IsEmitting = true; CallDeferred(MethodName.Shoot); } EmitSignal(SignalName.StateChanged, IsEmitting); } public override void _Process(double delta) { if (!IsEmitting) return; if (_isReloading) { _reloadTimer += delta; if (_reloadTimer >= BurstCoolDown) { _currentBullets = BulletsPerBurst; _isReloading = false; _reloadTimer = 0f; } return; } _emitTimer += delta; if (_emitTimer >= EmitCoolDown) { Shoot(); _emitTimer = 0f; } } public void Shoot() { _bulletSpawner.SpawnBullet(BulletResource.MakeBullet(this.GlobalPosition, Count, Spread, _currentEmissionRotation)); _currentEmissionRotation += RotationSpeed; _currentBullets--; if (_currentBullets <= 0) { _isReloading = true; } } public bool Activate(ActivationType activationType = ActivationType.Toggle) { switch (activationType) { case ActivationType.Open: case ActivationType.Enable: IsEmitting = !InvertSignal; _emitTimer = 0; break; case ActivationType.Close: case ActivationType.Disable: IsEmitting = InvertSignal; _emitTimer = 0; break; case ActivationType.Use: case ActivationType.Toggle: IsEmitting = !IsEmitting; _emitTimer = 0; break; case ActivationType.Destroy: break; } EmitSignal(SignalName.StateChanged, IsEmitting); return true; } }