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 players = new List(); 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(); 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; } } ); } } } }