public static IEnumerator <CommandDelegate> CoroutineOne(Ref <float> val, int depth, Ref <int> calledCount) { if (depth > 0) { ++calledCount.Value; yield return(Cmd.ChangeTo(val, 5.0f, 4.0f)); yield return(Cmd.WaitForSeconds(1.0f)); yield return(Cmd.ChangeBy(val, -4.0f, 4.0f)); yield return(null); // Wait for a single frame yield return(Cmd.Coroutine(() => CoroutineOne(val, depth - 1, calledCount))); } }
/// <summary> /// Pulsates a value. /// </summary> /// <param name="amount">The amount to increase the value by.</param> public static CommandDelegate PulsateScale(Ref <float> scale, float amount, double duration) { CheckArgumentNonNull(scale, "scale"); CommandDelegate tweenBack = null; return(Cmd.Sequence( Cmd.Do(() => { // Because we don't know what the original scale is at this point, // we have to recreate the scale back tween every time. tweenBack = Cmd.ChangeTo(scale, scale.Value, duration / 2.0, Ease.Smooth()); }), Cmd.ChangeBy(scale, amount, duration / 2.0, Ease.Smooth()), Cmd.Defer(() => tweenBack) )); }
/// <summary> /// Performs a squash and stretch animation, while changing to a target scale. /// </summary> /// <param name="scale">The value to animate.</param> /// <param name="endScale">The final scale.</param> /// <param name="amplitude">The amplitude of a squash and strech</param> /// <param name="duration">The duration of the animation</param> /// <param name="normal"> The normal of the animation. </param> /// <param name="tangent"> The tangent of the animation. </param> public static CommandDelegate ScaleSquashAndStretchTo(Ref <Vector3> scale, Vector3 endScale, float amplitude, double duration, Vector3 normal, Vector3 tangent) { CheckArgumentNonNull(scale, "scale"); var squashRef = Ref <Vector3> .Create(Vector3.one); var scaleRef = Ref <Vector3> .Create(); return(Cmd.Sequence( Cmd.Do(() => scaleRef.Value = scale.Value), Cmd.Parallel( SquashAndStretch(squashRef, amplitude, duration, normal, tangent), Cmd.ChangeTo(scaleRef, endScale, duration / 4, Ease.Smooth()), Cmd.Duration(t => scale.Value = Vector3.Scale(squashRef.Value, scaleRef.Value), duration) ) )); }
/// <summary> /// Shakes the vector several times in a random value, up to amount in magnitude. /// </summary> /// <param name="amount">The maximum displacement of the vector, with separate x,y and z values.</param> /// <param name="numShakes"> The number of shakes to perform. </param> public static CommandDelegate Shake(Ref <Vector3> vector, Vector3 amount, int numShakes, double duration) { CheckArgumentNonNull(vector); if (numShakes <= 0) { throw new ArgumentOutOfRangeException("numBounces", "Must be larger than 0."); } double avgDuration = duration / (numShakes + 1); CommandDelegate[] list = new CommandDelegate[numShakes + 1]; return(Cmd.Defer( () => { var baseVal = vector.Value; for (int i = 0; i < numShakes; ++i) { // Generate an offset within the range -1, 1 var offset = new Vector3( UnityEngine.Random.Range(-1f, 1f), UnityEngine.Random.Range(-1f, 1f), UnityEngine.Random.Range(-1f, 1f) ); if (offset.magnitude > 1f) { // Randomize the length of the offset if it is too large. offset = offset.normalized * UnityEngine.Random.Range(0f, 1f); } // Scale the offset, by the amount, and the scale factor. offset = new Vector3(offset.x * amount.x, offset.y * amount.y, offset.z * amount.z); list[i] = Cmd.ChangeTo(vector, baseVal + offset, avgDuration); } list[numShakes] = Cmd.ChangeTo(vector, baseVal, avgDuration); return Cmd.Sequence(list); } )); }
public static void TestChangeTo() { const float floatEnd = 4.8f; const float floatStart = 1.2f; float floatVal = floatStart; Ref <float> floatRef = new Ref <float>( () => floatVal, t => floatVal = t ); const double doubleEnd = 3.2; const double doubleStart = 9.2; double doubleVal = doubleStart; Ref <double> doubleRef = new Ref <double>( () => doubleVal, t => doubleVal = t ); Vector2 vec2End = new Vector2(9.5f, 2.0f); Vector2 vec2Start = new Vector2(4.0f, 5.0f); Vector2 vec2Val = vec2Start; Ref <Vector2> vec2Ref = new Ref <Vector2>( () => vec2Val, t => vec2Val = t ); Vector3 vec3End = new Vector3(4.0f, 19.0f, 2.0f); Vector3 vec3Start = new Vector3(92.0f, 0.5f, 34.0f); Vector3 vec3Val = vec3Start; Ref <Vector3> vec3Ref = new Ref <Vector3>( () => vec3Val, t => vec3Val = t ); Vector4 vec4End = new Vector4(92.0f, 0.5f, 14.0f, 7.0f); Vector4 vec4Start = new Vector4(0.4f, 10.0f, 3.0f, 82.0f); Vector4 vec4Val = vec4Start; Ref <Vector4> vec4Ref = new Ref <Vector4>( () => vec4Val, t => vec4Val = t ); CommandQueue queue = new CommandQueue(); queue.Enqueue( Cmd.Repeat(2, Cmd.Parallel( Cmd.ChangeTo(floatRef, floatEnd, 1.0), Cmd.ChangeTo(doubleRef, doubleEnd, 1.0), Cmd.ChangeTo(vec2Ref, vec2End, 1.0), Cmd.ChangeTo(vec3Ref, vec3End, 1.0), Cmd.ChangeTo(vec4Ref, vec4End, 1.0) ) ) ); queue.Update(0.3); // Check basic lerping works. Assert.AreEqual(floatVal, floatEnd * 0.3f + floatStart * 0.7f, 0.01); Assert.AreEqual(doubleVal, doubleEnd * 0.3 + doubleStart * 0.7, 0.01); AreEqual(vec2Val, vec2End * 0.3f + vec2Start * 0.7f, 0.01f); AreEqual(vec3Val, vec3End * 0.3f + vec3Start * 0.7f, 0.01f); AreEqual(vec4Val, vec4End * 0.3f + vec4Start * 0.7f, 0.01f); // Reset the vals to zero. Checks that 'ChangeTo' will force itself back on // track. floatVal = 0.0f; doubleVal = 0.0; vec2Val = Vector2.zero; vec3Val = Vector3.zero; vec4Val = Vector4.zero; queue.Update(0.2); // Completes the offset Assert.AreEqual(floatVal, floatEnd * 0.5f + floatStart * 0.5f, 0.01); Assert.AreEqual(doubleVal, doubleEnd * 0.5 + doubleStart * 0.5, 0.01); AreEqual(vec2Val, vec2End * 0.5f + vec2Start * 0.5f, 0.01f); AreEqual(vec3Val, vec3End * 0.5f + vec3Start * 0.5f, 0.01f); AreEqual(vec4Val, vec4End * 0.5f + vec4Start * 0.5f, 0.01f); queue.Update(0.5); Assert.AreEqual(floatVal, floatEnd, 0.01f); Assert.AreEqual(doubleVal, doubleEnd, 0.01); AreEqual(vec2Val, vec2End, 0.01f); AreEqual(vec3Val, vec3End, 0.01f); AreEqual(vec4Val, vec4End, 0.01f); queue.Update(0.5); // Check that it doesn't move once it has reached it's final position. Assert.AreEqual(floatVal, floatEnd, 0.01f); Assert.AreEqual(doubleVal, doubleEnd, 0.01); AreEqual(vec2Val, vec2End, 0.01f); AreEqual(vec3Val, vec3End, 0.01f); AreEqual(vec4Val, vec4End, 0.01f); Rect rectEnd = new Rect(-1.0f, 1.0f, 5.0f, 5.0f); Rect rectStart = new Rect(0.0f, 2.0f, 6.0f, 6.0f); Rect rectVal = new Rect(); Ref <Rect> rectRef = new Ref <Rect>( () => { return(rectVal); }, t => { rectVal = t; } ); Vector2 firstAnchor = new Vector2(0.0f, 0.0f); Vector2 secondAnchor = new Vector2(1.0f, 0.0f); Vector3 thirdAnchor = new Vector2(0.0f, 1.0f); Vector2 forthAnchor = new Vector2(1.0f, 1.0f); CommandDelegate reset = Cmd.Do(() => { rectVal = rectStart; }); queue = new CommandQueue(); queue.Enqueue( reset, Cmd.ChangeTo(rectRef, rectEnd, 1.0, firstAnchor), Cmd.WaitForFrames(1), reset, Cmd.ChangeTo(rectRef, rectEnd, 1.0, secondAnchor), Cmd.WaitForFrames(1), reset, Cmd.ChangeTo(rectRef, rectEnd, 1.0, thirdAnchor), Cmd.WaitForFrames(1), reset, Cmd.ChangeTo(rectRef, rectEnd, 1.0, forthAnchor) ); // Test the top left corner. queue.Update(0.5); AreEqual(rectVal, new Rect( -0.5f, 1.5f, (rectStart.width + rectEnd.width) * 0.5f, (rectStart.height + rectEnd.height) * 0.5f), 0.001f ); queue.Update(0.5); AreEqual(rectVal, rectEnd, 0.001f); queue.Update(0.0f); // Test the top right corner. queue.Update(0.3); AreEqual(rectVal, new Rect( 5.4f - 5.7f, 1.7f, rectStart.width * 0.7f + rectEnd.width * 0.3f, rectStart.height * 0.7f + rectEnd.height * 0.3f), 0.001f ); queue.Update(0.7); AreEqual(rectVal, rectEnd, 0.001f); queue.Update(0.0f); // Test the bottom left corner. queue.Update(0.4); AreEqual(rectVal, new Rect( -0.4f, 7.2f - 5.6f, rectStart.width * 0.6f + rectEnd.width * 0.4f, rectStart.height * 0.6f + rectEnd.height * 0.4f), 0.001f ); queue.Update(0.6); AreEqual(rectVal, rectEnd, 0.001f); queue.Update(0.0f); // Test the bottom right corner. queue.Update(0.4); AreEqual(rectVal, new Rect( 5.2f - 5.6f, 7.2f - 5.6f, rectStart.width * 0.6f + rectEnd.width * 0.4f, rectStart.height * 0.6f + rectEnd.height * 0.4f), 0.001f ); queue.Update(0.6); AreEqual(rectVal, rectEnd, 0.001f); queue.Update(0.0f); }