cirnogodot/Scripts/AttackPatterns/ShootingPattern3D.cs

228 lines
7 KiB
C#
Raw Normal View History

2025-06-20 15:39:19 +02:00
using Cirno.Scripts.Actors;
using Cirno.Scripts.Components;
using Cirno.Scripts.Resources;
using Cirno.Scripts.Utils;
using Godot;
using Godot.Collections;
namespace Cirno.Scripts.AttackPatterns;
[GlobalClass]
[Tool]
public partial class ShootingPattern3D : AttackPattern
{
[Export] public BulletResource BulletResource { get; set; }
[Export] public Vector3 EmitterOffset { get; set; } = Vector3.Zero;
[Export] public int bulletCount = 16;
[Export] public float rotationSpeed = 0f;
[Export] public float _rotationOffset = 0f;
[Export] public float duration = 5f;
[Export] public float spread = 360f;
[Export] public float burstInterval = 0.5f;
[ExportCategory("Burst")] [Export] public int ShotsPerBurst { get; private set; } = 100;
[Export] public float BurstRate { get; private set; } = 0f;
[ExportCategory("Other")] [Export] public bool _targetPlayer = false;
[ExportCategory("Other")] [Export] public bool _predictPlayer = false;
[ExportCategory("Overrides")]
[Export] public bool OverrideOwner { get; private set; } = false;
[Export] public BulletOwner Owner { get; private set; } = BulletOwner.None;
[Export] public bool OverrideDamageType { get; private set; } = false;
[Export] public DamageType DamageType { get; private set; } = DamageType.Neutral;
[Export] public bool OverrideControllable { get; private set; } = false;
[Export] public bool Controllable { get; private set; } = false;
[ExportCategory("Extra Modifiers")]
[Export]
public bool OverrideCreationModifier { get; private set; } = false;
[Export] public BulletCreationModifier Modifier;
[Export] public Array<TimeModifier> TimeModifiers = [];
protected virtual BulletInfo MakeBullet(Vector2 position, int count = 1, float spread = 0f, float rotationOffset = 0f)
{
var bullet = this.BulletResource.MakeBullet(position, count,
spread, rotationOffset);
if (OverrideOwner)
{
bullet.Owner = this.Owner;
}
if (OverrideDamageType)
{
bullet.DamageType = DamageType;
}
if (OverrideControllable)
{
bullet.Controllabe = Controllable;
}
if (OverrideCreationModifier)
{
bullet.Modifier = this.Modifier;
}
if (TimeModifiers.Count != 0)
{
bullet.TimeModifiers.AddRange(TimeModifiers);
}
return bullet;
}
public override IPatternMachine MakeMachine(Node parent)
{
return new SpiralPatternMachine(this, parent);
}
public class SpiralPatternMachine(ShootingPattern3D pattern, Node parent) : IPatternMachine
{
public Node Parent => parent;
public IScriptHost3D ScriptHost { get; private set; }
private double timer;
private double burstTimer;
//private double _burstRateTimer;
private BulletSpawner3D spawner;
private ShootStatus _state = ShootStatus.Idle;
private int _burstBullets;
public void Start()
{
ScriptHost = Parent as IScriptHost3D;
timer = 0;
_burstBullets = pattern.ShotsPerBurst;
burstTimer = pattern.burstInterval; // start immediately
spawner = parent.GetNode<BulletSpawner3D>("BulletSpawner3D");
_state = ShootStatus.Shooting;
}
private void WaitingBurstUpdate(double delta)
{
timer += delta;
burstTimer += delta;
if (burstTimer >= pattern.burstInterval)
{
_state = ShootStatus.Shooting;
}
}
private void WaitingReloadUpdate(double delta)
{
timer += delta;
burstTimer += delta;
if (burstTimer >= pattern.BurstRate)
{
_burstBullets = pattern.ShotsPerBurst;
_state = ShootStatus.Shooting;
}
}
private void ShootingUpdate(double delta)
{
timer += delta;
burstTimer = 0;
Shoot();
_burstBullets--;
if (_burstBullets <= 0)
{
_state = ShootStatus.WaitingReload;
}
else
{
_state = ShootStatus.WaitingBurst;
}
}
public void UpdatePattern(double delta)
{
switch (_state)
{
case ShootStatus.Idle:
case ShootStatus.Done:
return;
case ShootStatus.Shooting:
ShootingUpdate(delta);
break;
case ShootStatus.WaitingBurst:
WaitingBurstUpdate(delta);
break;
case ShootStatus.WaitingReload:
WaitingReloadUpdate(delta);
break;
}
if (timer >= pattern.duration)
{
_state = ShootStatus.Done;
}
}
private void Shoot()
{
float angleOffset = pattern._rotationOffset + (float)(pattern.rotationSpeed * timer);
Vector2 direction = pattern.BulletResource.Direction;
// TODO: Fix player aiming for 3D
// if (pattern._targetPlayer && GameManager.Instance.PlayerPosition.HasValue)
// {
// if (pattern._predictPlayer && GameManager.Instance.PlayerVelocity.HasValue)
// {
// var predictedDirection = MathFunctions.PredictInterceptPosition(ScriptHost.ParentObject.GlobalPosition,
// GameManager.Instance.PlayerPosition.Value, GameManager.Instance.PlayerVelocity.Value,
// pattern.BulletResource.BulletSpeed);
// if (predictedDirection.HasValue)
// {
// direction = (predictedDirection.Value - ScriptHost.ParentObject.GlobalPosition).Normalized();
// }
// }
// else
// {
// direction = (GameManager.Instance.PlayerPosition.Value - ScriptHost.ParentObject.GlobalPosition).Normalized();
// }
// }
var spawnPosition = ScriptHost.ParentObject.GlobalPosition + pattern.EmitterOffset;
var bullet = pattern.MakeBullet(spawnPosition.ToVector2(), pattern.bulletCount,
pattern.spread, angleOffset);
bullet.Direction = direction;
//spawner.SpawnBullet(MakeBullet(Boss.GlobalPosition, direction, angleOffset));
spawner.SpawnBullet(bullet, spawnPosition);
}
public bool IsComplete()
{
//return timer >= pattern.duration;
return _state is ShootStatus.Done;
}
private enum ShootStatus
{
Idle,
Shooting,
WaitingBurst,
WaitingReload,
Done
}
}
}