// Renders a frame if it is not null
 void TryRenderFrame(VisualStageObject visualStage)
 {
     if (visualStage != null)
     {
         RenderFrame(visualStage);
     }
 }
        // Update step info of the visual stage
        void UpdateInformationFrame(VisualStageObject visualStage)
        {
            String stepInfo     = visualStage.stageInfo;
            var    stepInfoText = InforScreen.GetComponentInChildren <Text>();

            stepInfoText.text = string.IsNullOrEmpty(stepInfo) ?
                                "No Step Informattion available" :
                                stepInfo;
        }
        // Renders a frame (stage), all visible objects will be drawn on the screen in this process
        void RenderFrame(VisualStageObject visualStage)
        {
            //Get subgoal info
            var stageIndex         = visualSolution.GetCurrentStageIndex();
            var subgoalNames       = visualSolution.GetSubgoalNames(stageIndex);
            var subgoalObjectNames = visualSolution.GetSubgoalObjectNames(stageIndex);

            // Render step info of current stage
            UpdateInformationFrame(visualStage);
            // Highlight stage object for rendering
            UpdateStepPanelUI(stageIndex);
            // Update subgoal UI
            UpdateSubgoalUI(subgoalNames);
            // Update visual sprites.
            // Including create, update, remove visual sprites and manage subgoal status
            UpdateVisualSprites(visualStage, subgoalObjectNames);
        }
        // Update visual sprites game object and manage subgoal status
        void UpdateVisualSprites(VisualStageObject visualStage, string[] subgoalObjectNames)
        {
            //Render all visual sprite objects of current visual stage
            foreach (var visualSprite in visualStage.visualSprites)
            {
                //Check existin
                if (spritePool.ContainsKey(visualSprite.name))
                {
                    var sprite     = spritePool[visualSprite.name];
                    var controller = sprite.GetComponent <SpriteController>();
                    controller.UpdateState(visualSprite);
                }
                //Create a new sprite if it does not exist
                else
                {
                    GameObject sprite;
                    var        imageKey    = visualSprite.prefabimage;
                    var        imageString = visualSolution.FetchImageString(imageKey);
                    sprite = imageString != null
                             // Render custom prefab image
                        ? UIVisualSpriteFactory.CreateCustom(imageString)
                             // Render built-in prefab
                        : UIVisualSpriteFactory.CreateBuiltIn(visualSprite.prefabimage);

                    // Set parent relationship
                    sprite.transform.SetParent(AniFrame.transform, false);
                    // Store in sprite pool
                    spritePool.Add(visualSprite.name, sprite);
                    // Initialise sprite controller and start presenting the object
                    var controller = sprite.GetComponent <SpriteController>();
                    controller.Init(visualSprite);
                    controller.Present();
                }
            }
            //Remove stored sprites if they are not longer existing
            if (spritePool.Count > visualStage.visualSprites.Length)
            {
                var existingSpriteKeys = from i in visualStage.visualSprites
                                         select i.name;
                var temps = new List <string>();
                foreach (var spriteKey in spritePool.Keys)
                {
                    if (!existingSpriteKeys.Contains(spriteKey))
                    {
                        temps.Add(spriteKey);
                    }
                }
                foreach (var temp in temps)
                {
                    var sprite     = spritePool[temp];
                    var controller = sprite.GetComponent <SpriteController>();
                    controller.OnDestory += (sender, e) =>
                    {
                        foreach (Transform child in sprite.transform)
                        {
                            Destroy(child.gameObject);
                        }
                        Destroy(sprite);
                        spritePool.Remove(temp);
                    };
                    controller.DisapperAndDestory();
                }
            }

            // Set subgoals
            foreach (var sprite in spritePool)
            {
                var controller = sprite.Value.GetComponent <SpriteController>();
                var flag       = subgoalObjectNames.Contains(sprite.Key);
                controller.SetSubgoal(flag);
            }
        }