Files
GameJamDungeon/Zennysoft.Game.Ma/src/enemy/behaviors/PatrolBehavior.cs

106 lines
2.8 KiB
C#

using Chickensoft.AutoInject;
using Chickensoft.Introspection;
using Godot;
using Godot.Collections;
using Zennysoft.Game.Abstractions.Entity;
namespace Zennysoft.Game.Ma;
[Meta(typeof(IAutoNode))]
public partial class PatrolBehavior : Node3D, IBehavior
{
public override void _Notification(int what) => this.Notify(what);
[Export] private double _patrolSpeed { get; set; } = 100f;
[Export] private double _thinkTime { get; set; } = 0.8f;
[Export] private float _patrolRange { get; set; } = 5f;
[Export] private float _patrolTime { get; set; } = 10f;
private Timer _patrolTimer { get; set; } = default!;
private NavigationAgent3D _navigationAgent;
private int _recursiveCounter = 0;
private Vector3 _homePosition;
public Vector3 HomePosition
{
get => _homePosition;
set
{
_homePosition = value;
_navigationAgent.TargetPosition = value;
}
}
[Signal] public delegate void OnVelocityComputedEventHandler(Vector3 safeVelocity);
public void OnReady()
{
_patrolTimer = new Timer() { WaitTime = _patrolTime };
_patrolTimer.Timeout += PatrolTimer_Timeout;
AddChild(_patrolTimer);
SetPhysicsProcess(false);
}
public void Init(NavigationAgent3D navigationAgent)
{
_navigationAgent = navigationAgent;
_navigationAgent.WaypointReached += NavigationAgent_WaypointReached;
}
private async void NavigationAgent_WaypointReached(Dictionary details)
{
await ToSignal(GetTree().CreateTimer(_thinkTime), "timeout");
}
public void StartPatrol()
{
SetPhysicsProcess(true);
_patrolTimer?.Start();
}
public void StopPatrol()
{
SetPhysicsProcess(false);
_patrolTimer?.Stop();
}
public void OnPhysicsProcess(double delta)
{
var nextVelocity = _navigationAgent.GetNextPathPosition();
var parent = GetParent() as Node3D;
var velocity = parent.GlobalPosition.DirectionTo(nextVelocity) * (float)_patrolSpeed * (float)delta;
EmitSignal(SignalName.OnVelocityComputed, velocity);
}
public void SetPatrolTarget()
{
var rng = new RandomNumberGenerator();
rng.Randomize();
var randomPointX = rng.RandfRange(-_patrolRange, _patrolRange);
var randomPointZ = rng.RandfRange(-_patrolRange, _patrolRange);
_navigationAgent.TargetPosition = HomePosition + new Vector3(randomPointX, 0, randomPointZ);
if (!_navigationAgent.IsTargetReachable())
{
_recursiveCounter++;
if (_recursiveCounter <= 100)
SetPatrolTarget();
else
_navigationAgent.TargetPosition = HomePosition;
}
_recursiveCounter = 0;
}
private void PatrolTimer_Timeout() => SetPatrolTarget();
public void OnExitTree()
{
_patrolTimer.Stop();
_patrolTimer.Timeout -= PatrolTimer_Timeout;
_navigationAgent.WaypointReached -= NavigationAgent_WaypointReached;
}
}