예제 #1
0
        public bool GetPortal(NavMeshNode other, List <Int3> left, List <Int3> right)
        {
            int first = -1;

            int acount = 3;
            int bcount = 3;

            // find the shared edge
            for (int a = 0; a < acount; a++)
            {
                var va  = GetVertex(a);
                var va2 = GetVertex((a + 1) % acount);
                for (int b = 0; b < bcount; b++)
                {
                    if (va == other.GetVertex((b + 1) % bcount) && va2 == other.GetVertex(b))
                    {
                        first = a;
                        a     = acount;                    // to stop the outer loop
                        break;
                    }
                }
            }

            if (first != -1)
            {
                //All triangles should be clockwise so second is the rightmost vertex (seen from this node)
                left.Add(GetVertex(first));
                right.Add(GetVertex((first + 1) % acount));
                return(true);
            }

            return(false);
        }
예제 #2
0
        protected override int CalCostH(ProcessingNode node, AStarContext context)
        {
            float       heuristicScale = 1.0f;
            NavMeshNode calNode        = node.astarNode as NavMeshNode;
            NavMeshNode targetNode     = context.GetTargetNode().astarNode as NavMeshNode;
            int         dist           = (calNode.position - targetNode.position).costMagnitude;

            return(UnityEngine.Mathf.RoundToInt(dist * heuristicScale));
        }
예제 #3
0
        static bool NodeIntersectsCircle(NavMeshNode node, Int3 p, int radius)
        {
            if (float.IsPositiveInfinity(radius))
            {
                return(true);
            }

            /** \bug Is not correct on the Y axis */
            return((p - node.ClosestPointOnNode(p)).sqrMagnitude < radius * radius);
        }
예제 #4
0
        int GetBox(NavMeshNode node, IntRect bounds)
        {
            if (count >= arr.Length)
            {
                EnsureCapacity(count + 1);
            }

            arr[count] = new BBTreeBox(node, bounds);
            count++;
            return(count - 1);
        }
예제 #5
0
        public override void Init(INavData data)
        {
            navData = data as NavMeshData;

            for (int i = 0; i < navData.nodes.Length; i++)
            {
                NavMeshNode node = navData.nodes[i] as NavMeshNode;
                AddNode(node);
            }

            bbTree.RebuildFrom(navData.nodes);
        }
예제 #6
0
        public static void Optimize(ref List <AStarNode> path, ref List <Int3> vectorPath)
        {
            if (path == null || path.Count == 0 || vectorPath == null || vectorPath.Count != path.Count)
            {
                return;
            }

            funnelPath.Clear();
            left.Clear();
            right.Clear();

            // Add start point
            left.Add(vectorPath[0]);
            right.Add(vectorPath[0]);

            for (int i = 0; i < path.Count - 1; i++)
            {
                NavMeshNode node0 = path[i] as NavMeshNode;
                NavMeshNode node1 = path[i + 1] as NavMeshNode;
                // Get the portal between path[i] and path[i+1] and add it to the left and right lists
                bool portalWasAdded = node0.GetPortal(node1, left, right);

                if (!portalWasAdded)
                {
                    // Fallback, just use the positions of the nodes
                    left.Add(node0.position);
                    right.Add(node0.position);

                    left.Add(node1.position);
                    right.Add(node1.position);
                }
            }

            // Add end point
            left.Add(vectorPath[vectorPath.Count - 1]);
            right.Add(vectorPath[vectorPath.Count - 1]);

            if (!RunFunnel(left, right, funnelPath))
            {
                // If funnel algorithm failed, degrade to simple line
                funnelPath.Add(vectorPath[0]);
                funnelPath.Add(vectorPath[vectorPath.Count - 1]);
            }

            vectorPath.Clear();
            vectorPath.AddRange(funnelPath);

            left.Clear();
            right.Clear();
        }
예제 #7
0
        private void FindPath(ProcessingNode start, ProcessingNode end, AStarContext context)
        {
            ProcessingNode endNode = DoAStar(context);

            context.rawPathNodeCache.Clear();
            context.rawPathPoints.Clear();
            ProcessingNode pathNode = endNode;

            while (pathNode != null)
            {
                NavMeshNode navNode = pathNode.astarNode as NavMeshNode;
                context.rawPathNodeCache.Add(navNode);
                context.rawPathPoints.Add(navNode.position);
                pathNode = pathNode.prev;
            }
        }
예제 #8
0
        /// <summary>
        /// calculate tactical G
        /// </summary>
        private int TacticalCost(NavMeshNode prevNode, NavMeshNode currentNode, AStarContext context)
        {
            int distCost = prevNode.GetConnectionCost(currentNode.id);
            int tacCost  = 0;

            PathFindingRequest request = context.Request as PathFindingRequest;

            // doer's team
            TwGame.Team team = (TwGame.Team)request.extend1;

            switch (team)
            {
            case TwGame.Team.Neutral:
                tacCost = 0;
                break;

            case TwGame.Team.Team_1:
            case TwGame.Team.Team_2:
            {
                int MaxInfluence = TwGame.ComInfluenceMap.MaxTeamStrengthValue;
                int cur          = TwGame.AIUtil.GetTeamStrength(currentNode.position, team);
                int pre          = TwGame.AIUtil.GetTeamStrength(prevNode.position, team);
                // avarage influence between current node's position and previous node's position.
                int infl = (cur + pre) >> 1;
                if (infl > 0)
                {
                    tacCost = System.Math.Max(-distCost + 1, -distCost * infl / MaxInfluence);
                }
                else if (infl < 0)
                {
                    tacCost = -distCost * infl / MaxInfluence * 2;
                }
            }
            break;
            }

            return(distCost + tacCost);
        }
예제 #9
0
        public NavMeshNode GetNeighborByEdge(int edge, out int otherEdge)
        {
            otherEdge = -1;
            if (((edge < 0) || (edge > 2)) || (this.connections == null))
            {
                return(null);
            }

            Int3 vertex0 = this.GetVertex(edge % 3);
            Int3 vertex1 = this.GetVertex((edge + 1) % 3);

            for (int i = 0; i < connections.Length; i++)
            {
                NavMeshNode node2 = graph.GetNode(connections[i]) as NavMeshNode;
                if (node2 != null)
                {
                    if ((node2.v1 == vertex0) && (node2.v0 == vertex1))
                    {
                        otherEdge = 0;
                    }
                    else if ((node2.v2 == vertex0) && (node2.v1 == vertex1))
                    {
                        otherEdge = 1;
                    }
                    else if ((node2.v0 == vertex0) && (node2.v2 == vertex1))
                    {
                        otherEdge = 2;
                    }
                    if (otherEdge != -1)
                    {
                        return(node2);
                    }
                }
            }
            return(null);
        }
예제 #10
0
 public BBTreeBox(NavMeshNode node, IntRect rect)
 {
     this.node = node;
     this.rect = rect;
     left      = right = -1;
 }
예제 #11
0
 public BBTreeBox(IntRect rect)
 {
     node      = null;
     this.rect = rect;
     left      = right = -1;
 }
예제 #12
0
        public override void OnDrawGizmosSelected(Transform transform)
        {
#if UNITY_EDITOR
            if (navmeshMaterial == null)
            {
                navmeshMaterial = UnityEditor.AssetDatabase.LoadAssetAtPath <Material>(editorAssets + "/Materials/Navmesh.mat");
                if (navmeshMaterial == null)
                {
                    editorAssets    = "Assets/Scripts/PathFinding/Editor/EditorAssets";
                    navmeshMaterial = UnityEditor.AssetDatabase.LoadAssetAtPath <Material>(editorAssets + "/Materials/Navmesh.mat");
                }
                if (navmeshMaterial == null)
                {
                    editorAssets    = "Assets/Editor/PathFinding/EditorAssets";
                    navmeshMaterial = UnityEditor.AssetDatabase.LoadAssetAtPath <Material>(editorAssets + "/Materials/Navmesh.mat");
                }
                //navmeshOutlineMaterial = UnityEditor.AssetDatabase.LoadAssetAtPath<Material>(editorAssets + "/Materials/NavmeshOutline.mat");
            }
#endif

            Matrix4x4 defaultMatrix = Gizmos.matrix;
            Gizmos.matrix = transform.localToWorldMatrix;
            Color defaultColor = Gizmos.color;

            // begin draw

            if (ShowOutline)
            {
                NavMeshNode[] nodes = this.nodes;
                for (int i = 0; i < nodes.Length; i++)
                {
                    NavMeshNode node = nodes[i] as NavMeshNode;

                    float a1 = VectorMath.SignedTriangleAreaTimes2XZ((Vector3)node.v0, (Vector3)node.v1, (Vector3)node.v2);

                    long a2 = VectorMath.SignedTriangleAreaTimes2XZ(node.v0, node.v1, node.v2);
                    if (a1 * a2 < 0)
                    {
                        Debug.LogError(a1 + " " + a2);
                    }

                    Vector3 up = Vector3.up * 0.01f;
                    if (VectorMath.IsClockwiseXZ(node.v0, node.v1, node.v2))
                    {
                        Debug.DrawLine((Vector3)node.v0, up + (Vector3)node.v1, lineColor);
                        Debug.DrawLine((Vector3)node.v1, up + (Vector3)node.v2, lineColor);
                        Debug.DrawLine((Vector3)node.v2, up + (Vector3)node.v0, lineColor);
                    }
                    else
                    {
                        Debug.DrawLine((Vector3)node.v0, up + (Vector3)node.v1, Color.red);
                        Debug.DrawLine((Vector3)node.v1, up + (Vector3)node.v2, Color.red);
                        Debug.DrawLine((Vector3)node.v2, up + (Vector3)node.v0, Color.red);
                    }
                }
            }

            UpdateGizmoMeshes();

            if (ShowMesh)
            {
                for (int pass = 0; pass <= 2; pass++)
                {
                    if (navmeshMaterial != null)
                    {
                        navmeshMaterial.SetPass(pass);
                    }
                    for (int i = 0; i < gizmoMeshes.Count; i++)
                    {
                        Graphics.DrawMeshNow(gizmoMeshes[i].surfaceMesh, Matrix4x4.identity);
                    }
                }
            }

            /*for (int i = 0; i < insertPoints.Count; i+=3)
             * {
             *      Debug.DrawLine(Vector3.up + (Vector3)insertPoints[i], Vector3.up + (Vector3)insertPoints[i + 1], Color.green);
             *      Debug.DrawLine(Vector3.up + (Vector3)insertPoints[i + 1], Vector3.up + (Vector3)insertPoints[i + 2], Color.green);
             *      Debug.DrawLine(Vector3.up + (Vector3)insertPoints[i + 2], Vector3.up + (Vector3)insertPoints[i], Color.green);
             * }*/


            // end draw
            Gizmos.color  = defaultColor;
            Gizmos.matrix = defaultMatrix;
        }
예제 #13
0
        void GenerateNodes(int[] triangles, Int3[] vertices)
        {
            UnityEngine.Profiling.Profiler.BeginSample("Constructing Nodes");

            nodes = new NavMeshNode[triangles.Length / 3];

            for (int i = 0; i < nodes.Length; i++)
            {
                nodes[i] = new NavMeshNode(i);
                NavMeshNode node = nodes[i];

                node.Penalty  = initialPenalty;
                node.Walkable = true;

                node.v0 = vertices[triangles[i * 3]];
                node.v1 = vertices[triangles[i * 3 + 1]];
                node.v2 = vertices[triangles[i * 3 + 2]];

                if (!VectorMath.IsClockwiseXZ(node.v0, node.v1, node.v2))
                {
                    Int3 tmp = node.v0;
                    node.v0 = node.v2;
                    node.v2 = tmp;
                }

                if (VectorMath.IsColinearXZ(node.v0, node.v1, node.v2))
                {
                    Debug.DrawLine((Vector3)node.v0, (Vector3)node.v1, Color.red);
                    Debug.DrawLine((Vector3)node.v1, (Vector3)node.v2, Color.red);
                    Debug.DrawLine((Vector3)node.v2, (Vector3)node.v0, Color.red);
                }

                // Make sure position is correctly set
                node.UpdatePositionFromVertices();
            }

            UnityEngine.Profiling.Profiler.EndSample();

            var sides = new Dictionary <Int2, NavMeshNode>();

            for (int i = 0, j = 0; i < triangles.Length; j += 1, i += 3)
            {
                sides[new Int2(triangles[i + 0], triangles[i + 1])] = nodes[j];
                sides[new Int2(triangles[i + 1], triangles[i + 2])] = nodes[j];
                sides[new Int2(triangles[i + 2], triangles[i + 0])] = nodes[j];
            }

            UnityEngine.Profiling.Profiler.BeginSample("Connecting Nodes");

            var connections     = new List <int>();
            var connectionCosts = new List <int>();

            for (int i = 0, j = 0; i < triangles.Length; j += 1, i += 3)
            {
                connections.Clear();
                connectionCosts.Clear();

                NavMeshNode node = nodes[j];

                for (int q = 0; q < 3; q++)
                {
                    NavMeshNode other;
                    if (sides.TryGetValue(new Int2(triangles[i + ((q + 1) % 3)], triangles[i + q]), out other))
                    {
                        connections.Add(other.id);
                        connectionCosts.Add((node.position - other.position).costMagnitude);
                    }
                }

                node.connections     = connections.ToArray();
                node.connectionCosts = connectionCosts.ToArray();
            }

            UnityEngine.Profiling.Profiler.EndSample();

            UnityEngine.Profiling.Profiler.BeginSample("Rebuilding BBTree");

            //RebuildBBTree(this);

            UnityEngine.Profiling.Profiler.EndSample();

            //Debug.Log("Node Count " + nodes.Length);
        }
예제 #14
0
 static Int3 ClosestPointOnNode(NavMeshNode node, Int3 pos)
 {
     return(Polygon.ClosestPointOnTriangle(node.v0, node.v1, node.v2, pos));
 }
예제 #15
0
        public override bool LineCastForMoving(ref HitInfo hit, MoveType mov)
        {
            Int3 from = hit.from;
            Int3 to   = hit.to;

            hit.hitPosition = from;

            if (trace != null)
            {
                trace.Clear();
            }

            Int3 end    = to;
            Int3 origin = from;

            if (origin == end)
            {
                hit.hitPosition = from;
                return(false);
            }

            NavMeshNode node = GetNearest(from, NNConstraint.None).node;

            if (node == null)
            {
                Debug.LogError("Could not find a valid node to start from");
                hit.hitPosition = from;
                return(true);
            }

            origin = node.ClosestPointOnNode(origin);

            List <Int3> left = Util.ListPool <Int3> .Claim();

            List <Int3> right = Util.ListPool <Int3> .Claim();

            int counter = 0;

            while (true)
            {
                counter++;
                if (counter > 2000)
                {
                    Debug.LogError("Linecast was stuck in infinite loop. Breaking.");
                    Util.ListPool <Int3> .Release(left);

                    Util.ListPool <Int3> .Release(right);

                    return(true);
                }

                NavMeshNode newNode = null;

                if (trace != null)
                {
                    trace.Add(node);
                }

                if (node.ContainsPoint(end))
                {
                    hit.hitPosition = to;
                    Util.ListPool <Int3> .Release(left);

                    Util.ListPool <Int3> .Release(right);

                    return(false);
                }

                for (int i = 0; i < node.connections.Length; i++)
                {
                    left.Clear();
                    right.Clear();

                    NavMeshNode other = GetNode(node.connections[i]) as NavMeshNode;
                    if (!node.GetPortal(other, left, right))
                    {
                        continue;
                    }

                    Int3 a = left[0];
                    Int3 b = right[0];

                    //i.e Left or colinear
                    if (!VectorMath.RightXZ(a, b, origin))
                    {
                        if (VectorMath.RightXZ(a, b, end))
                        {
                            //Since polygons are laid out in clockwise order, the ray would intersect (if intersecting) this edge going in to the node, not going out from it
                            continue;
                        }
                    }

                    float factor1, factor2;

                    if (VectorMath.LineIntersectionFactorXZ(a, b, origin, end, out factor1, out factor2))
                    {
                        //Intersection behind the start
                        if (factor2 < 0)
                        {
                            continue;
                        }

                        if (factor1 >= 0 && factor1 <= 1)
                        {
                            newNode = other;
                            break;
                        }
                    }
                }

                if (newNode == null)
                {
                    //Possible edge hit
                    int vs = node.GetVertexCount();

                    for (int i = 0; i < vs; i++)
                    {
                        var a = node.GetVertex(i);
                        var b = node.GetVertex((i + 1) % vs);


                        //i.e left or colinear
                        if (!VectorMath.RightXZ(a, b, origin))
                        {
                            //Since polygons are laid out in clockwise order, the ray would intersect (if intersecting) this edge going in to the node, not going out from it
                            if (VectorMath.RightXZ(a, b, end))
                            {
                                //Since polygons are laid out in clockwise order, the ray would intersect (if intersecting) this edge going in to the node, not going out from it
                                continue;
                            }
                        }

                        float factor1, factor2;
                        if (VectorMath.LineIntersectionFactorXZ(a, b, origin, end, out factor1, out factor2))
                        {
                            if (factor2 < 0)
                            {
                                continue;
                            }

                            if (factor1 >= 0 && factor1 <= 1)
                            {
                                Vector3 intersectionPoint = (Vector3)a + (Vector3)(b - a) * factor1;
                                hit.hitPosition = new Int3(intersectionPoint);

                                Util.ListPool <Int3> .Release(left);

                                Util.ListPool <Int3> .Release(right);

                                return(true);
                            }
                        }
                    }

                    //Ok, this is wrong...
                    Debug.LogWarning("Linecast failing because point not inside node, and line does not hit any edges of it");

                    Util.ListPool <Int3> .Release(left);

                    Util.ListPool <Int3> .Release(right);

                    return(false);
                }

                node = newNode;
            }
        }