cirnogodot/Scripts/Enemy.cs
2024-11-11 15:41:34 +01:00

198 lines
3.8 KiB
C#

using Cirno.Scripts;
using Godot;
using System;
using System.Diagnostics;
public partial class Enemy : Area2D, IDestructible
{
private InteractionController _cachedPlayer;
private EnemyState _currentState = EnemyState.Idle;
[Export]
public PackedScene BulletScene { get; set; }
[Export] public float Health = 4f;
[Export] public double RateOfFire = 0.4f; // Time between shots within a burst
[Export] public float BulletSpeed = 100f;
[Export] public int BurstCount = 3; // Number of shots per burst
[Export] public float BurstCooldown = 1f; // Time between bursts
[Export] public bool AimAtPlayer = true; // Whether to aim at player or shoot straight
private float _currentHealth = 0f;
private bool _isDestroyed = false;
private Timer _burstTimer;
private Timer _shotTimer;
private int _shotsFired = 0;
public override void _Ready()
{
_currentHealth = Health;
// Initialize timers
_burstTimer = new Timer();
_shotTimer = new Timer();
AddChild(_burstTimer);
AddChild(_shotTimer);
_burstTimer.WaitTime = BurstCooldown;
_burstTimer.OneShot = true;
_shotTimer.WaitTime = RateOfFire;
_shotTimer.OneShot = true;
_shotTimer.Timeout += OnShotTimerTimeout;
_burstTimer.Timeout += OnBurstTimerTimeout;
// Debug
DebugStats.Instance.AddProperty(this, "_currentHealth", "");
}
public override void _Process(double delta)
{
switch (_currentState)
{
case EnemyState.Idle:
break;
case EnemyState.Primed:
break;
default:
break;
}
}
public override void _PhysicsProcess(double delta)
{
HandlePlayerDetection();
}
private void HandlePlayerDetection()
{
if (_cachedPlayer == null || _currentState is not EnemyState.Primed)
{
return;
}
if (_burstTimer.IsStopped() && !_shotTimer.IsStopped() && IsPlayerInSight())
{
StartBurst();
}
}
private void StartBurst()
{
_shotsFired = 0;
_shotTimer.Start();
}
private void OnShotTimerTimeout()
{
if (_shotsFired < BurstCount)
{
Shoot();
_shotsFired++;
if (_shotsFired < BurstCount)
{
_shotTimer.Start(); // Restart for the next shot in the burst
}
}
else
{
_burstTimer.Start(); // Start cooldown between bursts
}
}
private void OnBurstTimerTimeout()
{
// Cooldown complete, can start new burst when conditions are met
}
private void Shoot()
{
var bullet = this.CreateChild<Bullet>(BulletScene);
if (AimAtPlayer)
{
bullet.SetDirection((_cachedPlayer.GlobalPosition - this.GlobalPosition).Normalized());
}
else
{
bullet.SetDirection(Vector2.Right.Rotated(this.Rotation));
}
bullet.Speed = BulletSpeed;
}
private bool IsPlayerInSight()
{
var spaceState = GetWorld2D().DirectSpaceState;
var query = PhysicsRayQueryParameters2D.Create(this.GlobalPosition, _cachedPlayer.GlobalPosition, CollisionMask, new Godot.Collections.Array<Rid> { GetRid() });
var result = spaceState.IntersectRay(query);
return result.Count == 0; // True if no obstacles between enemy and player
}
private void _on_player_detection_area_entered(Area2D area)
{
if (area is InteractionController player)
{
Debug.WriteLine("Enemy detection area Entered by interaction controller");
_cachedPlayer = player;
if (_currentState is EnemyState.Idle)
{
_currentState = EnemyState.Primed;
}
}
}
private void _on_player_detection_area_exited(Area2D area)
{
if (_currentState is EnemyState.Primed)
{
_currentState = EnemyState.Idle;
}
}
private void _on_area_entered(Area2D area)
{
// Collision handling
}
private void Explode()
{
Debug.WriteLine("Ded");
QueueFree();
}
public void Hit(float damage)
{
if (_isDestroyed) return;
_currentHealth -= damage;
if (!(_currentHealth <= 0)) return;
_isDestroyed = true;
Explode();
}
public bool IsDestroyed()
{
return _isDestroyed;
}
private enum EnemyState
{
Idle,
Primed
}
}