107 lines
2.9 KiB
C#
107 lines
2.9 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 position = new Vector3(parent.GlobalPosition.X, GlobalPosition.Y, parent.GlobalPosition.Z);
|
|
var velocity = position.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;
|
|
}
|
|
}
|