using System.Collections; using System.Collections.Generic; using System.Text.RegularExpressions; using System.Text; using Godot; namespace Rokojori { [Tool] [GlobalClass] public partial class Shake:SequenceAction, Animator { [Export] public ShakeEffect shakeEffect; [Export] public Node3D[] targets; List _targetValues; int _actionID = -1; int _currentSpanAnimationID = -1; public void OnAnimatorStart(){} public void OnAnimatorEnd(){} public void OnAnimatorCancel(){} protected override void _OnTrigger() { if ( _actionID != -1 ) { CancelAction( _actionID ); } _actionID = DispatchStart(); var random = LCG.Randomized(); var networkSeed = random.GetSeed(); var randomization = shakeEffect.shakeAmountCurve.Randomize( random ); var timeline = shakeEffect.timeline; var duration = shakeEffect.shakeAmountCurve.GetRandomizedEndTime( randomization ); var curve = shakeEffect; var start = TimeLineManager.GetPosition( shakeEffect.timeline ); var keyFrames = new List>(); var elapsed = 0f; while ( elapsed < duration ) { var key = new KeyFrame(); key.data = shakeEffect.GetShakeData( elapsed, randomization, random ); key.time = elapsed; keyFrames.Add( key ); elapsed += 1f / shakeEffect.GetShakeChangeFPSRandomized( elapsed, random ); } var kfAnimation = new KeyFrameAnimation(); kfAnimation.keyFrames = keyFrames; kfAnimation.FlagSorted(); KeyFrame lastKeyFrame = null; AnimationManager.StartAnimation( this, targets, AnimationMember.Transform ); if ( _targetValues == null || _targetValues.Count == 0 ) { _targetValues = Lists.Map( targets, t => TransformData.From( t, shakeEffect.globalPosition, shakeEffect.globalRotation ) ); } _currentSpanAnimationID = TimeLineScheduler.ScheduleSpanIn( timeline, 0, duration, ( int spanAnimationID, TimeLineSpanUpdateType type )=> { if ( spanAnimationID != _currentSpanAnimationID ) { return; } if ( ! AnimationManager.IsAnimating( this, targets, AnimationMember.Transform ) ) { return; } if ( TimeLineSpanUpdateType.End == type ) { AnimationManager.EndAnimation( this, targets, AnimationMember.Transform ); for ( int i = 0; i < targets.Length; i++ ) { var o = _targetValues[ i ]; o.Set( targets[ i ], shakeEffect.globalPosition, shakeEffect.globalRotation ); } _targetValues.Clear(); _actionID = -1; _currentSpanAnimationID = -1; return; } var offset = TimeLineManager.GetPosition( shakeEffect.timeline ) - start; var keyFrame = kfAnimation.GetKeyFrameAt( offset ); if ( keyFrame == lastKeyFrame && ! shakeEffect.smooth ) { return; } var offsetData = keyFrame.data; var delta = shakeEffect.timeline.delta; for ( int i = 0; i < targets.Length; i++ ) { var combined = offsetData.Clone(); var o = _targetValues[ i ]; if ( shakeEffect.scaleShakeIsRelative ) { combined.scale *= _targetValues[ i ].scale; } combined.rotation *= MathX.DegreesToRadians; var beforeAdd = combined.Clone(); combined.Add( o ); // this.LogInfo( "Applying:", beforeAdd, " + ", o, "=", combined ); if ( shakeEffect.smooth ) { var rawSmooth = Mathf.Clamp( shakeEffect.smoothingStrength, 0, 1 ); rawSmooth = Mathf.Pow( 1f - rawSmooth, 3 ); var smoothStrength = rawSmooth * 250f; var current = TransformData.From( targets[ i ], shakeEffect.globalPosition, shakeEffect.globalRotation ); combined.position = Smoother.SmoothTimeInvariant( current.position, combined.position, delta, smoothStrength ); combined.rotation = Smoother.SmoothTimeInvariant( current.rotation, combined.rotation, delta, smoothStrength ); combined.scale = Smoother.SmoothTimeInvariant( current.scale, combined.scale, delta, smoothStrength ); } combined.Set( targets[ i ], shakeEffect.globalPosition, shakeEffect.globalRotation ); } lastKeyFrame = keyFrame; } ); } public override void CancelAction( int actionID ) { if ( actionID != _actionID ) { return; } AnimationManager.EndAnimation( this, targets, AnimationMember.Transform ); _actionID = -1; _currentSpanAnimationID = -1; } } }