コード例 #1
0
ファイル: FPMathUtils.cs プロジェクト: garinrkpp/ttt
    public static FP ToFPRotation2D(this Quaternion r)
    {
#if QUANTUM_XY
        return(-FP.FromFloat_UNSAFE(r.eulerAngles.z * Mathf.Deg2Rad));
#else
        return(-FP.FromFloat_UNSAFE(r.eulerAngles.y * Mathf.Deg2Rad));
#endif
    }
コード例 #2
0
ファイル: LocalInput.cs プロジェクト: garinrkpp/ttt
    public override Tuple <Input, DeterministicInputFlags> PollInput(int player)
    {
        Input i = new Input();

        //Need to query unity to get controls
        FP x = FP.FromFloat_UNSAFE(UnityEngine.Input.GetAxis("Horizontal"));
        FP y = FP.FromFloat_UNSAFE(UnityEngine.Input.GetAxis("Vertical"));

        if (player == 1)
        {
            y = -y;
        }

        i.Movement = new FPVector2(x, y);
        i.Fire     = UnityEngine.Input.GetButton("Fire1");
        return(Tuple.Create(i, DeterministicInputFlags.Repeatable));
    }
コード例 #3
0
ファイル: GizmoUtils.cs プロジェクト: garinrkpp/ttt
        static public void DrawGizmoGrid(Vector3 bottomLeft, Int32 width, Int32 height, Int32 nodeSize, Color color)
        {
            Gizmos.color = color;

            for (Int32 z = 0; z < height; ++z)
            {
                for (Int32 x = 0; x < width; ++x)
                {
                    var zn = FP.FromFloat_UNSAFE(z * nodeSize + (nodeSize / 2f));
                    var xn = FP.FromFloat_UNSAFE(x * nodeSize + (nodeSize / 2f));

                    Gizmos.DrawWireCube(bottomLeft + new FPVector2(zn, xn).ToUnityVector3(), new FPVector2(nodeSize, nodeSize).ToUnityVector3());
                }
            }

            Gizmos.color = Color.white;
        }
コード例 #4
0
        public static void Draw(Rect p, SerializedProperty prop, GUIContent label)
        {
            // grab value
            var f = FP.FromRaw(prop.longValue);
            var v = (Single)Math.Round(f.AsFloat, 5);

            // edit value
            try {
                var n = label == null?EditorGUI.FloatField(p, v) : EditorGUI.FloatField(p, label, v);

                if (n != v)
                {
                    prop.longValue = FP.FromFloat_UNSAFE(n).RawValue;
                }

                GUI.Label(p, "(Fixed Point)", OverlayStyle);
            }
            catch (FormatException exn) {
                if (exn.Message != ".")
                {
                    Debug.LogException(exn);
                }
            }
        }
コード例 #5
0
    /*
     * [MenuItem("Assets/Export Mecanim Animation Controller", false, 301)]
     * private static void CreateAnimatorFile() {
     * var animatorController = Selection.activeObject as AnimatorController;
     * if (animatorController == null) {
     *  return;
     * }
     *
     * CreateAsset(animatorController);
     * }
     *
     * [MenuItem("Assets/Export Mecanim Animation Controller", true)]
     * private static bool CreateAnimatorController() {
     * return Selection.activeObject is AnimatorController;
     * }
     */

    //  public static AnimatorGraphAsset Fetch(string name) {
    //    AnimatorGraphAsset output = null;

    //#if UNITY_EDITOR
    //    string pathToAnimationResource = "Assets/Resources/DB/Animator/";
    //    string animationFilePath = pathToAnimationResource + name + ".asset";
    //    output = UnityEditor.AssetDatabase.LoadAssetAtPath(animationFilePath, typeof(AnimatorGraphAsset)) as AnimatorGraphAsset;

    //    if (output == null) {
    //      output = CreateInstance<AnimatorGraphAsset>();
    //      animationFilePath = UnityEditor.AssetDatabase.GenerateUniqueAssetPath(animationFilePath);
    //      UnityEditor.AssetDatabase.CreateAsset(output, animationFilePath);
    //      UnityEditor.AssetDatabase.SaveAssets();
    //      UnityEditor.AssetDatabase.Refresh();
    //    }
    //#endif

    //    if (output != null) {
    //      if (output.Settings == null)
    //        output.Settings = new AnimatorGraph();
    //    }

    //    return output;
    //  }

    public static void CreateAsset(AnimatorGraphAsset dataAsset, AnimatorController controller)
    {
        if (!controller)
        {
            return;
        }

        if (!dataAsset)
        {
            return;
        }

        QuantumRunner.Init();//make sure we can get debug calls from Quantum
        dataAsset.controller = controller;
        int weightTableResolution = (int)dataAsset.weight_table_resolution;
        int variableCount         = controller.parameters.Length;

        dataAsset.Settings.variables = new AnimatorVariable[variableCount];

        //Mecanim Parameters/Variables
        //make a dictionary of paramets by name for use when extracting conditions for transitions
        Dictionary <string, AnimatorControllerParameter> parameterDic = new Dictionary <string, AnimatorControllerParameter>();

        for (int v = 0; v < variableCount; v++)
        {
            AnimatorControllerParameter parameter = controller.parameters[v];
            parameterDic.Add(parameter.name, parameter);
            AnimatorVariable newVariable = new AnimatorVariable();

            newVariable.name  = parameter.name;
            newVariable.index = v;
            switch (parameter.type)
            {
            case AnimatorControllerParameterType.Bool:
                newVariable.type        = AnimatorVariable.VariableType.Bool;
                newVariable.defaultBool = parameter.defaultBool;
                break;

            case AnimatorControllerParameterType.Float:
                newVariable.type      = AnimatorVariable.VariableType.FP;
                newVariable.defaultFp = FP.FromFloat_UNSAFE(parameter.defaultFloat);
                break;

            case AnimatorControllerParameterType.Int:
                newVariable.type       = AnimatorVariable.VariableType.Int;
                newVariable.defaultInt = parameter.defaultInt;
                break;

            case AnimatorControllerParameterType.Trigger:
                newVariable.type = AnimatorVariable.VariableType.Trigger;
                break;
            }

            dataAsset.Settings.variables[v] = newVariable;
        }

        //Mecanim State Graph
        int layerCount = controller.layers.Length;

        dataAsset.clips.Clear();
        dataAsset.Settings.layers = new AnimatorLayer[layerCount];
        for (int l = 0; l < layerCount; l++)
        {
            AnimatorLayer newLayer = new AnimatorLayer();
            newLayer.name = controller.layers[l].name;
            newLayer.id   = l;

            int stateCount = controller.layers[l].stateMachine.states.Length;
            newLayer.states = new Quantum.AnimatorState[stateCount + 1];//additional element for the any state
            Dictionary <UnityEditor.Animations.AnimatorState, Quantum.AnimatorState> stateDictionary = new Dictionary <AnimatorState, Quantum.AnimatorState>();

            for (int s = 0; s < stateCount; s++)
            {
                UnityEditor.Animations.AnimatorState state = controller.layers[l].stateMachine.states[s].state;
                Quantum.AnimatorState newState             = new Quantum.AnimatorState();
                newState.name        = state.name;
                newState.id          = state.nameHash;
                newState.isDefault   = controller.layers[l].stateMachine.defaultState == state;
                newState.speed       = FP.FromFloat_UNSAFE(state.speed);
                newState.cycleOffset = FP.FromFloat_UNSAFE(state.cycleOffset);

                if (state.motion != null)
                {
                    AnimationClip clip = state.motion as AnimationClip;
                    if (clip != null)
                    {
                        dataAsset.clips.Add(clip);
                        AnimatorClip newClip = new AnimatorClip();
                        newClip.name    = state.motion.name;
                        newClip.data    = Extract(clip);
                        newState.motion = newClip;
                    }
                    else
                    {
                        BlendTree tree = state.motion as BlendTree;
                        if (tree != null)
                        {
                            int childCount = tree.children.Length;

                            AnimatorBlendTree newBlendTree = new AnimatorBlendTree();
                            newBlendTree.name        = state.motion.name;
                            newBlendTree.motionCount = childCount;
                            newBlendTree.motions     = new AnimatorMotion[childCount];
                            newBlendTree.positions   = new FPVector2[childCount];
                            newBlendTree.weights     = new FP[childCount];

                            string parameterXname = tree.blendParameter;
                            string parameterYname = tree.blendParameterY;
                            for (int v = 0; v < variableCount; v++)
                            {
                                if (controller.parameters[v].name == parameterXname)
                                {
                                    newBlendTree.blendParameterIndex = v;
                                }
                                if (controller.parameters[v].name == parameterYname)
                                {
                                    newBlendTree.blendParameterIndexY = v;
                                }
                            }

                            for (int c = 0; c < childCount; c++)
                            {
                                ChildMotion   cMotion = tree.children[c];
                                AnimationClip cClip   = cMotion.motion as AnimationClip;
                                newBlendTree.positions[c] = new FPVector2(FP.FromFloat_UNSAFE(cMotion.position.x), FP.FromFloat_UNSAFE(cMotion.position.y));

                                if (cClip != null)
                                {
                                    dataAsset.clips.Add(cClip);
                                    AnimatorClip newClip = new AnimatorClip();
                                    newClip.data            = Extract(cClip);
                                    newClip.name            = newClip.clipName;
                                    newBlendTree.motions[c] = newClip;
                                }
                            }


                            FP val = FP._0 / 21;
                            newBlendTree.CalculateWeightTable(weightTableResolution);

                            newState.motion = newBlendTree;
                        }
                    }
                }
                newLayer.states[s] = newState;

                stateDictionary.Add(state, newState);
            }

            //State Transistions
            //once the states have all been created
            //we'll hook up the transitions
            for (int s = 0; s < stateCount; s++)
            {
                UnityEditor.Animations.AnimatorState state = controller.layers[l].stateMachine.states[s].state;
                Quantum.AnimatorState newState             = newLayer.states[s];
                int transitionCount = state.transitions.Length;
                newState.transitions = new Quantum.AnimatorTransition[transitionCount];
                for (int t = 0; t < transitionCount; t++)
                {
                    AnimatorStateTransition transition = state.transitions[t];
                    if (!stateDictionary.ContainsKey(transition.destinationState))
                    {
                        continue;
                    }
                    Quantum.AnimatorTransition newTransition = new Quantum.AnimatorTransition();
                    newTransition.index                = t;
                    newTransition.name                 = string.Format("{0} to {1}", state.name, transition.destinationState.name);
                    newTransition.duration             = FP.FromFloat_UNSAFE(transition.duration * state.motion.averageDuration);
                    newTransition.hasExitTime          = transition.hasExitTime;
                    newTransition.exitTime             = FP.FromFloat_UNSAFE(transition.exitTime * state.motion.averageDuration);
                    newTransition.offset               = FP.FromFloat_UNSAFE(transition.offset * transition.destinationState.motion.averageDuration);
                    newTransition.destinationStateId   = stateDictionary[transition.destinationState].id;
                    newTransition.destinationStateName = stateDictionary[transition.destinationState].name;
                    newTransition.canTransitionToSelf  = transition.canTransitionToSelf;


                    int conditionCount = transition.conditions.Length;
                    newTransition.conditions = new Quantum.AnimatorCondition[conditionCount];
                    for (int c = 0; c < conditionCount; c++)
                    {
                        UnityEditor.Animations.AnimatorCondition condition = state.transitions[t].conditions[c];

                        if (!parameterDic.ContainsKey(condition.parameter))
                        {
                            continue;
                        }
                        AnimatorControllerParameter parameter    = parameterDic[condition.parameter];
                        Quantum.AnimatorCondition   newCondition = new Quantum.AnimatorCondition();

                        newCondition.variableName = condition.parameter;
                        newCondition.mode         = (Quantum.AnimatorCondition.Modes)condition.mode;

                        switch (parameter.type)
                        {
                        case AnimatorControllerParameterType.Float:
                            newCondition.thresholdFp = FP.FromFloat_UNSAFE(condition.threshold);
                            break;

                        case AnimatorControllerParameterType.Int:
                            newCondition.thresholdInt = Mathf.RoundToInt(condition.threshold);
                            break;
                        }

                        newTransition.conditions[c] = newCondition;
                    }

                    newState.transitions[t] = newTransition;
                }
            }

            //Create Any State
            Quantum.AnimatorState anyState = new Quantum.AnimatorState();
            anyState.name  = "Any State";
            anyState.id    = anyState.name.GetHashCode();
            anyState.isAny = true;//important for this one
            AnimatorStateTransition[] anyStateTransitions = controller.layers[l].stateMachine.anyStateTransitions;
            int anyStateTransitionCount = anyStateTransitions.Length;
            anyState.transitions = new Quantum.AnimatorTransition[anyStateTransitionCount];
            for (int t = 0; t < anyStateTransitionCount; t++)
            {
                AnimatorStateTransition transition = anyStateTransitions[t];
                if (!stateDictionary.ContainsKey(transition.destinationState))
                {
                    continue;
                }
                Quantum.AnimatorTransition newTransition = new Quantum.AnimatorTransition();
                newTransition.index                = t;
                newTransition.name                 = string.Format("Any State to {0}", transition.destinationState.name);
                newTransition.duration             = FP.FromFloat_UNSAFE(transition.duration);
                newTransition.hasExitTime          = transition.hasExitTime;
                newTransition.exitTime             = FP._1;
                newTransition.offset               = FP.FromFloat_UNSAFE(transition.offset * transition.destinationState.motion.averageDuration);
                newTransition.destinationStateId   = stateDictionary[transition.destinationState].id;
                newTransition.destinationStateName = stateDictionary[transition.destinationState].name;
                newTransition.canTransitionToSelf  = transition.canTransitionToSelf;

                int conditionCount = transition.conditions.Length;
                newTransition.conditions = new Quantum.AnimatorCondition[conditionCount];
                for (int c = 0; c < conditionCount; c++)
                {
                    UnityEditor.Animations.AnimatorCondition condition = anyStateTransitions[t].conditions[c];

                    if (!parameterDic.ContainsKey(condition.parameter))
                    {
                        continue;
                    }
                    AnimatorControllerParameter parameter    = parameterDic[condition.parameter];
                    Quantum.AnimatorCondition   newCondition = new Quantum.AnimatorCondition();

                    newCondition.variableName = condition.parameter;
                    newCondition.mode         = (Quantum.AnimatorCondition.Modes)condition.mode;

                    switch (parameter.type)
                    {
                    case AnimatorControllerParameterType.Float:
                        newCondition.thresholdFp = FP.FromFloat_UNSAFE(condition.threshold);
                        break;

                    case AnimatorControllerParameterType.Int:
                        newCondition.thresholdInt = Mathf.RoundToInt(condition.threshold);
                        break;
                    }

                    newTransition.conditions[c] = newCondition;
                }

                anyState.transitions[t] = newTransition;
            }
            newLayer.states[stateCount] = anyState;

            dataAsset.Settings.layers[l] = newLayer;
        }

        EditorUtility.SetDirty(dataAsset);
    }
コード例 #6
0
    public static AnimatorData Extract(AnimationClip clip)
    {
        AnimatorData animationData = new AnimatorData();

        animationData.clipName = clip.name;

        EditorCurveBinding[]  curveBindings = AnimationUtility.GetCurveBindings(clip);
        AnimationClipSettings settings      = AnimationUtility.GetAnimationClipSettings(clip);

        float usedTime = settings.stopTime - settings.startTime;

        animationData.frameRate  = Mathf.RoundToInt(clip.frameRate);
        animationData.length     = FP.FromFloat_UNSAFE(usedTime);
        animationData.frameCount = Mathf.RoundToInt(clip.frameRate * usedTime);
        animationData.frames     = new AnimatorFrame[animationData.frameCount];
        animationData.looped     = clip.isLooping && settings.loopTime;
        animationData.mirror     = settings.mirror;

        //Read the curves of animation
        int frameCount          = animationData.frameCount;
        int curveBindingsLength = curveBindings.Length;

        if (curveBindingsLength == 0)
        {
            return(animationData);
        }

        AnimationCurve curveTx = null, curveTy = null, curveTz = null, curveRx = null, curveRy = null, curveRz = null, curveRw = null;

        for (int c = 0; c < curveBindingsLength; c++)
        {
            string propertyName = curveBindings[c].propertyName;
            if (propertyName == "m_LocalPosition.x" || propertyName == "RootT.x")
            {
                curveTx = AnimationUtility.GetEditorCurve(clip, curveBindings[c]);
            }
            if (propertyName == "m_LocalPosition.y" || propertyName == "RootT.y")
            {
                curveTy = AnimationUtility.GetEditorCurve(clip, curveBindings[c]);
            }
            if (propertyName == "m_LocalPosition.z" || propertyName == "RootT.z")
            {
                curveTz = AnimationUtility.GetEditorCurve(clip, curveBindings[c]);
            }

            if (propertyName == "m_LocalRotation.x" || propertyName == "RootQ.x")
            {
                curveRx = AnimationUtility.GetEditorCurve(clip, curveBindings[c]);
            }
            if (propertyName == "m_LocalRotation.y" || propertyName == "RootQ.y")
            {
                curveRy = AnimationUtility.GetEditorCurve(clip, curveBindings[c]);
            }
            if (propertyName == "m_LocalRotation.z" || propertyName == "RootQ.z")
            {
                curveRz = AnimationUtility.GetEditorCurve(clip, curveBindings[c]);
            }
            if (propertyName == "m_LocalRotation.w" || propertyName == "RootQ.w")
            {
                curveRw = AnimationUtility.GetEditorCurve(clip, curveBindings[c]);
            }
        }

        //        if (curveBindingsLength >= 7)
        //        {
        //            //Position Curves
        //            curveTx = AnimationUtility.GetEditorCurve(clip, curveBindings[0]);
        //            curveTy = AnimationUtility.GetEditorCurve(clip, curveBindings[1]);
        //            curveTz = AnimationUtility.GetEditorCurve(clip, curveBindings[2]);
        //
        //            //Rotation Curves
        //            curveRx = AnimationUtility.GetEditorCurve(clip, curveBindings[3]);
        //            curveRy = AnimationUtility.GetEditorCurve(clip, curveBindings[4]);
        //            curveRz = AnimationUtility.GetEditorCurve(clip, curveBindings[5]);
        //            curveRw = AnimationUtility.GetEditorCurve(clip, curveBindings[6]);
        //        }

        bool hasPosition = curveTx != null && curveTy != null && curveTz != null;
        bool hasRotation = curveRx != null && curveRy != null && curveRz != null && curveRw != null;

        if (!hasPosition)
        {
            Debug.LogWarning("No movement data was found in the animation: " + clip.name);
        }
        if (!hasRotation)
        {
            Debug.LogWarning("No rotation data was found in the animation: " + clip.name);
        }

        //The initial pose might not be the first frame and might not face foward
        //calculate the initial direction and create an offset Quaternion to apply to transforms;

        Quaternion   startRotUq = Quaternion.identity;
        FPQuaternion startRot   = FPQuaternion.Identity;

        if (hasRotation)
        {
            float srotxu = curveRx.Evaluate(settings.startTime);
            float srotyu = curveRy.Evaluate(settings.startTime);
            float srotzu = curveRz.Evaluate(settings.startTime);
            float srotwu = curveRw.Evaluate(settings.startTime);

            FP srotx = FP.FromFloat_UNSAFE(srotxu);
            FP sroty = FP.FromFloat_UNSAFE(srotyu);
            FP srotz = FP.FromFloat_UNSAFE(srotzu);
            FP srotw = FP.FromFloat_UNSAFE(srotwu);

            startRotUq = new Quaternion(srotxu, srotyu, srotzu, srotwu);
            startRot   = new FPQuaternion(srotx, sroty, srotz, srotw);
        }

        Quaternion   offsetRotUq = Quaternion.Inverse(startRotUq);
        FPQuaternion offsetRot   = FPQuaternion.Inverse(startRot);

        for (int i = 0; i < frameCount; i++)
        {
            var frameData = new AnimatorFrame();
            frameData.id = i;
            float percent   = i / (frameCount - 1f);
            float frameTime = usedTime * percent;
            frameData.time = FP.FromFloat_UNSAFE(frameTime);
            float clipTIme = settings.startTime + percent * (settings.stopTime - settings.startTime);

            if (hasPosition)
            {
                FP        posx        = FP.FromFloat_UNSAFE(i > 0 ? curveTx.Evaluate(clipTIme) - curveTx.Evaluate(settings.startTime) : 0);
                FP        posy        = FP.FromFloat_UNSAFE(i > 0 ? curveTy.Evaluate(clipTIme) - curveTy.Evaluate(settings.startTime) : 0);
                FP        posz        = FP.FromFloat_UNSAFE(i > 0 ? curveTz.Evaluate(clipTIme) - curveTz.Evaluate(settings.startTime) : 0);
                FPVector3 newPosition = offsetRot * new FPVector3(posx, posy, posz);
                if (settings.mirror)
                {
                    newPosition.X = -newPosition.X;
                }
                frameData.position = newPosition;
            }

            if (hasRotation)
            {
                float      curveRxEval   = curveRx.Evaluate(clipTIme);
                float      curveRyEval   = curveRy.Evaluate(clipTIme);
                float      curveRzEval   = curveRz.Evaluate(clipTIme);
                float      curveRwEval   = curveRw.Evaluate(clipTIme);
                Quaternion curveRotation = offsetRotUq * new Quaternion(curveRxEval, curveRyEval, curveRzEval, curveRwEval);
                if (settings.mirror)//mirror the Y axis rotation
                {
                    Quaternion mirrorRotation = new Quaternion(curveRotation.x, -curveRotation.y, -curveRotation.z, curveRotation.w);

                    if (Quaternion.Dot(curveRotation, mirrorRotation) < 0)
                    {
                        mirrorRotation = new Quaternion(-mirrorRotation.x, -mirrorRotation.y, -mirrorRotation.z, -mirrorRotation.w);
                    }

                    curveRotation = mirrorRotation;
                }

                FP           rotx        = FP.FromFloat_UNSAFE(curveRotation.x);
                FP           roty        = FP.FromFloat_UNSAFE(curveRotation.y);
                FP           rotz        = FP.FromFloat_UNSAFE(curveRotation.z);
                FP           rotw        = FP.FromFloat_UNSAFE(curveRotation.w);
                FPQuaternion newRotation = new FPQuaternion(rotx, roty, rotz, rotw);
                frameData.rotation = newRotation * offsetRot;

                float rotY = curveRotation.eulerAngles.y * Mathf.Deg2Rad;
                while (rotY < -Mathf.PI)
                {
                    rotY += Mathf.PI * 2;
                }
                while (rotY > Mathf.PI)
                {
                    rotY += -Mathf.PI * 2;
                }
                frameData.rotationY = FP.FromFloat_UNSAFE(rotY);
            }

            animationData.frames[i] = frameData;
        }

        return(animationData);
    }
コード例 #7
0
ファイル: FPMathUtils.cs プロジェクト: garinrkpp/ttt
 public static FP ToFP(this Single v)
 {
     return(FP.FromFloat_UNSAFE(v));
 }
コード例 #8
0
    static void BakeData(MapData data, Boolean inEditor)
    {
#if UNITY_EDITOR
        if (inEditor)
        {
            if (EditorSceneManager.loadedSceneCount != 1)
            {
                Debug.LogErrorFormat("Can't bake map data when more than one scene is open.");
                return;
            }

            // set scene name
            data.Asset.Settings.Scene = EditorSceneManager.GetActiveScene().name;
        }
#endif

        // clear existing colliders
        data.Asset.Settings.StaticColliders = new MapStaticCollider[0];

        // circle colliders
        foreach (var collider in UnityEngine.Object.FindObjectsOfType <QuantumStaticCircleCollider2D>())
        {
            ArrayUtils.Add(ref data.Asset.Settings.StaticColliders, new MapStaticCollider {
                Position        = collider.transform.position.ToFPVector2(),
                Rotation        = collider.transform.rotation.ToFPRotation2D(),
                PhysicsMaterial = collider.Settings.PhysicsMaterial,
                Trigger         = collider.Settings.Trigger,
                StaticData      = GetStaticData(collider.gameObject, collider.Settings),
                Layer           = collider.gameObject.layer,

                // circle
                ShapeType    = Quantum.Core.DynamicShapeType.Circle,
                CircleRadius = FP.FromFloat_UNSAFE(collider.Radius.AsFloat * collider.transform.localScale.x)
            });
        }

        // polygon colliders
        foreach (var collider in UnityEngine.Object.FindObjectsOfType <QuantumStaticPolygonCollider2D>())
        {
            var s        = collider.transform.localScale;
            var vertices = collider.Vertices.Select(x => { var v = x.ToUnityVector3(); return(new Vector3(v.x * s.x, v.y * s.y, v.z * s.z)); }).Select(x => x.ToFPVector2()).ToArray();

            if (FPVector2.IsClockWise(vertices))
            {
                FPVector2.MakeCounterClockWise(vertices);
            }

            var normals = FPVector2.CalculatePolygonNormals(vertices);

            ArrayUtils.Add(ref data.Asset.Settings.StaticColliders, new MapStaticCollider {
                Position        = collider.transform.position.ToFPVector2(),
                Rotation        = collider.transform.rotation.ToFPRotation2D(),
                PhysicsMaterial = collider.Settings.PhysicsMaterial,
                Trigger         = collider.Settings.Trigger,
                StaticData      = GetStaticData(collider.gameObject, collider.Settings),
                Layer           = collider.gameObject.layer,

                // polygon
                ShapeType       = Quantum.Core.DynamicShapeType.Polygon,
                PolygonCollider = new PolygonCollider {
                    Vertices = vertices,
                    Normals  = normals
                }
            });
        }

        // polygon colliders
        foreach (var collider in UnityEngine.Object.FindObjectsOfType <QuantumStaticBoxCollider2D>())
        {
            var e = collider.Size.ToUnityVector3();
            var s = collider.transform.localScale;
            e.x *= s.x;
            e.y *= s.y;
            e.z *= s.z;

            ArrayUtils.Add(ref data.Asset.Settings.StaticColliders, new MapStaticCollider {
                Position        = collider.transform.position.ToFPVector2(),
                Rotation        = collider.transform.rotation.ToFPRotation2D(),
                PhysicsMaterial = collider.Settings.PhysicsMaterial,
                Trigger         = collider.Settings.Trigger,
                StaticData      = GetStaticData(collider.gameObject, collider.Settings),
                Layer           = collider.gameObject.layer,

                // polygon
                ShapeType  = Quantum.Core.DynamicShapeType.Box,
                BoxExtents = e.ToFPVector2() * FP._0_50
            });
        }

        // invoke callbacks
        foreach (var callback in Quantum.TypeUtils.GetSubClasses(typeof(MapDataBakerCallback), "Assembly-CSharp", "Assembly-CSharp-firstpass", "Assembly-CSharp-Editor", "Assembly-CSharp-Editor-firstpass"))
        {
            if (callback.IsAbstract == false)
            {
                try {
                    (Activator.CreateInstance(callback) as MapDataBakerCallback).OnBake(data);
                }
                catch (Exception exn) {
                    Debug.LogException(exn);
                }
            }
        }

        if (inEditor)
        {
            Debug.LogFormat("Baked {0} static colliders", data.Asset.Settings.StaticColliders.Length);
        }
    }
コード例 #9
0
        public static NavMesh BakeNavMesh(MapData data, MapNavMeshDefinition navmeshDefinition)
        {
            try {
                FPMathUtils.LoadLookupTables();

                var vs_array     = navmeshDefinition.Vertices.ToArray();
                var nav_vertices = vs_array.Map(x => new NavMeshVertex {
                    Point = x.Position.ToFPVector2(), Neighbors = new Int32[0], Triangles = new Int32[0], Borders = new Int32[0]
                });
                var nav_triangles = new NavMeshTriangle[0];

                // TRIANGLES
                for (Int32 i = 0; i < navmeshDefinition.Triangles.Length; ++i)
                {
                    Progress("Baking NavMesh '" + navmeshDefinition.name + "': Calculating Triangles", i, navmeshDefinition.Triangles.Length);

                    var t = navmeshDefinition.Triangles[i];

                    var v0 = Array.FindIndex(vs_array, x => x.Id == t.VertexIds[0]);
                    var v1 = Array.FindIndex(vs_array, x => x.Id == t.VertexIds[1]);
                    var v2 = Array.FindIndex(vs_array, x => x.Id == t.VertexIds[2]);

                    ArrayUtils.Add(ref nav_triangles, new NavMeshTriangle {
                        Vertex0 = v0,
                        Vertex1 = v1,
                        Vertex2 = v2,
                        Center  = (nav_vertices[v0].Point + nav_vertices[v1].Point + nav_vertices[v2].Point) / FP._3
                    });
                }


                // TRIANGLE GRID
                var nav_triangles_grid = new NavMeshTriangleNode[data.Asset.Settings.GridSize * data.Asset.Settings.GridSize];

                //for (Int32 i = 0; i < nav_triangles_grid.Length; ++i) {
                //  nav_triangles_grid[i] = i + 1;
                //}

                for (Int32 i = 0; i < nav_triangles.Length; ++i)
                {
                    Progress("Baking NavMesh '" + navmeshDefinition.name + "': Calculating Triangle Grid", i, nav_triangles.Length);

                    var v0 = nav_vertices[nav_triangles[i].Vertex0].Point;
                    var v1 = nav_vertices[nav_triangles[i].Vertex1].Point;
                    var v2 = nav_vertices[nav_triangles[i].Vertex2].Point;

                    for (Int32 z = 0; z < data.Asset.Settings.GridSize; ++z)
                    {
                        for (Int32 x = 0; x < data.Asset.Settings.GridSize; ++x)
                        {
                            var bl = data.Asset.Settings.WorldOffset + new FPVector2(x * data.Asset.Settings.GridNodeSize, z * data.Asset.Settings.GridNodeSize);
                            var br = bl + new FPVector2(data.Asset.Settings.GridNodeSize, 0);
                            var ur = bl + new FPVector2(data.Asset.Settings.GridNodeSize, data.Asset.Settings.GridNodeSize);
                            var ul = bl + new FPVector2(0, data.Asset.Settings.GridNodeSize);

                            if (
                                // if any of the corners are inside the triangle
                                FPCollision.TriangleContainsPoint(bl, v0, v1, v2) ||
                                FPCollision.TriangleContainsPoint(br, v0, v1, v2) ||
                                FPCollision.TriangleContainsPoint(ur, v0, v1, v2) ||
                                FPCollision.TriangleContainsPoint(ul, v0, v1, v2) ||

                                // BL => BR
                                FPCollision.TriangleContainsPoint(v0, v1, bl, br) ||
                                FPCollision.TriangleContainsPoint(v1, v2, bl, br) ||
                                FPCollision.TriangleContainsPoint(v2, v0, bl, br) ||

                                // BR => UR
                                FPCollision.TriangleContainsPoint(v0, v1, br, ur) ||
                                FPCollision.TriangleContainsPoint(v1, v2, br, ur) ||
                                FPCollision.TriangleContainsPoint(v2, v0, br, ur) ||

                                // UR => UL
                                FPCollision.TriangleContainsPoint(v0, v1, ur, ul) ||
                                FPCollision.TriangleContainsPoint(v1, v2, ur, ul) ||
                                FPCollision.TriangleContainsPoint(v2, v0, ur, ul) ||

                                // UL => BL
                                FPCollision.TriangleContainsPoint(v0, v1, ul, bl) ||
                                FPCollision.TriangleContainsPoint(v1, v2, ul, bl) ||
                                FPCollision.TriangleContainsPoint(v2, v0, ul, bl)
                                )
                            {
                                var idx = (z * data.Asset.Settings.GridSize) + x;

                                if (nav_triangles_grid[idx].Triangles == null)
                                {
                                    nav_triangles_grid[idx].Triangles = new Int32[0];
                                }

                                // add triangle to this grid node
                                ArrayUtils.Add(ref nav_triangles_grid[idx].Triangles, i);
                            }
                        }
                    }
                }

                // VERTEX NEIGHBORS

                for (Int32 v = 0; v < nav_vertices.Length; ++v)
                {
                    Progress("Baking NavMesh '" + navmeshDefinition.name + "': Calculating Vertex Neighbors", v, nav_vertices.Length);

                    var triangles = new HashSet <Int32>();
                    var neighbors = new HashSet <Int32>();

                    for (Int32 t = 0; t < nav_triangles.Length; ++t)
                    {
                        var tr = nav_triangles[t];
                        if (tr.Vertex0 == v || tr.Vertex1 == v || tr.Vertex2 == v)
                        {
                            triangles.Add(t);

                            neighbors.Add(tr.Vertex0);
                            neighbors.Add(tr.Vertex1);
                            neighbors.Add(tr.Vertex2);
                        }
                    }

                    // remove itself from neighbors set
                    neighbors.Remove(v);

                    //
                    nav_vertices[v].Triangles = triangles.OrderBy(x => x).ToArray();
                    nav_vertices[v].Neighbors = neighbors.ToArray();
                }

                // BORDER EDGES

                for (Int32 t = 0; t < nav_triangles.Length; ++t)
                {
                    Progress("Baking NavMesh '" + navmeshDefinition.name + "': Calculating Border Edges", t, nav_triangles.Length);

                    var tr = nav_triangles[t];
                    if (IsBorderEdge(nav_triangles, t, tr.Vertex0, tr.Vertex1))
                    {
                        ArrayUtils.Add(ref nav_vertices[tr.Vertex0].Borders, tr.Vertex1);
                        ArrayUtils.Add(ref nav_vertices[tr.Vertex1].Borders, tr.Vertex0);
                    }

                    if (IsBorderEdge(nav_triangles, t, tr.Vertex1, tr.Vertex2))
                    {
                        ArrayUtils.Add(ref nav_vertices[tr.Vertex1].Borders, tr.Vertex2);
                        ArrayUtils.Add(ref nav_vertices[tr.Vertex2].Borders, tr.Vertex1);
                    }

                    if (IsBorderEdge(nav_triangles, t, tr.Vertex2, tr.Vertex0))
                    {
                        ArrayUtils.Add(ref nav_vertices[tr.Vertex2].Borders, tr.Vertex0);
                        ArrayUtils.Add(ref nav_vertices[tr.Vertex0].Borders, tr.Vertex2);
                    }
                }

                // NORMALS

                var pt2 = FP._0_10 * FP._2;
                var pt3 = FP._0_10 * FP._3;

                for (Int32 i = 0; i < nav_vertices.Length; ++i)
                {
                    Progress("Baking NavMesh '" + navmeshDefinition.name + "': Calculating Normals", i, nav_vertices.Length);

                    var v  = nav_vertices[i];
                    var tn = new FPVector2[3];

                    if (v.Borders != null)
                    {
                        // 0. preferred middle of borders
                        var borders = v.Borders.Map(x => FPVector2.Normalize(nav_vertices[x].Point - v.Point));
                        if (borders.Length == 2)
                        {
                            tn[0] = FPVector2.Normalize(FPVector2.Lerp(borders[0], borders[1], FP._0_50));
                        }

                        // 1. second preferred neighbor edge that is furthest away from borders
                        if (v.Neighbors != null)
                        {
                            var neighbors = v.Neighbors.Where(x => !v.Borders.Contains(x)).Select(x =>
                                                                                                  new Neighbor {
                                Direction = FPVector2.Normalize(nav_vertices[x].Point - v.Point),
                                Vertex    = x
                            }
                                                                                                  ).ToArray();

                            var max_dot      = FP.MinValue;
                            var max_neighbor = default(Neighbor);
                            max_neighbor.Vertex = -1;

                            for (Int32 n = 0; n < neighbors.Length; ++n)
                            {
                                var dot = FP._0;

                                for (Int32 b = 0; b < borders.Length; ++b)
                                {
                                    dot += FPVector2.Dot(borders[b], neighbors[n].Direction);
                                }

                                dot = FPMath.Abs(dot);

                                if (dot > max_dot)
                                {
                                    max_dot      = dot;
                                    max_neighbor = neighbors[n];
                                }
                            }

                            if (max_neighbor.Vertex >= 0)
                            {
                                tn[1] = max_neighbor.Direction * pt2;
                            }
                        }
                    }

                    // 2. least preferred, avarage of triangle normals
                    foreach (var tc in v.Triangles.Select(x => FPVector2.Normalize(TriangleCenter(nav_triangles[x], nav_vertices) - v.Point)))
                    {
                        tn[2] += tc;
                    }

                    tn[2] = FPVector2.Normalize(tn[2]);

                    // find normal
                    var failed = true;

                    for (Int32 k = 0; failed && k < tn.Length; ++k)
                    {
                        if (tn[k] != FPVector2.Zero)
                        {
                            if (failed && TriangleContains(nav_triangles, nav_vertices, (v.Point + (tn[k] * pt3))))
                            {
                                nav_vertices[i].Normal = FPVector2.Normalize(tn[k] * pt2);

                                // we're done
                                failed = false;
                            }

                            if (failed && TriangleContains(nav_triangles, nav_vertices, (v.Point + (-tn[k] * pt3))))
                            {
                                nav_vertices[i].Normal = FPVector2.Normalize(-tn[k] * pt2);

                                // we're done
                                failed = false;
                            }
                        }
                    }
                }

                // BORDER SET

                HashSet <Border> border_set = new HashSet <Border>();

                for (Int32 v = 0; v < nav_vertices.Length; ++v)
                {
                    Progress(navmeshDefinition.name + " Baking: Border Set", v, nav_vertices.Length);

                    if (nav_vertices[v].Borders != null)
                    {
                        for (Int32 n = 0; n < nav_vertices[v].Borders.Length; ++n)
                        {
                            border_set.Add(new Border(v, nav_vertices[v].Borders[n], border_set.Count + 1));
                        }
                    }
                }

                // BORDER GRID

                var nav_border_grid = new NavMeshBorderNode[data.Asset.Settings.GridSize * data.Asset.Settings.GridSize];

                for (Int32 z = 0; z < data.Asset.Settings.GridSize; ++z)
                {
                    for (Int32 x = 0; x < data.Asset.Settings.GridSize; ++x)
                    {
                        var idx = (z * data.Asset.Settings.GridSize) + x;

                        Progress("Baking NavMesh '" + navmeshDefinition.name + "': Border Grid", idx, data.Asset.Settings.GridSize * data.Asset.Settings.GridSize);

                        // set index key
                        // nav_border_grid[idx].key = idx + 1;

                        //
                        var zn = (FP)z * data.Asset.Settings.GridNodeSize;
                        var xn = (FP)x * data.Asset.Settings.GridNodeSize;

                        FPVector2 bl = data.Asset.Settings.WorldOffset + new FPVector2(xn, zn);
                        FPVector2 br = data.Asset.Settings.WorldOffset + new FPVector2(xn + data.Asset.Settings.GridNodeSize, zn);
                        FPVector2 ur = data.Asset.Settings.WorldOffset + new FPVector2(xn + data.Asset.Settings.GridNodeSize, zn + data.Asset.Settings.GridNodeSize);
                        FPVector2 ul = data.Asset.Settings.WorldOffset + new FPVector2(xn, zn + data.Asset.Settings.GridNodeSize);

                        foreach (var b in border_set)
                        {
                            var p0 = nav_vertices[b.V0].Point;
                            var p1 = nav_vertices[b.V1].Point;

                            if (
                                FPCollision.LineIntersectsLine(p0, p1, bl, br) ||
                                FPCollision.LineIntersectsLine(p0, p1, br, ur) ||
                                FPCollision.LineIntersectsLine(p0, p1, ur, ul) ||
                                FPCollision.LineIntersectsLine(p0, p1, ul, bl)
                                )
                            {
                                if (nav_border_grid[idx].Borders == null)
                                {
                                    nav_border_grid[idx].Borders = new NavMeshBorder[0];
                                }

                                ArrayUtils.Add(ref nav_border_grid[idx].Borders, new NavMeshBorder {
                                    Key = b.Key,
                                    V0  = p0,
                                    V1  = p1,
                                });
                            }
                        }
                    }
                }

                // TRIANGLE CENTER GRID

                var nav_triangles_center_grid = new Int32[data.Asset.Settings.GridSize * data.Asset.Settings.GridSize];

                for (Int32 z = 0; z < data.Asset.Settings.GridSize; ++z)
                {
                    for (Int32 x = 0; x < data.Asset.Settings.GridSize; ++x)
                    {
                        var idx = (z * data.Asset.Settings.GridSize) + x;

                        Progress("Baking NavMesh '" + navmeshDefinition.name + "': Triangle Center Grid", idx, data.Asset.Settings.GridSize * data.Asset.Settings.GridSize);

                        var zn = (FP)(z * data.Asset.Settings.GridNodeSize);
                        var xn = (FP)(x * data.Asset.Settings.GridNodeSize);
                        var g  = data.Asset.Settings.WorldOffset + new FPVector2(xn, zn) + new FPVector2(FP.FromFloat_UNSAFE(data.Asset.Settings.GridNodeSize * 0.5f), FP.FromFloat_UNSAFE(data.Asset.Settings.GridNodeSize * 0.5f));

                        var d = FP.MaxValue;
                        var t = -1;

                        for (Int32 i = 0; i < nav_triangles.Length; ++i)
                        {
                            var c = nav_triangles[i].Center;

                            if (FPVector2.DistanceSquared(g, c) < d)
                            {
                                d = FPVector2.DistanceSquared(g, c);
                                t = i;
                            }
                        }

                        Assert.Check(t >= 0);

                        nav_triangles_center_grid[idx] = t;
                    }
                }

                NavMesh navmesh;

                navmesh              = new NavMesh();
                navmesh.GridSize     = data.Asset.Settings.GridSize;
                navmesh.GridNodeSize = data.Asset.Settings.GridNodeSize;
                navmesh.WorldOffset  = data.Asset.Settings.WorldOffset;

                navmesh.Name                = navmeshDefinition.name;
                navmesh.Vertices            = nav_vertices;
                navmesh.BorderGrid          = nav_border_grid;
                navmesh.Triangles           = nav_triangles;
                navmesh.TrianglesGrid       = nav_triangles_grid;
                navmesh.TrianglesCenterGrid = nav_triangles_center_grid;

                return(navmesh);
            }
            finally {
#if UNITY_EDITOR
                EditorUtility.ClearProgressBar();
#endif
            }
        }