// Update state machine. That means:
        //   Change state if transition conditions are fulfilled.
        //   Update skeleton.
        public void Update(ref MyAnimationUpdateData data)
        {
            if (data.CharacterBones == null)
            {
                return;               // safety
            }
            CurrentUpdateData = data; // local copy

            CurrentUpdateData.VisitedTreeNodesCounter = 0;
            CurrentUpdateData.VisitedTreeNodesPath    = m_lastVisitedTreeNodesPath;
            CurrentUpdateData.VisitedTreeNodesPath[0] = 0;

            if (BoneMask == null)                             // rebuild bone mask array if not done yet
            {
                RebuildBoneMask();
            }
            data.LayerBoneMask = CurrentUpdateData.LayerBoneMask = BoneMask;       // pass bone mask array to all subnodes and result
            Debug.Assert(data.LayerBoneMask != null);

            // setting animation finished flag
            MyAnimationStateMachineNode currentAnimationNode = CurrentNode as MyAnimationStateMachineNode;

            if (currentAnimationNode != null && currentAnimationNode.RootAnimationNode != null)
            {
                float finishedPercent = currentAnimationNode.RootAnimationNode.GetLocalTimeNormalized();
                data.Controller.Variables.SetValue(MyAnimationVariableStorageHints.StrIdAnimationFinished, finishedPercent);
            }
            else
            {
                data.Controller.Variables.SetValue(MyAnimationVariableStorageHints.StrIdAnimationFinished, 0);
            }

            base.Update();

            int[] swapVisitedTreeNodesPath = VisitedTreeNodesPath;
            VisitedTreeNodesPath                   = m_lastVisitedTreeNodesPath;
            m_lastVisitedTreeNodesPath             = swapVisitedTreeNodesPath;
            CurrentUpdateData.VisitedTreeNodesPath = null;     // disconnect our array

            // blended transitions
            //    - from most recent to oldest
            //    - please preserve order of blending for three or more states
            //      when CurrentState changes
            float weightMultiplier = 1.0f;

            for (int i = 0; i < m_stateTransitionBlending.Count; i++)
            {
                MyStateTransitionBlending stateTransitionBlending = m_stateTransitionBlending[i];
                float localWeight = (float)(stateTransitionBlending.TimeLeftInSeconds * stateTransitionBlending.InvTotalTime); // 1 to 0 over time
                weightMultiplier *= localWeight;

                // update nodes that we are just leaving
                var lastResult = CurrentUpdateData.BonesResult;
                CurrentUpdateData.BonesResult = null;
                stateTransitionBlending.SourceState.OnUpdate(this);
                if (lastResult != null && CurrentUpdateData.BonesResult != null)
                {
                    for (int j = 0; j < lastResult.Count; j++)
                    {
                        if (data.LayerBoneMask[j])
                        {
                            // these nodes lose their weight, it goes from 1 to 0
                            // we need to blend them to last result (current node or another node that we are leaving)
                            float w = ComputeEaseInEaseOut(MathHelper.Clamp(weightMultiplier, 0, 1));
                            CurrentUpdateData.BonesResult[j].Rotation    = Quaternion.Slerp(lastResult[j].Rotation, CurrentUpdateData.BonesResult[j].Rotation, w);
                            CurrentUpdateData.BonesResult[j].Translation = Vector3.Lerp(lastResult[j].Translation, CurrentUpdateData.BonesResult[j].Translation, w);
                        }
                    }
                    // give back last result (free list of bones), we dont need it anymore
                    data.Controller.ResultBonesPool.Free(lastResult);
                }
                // update, decrease remaining time
                stateTransitionBlending.TimeLeftInSeconds -= data.DeltaTimeInSeconds;
                m_stateTransitionBlending[i] = stateTransitionBlending;
                if (stateTransitionBlending.TimeLeftInSeconds <= 0)
                {
                    // skip older blended states and mark them for deletion, because their (global) weight is now zero
                    for (int j = i + 1; j < m_stateTransitionBlending.Count; j++)
                    {
                        var temp = m_stateTransitionBlending[j];
                        temp.TimeLeftInSeconds       = 0; //
                        m_stateTransitionBlending[j] = temp;
                    }
                    break;
                }
            }
            m_stateTransitionBlending.RemoveAll(s => s.TimeLeftInSeconds <= 0.0);

            data.BonesResult = CurrentUpdateData.BonesResult; // local copy contains resulting list of bones
        }
Exemple #2
0
        // Initialize state machine of one layer.
        private static bool InitLayerNodes(MyAnimationStateMachine layer, string stateMachineName, MyAnimationControllerDefinition animControllerDefinition,
                                           MyAnimationController animationController, string currentNodeNamePrefix, MyAnimationVirtualNodes virtualNodes)
        {
            var objBuilderStateMachine = animControllerDefinition.StateMachines.FirstOrDefault(x => x.Name == stateMachineName);

            if (objBuilderStateMachine == null)
            {
                Debug.Fail("Animation state machine " + stateMachineName + " was not found.");
                return(false);
            }

            bool result = true;

            // 1st step: generate nodes
            if (objBuilderStateMachine.Nodes != null)
            {
                foreach (var objBuilderNode in objBuilderStateMachine.Nodes)
                {
                    string absoluteNodeName = currentNodeNamePrefix + objBuilderNode.Name;
                    if (objBuilderNode.StateMachineName != null)
                    {
                        // embedded state machine, copy its nodes
                        if (!InitLayerNodes(layer, objBuilderNode.StateMachineName, animControllerDefinition, animationController, absoluteNodeName + "/", virtualNodes))
                        {
                            result = false;
                        }
                    }
                    else
                    {
                        var smNode = new VRage.Animations.MyAnimationStateMachineNode(absoluteNodeName);
                        if (objBuilderNode.Type == MyObjectBuilder_AnimationSMNode.MySMNodeType.PassThrough ||
                            objBuilderNode.Type == MyObjectBuilder_AnimationSMNode.MySMNodeType.Any ||
                            objBuilderNode.Type == MyObjectBuilder_AnimationSMNode.MySMNodeType.AnyExceptTarget)
                        {
                            smNode.PassThrough = true;
                        }
                        else
                        {
                            smNode.PassThrough = false;
                        }

                        if (objBuilderNode.Type == MyObjectBuilder_AnimationSMNode.MySMNodeType.Any ||
                            objBuilderNode.Type == MyObjectBuilder_AnimationSMNode.MySMNodeType.AnyExceptTarget)
                        {
                            virtualNodes.NodesAny.Add(absoluteNodeName, new MyAnimationVirtualNodeData()
                            {
                                AnyNodePrefix = currentNodeNamePrefix,
                                ExceptTarget  = (objBuilderNode.Type == MyObjectBuilder_AnimationSMNode.MySMNodeType.AnyExceptTarget)
                            });
                        }

                        layer.AddNode(smNode);

                        if (objBuilderNode.AnimationTree != null)
                        {
                            var smNodeAnimTree = InitNodeAnimationTree(objBuilderNode.AnimationTree.Child);
                            smNode.RootAnimationNode = smNodeAnimTree;
                        }
                        else
                        {
                            smNode.RootAnimationNode = new MyAnimationTreeNodeDummy();
                        }
                    }
                }
            }

            // 2nd step: generate transitions
            if (objBuilderStateMachine.Transitions != null)
            {
                foreach (var objBuilderTransition in objBuilderStateMachine.Transitions)
                {
                    string absoluteNameNodeFrom = currentNodeNamePrefix + objBuilderTransition.From;
                    string absoluteNameNodeTo   = currentNodeNamePrefix + objBuilderTransition.To;

                    MyAnimationVirtualNodeData virtualNodeData;
                    if (virtualNodes.NodesAny.TryGetValue(absoluteNameNodeFrom, out virtualNodeData))
                    {
                        // nodes of type "any":
                        // "any" node is source: we create transitions directly from all nodes
                        // "any" node is target: we will use "any" node as pass through
                        foreach (var nodeFromCandidate in layer.AllNodes)
                        {
                            if (nodeFromCandidate.Key.StartsWith(virtualNodeData.AnyNodePrefix) && // select nodes in the same SM
                                nodeFromCandidate.Key != absoluteNameNodeFrom)   // disallow from "any" to the same "any"
                            {
                                // create transition if target is different from source or when we don't care about it
                                if (!virtualNodeData.ExceptTarget || absoluteNameNodeTo != nodeFromCandidate.Key)
                                {
                                    CreateTransition(layer, animationController, nodeFromCandidate.Key, absoluteNameNodeTo, objBuilderTransition);
                                }
                            }
                        }
                    }

                    CreateTransition(layer, animationController, absoluteNameNodeFrom, absoluteNameNodeTo, objBuilderTransition);
                }
            }

            return(result);
        }
Exemple #3
0
        // Initialize state machine of one layer.
        private static bool InitLayerNodes(VRage.Animations.MyAnimationStateMachine layer, string stateMachineName, MyAnimationControllerDefinition animControllerDefinition,
                                           VRage.Animations.MyAnimationController animationController, string currentNodeNamePrefix = "")
        {
            var objBuilderStateMachine = animControllerDefinition.StateMachines.FirstOrDefault(x => x.Name == stateMachineName);

            if (objBuilderStateMachine == null)
            {
                Debug.Fail("Animation state machine " + stateMachineName + " was not found.");
                return(false);
            }

            bool result = true;

            // 1st step: generate nodes
            if (objBuilderStateMachine.Nodes != null)
            {
                foreach (var objBuilderNode in objBuilderStateMachine.Nodes)
                {
                    string absoluteNodeName = currentNodeNamePrefix + objBuilderNode.Name;
                    if (objBuilderNode.StateMachineName != null)
                    {
                        // embedded state machine, copy its nodes
                        if (!InitLayerNodes(layer, objBuilderNode.StateMachineName, animControllerDefinition, animationController, absoluteNodeName + "/"))
                        {
                            result = false;
                        }
                    }
                    else
                    {
                        if (objBuilderNode.AnimationTree == null)
                        {
                            // no animation tree, just skip
                            continue;
                        }

                        var smNode = new VRage.Animations.MyAnimationStateMachineNode(absoluteNodeName);
                        layer.AddNode(smNode);

                        var smNodeAnimTree = InitNodeAnimationTree(objBuilderNode.AnimationTree.Child);
                        smNode.RootAnimationNode = smNodeAnimTree;
                    }
                }
            }

            // 2nd step: generate transitions
            if (objBuilderStateMachine.Transitions != null)
            {
                foreach (var objBuilderTransition in objBuilderStateMachine.Transitions)
                {
                    int conditionConjunctionIndex = 0;
                    do
                    {
                        // generate transition for each condition conjunction
                        var transition = layer.AddTransition(objBuilderTransition.From, objBuilderTransition.To,
                                                             new VRage.Animations.MyAnimationStateMachineTransition()) as
                                         VRage.Animations.MyAnimationStateMachineTransition;
                        // if ok, fill in conditions
                        if (transition != null)
                        {
                            transition.Name = MyStringId.GetOrCompute(objBuilderTransition.Name);
                            transition.TransitionTimeInSec = objBuilderTransition.TimeInSec;
                            transition.Sync = objBuilderTransition.Sync;
                            if (objBuilderTransition.Conditions != null &&
                                objBuilderTransition.Conditions[conditionConjunctionIndex] != null)
                            {
                                var conjunctionOfConditions =
                                    objBuilderTransition.Conditions[conditionConjunctionIndex].Conditions;
                                foreach (var objBuilderCondition in conjunctionOfConditions)
                                {
                                    var condition = ParseOneCondition(animationController, objBuilderCondition);
                                    if (condition != null)
                                    {
                                        transition.Conditions.Add(condition);
                                    }
                                }
                            }
                        }
                        conditionConjunctionIndex++;
                    } while (objBuilderTransition.Conditions != null &&
                             conditionConjunctionIndex < objBuilderTransition.Conditions.Length);
                }
            }

            return(result);
        }
Exemple #4
0
        // Update state machine. That means:
        //   Change state if transition conditions are fulfilled.
        //   Update skeleton.
        public void Update(ref MyAnimationUpdateData data)
        {
            if (data.CharacterBones == null)
            {
                return;               // safety
            }
            CurrentUpdateData = data; // local copy
            if (BoneMask == null)     // rebuild bone mask array if not done yet
            {
                RebuildBoneMask();
            }
            data.LayerBoneMask = CurrentUpdateData.LayerBoneMask = BoneMask;       // pass bone mask array to all subnodes and result
            Debug.Assert(data.LayerBoneMask != null);
            base.Update();

            // blended transitions
            //    - from most recent to oldest
            //    - please preserve order of blending for three or more states
            //      when CurrentState changes
            for (int i = 0; i < m_stateTransitionBlending.Count; i++)
            {
                MyStateTransitionBlending stateTransitionBlending = m_stateTransitionBlending[i];
                float weight = 1 - (float)(stateTransitionBlending.TimeLeftInSeconds * stateTransitionBlending.InvTotalTime);

                // update nodes that we are just leaving
                var lastResult = CurrentUpdateData.BonesResult;
                CurrentUpdateData.BonesResult = null;
                stateTransitionBlending.SourceState.OnUpdate(this);
                if (lastResult != null && CurrentUpdateData.BonesResult != null)
                {
                    for (int j = 0; j < lastResult.Count; j++)
                    {
                        if (data.LayerBoneMask[j])
                        {
                            // these nodes lose their weight, it goes from 1 to 0
                            // we need to blend them to last result (current node or another node that we are leaving)
                            CurrentUpdateData.BonesResult[j].Rotation    = Quaternion.Slerp(lastResult[j].Rotation, CurrentUpdateData.BonesResult[j].Rotation, 1 - weight);
                            CurrentUpdateData.BonesResult[j].Translation = Vector3.Lerp(lastResult[j].Translation, CurrentUpdateData.BonesResult[j].Translation, weight);
                        }
                    }
                    // give back last result (free list of bones), we dont need it anymore
                    if (lastResult != null)
                    {
                        data.Controller.ResultBonesPool.Free(lastResult);
                    }
                }
                // update, decrease remaining time
                stateTransitionBlending.TimeLeftInSeconds -= data.DeltaTimeInSeconds;
                m_stateTransitionBlending[i] = stateTransitionBlending;
            }
            m_stateTransitionBlending.RemoveAll(s => s.TimeLeftInSeconds <= 0.0);

            data.BonesResult = CurrentUpdateData.BonesResult; // local copy contains resulting list of bones

            // setting animation finished flag
            MyAnimationStateMachineNode currentAnimationNode = CurrentNode as MyAnimationStateMachineNode;

            if (currentAnimationNode != null && currentAnimationNode.RootAnimationNode != null)
            {
                float finishedPercent = currentAnimationNode.RootAnimationNode.GetLocalTimeNormalized();
                data.Controller.Variables.SetValue(m_variableAnimationFinished, finishedPercent);
            }
        }
        // Initialize state machine of one layer.
        private static bool InitLayerNodes(VRage.Animations.MyAnimationStateMachine layer, string stateMachineName, MyAnimationControllerDefinition animControllerDefinition,
            VRage.Animations.MyAnimationController animationController, string currentNodeNamePrefix = "")
        {
            var objBuilderStateMachine = animControllerDefinition.StateMachines.FirstOrDefault(x => x.Name == stateMachineName);
            if (objBuilderStateMachine == null)
            {
                Debug.Fail("Animation state machine " + stateMachineName + " was not found.");
                return false;
            }

            bool result = true;
            // 1st step: generate nodes
            if (objBuilderStateMachine.Nodes != null)
            foreach (var objBuilderNode in objBuilderStateMachine.Nodes)
            {
                string absoluteNodeName = currentNodeNamePrefix + objBuilderNode.Name;
                if (objBuilderNode.StateMachineName != null)
                {
                    // embedded state machine, copy its nodes
                    if (!InitLayerNodes(layer, objBuilderNode.StateMachineName, animControllerDefinition, animationController, absoluteNodeName + "/"))
                        result = false;
                }
                else
                {
                    if (objBuilderNode.AnimationTree == null)
                    {
                        // no animation tree, just skip
                        continue;
                    }

                    var smNode = new VRage.Animations.MyAnimationStateMachineNode(absoluteNodeName);
                    layer.AddNode(smNode);

                    var smNodeAnimTree = InitNodeAnimationTree(objBuilderNode.AnimationTree.Child);
                    smNode.RootAnimationNode = smNodeAnimTree;
                }
            }

            // 2nd step: generate transitions
            if (objBuilderStateMachine.Transitions != null)
            foreach (var objBuilderTransition in objBuilderStateMachine.Transitions)
            {
                int conditionConjunctionIndex = 0;
                do
                {
                    // generate transition for each condition conjunction
                    var transition = layer.AddTransition(objBuilderTransition.From, objBuilderTransition.To,
                        new VRage.Animations.MyAnimationStateMachineTransition()) as
                        VRage.Animations.MyAnimationStateMachineTransition;
                    // if ok, fill in conditions
                    if (transition != null)
                    {
                        transition.Name = MyStringId.GetOrCompute(objBuilderTransition.Name);
                        transition.TransitionTimeInSec = objBuilderTransition.TimeInSec;
                        transition.Sync = objBuilderTransition.Sync;
                        if (objBuilderTransition.Conditions != null &&
                            objBuilderTransition.Conditions[conditionConjunctionIndex] != null)
                        {
                            var conjunctionOfConditions =
                                objBuilderTransition.Conditions[conditionConjunctionIndex].Conditions;
                            foreach (var objBuilderCondition in conjunctionOfConditions)
                            {
                                var condition = ParseOneCondition(animationController, objBuilderCondition);
                                if (condition != null)
                                    transition.Conditions.Add(condition);
                            }
                        }
                    }
                    conditionConjunctionIndex++;
                } while (objBuilderTransition.Conditions != null &&
                         conditionConjunctionIndex < objBuilderTransition.Conditions.Length);
            }

            return result;
        }
        // Initialize state machine of one layer.
        private static bool InitLayerNodes(MyAnimationStateMachine layer, string stateMachineName, MyAnimationControllerDefinition animControllerDefinition, 
            MyAnimationController animationController, string currentNodeNamePrefix, MyAnimationVirtualNodes virtualNodes)
        {
            var objBuilderStateMachine = animControllerDefinition.StateMachines.FirstOrDefault(x => x.Name == stateMachineName);
            if (objBuilderStateMachine == null)
            {
                Debug.Fail("Animation state machine " + stateMachineName + " was not found.");
                return false;
            }

            bool result = true;
            // 1st step: generate nodes
            if (objBuilderStateMachine.Nodes != null)
            foreach (var objBuilderNode in objBuilderStateMachine.Nodes)
            {
                string absoluteNodeName = currentNodeNamePrefix + objBuilderNode.Name;
                if (objBuilderNode.StateMachineName != null)
                {
                    // embedded state machine, copy its nodes
                    if (!InitLayerNodes(layer, objBuilderNode.StateMachineName, animControllerDefinition, animationController, absoluteNodeName + "/", virtualNodes))
                        result = false;
                }
                else
                {
                    var smNode = new VRage.Animations.MyAnimationStateMachineNode(absoluteNodeName);
                    if (objBuilderNode.Type == MyObjectBuilder_AnimationSMNode.MySMNodeType.PassThrough
                        || objBuilderNode.Type == MyObjectBuilder_AnimationSMNode.MySMNodeType.Any
                        || objBuilderNode.Type == MyObjectBuilder_AnimationSMNode.MySMNodeType.AnyExceptTarget)
                    {
                        smNode.PassThrough = true;
                    }
                    else
                    {
                        smNode.PassThrough = false;
                    }

                    if (objBuilderNode.Type == MyObjectBuilder_AnimationSMNode.MySMNodeType.Any
                        || objBuilderNode.Type == MyObjectBuilder_AnimationSMNode.MySMNodeType.AnyExceptTarget)
                    {
                        virtualNodes.NodesAny.Add(absoluteNodeName, new MyAnimationVirtualNodeData()
                        {
                            AnyNodePrefix = currentNodeNamePrefix,
                            ExceptTarget = (objBuilderNode.Type == MyObjectBuilder_AnimationSMNode.MySMNodeType.AnyExceptTarget)
                        });
                    }

                    layer.AddNode(smNode);

                    if (objBuilderNode.AnimationTree != null)
                    {
                        var smNodeAnimTree = InitNodeAnimationTree(objBuilderNode.AnimationTree.Child);
                        smNode.RootAnimationNode = smNodeAnimTree;
                    }
                    else
                    {
                        smNode.RootAnimationNode = new MyAnimationTreeNodeDummy();
                    }
                }
            }

            // 2nd step: generate transitions
            if (objBuilderStateMachine.Transitions != null)
            foreach (var objBuilderTransition in objBuilderStateMachine.Transitions)
            {
                string absoluteNameNodeFrom = currentNodeNamePrefix + objBuilderTransition.From;
                string absoluteNameNodeTo = currentNodeNamePrefix + objBuilderTransition.To;

                MyAnimationVirtualNodeData virtualNodeData;
                if (virtualNodes.NodesAny.TryGetValue(absoluteNameNodeFrom, out virtualNodeData))
                {
                    // nodes of type "any":
                    // "any" node is source: we create transitions directly from all nodes
                    // "any" node is target: we will use "any" node as pass through
                    foreach (var nodeFromCandidate in layer.AllNodes)
                    {
                        if (nodeFromCandidate.Key.StartsWith(virtualNodeData.AnyNodePrefix) // select nodes in the same SM
                            && nodeFromCandidate.Key != absoluteNameNodeFrom)    // disallow from "any" to the same "any"
                        {
                            // create transition if target is different from source or when we don't care about it
                            if (!virtualNodeData.ExceptTarget || absoluteNameNodeTo != nodeFromCandidate.Key)
                                CreateTransition(layer, animationController, nodeFromCandidate.Key, absoluteNameNodeTo, objBuilderTransition);
                        }
                    }
                }

                CreateTransition(layer, animationController, absoluteNameNodeFrom, absoluteNameNodeTo, objBuilderTransition);
            }

            return result;
        }