rj-action-library/Runtime/Actions/Node3D/PlaySound.cs

98 lines
2.3 KiB
C#

using Godot;
using System.Collections.Generic;
namespace Rokojori
{
[Tool][GlobalClass]
public partial class PlaySound:Action
{
[Export]
public AudioStreamPlayer3D player;
[ExportGroup("Randomize Playback Position")]
[Export]
public bool randomizePlaybackPosition = false;
[Export]
public Duration durationPerSound;
[Export]
public bool generatePools = true;
List<AudioStreamPlayer3D> players = new List<AudioStreamPlayer3D>();
AudioStreamPlayer3D GetFreePlayer()
{
if ( players.Count == 0 )
{
players.Add( player );
}
var freePlayer = players.Find( p => ! p.Playing );
if ( freePlayer != null )
{
return freePlayer;
}
var newPlayer = player.GetParent().CreateChild<AudioStreamPlayer3D>();
newPlayer.Stream = player.Stream;
newPlayer.VolumeDb = player.VolumeDb;
newPlayer.MaxDb = player.MaxDb;
newPlayer.UnitSize = player.UnitSize;
newPlayer.AttenuationModel = player.AttenuationModel;
players.Add( newPlayer );
return newPlayer;
}
protected override void _OnTrigger()
{
var offset = 0f;
var player = generatePools ? GetFreePlayer() : this.player;
if ( randomizePlaybackPosition )
{
var random = LCG.WithSeed( networkSeed );
var length = player.Stream.GetLength();
var numOffsets = Mathf.FloorToInt( length / durationPerSound.GetDurationInSeconds() );
var randomIndex = random.IntegerExclusive( numOffsets );
offset = randomIndex * durationPerSound.GetDurationInSeconds();
// this.LogInfo( "Offset", numOffsets, randomIndex, offset );
}
player.Play( offset );
if ( randomizePlaybackPosition )
{
var tl = TimeLineManager.Ensure( durationPerSound.timeLine );
var start = tl.position;
TimeLineManager.ScheduleSpanIn( durationPerSound.timeLine, 0, durationPerSound.GetDurationInSeconds(),
( span, type )=>
{
var timeNow = tl.position;
var elapsed = timeNow - start;
var phase = span.phase;
if ( type == TimeLineSpanUpdateType.End )
{
player.Stop();
player.Playing = false;
}
}
);
}
}
}
}