using Godot; using System; using Movementtests.interfaces; [GlobalClass] public partial class FlyingEnemy : CharacterBody3D, IDamageable, IHealthable, IKnockbackable, IDamageMaker { [Export] public Node3D Target { get; set; } [Export] public FlyingEnemyInputs Inputs { get; set; } [Export] public RDamage GetDamageDealt { get; set; } [Export] public CHealth CHealth { get; set; } [Export] public CDamageable CDamage { get; set; } [Export] public RDeathEffect[] DeathEffects { get; set; } private RayCast3D _groundDistanceRaycast; private Area3D _damageBox; private bool _movingToDesiredHeight = true; private Vector3 _randomDirection; public override void _Ready() { _groundDistanceRaycast = GetNode("GroundDistance"); _groundDistanceRaycast.TargetPosition = new Vector3(0, 0, 0); _damageBox = GetNode("DamageBox"); _damageBox.BodyEntered += OnDamageBoxTriggered; _randomDirection = new Vector3(GD.RandRange(-1, 1), 1, GD.RandRange(-1, 1)).Normalized(); CDamage.DamageTaken += ReduceHealth; CHealth.Dead += Kill; } public override void _PhysicsProcess(double delta) { var spaceState = GetWorld3D().DirectSpaceState; var target = Target.GlobalPosition; var direction = (target - GlobalPosition).Normalized(); Vector3 velocity = Velocity; LookAt(target); // Check if we have a direct line of sight to the player if (!_movingToDesiredHeight) { velocity = direction * Inputs.Speed; var query = PhysicsRayQueryParameters3D.Create(GlobalPosition, target, _groundDistanceRaycast.CollisionMask); var result = spaceState.IntersectRay(query); if (result.Count > 0) { _movingToDesiredHeight = true; _randomDirection = new Vector3(GD.RandRange(-1, 1), 1, GD.RandRange(-1, 1)).Normalized(); } } else { velocity = _randomDirection * Inputs.Speed; var groundQuery = PhysicsRayQueryParameters3D.Create(GlobalPosition, GlobalPosition+Vector3.Down*Inputs.TargetHeight, _groundDistanceRaycast.CollisionMask); var groundResult = spaceState.IntersectRay(groundQuery); if (groundResult.Count == 0) { velocity.Y = 0; var query = PhysicsRayQueryParameters3D.Create(GlobalPosition, target, _groundDistanceRaycast.CollisionMask); var result = spaceState.IntersectRay(query); if (result.Count == 0) { _movingToDesiredHeight = false; } } } Velocity = velocity; MoveAndSlide(); } public void OnDamageBoxTriggered(Node3D body) { if(body is IDamageable damageable) damageable.TakeDamage(GetDamageDealt); } public event Action DamageTaken; public float TakeDamage(RDamage damage) { return CDamage.TakeDamage(damage); } public void ReduceHealth(float amount) { CHealth.ReduceHealth(amount); } public void Kill() { foreach (var killable in DeathEffects.ToIKillables()) { killable.Kill(); } QueueFree(); } }