public static CommandDelegate ChangeTo(Ref <Rect> rect, Rect endRect, double duration, Vector2 anchorPoint, CommandEase ease = null) { CheckArgumentNonNull(rect, "rect"); Rect startRect = new Rect(); Vector2 startAnchorPoint = Vector2.zero; Vector2 endAnchorPoint = Vector2.zero; return(Cmd.Sequence( Cmd.Do(delegate() { startRect = rect.Value; startAnchorPoint = new Vector2( startRect.x + startRect.width * anchorPoint.x, startRect.y + startRect.height * anchorPoint.y ); endAnchorPoint = new Vector2( endRect.x + endRect.width * anchorPoint.x, endRect.y + endRect.height * anchorPoint.y ); }), Cmd.Duration(delegate(double t) { Rect newRect = new Rect(); newRect.width = (endRect.width - startRect.width) * (float)t + startRect.width; newRect.height = (endRect.height - startRect.height) * (float)t + startRect.height; Vector2 newAnchorPoint = Vector2.Lerp(startAnchorPoint, endAnchorPoint, (float)t); newRect.x = newAnchorPoint.x - anchorPoint.x * newRect.width; newRect.y = newAnchorPoint.y - anchorPoint.y * newRect.height; rect.Value = newRect; }, duration, ease) )); }
/// <summary> /// Takes an Enumerable of a given type, and a function that converts /// T into a CommandDelegate, the executes them in parallel. /// </summary> /// <param name="collection">A collection of objects.</param> /// <param name="factory">The conversion method.</param> /// <param name="delay"> Each successive element in the collection is delayed by delay * index.</param> public static CommandDelegate ForEachParallelWithDelay <T>(this IEnumerable <T> collection, Func <T, CommandDelegate> factory, double delay) { CheckArgumentNonNull(collection, "collection"); CheckArgumentNonNull(factory, "factory"); CheckDurationGreaterThanZero(delay); var commands = new List <CommandDelegate>(); double totalDelay = 0f; foreach (var item in collection) { CommandDelegate output = factory(item); if (totalDelay > 0.0) { output = Cmd.Sequence( Cmd.WaitForSeconds(totalDelay), output ); } totalDelay += delay; commands.Add(output); } return(Cmd.Parallel(commands.ToArray())); }
/// <summary> /// Oscilates a quaternion. /// </summary> /// <param name="amount"> The amount to wiggle by in degrees.</param> /// <param name="axis"> The axis to wiggle around </param> public static CommandDelegate Wiggle(Ref <Quaternion> rotation, float amount, double duration, Vector3 axis) { CheckArgumentNonNull(rotation, "rotation"); Quaternion startQuaternion = Quaternion.identity; float val = 0.0f; Ref <float> floatRef = new Ref <float>( () => val, (t) => { val = t; rotation.Value = startQuaternion * Quaternion.AngleAxis(val, axis); } ); return(Cmd.Sequence( Cmd.Do(() => { startQuaternion = rotation.Value; val = 0.0f; }), Cmd.Oscillate( floatRef, amount, duration, Ease.Smooth() ) )); }
public static void TestTintFrom() { Color colourStart = new Color(0.4f, 0.2f, 0.7f, 0.5f); Color colourEnd = new Color(0.3f, 0.4f, 0.15f, 0.25f); Color colourVal = colourStart; Ref <Color> colourRef = new Ref <Color>( () => colourVal, t => colourVal = t ); CommandQueue queue = new CommandQueue(); queue.Sequence( Cmd.Repeat(2, Cmd.Sequence( Cmd.TintFrom(colourRef, colourEnd, 1.0), Cmd.WaitForFrames(1) ) ) ); queue.Update(0.2); AreEqual(colourVal, colourStart * 0.2f + colourEnd * 0.8f, 0.001f); colourVal = colourStart; queue.Update(0.8); AreEqual(colourVal, colourStart, 0.001f); queue.Update(0.0); queue.Update(0.5); AreEqual(colourVal, colourStart * 0.5f + colourEnd * 0.5f, 0.001f); }
/// <summary> /// Oscillates around a value. This will animation from /// startValue > startValue + amount > startValue - amount- > startValue, /// in a smooth circular motion. /// </summary> /// <param name="amount"> /// The maximum amount to oscillate away from the default value. /// </param> public static CommandDelegate Oscillate(Ref <float> single, float amount, double duration, CommandEase ease = null) { CheckArgumentNonNull(single, "single"); float baseValue = 0f; return(Cmd.Sequence( Cmd.Do(() => baseValue = single.Value), Cmd.Duration(t => { single.Value = baseValue + Mathf.Sin((float)t * 2f * Mathf.PI) * amount; }, duration, ease) )); }
public static CommandDelegate TintTo(Ref <Color> color, Color endColor, double duration, CommandEase ease = null) { CheckArgumentNonNull(color, "color"); Color startColor = Color.white; return(Cmd.Sequence( Cmd.Do(delegate() { startColor = color.Value; }), Cmd.Duration(delegate(double t) { color.Value = Color.Lerp(startColor, endColor, (float)t); }, duration, ease) )); }
public static CommandDelegate ChangeTo(Ref <Vector2> vector, Vector2 endVector, double duration, CommandEase ease = null) { CheckArgumentNonNull(vector, "vector"); Vector2 startVector = Vector2.zero; return(Cmd.Sequence( Cmd.Do(delegate() { startVector = vector.Value; }), Cmd.Duration(delegate(double t) { vector.Value = (endVector - startVector) * (float)t + startVector; }, duration, ease) )); }
public static void TestTiming() { CommandQueue queue = new CommandQueue(); const double FIRST_Command_DURATION = 4.5; const double SECOND_Command_DURATION = 1.0; const double WAIT_DURATION = 1.5; const int REPEAT_COUNT = 8640; double lastT = 0.0; // This test ensures that between alternating CommandDurations, // there is no accumulation of error in timing. We use a repeat // here to accentuate the error. queue.Enqueue( Cmd.Repeat(REPEAT_COUNT, Cmd.Sequence( Cmd.WaitForSeconds(WAIT_DURATION), Cmd.Do(() => lastT = 0.0), Cmd.Duration((t) => { Assert.IsTrue(t <= 1.0); Assert.IsTrue(lastT <= t); lastT = t; }, FIRST_Command_DURATION), Cmd.Do(() => lastT = 0.0), Cmd.Parallel( Cmd.Duration((t) => {}, SECOND_Command_DURATION / 2.0), // The following two Duration Cmd should finish in the same Update call. Cmd.Duration((t) => {}, SECOND_Command_DURATION - (DELTA_TIME_RATE / 2.0)), Cmd.Duration((t) => { Assert.IsTrue(t <= 1.0); Assert.IsTrue(lastT <= t); lastT = t; }, SECOND_Command_DURATION) ) ) ) ); double totalTime = 0.0; while (!queue.Update(DELTA_TIME_RATE)) { totalTime += DELTA_TIME_RATE; } const double EXPECTED_TIME = (FIRST_Command_DURATION + SECOND_Command_DURATION + WAIT_DURATION) * REPEAT_COUNT; Assert.AreEqual(totalTime, EXPECTED_TIME, DELTA_TIME_RATE, "Time delta accumulation too large."); }
public static CommandDelegate TintBy(Ref <Color> color, Color offset, double duration, CommandEase ease = null) { CheckArgumentNonNull(color, "color"); double lastT = 0.0; return(Cmd.Sequence( Cmd.Do(delegate() { lastT = 0.0; }), Cmd.Duration(delegate(double t) { color.Value += offset * (float)(t - lastT); lastT = t; }, duration, ease) )); }
/// <summary> /// Takes an Enumerable of a given type, and a function that converts /// T into a CommandDelegate, the executes them sequentially. /// </summary> /// <param name="collection">A collection of objects.</param> /// <param name="factory">The conversion method.</param> public static CommandDelegate ForEachSequence <T>(this IEnumerable <T> collection, Func <T, CommandDelegate> factory) { CheckArgumentNonNull(collection, "collection"); CheckArgumentNonNull(factory, "factory"); var commands = new List <CommandDelegate>(); foreach (var item in collection) { CommandDelegate output = factory(item); commands.Add(output); } return(Cmd.Sequence(commands.ToArray())); }
/// <summary> /// Performs a squash and stretch animation, while changing from a target scale. /// </summary> /// <param name="scale">The value to animate.</param> /// <param name="startScale">The scale to animate from.</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 ScaleSquashAndStretchFrom(Ref <Vector3> scale, Vector3 startScale, float amplitude, double duration, Vector3 normal, Vector3 tangent) { CheckArgumentNonNull(scale, "scale"); Vector3 targetScale = Vector3.zero; return(Cmd.Sequence( Cmd.Do(() => { targetScale = scale.Value; scale.Value = startScale; }), Cmd.Defer(() => Cmd.ScaleSquashAndStretchTo(scale, targetScale, amplitude, duration, normal, tangent)) )); }
/// <summary> /// Shakes the vector several times in a random value, up to amount in magnitude. /// </summary> /// <param name="amount">The maximum displacement of the rotation, in degrees.</param> /// <param name="numShakes"> The number of shakes to perform. </param> public static CommandDelegate Shake(Ref <Quaternion> rotation, float amount, int numShakes, double duration) { CheckArgumentNonNull(rotation); if (amount <= 0f || amount > 180f) { throw new ArgumentOutOfRangeException("amount", "Must be larger than 0."); } if (numShakes <= 0) { throw new ArgumentOutOfRangeException("numBounces", "Must be larger than 0."); } amount = Mathf.Abs(amount); double avgDuration = duration / (numShakes + 1); CommandDelegate[] list = new CommandDelegate[numShakes + 1]; return(Cmd.Defer( () => { var baseVal = rotation.Value; for (int i = 0; i < numShakes; ++i) { // Generate an offset within the range -amount, amount var offset = Quaternion.Euler( UnityEngine.Random.Range(-amount, amount), UnityEngine.Random.Range(-amount, amount), UnityEngine.Random.Range(-amount, amount) ); float angle = Quaternion.Angle(Quaternion.identity, offset); // Clamp the offset if (angle > amount) { float t = UnityEngine.Random.Range(0f, angle / amount); offset = Quaternion.LerpUnclamped(Quaternion.identity, offset, t); } list[i] = Cmd.RotateTo(rotation, baseVal * offset, avgDuration); } list[numShakes] = Cmd.RotateTo(rotation, baseVal, avgDuration); return Cmd.Sequence(list); } )); }
public static CommandDelegate RotateFrom(Ref <Quaternion> rotation, Quaternion startRotation, double duration, CommandEase ease = null) { CheckArgumentNonNull(rotation, "rotation"); Quaternion endRotation = Quaternion.identity; return(Cmd.Sequence( Cmd.Do(delegate() { endRotation = rotation.Value; }), Cmd.Duration( delegate(double t) { rotation.Value = Quaternion.LerpUnclamped(startRotation, endRotation, (float)t); }, duration, ease) )); }
public static CommandDelegate ChangeBy(Ref <Vector2> vector, Vector2 offset, double duration, CommandEase ease = null) { CheckArgumentNonNull(vector, "vector"); double lastT = 0.0; return(Cmd.Sequence( Cmd.Do(delegate() { lastT = 0.0; }), Cmd.Duration(delegate(double t) { vector.Value += offset * (float)(t - lastT); lastT = t; }, duration, ease) )); }
/// <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) )); }
public static void TestRequire() { CommandQueue queue = new CommandQueue(); bool shouldStop = false; bool didFinish = false; int callCount = 0; queue.Enqueue( Cmd.RepeatForever( Cmd.Require(() => !shouldStop, () => Cmd.RepeatForever( Cmd.Sequence( Cmd.Do(() => callCount++), Cmd.WaitForFrames(1) ) ) ), Cmd.Do(() => didFinish = true), Cmd.WaitForFrames(1) ) ); Assert.AreEqual(callCount, 0); queue.Update(1.0f); Assert.AreEqual(callCount, 1); queue.Update(1.0f); Assert.AreEqual(callCount, 2); queue.Update(1.0f); Assert.AreEqual(callCount, 3); // Require should only re-evaluate on next update. shouldStop = true; Assert.AreEqual(didFinish, false); queue.Update(1.0f); Assert.AreEqual(callCount, 3); Assert.AreEqual(didFinish, true); queue.Update(1.0f); Assert.AreEqual(callCount, 3); Assert.AreEqual(didFinish, true); shouldStop = false; queue.Update(1.0f); Assert.AreEqual(callCount, 4); Assert.AreEqual(didFinish, true); }
/// <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) ) )); }
public static void TestRotateFrom() { Quaternion quatStart = Quaternion.Euler(10.0f, 20.0f, 30.0f); Quaternion quatEnd = Quaternion.Euler(30.0f, 20.0f, 10.0f); Quaternion quatVal = quatStart; Ref <Quaternion> quatRef = new Ref <Quaternion>( () => quatVal, t => quatVal = t ); CommandQueue queue = new CommandQueue(); queue.Enqueue( Cmd.Repeat(2, Cmd.Sequence( Cmd.RotateFrom(quatRef, quatEnd, 1.0), Cmd.WaitForFrames(1) ) ) ); queue.Update(0.5); AreEqual(quatVal, Quaternion.Slerp(quatEnd, quatStart, 0.5f), 0.000001f); quatVal = Quaternion.identity; queue.Update(0.5); AreEqual(quatVal, quatStart, 0.000001f); queue.Update(0.0); queue.Update(0.5); AreEqual(quatVal, Quaternion.Slerp(quatEnd, quatStart, 0.5f), 0.000001f); // Make sure the rotation ends in the correct position when given a complex easing function. queue = new CommandQueue(); quatVal = quatStart; queue.Enqueue( Cmd.RotateFrom(quatRef, quatEnd, 1f, Ease.OutElastic()) ); while (!queue.Update(1 / 30f)) { } AreEqual(quatVal, quatStart, 0.001f); }
public static CommandDelegate RotateBy(Ref <Quaternion> rotation, Quaternion offsetRotation, double duration, CommandEase ease = null) { CheckArgumentNonNull(rotation, "rotation"); double lastT = 0.0; return(Cmd.Sequence( Cmd.Do(delegate() { lastT = 0.0; }), Cmd.Duration(delegate(double t) { rotation.Value *= Quaternion.LerpUnclamped(Quaternion.identity, offsetRotation, (float)t) * Quaternion.Inverse(Quaternion.LerpUnclamped(Quaternion.identity, offsetRotation, (float)lastT)); lastT = t; }, duration, ease) )); }
public static CommandDelegate ScaleBy(Ref <Vector2> scale, Vector2 scaleFactor, double duration, CommandEase ease = null) { CheckArgumentNonNull(scale, "scale"); Vector2 lastScaleFactor = Vector2.one; return(Cmd.Sequence( Cmd.Do(delegate() { lastScaleFactor = Vector2.one; }), Cmd.Duration(delegate(double t) { Vector2 newScaleFactor = (float)t * (scaleFactor - Vector2.one) + Vector2.one; scale.Value = new Vector2( scale.Value.x * newScaleFactor.x / lastScaleFactor.x, scale.Value.y * newScaleFactor.y / lastScaleFactor.y ); lastScaleFactor = newScaleFactor; }, duration, ease) )); }
public static CommandDelegate TintBy(Ref <Color32> color, Color32 offset, double duration, CommandEase ease = null) { CheckArgumentNonNull(color, "color"); double lastT = 0.0; return(Cmd.Sequence( Cmd.Do(delegate() { lastT = 0.0; }), Cmd.Duration(delegate(double t) { color.Value = new Color32( (byte)(color.Value.r + offset.r * (t - lastT)), (byte)(color.Value.g + offset.g * (t - lastT)), (byte)(color.Value.b + offset.b * (t - lastT)), (byte)(color.Value.a + offset.a * (t - lastT)) ); lastT = t; }, duration, ease) )); }
/// <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); } )); }
/// <summary> /// Wobble a value. This oscilates a value, with a decay. /// </summary> /// <param name="amplitude">Amplitude.</param> /// <param name="duration">Duration.</param> public static CommandDelegate Wobble(Ref <float> single, float amount, double duration) { CheckArgumentNonNull(single, "val"); float intervals = 3f; float decay = Mathf.Log(100f * amount); float baseVal = 0f; return(Cmd.Sequence( Cmd.Do(() => { baseVal = single.Value; }), Cmd.Duration( t => { float decayCoeef = Mathf.Exp((float)t * decay); single.Value = baseVal + amount * Mathf.Sin(intervals * (float)t * 2 * Mathf.PI) / decayCoeef; }, duration ), Cmd.Do(() => { single.Value = baseVal; }) )); }
/// <summary> /// Squashes the y axis, while inversely stretching the x axis. /// </summary> /// <param name="val">The value to animate.</param> /// <param name="amplitude">The size of the squash.</param> /// <param name="duration">The duration of the squash.</param> public static CommandDelegate SquashAndStretch(Ref <Vector2> scale, float amplitude, double duration) { CheckArgumentNonNull(scale, "scale"); Vector2 startScale = Vector2.zero; float area = 0f; Ref <float> widthRef = new Ref <float>( () => scale.Value.x, (t) => { Vector2 tempVal = scale.Value; tempVal.x = t; scale.Value = tempVal; } ); return(Cmd.Sequence( Cmd.Do(() => { area = scale.Value.x * scale.Value.y; startScale = scale.Value; }), Cmd.Parallel( Wobble(widthRef, amplitude, duration), Cmd.Duration((t) => { Vector2 tempVal = scale.Value; if (tempVal.x != 0f) { tempVal.y = area / tempVal.x; } scale.Value = tempVal; }, duration) ), Cmd.Do(() => { scale.Value = startScale; }) )); }
public static void TestWaitFrames() { int count = 0; CommandDelegate incr = Cmd.Do(() => ++ count); CommandQueue queue = new CommandQueue(); queue.Enqueue( Cmd.WaitForFrames(1), incr, Cmd.WaitForFrames(2), incr, Cmd.Repeat(3, Cmd.Sequence( Cmd.WaitForFrames(2), incr ) ) ); queue.Update(0.1); Assert.AreEqual(count, 0); queue.Update(0.1); Assert.AreEqual(count, 1); queue.Update(0.1); Assert.AreEqual(count, 1); queue.Update(0.1); Assert.AreEqual(count, 2); queue.Update(0.1); Assert.AreEqual(count, 2); queue.Update(0.1); Assert.AreEqual(count, 3); queue.Update(0.1); Assert.AreEqual(count, 3); queue.Update(0.1); Assert.AreEqual(count, 4); queue.Update(0.1); Assert.AreEqual(count, 4); }
public static void TestOrdering() { CommandScheduler scheduler = new CommandScheduler(); int a = 0; scheduler.Add( Cmd.Sequence( Cmd.WaitForSeconds(1.0f), Cmd.Do(() => ++ a) ) ); int b = 0; scheduler.Add( Cmd.Sequence( Cmd.WaitForSeconds(1.0f), Cmd.Do(() => ++ b) ) ); scheduler.Add( Cmd.Sequence( Cmd.WaitForSeconds(1.5f), Cmd.Do(() => ++ b) ) ); Assert.AreEqual(a, 0); Assert.AreEqual(b, 0); scheduler.Update(1.0f); Assert.AreEqual(a, 1); Assert.AreEqual(b, 1); scheduler.Update(0.5f); Assert.AreEqual(a, 1); Assert.AreEqual(b, 2); }
public static void TestScaleBy() { const float floatScale = 4.8f; const float floatStart = 1.2f; float floatVal = floatStart; Ref <float> floatRef = new Ref <float>( () => floatVal, t => floatVal = t ); const double doubleScale = 3.2; const double doubleStart = 9.2; double doubleVal = doubleStart; Ref <double> doubleRef = new Ref <double>( () => doubleVal, t => doubleVal = t ); Vector2 vec2Scale = 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 vec3Scale = 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 vec4Scale = 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.Sequence( Cmd.Parallel( Cmd.ScaleBy(floatRef, floatScale, 1.0), Cmd.ScaleBy(doubleRef, doubleScale, 1.0), Cmd.ScaleBy(vec2Ref, vec2Scale, 1.0), Cmd.ScaleBy(vec3Ref, vec3Scale, 1.0), Cmd.ScaleBy(vec4Ref, vec4Scale, 1.0) ), Cmd.WaitForFrames(1) ) ) ); queue.Update(0.2f); Vector2 vec2ExpectedScale = vec2Scale; Vector3 vec3ExpectedScale = vec3Scale; Vector4 vec4ExpectedScale = vec4Scale; vec2ExpectedScale.Scale(new Vector2(0.2f, 0.2f)); vec3ExpectedScale.Scale(new Vector3(0.2f, 0.2f, 0.2f)); vec4ExpectedScale.Scale(new Vector4(0.2f, 0.2f, 0.2f, 0.2f)); vec2ExpectedScale += new Vector2(0.8f, 0.8f); vec3ExpectedScale += new Vector3(0.8f, 0.8f, 0.8f); vec4ExpectedScale += new Vector4(0.8f, 0.8f, 0.8f, 0.8f); vec2ExpectedScale.Scale(vec2Start); vec3ExpectedScale.Scale(vec3Start); vec4ExpectedScale.Scale(vec4Start); AreEqual(floatVal, floatStart * (0.8f + floatScale * 0.2f), 0.001f); AreEqual(doubleVal, doubleStart * (0.8 + doubleScale * 0.2), 0.001f); AreEqual(vec2Val, vec2ExpectedScale, 0.001f); AreEqual(vec3Val, vec3ExpectedScale, 0.001f); AreEqual(vec4Val, vec4ExpectedScale, 0.001f); queue.Update(0.8); vec2ExpectedScale = vec2Scale; vec3ExpectedScale = vec3Scale; vec4ExpectedScale = vec4Scale; vec2ExpectedScale.Scale(vec2Start); vec3ExpectedScale.Scale(vec3Start); vec4ExpectedScale.Scale(vec4Start); AreEqual(floatVal, floatStart * floatScale, 0.001f); AreEqual(doubleVal, doubleStart * doubleScale, 0.001f); AreEqual(vec2Val, vec2ExpectedScale, 0.001f); AreEqual(vec3Val, vec3ExpectedScale, 0.001f); AreEqual(vec4Val, vec4ExpectedScale, 0.001f); floatVal = floatStart; doubleVal = doubleStart; vec2Val = vec2Start; vec3Val = vec3Start; vec4Val = vec4Start; queue.Update(0.0); queue.Update(0.5); vec2ExpectedScale = vec2Scale; vec3ExpectedScale = vec3Scale; vec4ExpectedScale = vec4Scale; vec2ExpectedScale.Scale(new Vector2(0.5f, 0.5f)); vec3ExpectedScale.Scale(new Vector3(0.5f, 0.5f, 0.5f)); vec4ExpectedScale.Scale(new Vector4(0.5f, 0.5f, 0.5f, 0.5f)); vec2ExpectedScale += new Vector2(0.5f, 0.5f); vec3ExpectedScale += new Vector3(0.5f, 0.5f, 0.5f); vec4ExpectedScale += new Vector4(0.5f, 0.5f, 0.5f, 0.5f); vec2ExpectedScale.Scale(vec2Start); vec3ExpectedScale.Scale(vec3Start); vec4ExpectedScale.Scale(vec4Start); AreEqual(floatVal, floatStart * (0.5f + floatScale * 0.5f), 0.001f); AreEqual(doubleVal, doubleStart * (0.5 + doubleScale * 0.5), 0.001f); AreEqual(vec2Val, vec2ExpectedScale, 0.001f); AreEqual(vec3Val, vec3ExpectedScale, 0.001f); AreEqual(vec4Val, vec4ExpectedScale, 0.001f); }
public static void TestChangeFrom() { 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.Sequence( Cmd.Parallel( Cmd.ChangeFrom(floatRef, floatEnd, 1.0), Cmd.ChangeFrom(doubleRef, doubleEnd, 1.0), Cmd.ChangeFrom(vec2Ref, vec2End, 1.0), Cmd.ChangeFrom(vec3Ref, vec3End, 1.0), Cmd.ChangeFrom(vec4Ref, vec4End, 1.0) ), Cmd.WaitForFrames(1) ) ) ); queue.Update(0.3); // Check basic lerping works. AreEqual(floatVal, floatEnd * 0.7f + floatStart * 0.3f, 0.01); AreEqual(doubleVal, doubleEnd * 0.7 + doubleStart * 0.3, 0.01); AreEqual(vec2Val, vec2End * 0.7f + vec2Start * 0.3f, 0.01f); AreEqual(vec3Val, vec3End * 0.7f + vec3Start * 0.3f, 0.01f); AreEqual(vec4Val, vec4End * 0.7f + vec4Start * 0.3f, 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 AreEqual(floatVal, floatEnd * 0.5f + floatStart * 0.5f, 0.01); 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); AreEqual(floatVal, floatStart, 0.01f); AreEqual(doubleVal, doubleStart, 0.01); AreEqual(vec2Val, vec2Start, 0.01f); AreEqual(vec3Val, vec3Start, 0.01f); AreEqual(vec4Val, vec4Start, 0.01f); queue.Update(0.0); queue.Update(0.5); // Check that it does jump on repeat AreEqual(floatVal, floatEnd * 0.5f + floatStart * 0.5f, 0.01); 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); 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 = rectStart; Ref <Rect> rectRef = new Ref <Rect>( () => 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); queue = new CommandQueue(); queue.Enqueue( Cmd.ChangeFrom(rectRef, rectEnd, 1.0, firstAnchor), Cmd.WaitForFrames(1), Cmd.ChangeFrom(rectRef, rectEnd, 1.0, secondAnchor), Cmd.WaitForFrames(1), Cmd.ChangeFrom(rectRef, rectEnd, 1.0, thirdAnchor), Cmd.WaitForFrames(1), Cmd.ChangeFrom(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, rectStart, 0.001f); queue.Update(0.0f); // Test the top right corner. queue.Update(0.7); 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.3); AreEqual(rectVal, rectStart, 0.001f); queue.Update(0.0f); // Test the bottom left corner. queue.Update(0.6); 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.4); AreEqual(rectVal, rectStart, 0.001f); queue.Update(0.0); // Test the bottom right corner. queue.Update(0.6); 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.4); AreEqual(rectVal, rectStart, 0.001f); queue.Update(0.0f); }
/// <summary> /// Schedule a list of commands. /// </summary> /// <param name="commands"> The commands to be executed sequentially.</param> public void Schedule(params CommandDelegate[] commands) { _scheduler.Add(Cmd.Sequence(commands)); }