AI/Animals/Actions/SleepAction.cs
using System;
namespace HC3;
public sealed class SleepAction : BehaviorTreeAction
{
private Vector3 _sleepSpot;
private float _sleepDuration;
private bool _isSleeping;
[Property] public RangedFloat SleepDuration { get; set; } = new RangedFloat( 20f, 40f );
[Property] public float EnergyThreshold { get; set; } = 0.3f;
public override float Score()
{
if ( !Agent.IsValid() ) return 0f;
var needSystem = Agent.GetComponent<NeedSystem>();
if ( needSystem == null ) return 0f;
var energyNeed = needSystem.GetNeed( "Energy" );
if ( energyNeed == null ) return 0f;
// If already sleeping, keep sleeping
if ( _isSleeping ) return 300f;
// If energy is low enough, sleep
if ( energyNeed.GetPriority() > EnergyThreshold )
{
// Find a sleep spot - for now just use current position
_sleepSpot = Agent.WorldPosition;
return 150f;
}
return 0f;
}
protected override void OnTreeStart()
{
_sleepDuration = Random.Float( SleepDuration.Min, SleepDuration.Max );
_isSleeping = true;
Agent.Tags.Set( "sleep", true );
}
protected override void OnTreeStop()
{
_isSleeping = false;
Agent.Tags.Set( "sleep", false );
}
protected override Node BuildTree()
{
return new SequenceNode( new()
{
new MoveToNode(Agent, _sleepSpot, "Finding a place to sleep"),
new SleepNode(Agent, _sleepDuration),
new RestoreNeedNode(Agent, "Energy", 0.0f )
} );
}
}
file sealed class SleepNode : Node
{
private readonly Agent Agent;
private readonly float Duration;
private TimeUntil _sleepTime;
public SleepNode( Agent agent, float duration )
{
Agent = agent;
Duration = duration;
}
protected override void OnStart()
{
_sleepTime = Duration;
}
public override Status Tick()
{
if ( _sleepTime <= 0 )
return Status.Success;
return Status.Running;
}
public override ActionDisplayInfo? GetDisplay()
{
float progress = 1f - (_sleepTime / Duration).Clamp( 0f, 1f );
return new ActionDisplayInfo( "hotel_class", "Sleeping...", progress );
}
}