This commit is contained in:
Marco 2025-02-14 10:59:32 +01:00
commit ba2f6a97fc
9 changed files with 254 additions and 26 deletions

View file

@ -0,0 +1,28 @@
using Cirno.Scripts.Components;
using Godot;
namespace Cirno.Scripts.AttackPatterns;
[GlobalClass]
public partial class LaserPattern : SpiralPattern
{
[ExportGroup("Laser")][Export] public float SpawnDelay { get; set; } = 0.3f; // Delay before beam appears
[ExportGroup("Laser")][Export] public float PreFireTime { get; set; } = 0.5f; // Time before laser becomes lethal
[ExportGroup("Laser")][Export] public float LethalTime { get; set; } = 1.5f; // Time laser remains lethal
[ExportGroup("Laser")][Export] public Color PreFireColor { get; set; } = new Color(1, 0, 0, 0.5f); // Thin red beam
[ExportGroup("Laser")][Export] public Color LethalColor { get; set; } = new Color(1, 0, 0, 1.0f); // Thicker beam
protected override BulletInfo MakeBullet(Vector2 position, Vector2 direction, float angleOffset)
{
var bf = base.MakeBullet(position, direction, angleOffset);
bf.IsLaser = true;
bf.PreFireTime = PreFireTime;
bf.LethalTime = LethalTime;
bf.PreFireColor = PreFireColor;
bf.LethalColor = LethalColor;
bf.SpawnDelay = SpawnDelay;
return bf;
}
}

View file

@ -23,7 +23,9 @@ public partial class SpiralPattern : AttackPattern
[Export] private BulletOwner owner = BulletOwner.Enemy;
[Export] private DamageType _damageType = DamageType.Neutral;
[Export] private float _bulletDamage = 1f;
[ExportGroup("Modifiers")]
[Export] private BulletCreationModifier _modifier;
[ExportGroup("Modifiers")]
[Export] private Array<TimeModifier> _timeModifiers;
[Export] private bool _targetPlayer = false;
@ -55,29 +57,54 @@ public partial class SpiralPattern : AttackPattern
direction = (Boss.GameManager.PlayerPosition.Value - Boss.GlobalPosition).Normalized();
}
spawner.SpawnBullet(new BulletInfo()
{
Position = Boss.GlobalPosition,
Direction = direction,
Speed = bulletSpeed,
Owner = owner,
DamageType = _damageType,
Damage = _bulletDamage,
BulletCount = bulletCount,
Spread = spread,
BulletScene = BulletScene,
RotationOffset = angleOffset,
Modifier = _modifier,
TimeModifiers = ((_timeModifiers?.Where(mod => mod != null)) ?? Array.Empty<TimeModifier>()).Select(m => new ModifierWrapper()
spawner.SpawnBullet(MakeBullet(Boss.GlobalPosition, direction, angleOffset));
// spawner.SpawnBullet(new BulletInfo()
// {
// Position = Boss.GlobalPosition,
// Direction = direction,
// Speed = bulletSpeed,
// Owner = owner,
// DamageType = _damageType,
// Damage = _bulletDamage,
// BulletCount = bulletCount,
// Spread = spread,
// BulletScene = BulletScene,
// RotationOffset = angleOffset,
// Modifier = _modifier,
// TimeModifiers = ((_timeModifiers?.Where(mod => mod != null)) ?? Array.Empty<TimeModifier>()).Select(m => new ModifierWrapper()
// {
// TimeModifier = m,
// Applied = false
// }).ToList()
// });
burstTimer = 0;
}
}
protected virtual BulletInfo MakeBullet(Vector2 position, Vector2 direction, float angleOffset)
{
return new BulletInfo()
{
Position = position,
Direction = direction,
Speed = bulletSpeed,
Owner = owner,
DamageType = _damageType,
Damage = _bulletDamage,
BulletCount = bulletCount,
Spread = spread,
BulletScene = BulletScene,
RotationOffset = angleOffset,
Modifier = _modifier,
TimeModifiers = ((_timeModifiers?.Where(mod => mod != null)) ?? Array.Empty<TimeModifier>()).Select(m =>
new ModifierWrapper()
{
TimeModifier = m,
Applied = false
}).ToList()
});
// spawner.SpawnSpiralPattern(Boss.GlobalPosition, bulletSpeed, owner, bulletCount, rotationSpeed, timer, spread, BulletScene);
burstTimer = 0;
}
};
}
public override bool IsComplete()

View file

@ -18,7 +18,7 @@ public partial class Bullet : Area2D
public DamageType DamageType => _bulletInfo?.DamageType ?? DamageType.Neutral;
private Vector2 _direction = Vector2.Right;
protected Vector2 _direction = Vector2.Right;
private double _elapsedTime = 0f;
private BulletInfo _bulletInfo;
@ -75,7 +75,7 @@ public partial class Bullet : Area2D
}
}
private void RotateBullet(float degrees)
protected virtual void RotateBullet(float degrees)
{
float radians = Mathf.DegToRad(degrees);
_direction = _direction.Rotated(radians).Normalized(); // Rotate direction
@ -88,6 +88,7 @@ public partial class Bullet : Area2D
if (_gameManager.Player != null)
{
_direction = (_gameManager.Player.GlobalPosition - this.GlobalPosition).Normalized();
RotateBullet(0); // quick hack to rotate lasers
//LookAt(player.GlobalPosition);
}
}

View file

@ -1,6 +1,7 @@
using System;
using System.Collections.Generic;
using Cirno.Scripts.Resources;
using Cirno.Scripts.Weapons;
using Godot;
using Godot.Collections;
@ -18,9 +19,17 @@ public partial class BulletSpawner : Node2D
public void SpawnBullet(BulletInfo bulletInfo)
{
var bulletScene = bulletInfo.BulletScene ?? BulletScene;
Bullet bullet;
for (int i = 0; i < bulletInfo.BulletCount; i++)
{
var bullet = this.CreateChildOf<Bullet>(_gameManager.BulletsContainer, bulletInfo.BulletScene ?? BulletScene, bulletInfo.Position);
if (bulletInfo.IsLaser)
bullet = this.CreateChildOf<LaserBullet>(_gameManager.BulletsContainer, bulletScene, bulletInfo.Position);
else
bullet = this.CreateChildOf<Bullet>(_gameManager.BulletsContainer, bulletScene, bulletInfo.Position);
// var bullet = this.CreateChildOf<Bullet>(_gameManager.BulletsContainer, bulletInfo.BulletScene ?? BulletScene, bulletInfo.Position);
bullet.Initialize(bulletInfo, _gameManager);
@ -91,4 +100,13 @@ public class BulletInfo
public PackedScene DestructionParticlesScene { get; set; }
public IBulletModifier Modifier { get; set; }
public List<ModifierWrapper> TimeModifiers { get; set; } = new List<ModifierWrapper>();
}
#region Laser
public bool IsLaser { get; set; }
public float SpawnDelay { get; set; } = 0.3f; // Delay before beam appears
public float PreFireTime { get; set; } = 0.5f; // Time before laser becomes lethal
public float LethalTime { get; set; } = 1.5f; // Time laser remains lethal
public Color PreFireColor { get; set; } = new Color(1, 0, 0, 0.5f); // Thin red beam
public Color LethalColor { get; set; } = new Color(1, 0, 0, 1.0f); // Thicker beam
#endregion
}

View file

@ -0,0 +1,82 @@
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();
}
protected 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;
}
}