using System.Linq; using Godot; namespace Cirno.Scripts.Weapons; public partial class LaserBullet : Bullet { private Line2D _beam; private Timer _preFireTimer; private Timer _lethalTimer; private Timer _spawnDelayTimer; private bool _isLethal = false; public override void _Ready() { base._Ready(); _beam = new Line2D { DefaultColor = BulletInfo.PreFireColor, Width = 1, Visible = false }; AddChild(_beam); _beam.GlobalPosition = this.GlobalPosition; // Delay before the beam appears _spawnDelayTimer = new Timer { WaitTime = BulletInfo.SpawnDelay, OneShot = true }; _spawnDelayTimer.Timeout += ShowBeam; AddChild(_spawnDelayTimer); _spawnDelayTimer.Start(); FireLaser(); } public void FireLaser() { Vector2 endPoint = GetLaserEndPoint(GlobalPosition, BulletInfo.Direction); _beam.ClearPoints(); _beam.AddPoint(Vector2.Zero); _beam.AddPoint(ToLocal(endPoint)); _preFireTimer = new Timer { WaitTime = BulletInfo.PreFireTime, OneShot = true }; _preFireTimer.Timeout += MakeLethal; AddChild(_preFireTimer); _preFireTimer.Start(); } private void ShowBeam() { _beam.Visible = true; } private void MakeLethal() { _isLethal = true; _beam.DefaultColor = BulletInfo.LethalColor; _beam.Width = 3; _lethalTimer = new Timer { WaitTime = BulletInfo.LethalTime, OneShot = true }; _lethalTimer.Timeout += QueueFree; // Destroy after lethal phase AddChild(_lethalTimer); _lethalTimer.Start(); } public override void RotateBullet(float degrees) { base.RotateBullet(degrees); _beam.SetPointPosition(_beam.Points.Length -1, ToLocal(GetLaserEndPoint(GlobalPosition, _direction))); } private Vector2 GetLaserEndPoint(Vector2 start, Vector2 direction) { var spaceState = GetWorld2D().DirectSpaceState; var query = PhysicsRayQueryParameters2D.Create(start, start + direction * 1000); query.CollisionMask = 1 << 0; // World layer var result = spaceState.IntersectRay(query); return result.Count > 0 ? (Vector2)result["position"] : start + direction * 1000; } }