mirror of
https://gitlab.com/MaddoScientisto/cirnogodot.git
synced 2026-06-01 09:55:35 +00:00
198 lines
3.8 KiB
C#
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
|
|
}
|
|
}
|