Exemplo n.º 1
0
        private void GenerateOrderedStateAndSubAnimationCode(StateCodeGeneratorContext context, ICodeBlock currentBlock, AnimationSave animation, string animationType, AbsoluteOrRelative absoluteOrRelative)
        {
            List <AnimatedStateSave> remainingStates = new List <AnimatedStateSave>();

            remainingStates.AddRange(animation.States);

            List <AnimationReferenceSave> remainingSubAnimations = new List <AnimationReferenceSave>();

            remainingSubAnimations.AddRange(animation.Animations);

            double nextStateTime;
            double nextAnimationTime;


            AnimatedStateSave previousState = null;
            AnimatedStateSave currentState  = null;

            while (remainingStates.Count > 0 || remainingSubAnimations.Count > 0)
            {
                if (remainingStates.Count > 0)
                {
                    nextStateTime = remainingStates[0].Time;
                }
                else
                {
                    nextStateTime = double.PositiveInfinity;
                }

                if (remainingSubAnimations.Count > 0)
                {
                    nextAnimationTime = remainingSubAnimations[0].Time;
                }
                else
                {
                    nextAnimationTime = double.PositiveInfinity;
                }

                if (nextAnimationTime < nextStateTime)
                {
                    CreateInstructionForSubAnimation(currentBlock, remainingSubAnimations[0], absoluteOrRelative, animation, context);

                    remainingSubAnimations.RemoveAt(0);
                }
                else
                {
                    currentState = remainingStates[0];
                    CreateInstructionForInterpolation(context, currentBlock, animationType, previousState,
                                                      currentState, absoluteOrRelative, animation.PropertyNameInCode());
                    previousState = currentState;

                    remainingStates.RemoveAt(0);
                }
            }
        }
Exemplo n.º 2
0
        private void CreateInstructionForInterpolation(StateCodeGeneratorContext context, ICodeBlock currentBlock, string animationType, AnimatedStateSave previousState, AnimatedStateSave currentState, AbsoluteOrRelative absoluteOrRelative, string animationName)
        {
            currentBlock = currentBlock.Block();

            if (absoluteOrRelative == AbsoluteOrRelative.Absolute)
            {
                CreateInstructionForInterpolationAbsolute(context, currentBlock, animationType, previousState, currentState, animationName);
            }
            else
            {
                CreateInstructionForInterpolationRelative(context, currentBlock, previousState, currentState);
            }
            currentBlock = currentBlock.End();
        }
        private void GenerateAnimationEnumerables(ElementSave elementSave, ICodeBlock currentBlock)
        {
            currentBlock.Line("#region State Animations");

            StateCodeGeneratorContext context = new StateCodeGeneratorContext();
            context.Element = elementSave;

            ElementAnimationsSave animations = GetAnimationsFor(elementSave);

            if(animations != null)
            {
                foreach(var animation in animations.Animations)
                {
                    GenerateEnumerableFor(context, currentBlock, animation, AbsoluteOrRelative.Absolute);
                    GenerateEnumerableFor(context, currentBlock, animation, AbsoluteOrRelative.Relative);

                    GenerateAnimationMember(context, currentBlock, animation, AbsoluteOrRelative.Absolute);
                    GenerateAnimationMember(context, currentBlock, animation, AbsoluteOrRelative.Relative);
                }
            }

            currentBlock.Line("#endregion");
        }
Exemplo n.º 4
0
        private void GenerateAnimationEnumerables(ElementSave elementSave, ICodeBlock currentBlock)
        {
            currentBlock.Line("#region State Animations");

            StateCodeGeneratorContext context = new StateCodeGeneratorContext();

            context.Element = elementSave;

            ElementAnimationsSave animations = GetAnimationsFor(elementSave);

            if (animations != null)
            {
                foreach (var animation in animations.Animations)
                {
                    GenerateGetEnumerableFor(context, currentBlock, animation, AbsoluteOrRelative.Absolute);
                    GenerateGetEnumerableFor(context, currentBlock, animation, AbsoluteOrRelative.Relative);

                    GenerateAnimationMember(context, currentBlock, animation, AbsoluteOrRelative.Absolute);
                    GenerateAnimationMember(context, currentBlock, animation, AbsoluteOrRelative.Relative);
                }
            }

            currentBlock.Line("#endregion");
        }
Exemplo n.º 5
0
        private void GenerateAnimationMember(StateCodeGeneratorContext context, ICodeBlock currentBlock, AnimationSave animation, AbsoluteOrRelative absoluteOrRelative)
        {
            string propertyName = animation.PropertyNameInCode();

            if (absoluteOrRelative == AbsoluteOrRelative.Relative)
            {
                propertyName += "Relative";
            }
            string referencedInstructionProperty = propertyName + "Instructions";
            // Force the property to be upper-case, since the field is lower-case:



            // We want to generate something like:
            //private FlatRedBall.Gum.Animation.GumAnimation uncategorizedAnimation;
            //public FlatRedBall.Gum.Animation.GumAnimation UncategorizedAnimation
            //{
            //    get
            //    {
            //        if (uncategorizedAnimation == null)
            //        {
            //            uncategorizedAnimation = new FlatRedBall.Gum.Animation.GumAnimation(1, () => UncategorizedAnimationInstructions);
            //            uncategorizedAnimation.AddEvent("Event1", 3.0f);
            //        }
            //        return uncategorizedAnimation;
            //    }
            //}

            var firstCharacterLower = propertyName.Substring(0, 1).ToLowerInvariant();
            var fieldName           = firstCharacterLower + propertyName.Substring(1);


            currentBlock.Line($"private FlatRedBall.Gum.Animation.GumAnimation {fieldName};");

            currentBlock = currentBlock.Property("public FlatRedBall.Gum.Animation.GumAnimation", propertyName).Get();



            float length = GetAnimationLength(context.Element, animation);

            string lengthAsString = ToFloatString(length);

            var ifBlock = currentBlock.If($"{fieldName} == null");

            {
                ifBlock.Line(
                    $"{fieldName} = new FlatRedBall.Gum.Animation.GumAnimation({lengthAsString}, {referencedInstructionProperty});");

                foreach (var namedEvent in animation.Events)
                {
                    string timeAsString = ToFloatString(namedEvent.Time);
                    ifBlock.Line(
                        $"{fieldName}.AddEvent(\"{namedEvent.Name}\", {timeAsString});");
                }
                foreach (var subAnimation in animation.Animations)
                {
                    if (string.IsNullOrEmpty(subAnimation.SourceObject) == false)
                    {
                        var isMissingInstance = context.Element.GetInstance(subAnimation.SourceObject) == null;
                        if (isMissingInstance)
                        {
                            ifBlock.Line($"//Missing object {subAnimation.SourceObject}");
                        }
                        else
                        {
                            ifBlock.Line($"{fieldName}.SubAnimations.Add({subAnimation.PropertyNameInCode()});");
                        }
                    }
                }
            }

            currentBlock.Line($"return {fieldName};");
        }
Exemplo n.º 6
0
        private void CreateInstructionForInterpolationAbsolute(StateCodeGeneratorContext context, ICodeBlock currentBlock, string animationType, AnimatedStateSave previousState, AnimatedStateSave currentState, string animationName)
        {
            if (previousState == null)
            {
                string variableStateName = null;

                variableStateName = "CurrentVariableState";

                if (currentState.StateName.Contains("/"))
                {
                    var split = currentState.StateName.Split('/');
                    animationType = split[0];
                }

                if (animationType != "VariableState")
                {
                    variableStateName = "Current" + animationType + "State";
                }

                // todo:  Change this on categories
                //System.Action action = () => this.CurrentState = fromState;

                string enumValue = currentState.StateName;
                if (enumValue.Contains("/"))
                {
                    enumValue = enumValue.Split('/')[1];
                }

                currentBlock.Line("var toReturn = new FlatRedBall.Instructions.DelegateInstruction( ()=> this." + variableStateName + " = " +
                                  animationType + "." + enumValue + ");");
                currentBlock.Line("toReturn.TimeToExecute = FlatRedBall.TimeManager.CurrentTime;");
                currentBlock.Line("toReturn.Target = target;");
            }
            else
            {
                var previousCategory = context.Element.Categories.FirstOrDefault(item => item.States.Any(stateCandiate => stateCandiate.Name == previousState.StateName));
                var currentCategory  = context.Element.Categories.FirstOrDefault(item => item.States.Any(stateCandiate => stateCandiate.Name == currentState.StateName));

                // Now that we interpolateTo a single state, we don't
                // need to pass in the StateSave object:
                //bool differentCategories = previousCategory != currentCategory;

                // November 3, 2015
                // Gum uses a "cumulative
                // state" system, so that each
                // keyframe in an animation will
                // tween with variables both before
                // and after.
                // The code as of the time of the writing
                // of this comment does InterpolateBetween
                // two states, which does not consider the state
                // of the object and only tweens variables common
                // to the two states. This makes the runtime behave
                // different than Glue, and it also makes the runtime
                // behave in confusing ways as authors don't often think
                // about the individual variables that may be set in a state.
                // We can solve this by instead doing Interpolate to between the
                // current state of the instance and the state that we are interpolating
                // to. Going to accomplish this by getting rid of the "from" state:
                //string fromState = null;

                string toState = null;

                string enumValue = currentState.StateName;
                if (currentState.StateName.Contains("/"))
                {
                    currentCategory = context.Element.Categories.FirstOrDefault(item => item.Name == currentState.StateName.Split('/')[0]);
                    enumValue       = currentState.StateName.Split('/')[1];
                }


                //if (differentCategories)
                //{
                //fromState = "this.ElementSave.AllStates.FirstOrDefault(item => item.Name == \"" + previousState.StateName + "\")";
                //toState = "this.ElementSave.AllStates.FirstOrDefault(item => item.Name == \"" + currentState.StateName + "\")";
                //}
                //else
                //{
                //fromState = animationType + "." + previousState.StateName;
                if (currentCategory == null)
                {
                    toState = "VariableState." + enumValue;
                }
                else
                {
                    toState = currentCategory.Name + "." + enumValue;
                }
                //}

                string previousStateTime = ToFloatString(previousState.Time);

                string interpolationTime = ToFloatString(currentState.Time - previousState.Time);

                string easing            = "FlatRedBall.Glue.StateInterpolation.Easing." + previousState.Easing;
                string interpolationType = "FlatRedBall.Glue.StateInterpolation.InterpolationType." + previousState.InterpolationType;

                var line = "var toReturn = new FlatRedBall.Instructions.DelegateInstruction(  () => this.InterpolateTo(" +
                           string.Format("{0}, {1}, {2}, {3}, {4}));", toState, interpolationTime, interpolationType, easing, animationName);

                currentBlock.Line(line);
                currentBlock.Line("toReturn.Target = target;");
                currentBlock.Line("toReturn.TimeToExecute = FlatRedBall.TimeManager.CurrentTime + " + previousStateTime + ";");
            }
            currentBlock.Line("yield return toReturn;");
            //System.Action action = () => this.InterpolateTo(fromState, toState, timeToTake, interpolationType, easing);
        }
Exemplo n.º 7
0
        private void CreateInstructionForInterpolationRelative(StateCodeGeneratorContext context, ICodeBlock currentBlock, AnimatedStateSave previousState, AnimatedStateSave currentState)
        {
            if (previousState != null)
            {
                currentBlock.Line("var toReturn = new FlatRedBall.Instructions.DelegateInstruction(() =>");
                {
                    currentBlock = currentBlock.Block();

                    // Is the start clone necessary?
                    currentBlock.Line("var relativeStart = ElementSave.AllStates.FirstOrDefault(item => item.Name == \"" + previousState.StateName + "\").Clone();");
                    currentBlock.Line("var relativeEnd = ElementSave.AllStates.FirstOrDefault(item => item.Name == \"" + currentState.StateName + "\").Clone();");
                    currentBlock.Line("Gum.DataTypes.Variables.StateSaveExtensionMethods.SubtractFromThis(relativeEnd, relativeStart);");
                    currentBlock.Line("var difference = relativeEnd;");

                    string categoryName = "VariableState";
                    var    category     = context.Element.Categories.FirstOrDefault(item => item.States.Any(stateCandidate => stateCandidate.Name == currentState.StateName));

                    string enumValue = currentState.StateName;

                    if (currentState.StateName.Contains('/'))
                    {
                        var split = currentState.StateName.Split('/');

                        category  = context.Element.Categories.FirstOrDefault(item => item.Name == split[0]);
                        enumValue = split[1];
                    }

                    if (category != null)
                    {
                        categoryName = category.Name;
                    }
                    currentBlock.Line("Gum.DataTypes.Variables.StateSave first = GetCurrentValuesOnState(" + categoryName + "." + enumValue + ");");

                    currentBlock.Line("Gum.DataTypes.Variables.StateSave second = first.Clone();");
                    currentBlock.Line("Gum.DataTypes.Variables.StateSaveExtensionMethods.AddIntoThis(second, difference);");


                    string interpolationTime = ToFloatString(currentState.Time - previousState.Time);

                    string easing            = "FlatRedBall.Glue.StateInterpolation.Easing." + previousState.Easing;
                    string interpolationType = "FlatRedBall.Glue.StateInterpolation.InterpolationType." + previousState.InterpolationType;


                    currentBlock.Line(
                        string.Format("FlatRedBall.Glue.StateInterpolation.Tweener tweener = new FlatRedBall.Glue.StateInterpolation.Tweener(from: 0, to: 1, duration: {0}, type: {1}, easing: {2});",
                                      interpolationTime,
                                      interpolationType,
                                      easing));

                    currentBlock.Line("tweener.Owner = this;");

                    currentBlock.Line("tweener.PositionChanged = newPosition => this.InterpolateBetween(first, second, newPosition);");
                    currentBlock.Line("tweener.Start();");
                    currentBlock.Line("StateInterpolationPlugin.TweenerManager.Self.Add(tweener);");


                    currentBlock = currentBlock.End();
                }
                currentBlock.Line(");");
                string previousStateTime = ToFloatString(previousState.Time);

                currentBlock.Line("toReturn.TimeToExecute = FlatRedBall.TimeManager.CurrentTime + " + previousStateTime + ";");
                currentBlock.Line("toReturn.Target = target;");

                currentBlock.Line("yield return toReturn;");
            }
        }
Exemplo n.º 8
0
        private static void CreateInstructionForSubAnimation(ICodeBlock currentBlock, AnimationReferenceSave animationReferenceSave, AbsoluteOrRelative absoluteOrRelative, AnimationSave parentAnimation, StateCodeGeneratorContext context)
        {
            currentBlock = currentBlock.Block();

            //var instruction = new FlatRedBall.Instructions.DelegateInstruction(() =>
            //FlatRedBall.Instructions.InstructionManager.Instructions.AddRange(ClickableBushInstance.GrowAnimation));
            //instruction.TimeToExecute = FlatRedBall.TimeManager.CurrentTime + asdf;
            //yield return instruction;

            var isReferencingMissingInstance = !string.IsNullOrEmpty(animationReferenceSave.SourceObject) &&
                                               context.Element.GetInstance(animationReferenceSave.SourceObject) == null;

            ////////////////Early Out///////////////
            if (isReferencingMissingInstance)
            {
                currentBlock.Line($"// This animation references a missing instance named {animationReferenceSave.SourceObject}");
                return;
            }
            /////////////End Early Out/////////////


            string animationName = animationReferenceSave.PropertyNameInCode();

            //animationReferenceSave. FlatRedBall.IO.FileManager.RemovePath(animationReferenceSave.Name) + "Animation";
            if (absoluteOrRelative == AbsoluteOrRelative.Relative)
            {
                animationName += "Relative";
            }

            currentBlock.Line($"var instruction = new FlatRedBall.Instructions.DelegateInstruction(()=>{animationName}.Play({parentAnimation.PropertyNameInCode()}));");
            currentBlock.Line("instruction.TimeToExecute = FlatRedBall.TimeManager.CurrentTime + " + ToFloatString(animationReferenceSave.Time) + ";");


            currentBlock.Line("yield return instruction;");
            currentBlock = currentBlock.End();
        }
Exemplo n.º 9
0
        private void GenerateGetEnumerableFor(StateCodeGeneratorContext context, ICodeBlock currentBlock, AnimationSave animation, AbsoluteOrRelative absoluteOrRelative)
        {
            string animationType = "VariableState";

            string animationName = animation.PropertyNameInCode();

            if (absoluteOrRelative == AbsoluteOrRelative.Relative)
            {
                animationName += "Relative";
            }

            string propertyName = animationName + "Instructions";

            // Instructions used to be public - the user would grab them and add them to the InstructionManager,
            // but now everything is encased in an Animation object which handles stopping itself and provides a simple
            // Play method.

            const string signature = "private System.Collections.Generic.IEnumerable<FlatRedBall.Instructions.Instruction>";

            if (animation.States.Count == 0 && animation.Animations.Count == 0)
            {
                currentBlock = currentBlock.Function(signature, propertyName, "object target");

                currentBlock.Line("yield break;");
            }
            else if (absoluteOrRelative == AbsoluteOrRelative.Relative && animation.States.Count < 2 && animation.Animations.Count == 0)
            {
                currentBlock = currentBlock.Function(signature, propertyName, "object target");

                currentBlock.Line("yield break;");
            }
            else
            {
                if (animation.States.Count != 0)
                {
                    var firstState = context.Element.AllStates.FirstOrDefault(item => item.Name == animation.States.First().StateName);

                    var category = context.Element.Categories.FirstOrDefault(item => item.States.Contains(firstState));

                    if (category != null)
                    {
                        animationType = category.Name;
                    }
                }

                currentBlock = currentBlock.Function(signature, propertyName, "object target");

                GenerateOrderedStateAndSubAnimationCode(context, currentBlock, animation, animationType, absoluteOrRelative);

                if (animation.Loops)
                {
                    currentBlock = currentBlock.Block();

                    currentBlock.Line("var toReturn = new FlatRedBall.Instructions.DelegateInstruction(  " +
                                      "() => FlatRedBall.Instructions.InstructionManager.Instructions.AddRange(this." + propertyName + "(target)));");
                    string executionTime = "0.0f";

                    if (animation.States.Count != 0)
                    {
                        executionTime = ToFloatString(animation.States.Last().Time);
                    }

                    currentBlock.Line("toReturn.TimeToExecute = FlatRedBall.TimeManager.CurrentTime + " + executionTime + ";");
                    currentBlock.Line("toReturn.Target = target;");

                    currentBlock.Line("yield return toReturn;");
                    currentBlock = currentBlock.End();
                }
            }
        }
        private void GenerateAnimationMember(StateCodeGeneratorContext context, ICodeBlock currentBlock, AnimationSave animation, AbsoluteOrRelative absoluteOrRelative)
        {
            string propertyName = animation.PropertyNameInCode();
            if (absoluteOrRelative == AbsoluteOrRelative.Relative)
            {
                propertyName += "Relative";
            }
            string referencedInstructionProperty = propertyName + "Instructions";
            // Force the property to be upper-case, since the field is lower-case:



            // We want to generate something like:
            //private FlatRedBall.Gum.Animation.GumAnimation uncategorizedAnimation;
            //public FlatRedBall.Gum.Animation.GumAnimation UncategorizedAnimation
            //{
            //    get
            //    {
            //        if (uncategorizedAnimation == null)
            //        {
            //            uncategorizedAnimation = new FlatRedBall.Gum.Animation.GumAnimation(1, () => UncategorizedAnimationInstructions);
            //            uncategorizedAnimation.AddEvent("Event1", 3.0f);
            //        }
            //        return uncategorizedAnimation;
            //    }
            //}

            var firstCharacterLower = propertyName.Substring(0, 1).ToLowerInvariant();
            var fieldName = firstCharacterLower + propertyName.Substring(1);
            

            currentBlock.Line($"private FlatRedBall.Gum.Animation.GumAnimation {fieldName};");

            currentBlock = currentBlock.Property("public FlatRedBall.Gum.Animation.GumAnimation", propertyName).Get();



            float length = GetAnimationLength(context.Element, animation);

            string lengthAsString = ToFloatString(length);

            var ifBlock = currentBlock.If($"{fieldName} == null");
            {
                ifBlock.Line(
                    $"{fieldName} = new FlatRedBall.Gum.Animation.GumAnimation({lengthAsString}, () => {referencedInstructionProperty});");

                foreach(var namedEvent in animation.Events)
                {
                    string timeAsString = ToFloatString(namedEvent.Time);
                    ifBlock.Line(
                        $"{fieldName}.AddEvent(\"{namedEvent.Name}\", {timeAsString});");
                }
                foreach(var subAnimation in animation.Animations)
                {
                    if(string.IsNullOrEmpty(subAnimation.SourceObject) == false)
                    {
                        ifBlock.Line($"{fieldName}.SubAnimations.Add({subAnimation.PropertyNameInCode()});");
                    }
                }
            }

            currentBlock.Line($"return {fieldName};");
        }
        private void CreateInstructionForInterpolationAbsolute(StateCodeGeneratorContext context, ICodeBlock currentBlock, string animationType, AnimatedStateSave previousState, AnimatedStateSave currentState, string animationName)
        {

            if (previousState == null)
            {
                string variableStateName = null;

                variableStateName = "CurrentVariableState";

                if (currentState.StateName.Contains("/"))
                {
                    var split = currentState.StateName.Split('/');
                    animationType = split[0];
                }

                if (animationType != "VariableState")
                {
                    variableStateName = "Current" + animationType + "State";
                }

                // todo:  Change this on categories
                //System.Action action = () => this.CurrentState = fromState;

                string enumValue = currentState.StateName;
                if(enumValue.Contains("/"))
                {
                    enumValue = enumValue.Split('/')[1];
                }

                currentBlock.Line("var toReturn = new FlatRedBall.Instructions.DelegateInstruction( ()=> this." + variableStateName + " = " +
                    animationType + "." + enumValue + ");");
                currentBlock.Line("toReturn.TimeToExecute = FlatRedBall.TimeManager.CurrentTime;");

            }
            else
            {
                var previousCategory = context.Element.Categories.FirstOrDefault(item => item.States.Any(stateCandiate => stateCandiate.Name == previousState.StateName));
                var currentCategory = context.Element.Categories.FirstOrDefault(item => item.States.Any(stateCandiate => stateCandiate.Name == currentState.StateName));

                // Now that we interpolateTo a single state, we don't
                // need to pass in the StateSave object:
                //bool differentCategories = previousCategory != currentCategory;

                // November 3, 2015
                // Gum uses a "cumulative 
                // state" system, so that each 
                // keyframe in an animation will 
                // tween with variables both before 
                // and after.
                // The code as of the time of the writing 
                // of this comment does InterpolateBetween
                // two states, which does not consider the state
                // of the object and only tweens variables common
                // to the two states. This makes the runtime behave
                // different than Glue, and it also makes the runtime
                // behave in confusing ways as authors don't often think
                // about the individual variables that may be set in a state.
                // We can solve this by instead doing Interpolate to between the
                // current state of the instance and the state that we are interpolating
                // to. Going to accomplish this by getting rid of the "from" state:
                //string fromState = null;

                string toState = null;

                string enumValue = currentState.StateName;
                if(currentState.StateName.Contains("/"))
                {
                    currentCategory = context.Element.Categories.FirstOrDefault(item => item.Name == currentState.StateName.Split('/')[0]);
                    enumValue = currentState.StateName.Split('/')[1];
                }


                //if (differentCategories)
                //{
                //fromState = "this.ElementSave.AllStates.FirstOrDefault(item => item.Name == \"" + previousState.StateName + "\")";
                //toState = "this.ElementSave.AllStates.FirstOrDefault(item => item.Name == \"" + currentState.StateName + "\")";
                //}
                //else
                //{
                //fromState = animationType + "." + previousState.StateName;
                if (currentCategory == null)
                {
                    toState = "VariableState." + enumValue;

                }
                else
                {
                    toState = currentCategory.Name + "." + enumValue;
                }
                //}

                string previousStateTime = ToFloatString(previousState.Time);

                string interpolationTime = ToFloatString(currentState.Time - previousState.Time);

                string easing = "FlatRedBall.Glue.StateInterpolation.Easing." + previousState.Easing;
                string interpolationType = "FlatRedBall.Glue.StateInterpolation.InterpolationType." + previousState.InterpolationType;

                var line = "var toReturn = new FlatRedBall.Instructions.DelegateInstruction(  () => this.InterpolateTo(" +
                    string.Format("{0}, {1}, {2}, {3}, {4}));", toState, interpolationTime, interpolationType, easing, animationName);

                // vic says - 
                // For some reason I'm getting some weird code generation issues when generating one of my objects for the racing game
                // I don't have perfect repro steps, so I wanted to catch it in the debugger:

                //var toReturn = new FlatRedBall.Instructions.DelegateInstruction(  () => this.InterpolateTo(VariableState.Shown, 0.25f, FlatRedBall.Glue.StateInterpolation.InterpolationType.Linear, FlatRedBall.Glue.StateInterpolation.Easing.Out, FadeInAnimation));
                if (line.Contains("var toReturn = new FlatRedBall.Instructions.DelegateInstruction(  () => this.InterpolateTo(VariableState.Shown, 0.25f, FlatRedBall.Glue.StateInterpolation.InterpolationType.Linear, FlatRedBall.Glue.StateInterpolation.Easing.Out, FadeInAnimation));"))
                {
                    int m = 3;
                }

                
                currentBlock.Line(line);
                currentBlock.Line("toReturn.TimeToExecute = FlatRedBall.TimeManager.CurrentTime + " + previousStateTime + ";");

            }
            currentBlock.Line("yield return toReturn;");
            //System.Action action = () => this.InterpolateTo(fromState, toState, timeToTake, interpolationType, easing);
        }
        private void CreateInstructionForInterpolationRelative(StateCodeGeneratorContext context, ICodeBlock currentBlock, AnimatedStateSave previousState, AnimatedStateSave currentState)
        {
            if(previousState != null)
            {
                currentBlock.Line("var toReturn = new FlatRedBall.Instructions.DelegateInstruction(() =>");
                {
                    currentBlock = currentBlock.Block();

                    // Is the start clone necessary?
                    currentBlock.Line("var relativeStart = ElementSave.AllStates.FirstOrDefault(item => item.Name == \"" + previousState.StateName + "\").Clone();");
                    currentBlock.Line("var relativeEnd = ElementSave.AllStates.FirstOrDefault(item => item.Name == \"" + currentState.StateName + "\").Clone();");
                    currentBlock.Line("Gum.DataTypes.Variables.StateSaveExtensionMethods.SubtractFromThis(relativeEnd, relativeStart);");
                    currentBlock.Line("var difference = relativeEnd;");

                    string categoryName = "VariableState";
                    var category = context.Element.Categories.FirstOrDefault(item => item.States.Any(stateCandidate => stateCandidate.Name == currentState.StateName));

                    string enumValue = currentState.StateName;

                    if(currentState.StateName.Contains('/'))
                    {
                        var split = currentState.StateName.Split('/');

                        category = context.Element.Categories.FirstOrDefault(item => item.Name == split[0]);
                        enumValue = split[1];
                    }

                    if(category != null)
                    {
                        categoryName = category.Name;
                    }
                    currentBlock.Line("Gum.DataTypes.Variables.StateSave first = GetCurrentValuesOnState(" + categoryName + "." + enumValue + ");");

                    currentBlock.Line("Gum.DataTypes.Variables.StateSave second = first.Clone();");
                    currentBlock.Line("Gum.DataTypes.Variables.StateSaveExtensionMethods.AddIntoThis(second, difference);");


                    string interpolationTime = ToFloatString(currentState.Time - previousState.Time);

                    string easing = "FlatRedBall.Glue.StateInterpolation.Easing." + previousState.Easing;
                    string interpolationType = "FlatRedBall.Glue.StateInterpolation.InterpolationType." + previousState.InterpolationType;


                    currentBlock.Line(
                        string.Format("FlatRedBall.Glue.StateInterpolation.Tweener tweener = new FlatRedBall.Glue.StateInterpolation.Tweener(from: 0, to: 1, duration: {0}, type: {1}, easing: {2});",
                        interpolationTime,
                        interpolationType,
                        easing));

                    currentBlock.Line("tweener.Owner = this;");

                    currentBlock.Line("tweener.PositionChanged = newPosition => this.InterpolateBetween(first, second, newPosition);");
                    currentBlock.Line("tweener.Start();");
                    currentBlock.Line("StateInterpolationPlugin.TweenerManager.Self.Add(tweener);");


                    currentBlock = currentBlock.End();
                }
                currentBlock.Line(");");
                string previousStateTime = ToFloatString(previousState.Time);

                currentBlock.Line("toReturn.TimeToExecute = FlatRedBall.TimeManager.CurrentTime + " + previousStateTime + ";");
                currentBlock.Line("yield return toReturn;");
                
            }
        }
        private void CreateInstructionForInterpolation(StateCodeGeneratorContext context, ICodeBlock currentBlock, string animationType, AnimatedStateSave previousState, AnimatedStateSave currentState, AbsoluteOrRelative absoluteOrRelative, string animationName)
        {

            currentBlock = currentBlock.Block();

            if (absoluteOrRelative == AbsoluteOrRelative.Absolute)
            {

                CreateInstructionForInterpolationAbsolute(context, currentBlock, animationType, previousState, currentState, animationName);
            }
            else
            {
                CreateInstructionForInterpolationRelative(context,currentBlock,  previousState, currentState);
            }
            currentBlock = currentBlock.End();
        }
        private void GenerateOrderedStateAndSubAnimationCode(StateCodeGeneratorContext context, ICodeBlock currentBlock, AnimationSave animation, string animationType, AbsoluteOrRelative absoluteOrRelative)
        {
            List<AnimatedStateSave> remainingStates = new List<AnimatedStateSave>();
            remainingStates.AddRange(animation.States);

            List<AnimationReferenceSave> remainingSubAnimations = new List<AnimationReferenceSave>();
            remainingSubAnimations.AddRange(animation.Animations);

            double nextStateTime;
            double nextAnimationTime;


            AnimatedStateSave previousState = null;
            AnimatedStateSave currentState = null;

            while (remainingStates.Count > 0 || remainingSubAnimations.Count > 0)
            {
                if (remainingStates.Count > 0)
                {
                    nextStateTime = remainingStates[0].Time;
                }
                else
                {
                    nextStateTime = double.PositiveInfinity;
                }

                if (remainingSubAnimations.Count > 0)
                {
                    nextAnimationTime = remainingSubAnimations[0].Time;
                }
                else
                {
                    nextAnimationTime = double.PositiveInfinity;
                }

                if (nextAnimationTime < nextStateTime)
                {
                    CreateInstructionForSubAnimation(currentBlock, remainingSubAnimations[0], absoluteOrRelative, animation);

                    remainingSubAnimations.RemoveAt(0);
                }
                else
                {
                    currentState = remainingStates[0];
                    CreateInstructionForInterpolation(context, currentBlock, animationType, previousState, 
                        currentState, absoluteOrRelative, animation.PropertyNameInCode());
                    previousState = currentState;

                    remainingStates.RemoveAt(0);
                }
            }
        }
        private void GenerateEnumerableFor(StateCodeGeneratorContext context, ICodeBlock currentBlock, AnimationSave animation, AbsoluteOrRelative absoluteOrRelative)
        {
            string animationType = "VariableState";

            string animationName = animation.PropertyNameInCode();

            if(absoluteOrRelative == AbsoluteOrRelative.Relative)
            {
                animationName += "Relative";
            }

            string propertyName = animationName + "Instructions";

            // Instructions used to be public - the user would grab them and add them to the InstructionManager,
            // but now everything is encased in an Animation object which handles stopping itself and provides a simple
            // Play method.
            if (animation.States.Count == 0 && animation.Animations.Count == 0)
            {
                currentBlock = currentBlock.Property("private System.Collections.Generic.IEnumerable<FlatRedBall.Instructions.Instruction>", propertyName).Get();

                currentBlock.Line("yield break;");

            }
            else if(absoluteOrRelative == AbsoluteOrRelative.Relative && animation.States.Count < 2 && animation.Animations.Count == 0)
            {

                currentBlock = currentBlock.Property("private System.Collections.Generic.IEnumerable<FlatRedBall.Instructions.Instruction>", propertyName).Get();

                currentBlock.Line("yield break;");
            }
            else
            {
                if (animation.States.Count != 0)
                {
                    var firstState = context.Element.AllStates.FirstOrDefault(item => item.Name == animation.States.First().StateName);

                    var category = context.Element.Categories.FirstOrDefault(item => item.States.Contains(firstState));

                    if (category != null)
                    {
                        animationType = category.Name;
                    }
                }

                currentBlock = currentBlock.Property("private System.Collections.Generic.IEnumerable<FlatRedBall.Instructions.Instruction>", propertyName).Get();

                GenerateOrderedStateAndSubAnimationCode(context, currentBlock, animation, animationType, absoluteOrRelative);

                if(animation.Loops)
                {
                    currentBlock = currentBlock.Block();

                    currentBlock.Line("var toReturn = new FlatRedBall.Instructions.DelegateInstruction(  " + 
                        "() => FlatRedBall.Instructions.InstructionManager.Instructions.AddRange(this." + propertyName + "));");
                    string executionTime = "0.0f";

                    if(animation.States.Count != 0)
                    {
                        executionTime = ToFloatString( animation.States.Last().Time);
                    }

                    currentBlock.Line("toReturn.TimeToExecute = FlatRedBall.TimeManager.CurrentTime + " + executionTime + ";");

                    currentBlock.Line("yield return toReturn;");
                    currentBlock = currentBlock.End();

                }
            }
            
        }