rokojori_action_library/Runtime/Behavior/Receptor.cs

96 lines
1.8 KiB
C#

using Godot;
using System.Collections.Generic;
using Rokojori.Extensions;
namespace Rokojori;
[Tool]
[GlobalClass, Icon("res://addons/rokojori_action_library/Icons/Action.svg")]
public partial class Receptor:Action
{
[Export]
public SceneCondition sceneCondition;
[Export( PropertyHint.Range, "0.1,100")]
public float receiptionTriggerCoverage = 75f;
[Export( PropertyHint.Range, "10,2000")]
public float receiptionWindowDurationMS = 500f;
[Export( PropertyHint.Range, "10,1000")]
public float tickRateMS = 100f;
[Export]
public Timeline timeline;
int resultSize => Mathf.CeilToInt( receiptionWindowDurationMS / tickRateMS );
RingBuffer<bool> _resultsBuffer;
bool _activated = false;
public bool activated => _activated;
bool _active = false;
public bool active => _active;
int _eventID = -1;
public void Start()
{
if ( _active )
{
return;
}
_active = true;
var duration = tickRateMS / 1000f;
var tle = TimelineManager.ScheduleLoopEvent( timeline, duration, 0, tle => Sample() );
_eventID = tle.id;
}
public void Stop()
{
if ( ! _active )
{
return;
}
_active = false;
TimelineManager.RemoveEvent( timeline, _eventID );
_eventID = -1;
}
protected override void _OnTrigger()
{
Sample();
}
void Sample()
{
if ( sceneCondition == null )
{
return;
}
if ( _resultsBuffer == null || _resultsBuffer.capacity != resultSize )
{
_resultsBuffer = new RingBuffer<bool>( resultSize );
}
_resultsBuffer.Add( sceneCondition.Evaluate() );
if ( _resultsBuffer.count != resultSize )
{
_activated = false;
return;
}
var numActive = _resultsBuffer.CountItems( b => b );
_activated = numActive / (float) resultSize >= receiptionTriggerCoverage / 100f;
}
}