Inheritance: NavGraph, IUpdatableGraph
Esempio n. 1
0
 protected override void DrawNeighbours(GridGraph graph)
 {
     graph.neighbours = NumNeighbours.Four;
     EditorGUI.BeginDisabledGroup(true);
     EditorGUILayout.EnumPopup (new GUIContent ("Connections","Only 4 connections per node is possible on layered grid graphs"),graph.neighbours);
     EditorGUI.EndDisabledGroup();
 }
Esempio n. 2
0
    public void Reset()
    {
        foreach (var t in GameObject.FindGameObjectsWithTag("Tower"))
        {
            Destroy(t);
        }


        gg = AstarPath.active.astarData.gridGraph;

        BuildingPlane = new Plane(Vector3.up, gg.center);

        w = gg.width;
        h = gg.depth;


        towers = new Tower[w * h];

        buildingLocations = new bool[w * h];


        for (int i = 0; i < w * h; i++)
        {
            int ti = i % w;
            int tj = w - 1 - i / w;
            buildingLocations[ti + tj * w] = gg.nodes[i].Walkable;
        }
    }
Esempio n. 3
0
		public static void SetGridGraph (int graphIndex, GridGraph graph) {
			if (_gridGraphs.Length <= graphIndex) {
				var gg = new GridGraph[graphIndex+1];
				for (int i = 0; i < _gridGraphs.Length; i++) gg[i] = _gridGraphs[i];
				_gridGraphs = gg;
			}

			_gridGraphs[graphIndex] = graph;
		}
		protected override void DrawMaxClimb (GridGraph graph) {
			var layerGridGraph = graph as LayerGridGraph;

			base.DrawMaxClimb(graph);
			layerGridGraph.maxClimb = Mathf.Clamp(layerGridGraph.maxClimb, 0, layerGridGraph.characterHeight);

			if (layerGridGraph.maxClimb == layerGridGraph.characterHeight) {
				EditorGUILayout.HelpBox("Max climb needs to be smaller or equal to character height", MessageType.Info);
			}
		}
Esempio n. 5
0
    private IEnumerator newMazeGame()
    {
        mainLight = GameObject.FindWithTag("MainLight");

        menuControl.loadingState = "Generating Maze...";
        MazeGenerator mazeGenerator = GameObject.FindWithTag("Maze").GetComponent <MazeGenerator>();

        yield return(new WaitForEndOfFrame());

        mazeGenerator.newMaze(5 * (((int)difficulty) + 1));
        yield return(new WaitForEndOfFrame());

        menuControl.loadingState = "Funerizing Maze...";
        yield return(mazeGenerator.StartCoroutine("removeRandomWalls"));

        menuControl.loadingState = "Generating navmesh...";
        Pathfinding.GridGraph graph = (Pathfinding.GridGraph)AstarPath.active.graphs[0];
        int   graphSize             = 50 * ((((int)difficulty) + 1));
        float pos = graphSize / 2 * graph.nodeSize;

        graph.width  = graphSize;
        graph.depth  = graphSize;
        graph.center = new Vector3(pos, 0, pos);
        graph.UpdateSizeFromWidthDepth();
        AstarPath.active.Scan();
        yield return(new WaitForEndOfFrame());

        menuControl.loadingState = "Generating keys and exit...";
        keysOnMap = (((int)difficulty) + 1) * 2;
        spawnControl.spawnPoints = new List <MazeNode>(mazeGenerator.spawnPoints);
        spawnControl.spawnKeys(keysOnMap);
        spawnControl.spawnDoor();
        yield return(new WaitForEndOfFrame());

        menuControl.loadingState = "Spawning player...";
        player = spawnControl.spawnPlayer();
        yield return(new WaitForEndOfFrame());

        menuControl.loadingState = "Spawning enemy...";
        enemies                  = new List <GameObject>();
        enemiesChasing           = new List <GameObject>();
        spawnControl.spawnPoints = new List <MazeNode>(mazeGenerator.spawnPoints);
        for (int i = 0; i < ((int)difficulty); i++)
        {
            spawnEnemy();
        }
        yield return(new WaitForEndOfFrame());

        menuControl.loadingState = "Initialising game...";
        audioControl.playAsset(ambience);
        StartCoroutine(updateParameterWithList(enemies, true));
        loading = false;
        setGameOver(false);
    }
Esempio n. 6
0
 public void CutCorners(int Value)
 {
     Pathfinding.GridGraph gGraph = AstarPath.active.data.gridGraph;
     if (Value == 0)
     {
         gGraph.cutCorners = true;
     }
     else if (Value == 1)
     {
         gGraph.cutCorners = false;
     }
 }
		protected override void DrawMiddleSection (GridGraph graph) {
			var layerGridGraph = graph as LayerGridGraph;

			DrawNeighbours(graph);

			layerGridGraph.characterHeight = EditorGUILayout.FloatField("Character Height", layerGridGraph.characterHeight);
			DrawMaxClimb(graph);

			DrawMaxSlope(graph);
			DrawErosion(graph);

			layerGridGraph.mergeSpanRange = EditorGUILayout.FloatField("Merge Span Range", layerGridGraph.mergeSpanRange);
		}
Esempio n. 8
0
    public void makepath()
    {
        FindAllStones();
        FindAllTrees();
        foreach (GameObject item in GameObject.FindGameObjectsWithTag("Mark"))
        {
            Destroy(item);
        }
        int msize = (int)fireplaceStats.maxDistance.Value;

        gGraph       = AstarPath.active.data.gridGraph;
        gGraph.width = msize;
        gGraph.depth = msize;
        gGraph.UpdateSizeFromWidthDepth();
        markLD.SetActive(true);
        markLU.SetActive(true);
        markRD.SetActive(true);
        markRU.SetActive(true);
        markLD.transform.position = transform.position + new Vector3(-msize / 4 + 0.2f, -msize / 4 + 1.5f);
        markLU.transform.position = transform.position + new Vector3(-msize / 4 + 0.2f, msize / 4 + 1);
        markRD.transform.position = transform.position + new Vector3(msize / 4 - 0.2f, -msize / 4 + 1.5f);
        markRU.transform.position = transform.position + new Vector3(msize / 4 - 0.2f, msize / 4 + 1);
        for (int i = -msize / 4; i < msize / 4; i += 10)
        {
            GameObject mark = GameObject.Instantiate(marker, transform.position + new Vector3(-msize / 4 + 0.2f, i), Quaternion.identity);
            mark.SetActive(true);
            mark.transform.parent = this.transform;
        }
        for (int i = -msize / 4; i < msize / 4; i += 10)
        {
            GameObject mark = GameObject.Instantiate(marker, transform.position + new Vector3(msize / 4 + 0.2f, i), Quaternion.identity);
            mark.SetActive(true);
            mark.transform.parent = this.transform;
        }
        for (int i = -msize / 4; i < msize / 4; i += 10)
        {
            GameObject mark = GameObject.Instantiate(marker, transform.position + new Vector3(i, msize / 4 + 0.2f), Quaternion.identity);
            mark.SetActive(true);
            mark.transform.parent = this.transform;
        }
        for (int i = -msize / 4; i < msize / 4; i += 10)
        {
            GameObject mark = GameObject.Instantiate(marker, transform.position + new Vector3(i, -msize / 4 + 0.2f), Quaternion.identity);
            mark.SetActive(true);
            mark.transform.parent = this.transform;
        }

        gGraph.center = transform.position;
        AstarPath.active.Scan();
    }
		void DrawFirstSection (GridGraph graph) {
			DrawWidthDepthFields (graph);

			newNodeSize = EditorGUILayout.FloatField (new GUIContent ("Node size","The size of a single node. The size is the side of the node square in world units"),graph.nodeSize);

			newNodeSize = newNodeSize <= 0.01F ? 0.01F : newNodeSize;

			float prevRatio = graph.aspectRatio;
			graph.aspectRatio = EditorGUILayout.FloatField (new GUIContent ("Aspect Ratio","Scaling of the nodes width/depth ratio. Good for isometric games"),graph.aspectRatio);

			DrawIsometricField(graph);

			if (graph.nodeSize != newNodeSize || prevRatio != graph.aspectRatio) {
				if (!locked) {
					graph.nodeSize = newNodeSize;
					Matrix4x4 oldMatrix = graph.matrix;
					graph.GenerateMatrix ();
					if (graph.matrix != oldMatrix) {
						//Rescann the graphs
						//AstarPath.active.AutoScan ();
						GUI.changed = true;
					}
				} else {
					int tmpWidth = graph.width;
					int tmpDepth = graph.depth;

					float delta = newNodeSize / graph.nodeSize;
					graph.nodeSize = newNodeSize;
					graph.unclampedSize = RoundVector3 (new Vector2 (tmpWidth*graph.nodeSize,tmpDepth*graph.nodeSize));
					Vector3 newCenter = graph.matrix.MultiplyPoint3x4 (new Vector3 ((tmpWidth/2F)*delta,0,(tmpDepth/2F)*delta));
					graph.center = RoundVector3 (newCenter);

					graph.GenerateMatrix ();

					//Make sure the width & depths stay the same
					graph.width = tmpWidth;
					graph.depth = tmpDepth;
					AutoScan ();
				}
			}

			DrawPositionField(graph);

			graph.rotation = EditorGUILayout.Vector3Field ("Rotation", graph.rotation);

			if (GUILayout.Button (new GUIContent ("Snap Size","Snap the size to exactly fit nodes"), GUILayout.MaxWidth (100), GUILayout.MaxHeight (16))) {
				SnapSizeToNodes (graph.width,graph.depth,graph);
			}
		}
Esempio n. 10
0
 public void Heuristic(int Value)
 {
     Pathfinding.GridGraph gGraph = AstarPath.active.data.gridGraph;
     if (Value == 0)
     {
         gGraph.active.heuristic = Pathfinding.Heuristic.Euclidean;
     }
     else if (Value == 1)
     {
         gGraph.active.heuristic = Pathfinding.Heuristic.DiagonalManhattan;
     }
     else if (Value == 2)
     {
         gGraph.active.heuristic = Pathfinding.Heuristic.Manhattan;
     }
     else if (Value == 3)
     {
         gGraph.active.heuristic = Pathfinding.Heuristic.None;
     }
 }
        public static int SetGridGraph(GridGraph graph)
        {
            if (gridGraphs == null) {
                gridGraphs = new GridGraph[1];
            } else {

                for (int i=0;i<gridGraphs.Length;i++) {
                    if (gridGraphs[i] == graph) {
                        return i;
                    }
                }

                GridGraph[] tmp = new GridGraph[gridGraphs.Length+1];
                for (int i=0;i<gridGraphs.Length;i++) {
                    tmp[i] = gridGraphs[i];
                }
                gridGraphs = tmp;
            }

            gridGraphs[gridGraphs.Length-1] = graph;
            return gridGraphs.Length-1;
        }
Esempio n. 12
0
    //private bool equationCorrect;

    /* void Start()
     * {
     *   equation = dangerEquation.GetComponentInChildren<InputField>();
     *   dangerEquationInfo = dangerEquation.transform.Find("Info").GetComponent<Text>();
     *   saveDangerEqButton = dangerEquation.GetComponentInChildren<Button>();
     *
     *   nightAtack = GameObject.FindGameObjectWithTag("DayNightSystem").GetComponent<EnemiesNightAtack>();
     *   equation.text= nightAtack.difficultyEquation;
     *   IsEquationCorrect(nightAtack.difficultyEquation);
     *
     *  Pathfinding.GridGraph gGraph = AstarPath.active.data.gridGraph;
     *   diameter.value = gGraph.collision.diameter;
     *   nearestNode.value = gGraph.active.maxNearestNodeDistance;
     *   heuristicScale.value = gGraph.active.heuristicScale;
     *
     * }*/
    private void OnEnable()
    {
        AddWorldStats();
        if (dangerEquation != null)
        {
            equation           = dangerEquation.GetComponentInChildren <InputField>();
            dangerEquationInfo = dangerEquation.transform.Find("Info").GetComponent <Text>();
            saveDangerEqButton = dangerEquation.GetComponentInChildren <Button>();

            nightAtack     = GameObject.FindGameObjectWithTag("DayNightSystem").GetComponent <EnemiesNightAtack>();
            dayNightSystem = GameObject.FindGameObjectWithTag("DayNightSystem").GetComponent <DayNightSystem>();
            equation.text  = nightAtack.difficultyEquation;
            IsEquationCorrect(nightAtack.difficultyEquation);

            daySlider.value  = dayNightSystem.dayTime;
            nightSider.value = dayNightSystem.nightTime;

            Pathfinding.GridGraph gGraph = AstarPath.active.data.gridGraph;
            diameter.value       = gGraph.collision.diameter;
            nearestNode.value    = gGraph.active.maxNearestNodeDistance;
            heuristicScale.value = gGraph.active.heuristicScale;
        }
    }
        public static void RemoveGridGraph(GridGraph graph)
        {
            if (gridGraphs == null) {
                return;
            }

            for (int i=0;i<gridGraphs.Length;i++) {
                if (gridGraphs[i] == graph) {
                    if (gridGraphs.Length == 1) {
                        gridGraphs = null;
                        return;
                    }

                    for (int j=i+1;j<gridGraphs.Length;j++) {

                        GridGraph gg = gridGraphs[j];

                        if (gg.nodes != null) {
                            for (int n=0;n<gg.nodes.Length;n++) {
                                if (gg.nodes[n] != null)
                                    ((GridNode)gg.nodes[n]).SetGridIndex (j-1);
                            }
                        }
                    }

                    GridGraph[] tmp = new GridGraph[gridGraphs.Length-1];
                    for (int j=0;j<i;j++) {
                        tmp[j] = gridGraphs[j];
                    }
                    for (int j=i+1;j<gridGraphs.Length;j++) {
                        tmp[j-1] = gridGraphs[j];
                    }
                    return;
                }
            }
        }
Esempio n. 14
0
 protected void DrawMaxSlope(GridGraph graph)
 {
     graph.maxSlope = EditorGUILayout.Slider(new GUIContent("Max Slope", "Sets the max slope in degrees for a point to be walkable. Only enabled if Height Testing is enabled."), graph.maxSlope, 0, 90F);
 }
Esempio n. 15
0
        public override Vector3 RandomPointOnSurface()
        {
            GridGraph gg = GridNode.GetGridGraph(GraphIndex);

            return((Vector3)position + new Vector3(Random.value - 0.5f, 0, Random.value - 0.5f) * gg.nodeSize);
        }
 bool IsHexagonal(GridGraph graph)
 {
     return(Mathf.Approximately(graph.isometricAngle, standardIsometric) && graph.neighbours == NumNeighbours.Six && graph.uniformEdgeCosts);
 }
 static bool Is2D(GridGraph graph)
 {
     return(Quaternion.Euler(graph.rotation) * Vector3.up == -Vector3.forward);
 }
Esempio n. 18
0
        //GraphUndo undoState;
        //byte[] savedBytes;

        public override void OnSceneGUI(NavGraph target)
        {
            Event e = Event.current;



            GridGraph graph = target as GridGraph;

            Matrix4x4 matrixPre = graph.matrix;

            graph.GenerateMatrix();

            if (e.type == EventType.MouseDown)
            {
                isMouseDown = true;
            }
            else if (e.type == EventType.MouseUp)
            {
                isMouseDown = false;
            }

            if (!isMouseDown)
            {
                savedMatrix = graph.boundsMatrix;
            }

            Handles.matrix = savedMatrix;

            if ((graph.GetType() == typeof(GridGraph) && graph.nodes == null) || (graph.uniformWidthDepthGrid && graph.depth * graph.width != graph.nodes.Length) || graph.matrix != matrixPre)
            {
                //Rescan the graphs
                if (AutoScan())
                {
                    GUI.changed = true;
                }
            }

            Matrix4x4 inversed = savedMatrix.inverse;

            Handles.color = AstarColor.BoundsHandles;

            Handles.DrawCapFunction cap = Handles.CylinderCap;

            Vector2 extents = graph.unclampedSize * 0.5F;

            Vector3 center = inversed.MultiplyPoint3x4(graph.center);


        #if UNITY_3_3
            if (Tools.current == 3)
            {
        #else
            if (Tools.current == Tool.Scale)
            {
        #endif

                Vector3 p1 = Handles.Slider(center + new Vector3(extents.x, 0, 0), Vector3.right, 0.1F * HandleUtility.GetHandleSize(center + new Vector3(extents.x, 0, 0)), cap, 0);
                Vector3 p2 = Handles.Slider(center + new Vector3(0, 0, extents.y), Vector3.forward, 0.1F * HandleUtility.GetHandleSize(center + new Vector3(0, 0, extents.y)), cap, 0);
                //Vector3 p3 = Handles.Slider (center+new Vector3 (0,extents.y,0),	Vector3.up,			0.1F*HandleUtility.GetHandleSize (center+new Vector3 (0,extents.y,0)),cap,0);

                Vector3 p4 = Handles.Slider(center + new Vector3(-extents.x, 0, 0), -Vector3.right, 0.1F * HandleUtility.GetHandleSize(center + new Vector3(-extents.x, 0, 0)), cap, 0);
                Vector3 p5 = Handles.Slider(center + new Vector3(0, 0, -extents.y), -Vector3.forward, 0.1F * HandleUtility.GetHandleSize(center + new Vector3(0, 0, -extents.y)), cap, 0);

                Vector3 p6 = Handles.Slider(center, Vector3.up, 0.1F * HandleUtility.GetHandleSize(center), cap, 0);

                Vector3 r1 = new Vector3(p1.x, p6.y, p2.z);
                Vector3 r2 = new Vector3(p4.x, p6.y, p5.z);

                //Debug.Log (graph.boundsMatrix.MultiplyPoint3x4 (Vector3.zero)+" "+graph.boundsMatrix.MultiplyPoint3x4 (Vector3.one));

                //if (Tools.viewTool != ViewTool.Orbit) {

                graph.center = savedMatrix.MultiplyPoint3x4((r1 + r2) / 2F);

                Vector3 tmp = r1 - r2;
                graph.unclampedSize = new Vector2(tmp.x, tmp.z);

                //}

        #if UNITY_3_3
            }
            else if (Tools.current == 1)
            {
        #else
            }
            else if (Tools.current == Tool.Move)
            {
        #endif

                if (Tools.pivotRotation == PivotRotation.Local)
                {
                    center = Handles.PositionHandle(center, Quaternion.identity);

                    if (Tools.viewTool != ViewTool.Orbit)
                    {
                        graph.center = savedMatrix.MultiplyPoint3x4(center);
                    }
                }
                else
                {
                    Handles.matrix = Matrix4x4.identity;

                    center = Handles.PositionHandle(graph.center, Quaternion.identity);

                    if (Tools.viewTool != ViewTool.Orbit)
                    {
                        graph.center = center;
                    }
                }
        #if UNITY_3_3
            }
            else if (Tools.current == 2)
            {
        #else
            }
            else if (Tools.current == Tool.Rotate)
            {
        #endif
                //The rotation handle doesn't seem to be able to handle different matrixes of some reason
                Handles.matrix = Matrix4x4.identity;

                Quaternion rot = Handles.RotationHandle(Quaternion.Euler(graph.rotation), graph.center);

                if (Tools.viewTool != ViewTool.Orbit)
                {
                    graph.rotation = rot.eulerAngles;
                }
            }

            //graph.size.x = Mathf.Max (graph.size.x,1);
            //graph.size.y = Mathf.Max (graph.size.y,1);
            //graph.size.z = Mathf.Max (graph.size.z,1);

            Handles.matrix = Matrix4x4.identity;



        #if ASTARDEBUG
            //Draws some info over the node closest to the mouse
            Ray ray = HandleUtility.GUIPointToWorldRay(Event.current.mousePosition);

            Vector3 p = ray.GetPoint(100);


            if (Event.current.shift)
            {
                GraphNode close = graph.GetNearest(p).node;

                if (close != null)
                {
                    node1 = close;
                }

                if (node1 == null)
                {
                    return;
                }

                Handles.SphereCap(0, (Vector3)node1.position, Quaternion.identity, graph.nodeSize * 0.5F);


                //Node node = node1;

                GUI.color = Color.white;
                //Handles.Label((Vector3)node.position + Vector3.up*2,"G : "+node.+"\nH : "+node.h+"\nF : "+node.f+"\nPosition : "+node.position.ToString (),EditorStyles.whiteBoldLabel);
            }
        #endif
        }
Esempio n. 19
0
        public override void OnInspectorGUI(NavGraph target)
        {
            GridGraph graph = target as GridGraph;

            //GUILayout.BeginHorizontal ();
            //GUILayout.BeginVertical ();
            Rect lockRect;

            GUIStyle lockStyle = AstarPathEditor.astarSkin.FindStyle("GridSizeLock");

            if (lockStyle == null)
            {
                lockStyle = new GUIStyle();
            }

        #if !UNITY_LE_4_3 || true
            GUILayout.BeginHorizontal();
            GUILayout.BeginVertical();
            int newWidth = EditorGUILayout.IntField(new GUIContent("Width (nodes)", "Width of the graph in nodes"), graph.width);
            int newDepth = EditorGUILayout.IntField(new GUIContent("Depth (nodes)", "Depth (or height you might also call it) of the graph in nodes"), graph.depth);
            GUILayout.EndVertical();

            lockRect = GUILayoutUtility.GetRect(lockStyle.fixedWidth, lockStyle.fixedHeight);

            // Add a small offset to make it better centred around the controls
            lockRect.y += 3;
            GUILayout.EndHorizontal();

            // All the layouts mess up the margin to the next control, so add it manually
            GUILayout.Space(2);
        #elif UNITY_4
            Rect tmpLockRect;
            int  newWidth = IntField(new GUIContent("Width (nodes)", "Width of the graph in nodes"), graph.width, 100, 0, out lockRect, out sizeSelected1);
            int  newDepth = IntField(new GUIContent("Depth (nodes)", "Depth (or height you might also call it) of the graph in nodes"), graph.depth, 100, 0, out tmpLockRect, out sizeSelected2);
        #else
            Rect tmpLockRect;
            int  newWidth = IntField(new GUIContent("Width (nodes)", "Width of the graph in nodes"), graph.width, 50, 0, out lockRect, out sizeSelected1);
            int  newDepth = IntField(new GUIContent("Depth (nodes)", "Depth (or height you might also call it) of the graph in nodes"), graph.depth, 50, 0, out tmpLockRect, out sizeSelected2);
        #endif

            lockRect.width  = lockStyle.fixedWidth;
            lockRect.height = lockStyle.fixedHeight;
            lockRect.x     += lockStyle.margin.left;
            lockRect.y     += lockStyle.margin.top;

            locked = GUI.Toggle(lockRect, locked, new GUIContent("", "If the width and depth values are locked, changing the node size will scale the grid which keeping the number of nodes consistent instead of keeping the size the same and changing the number of nodes in the graph"), lockStyle);

            //GUILayout.EndHorizontal ();

            if (newWidth != graph.width || newDepth != graph.depth)
            {
                SnapSizeToNodes(newWidth, newDepth, graph);
            }

            GUI.SetNextControlName("NodeSize");
            newNodeSize = EditorGUILayout.FloatField(new GUIContent("Node size", "The size of a single node. The size is the side of the node square in world units"), graph.nodeSize);

            newNodeSize = newNodeSize <= 0.01F ? 0.01F : newNodeSize;

            float prevRatio = graph.aspectRatio;
            graph.aspectRatio = EditorGUILayout.FloatField(new GUIContent("Aspect Ratio", "Scaling of the nodes width/depth ratio. Good for isometric games"), graph.aspectRatio);

            if (graph.nodeSize != newNodeSize || prevRatio != graph.aspectRatio)
            {
                if (!locked)
                {
                    graph.nodeSize = newNodeSize;
                    Matrix4x4 oldMatrix = graph.matrix;
                    graph.GenerateMatrix();
                    if (graph.matrix != oldMatrix)
                    {
                        //Rescann the graphs
                        //AstarPath.active.AutoScan ();
                        GUI.changed = true;
                    }
                }
                else
                {
                    float delta = newNodeSize / graph.nodeSize;
                    graph.nodeSize      = newNodeSize;
                    graph.unclampedSize = new Vector2(newWidth * graph.nodeSize, newDepth * graph.nodeSize);
                    Vector3 newCenter = graph.matrix.MultiplyPoint3x4(new Vector3((newWidth / 2F) * delta, 0, (newDepth / 2F) * delta));
                    graph.center = newCenter;
                    graph.GenerateMatrix();

                    //Make sure the width & depths stay the same
                    graph.width = newWidth;
                    graph.depth = newDepth;
                    AutoScan();
                }
            }

            Vector3 pivotPoint;
            Vector3 diff;

        #if UNITY_LE_4_3
            EditorGUIUtility.LookLikeControls();
        #endif

        #if !UNITY_4
            EditorGUILayoutx.BeginIndent();
        #else
            GUILayout.BeginHorizontal();
        #endif

            switch (pivot)
            {
            case GridPivot.Center:
                graph.center = RoundVector3(graph.center);
                graph.center = EditorGUILayout.Vector3Field("Center", graph.center);
                break;

            case GridPivot.TopLeft:
                pivotPoint   = graph.matrix.MultiplyPoint3x4(new Vector3(0, 0, graph.depth));
                pivotPoint   = RoundVector3(pivotPoint);
                diff         = pivotPoint - graph.center;
                pivotPoint   = EditorGUILayout.Vector3Field("Top-Left", pivotPoint);
                graph.center = pivotPoint - diff;
                break;

            case GridPivot.TopRight:
                pivotPoint   = graph.matrix.MultiplyPoint3x4(new Vector3(graph.width, 0, graph.depth));
                pivotPoint   = RoundVector3(pivotPoint);
                diff         = pivotPoint - graph.center;
                pivotPoint   = EditorGUILayout.Vector3Field("Top-Right", pivotPoint);
                graph.center = pivotPoint - diff;
                break;

            case GridPivot.BottomLeft:
                pivotPoint   = graph.matrix.MultiplyPoint3x4(new Vector3(0, 0, 0));
                pivotPoint   = RoundVector3(pivotPoint);
                diff         = pivotPoint - graph.center;
                pivotPoint   = EditorGUILayout.Vector3Field("Bottom-Left", pivotPoint);
                graph.center = pivotPoint - diff;
                break;

            case GridPivot.BottomRight:
                pivotPoint   = graph.matrix.MultiplyPoint3x4(new Vector3(graph.width, 0, 0));
                pivotPoint   = RoundVector3(pivotPoint);
                diff         = pivotPoint - graph.center;
                pivotPoint   = EditorGUILayout.Vector3Field("Bottom-Right", pivotPoint);
                graph.center = pivotPoint - diff;
                break;
            }

            graph.GenerateMatrix();

            pivot = PivotPointSelector(pivot);

        #if !UNITY_4
            EditorGUILayoutx.EndIndent();

            EditorGUILayoutx.BeginIndent();
        #else
            GUILayout.EndHorizontal();
        #endif

            graph.rotation = EditorGUILayout.Vector3Field("Rotation", graph.rotation);

        #if UNITY_LE_4_3
            //Add some space to make the Rotation and postion fields be better aligned (instead of the pivot point selector)
            //GUILayout.Space (19+7);
        #endif
            //GUILayout.EndHorizontal ();

        #if !UNITY_4
            EditorGUILayoutx.EndIndent();
        #endif
        #if UNITY_LE_4_3
            EditorGUIUtility.LookLikeInspector();
        #endif

            if (GUILayout.Button(new GUIContent("Snap Size", "Snap the size to exactly fit nodes"), GUILayout.MaxWidth(100), GUILayout.MaxHeight(16)))
            {
                SnapSizeToNodes(newWidth, newDepth, graph);
            }

            Separator();

            graph.cutCorners = EditorGUILayout.Toggle(new GUIContent("Cut Corners", "Enables or disables cutting corners. See docs for image example"), graph.cutCorners);
            graph.neighbours = (NumNeighbours)EditorGUILayout.EnumPopup(new GUIContent("Connections", "Sets how many connections a node should have to it's neighbour nodes."), graph.neighbours);

            //GUILayout.BeginHorizontal ();
            //EditorGUILayout.PrefixLabel ("Max Climb");
            graph.maxClimb = EditorGUILayout.FloatField(new GUIContent("Max Climb", "How high, relative to the graph, should a climbable level be. A zero (0) indicates infinity"), graph.maxClimb);
            if (graph.maxClimb < 0)
            {
                graph.maxClimb = 0;
            }
            EditorGUI.indentLevel++;
            graph.maxClimbAxis = EditorGUILayout.IntPopup(new GUIContent("Climb Axis", "Determines which axis the above setting should test on"), graph.maxClimbAxis, new GUIContent[3] {
                new GUIContent("X"), new GUIContent("Y"), new GUIContent("Z")
            }, new int[3] {
                0, 1, 2
            });
            EditorGUI.indentLevel--;

            if (graph.maxClimb > 0 && Mathf.Abs((Quaternion.Euler(graph.rotation) * new Vector3(graph.nodeSize, 0, graph.nodeSize))[graph.maxClimbAxis]) > graph.maxClimb)
            {
                EditorGUILayout.HelpBox("Nodes are spaced further apart than this in the grid. You might want to increase this value or change the axis", MessageType.Warning);
            }

            //GUILayout.EndHorizontal ();

            graph.maxSlope = EditorGUILayout.Slider(new GUIContent("Max Slope", "Sets the max slope in degrees for a point to be walkable. Only enabled if Height Testing is enabled."), graph.maxSlope, 0, 90F);

            graph.erodeIterations = EditorGUILayout.IntField(new GUIContent("Erosion iterations", "Sets how many times the graph should be eroded. This adds extra margin to objects. This will not work when using Graph Updates, so if you can, use the Diameter setting in collision settings instead"), graph.erodeIterations);
            graph.erodeIterations = graph.erodeIterations < 0 ? 0 : (graph.erodeIterations > 16 ? 16 : graph.erodeIterations);             //Clamp iterations to [0,16]

            if (graph.erodeIterations > 0)
            {
                EditorGUI.indentLevel++;
                graph.erosionUseTags = EditorGUILayout.Toggle(new GUIContent("Erosion Uses Tags", "Instead of making nodes unwalkable, " +
                                                                             "nodes will have their tag set to a value corresponding to their erosion level, " +
                                                                             "which is a quite good measurement of their distance to the closest wall.\nSee online documentation for more info."),
                                                              graph.erosionUseTags);
                if (graph.erosionUseTags)
                {
                    EditorGUI.indentLevel++;
                    graph.erosionFirstTag = EditorGUILayoutx.SingleTagField("First Tag", graph.erosionFirstTag);
                    EditorGUI.indentLevel--;
                }
                EditorGUI.indentLevel--;
            }
            DrawCollisionEditor(graph.collision);

            if (graph.collision.use2D)
            {
                if (Mathf.Abs(Vector3.Dot(Vector3.forward, Quaternion.Euler(graph.rotation) * Vector3.up)) < 0.9f)
                {
                    EditorGUILayout.HelpBox("When using 2D it is recommended to rotate the graph so that it aligns with the 2D plane.", MessageType.Warning);
                }
            }

            Separator();

            showExtra = EditorGUILayout.Foldout(showExtra, "Extra");

            if (showExtra)
            {
                EditorGUI.indentLevel += 2;

                graph.penaltyAngle = ToggleGroup(new GUIContent("Angle Penalty", "Adds a penalty based on the slope of the node"), graph.penaltyAngle);
                //bool preGUI = GUI.enabled;
                //GUI.enabled = graph.penaltyAngle && GUI.enabled;
                if (graph.penaltyAngle)
                {
                    EditorGUI.indentLevel++;
                    graph.penaltyAngleFactor = EditorGUILayout.FloatField(new GUIContent("Factor", "Scale of the penalty. A negative value should not be used"), graph.penaltyAngleFactor);
                    //GUI.enabled = preGUI;
                    HelpBox("Applies penalty to nodes based on the angle of the hit surface during the Height Testing");

                    EditorGUI.indentLevel--;
                }

                graph.penaltyPosition = ToggleGroup("Position Penalty", graph.penaltyPosition);
                //EditorGUILayout.Toggle ("Position Penalty",graph.penaltyPosition);
                //preGUI = GUI.enabled;
                //GUI.enabled = graph.penaltyPosition && GUI.enabled;
                if (graph.penaltyPosition)
                {
                    EditorGUI.indentLevel++;
                    graph.penaltyPositionOffset = EditorGUILayout.FloatField("Offset", graph.penaltyPositionOffset);
                    graph.penaltyPositionFactor = EditorGUILayout.FloatField("Factor", graph.penaltyPositionFactor);
                    HelpBox("Applies penalty to nodes based on their Y coordinate\nSampled in Int3 space, i.e it is multiplied with Int3.Precision first (" + Int3.Precision + ")\n" +
                            "Be very careful when using negative values since a negative penalty will underflow and instead get really high");
                    //GUI.enabled = preGUI;
                    EditorGUI.indentLevel--;
                }

                if (textureVisible)
                {
                    DrawTextureData(graph.textureData, graph);
                }
                EditorGUI.indentLevel -= 2;
            }
        }
Esempio n. 20
0
		protected virtual void DrawJPS (GridGraph graph) {
			graph.useJumpPointSearch = EditorGUILayout.Toggle(new GUIContent("Use Jump Point Search", "Jump Point Search can significantly speed up pathfinding. But only works on uniformly weighted graphs"), graph.useJumpPointSearch);
			if (graph.useJumpPointSearch) {
				EditorGUILayout.HelpBox("Jump Point Search assumes that there are no penalties applied to the graph. Tag penalties cannot be used either.", MessageType.Warning);

#if !ASTAR_JPS
				EditorGUILayout.HelpBox("JPS needs to be enabled using a compiler directive before it can be used.\n" +
					"Enabling this will add ASTAR_JPS to the Scriping Define Symbols field in the Unity Player Settings", MessageType.Warning);
				if (GUILayout.Button("Enable Jump Point Search support")) {
					OptimizationHandler.EnableDefine("ASTAR_JPS");
				}
#endif
			} else {
#if ASTAR_JPS
				EditorGUILayout.HelpBox("If you are not using JPS in any scene, you can disable it to save memory", MessageType.Info);
				if (GUILayout.Button("Disable Jump Point Search support")) {
					OptimizationHandler.DisableDefine("ASTAR_JPS");
				}
#endif
			}
		}
Esempio n. 21
0
 private void ApplyGridGraphEndpointSpecialCase()
 {
     NavGraph[] graphs = AstarPath.active.graphs;
     for (int i = 0; i < graphs.Length; i++)
     {
         GridGraph graph = graphs[i] as GridGraph;
         if (graph != null)
         {
             GridNode[] nodes = graph.nodes;
             int        num2  = (graph.neighbours != NumNeighbours.Four) ? ((graph.neighbours != NumNeighbours.Eight) ? 6 : 8) : 4;
             for (int j = 0; j < graph.depth; j++)
             {
                 for (int k = 0; k < graph.width; k++)
                 {
                     GridNode node = nodes[(j * graph.width) + k];
                     if (!node.Walkable)
                     {
                         int num5 = node.NodeIndex * this.pivotCount;
                         for (int m = 0; m < this.pivotCount; m++)
                         {
                             this.costs[num5 + m] = uint.MaxValue;
                         }
                         for (int n = 0; n < num2; n++)
                         {
                             int num8;
                             int num9;
                             if (graph.neighbours == NumNeighbours.Six)
                             {
                                 num8 = k + graph.neighbourXOffsets[GridGraph.hexagonNeighbourIndices[n]];
                                 num9 = j + graph.neighbourZOffsets[GridGraph.hexagonNeighbourIndices[n]];
                             }
                             else
                             {
                                 num8 = k + graph.neighbourXOffsets[n];
                                 num9 = j + graph.neighbourZOffsets[n];
                             }
                             if (((num8 >= 0) && (num9 >= 0)) && ((num8 < graph.width) && (num9 < graph.depth)))
                             {
                                 GridNode node2 = graph.nodes[(num9 * graph.width) + num8];
                                 if (node2.Walkable)
                                 {
                                     for (int num10 = 0; num10 < this.pivotCount; num10++)
                                     {
                                         uint num11 = this.costs[(node2.NodeIndex * this.pivotCount) + num10] + graph.neighbourCosts[n];
                                         this.costs[num5 + num10] = Math.Min(this.costs[num5 + num10], num11);
                                         Debug.DrawLine((Vector3)node.position, (Vector3)node2.position, Color.blue, 1f);
                                     }
                                 }
                             }
                         }
                         for (int num12 = 0; num12 < this.pivotCount; num12++)
                         {
                             if (this.costs[num5 + num12] == uint.MaxValue)
                             {
                                 this.costs[num5 + num12] = 0;
                             }
                         }
                     }
                 }
             }
         }
     }
 }
		void DrawPositionField (GridGraph graph) {
			Vector3 pivotPoint;
			Vector3 diff;

			GUILayout.BeginHorizontal ();

			switch (pivot) {
				case GridPivot.Center:
					graph.center = RoundVector3 ( graph.center );
					graph.center = EditorGUILayout.Vector3Field ("Center",graph.center);
					break;
				case GridPivot.TopLeft:
					pivotPoint = graph.matrix.MultiplyPoint3x4 (new Vector3 (0,0,graph.depth));
					pivotPoint = RoundVector3 ( pivotPoint );
					diff = pivotPoint-graph.center;
					pivotPoint = EditorGUILayout.Vector3Field ("Top-Left",pivotPoint);
					graph.center = pivotPoint-diff;
					break;
				case GridPivot.TopRight:
					pivotPoint = graph.matrix.MultiplyPoint3x4 (new Vector3 (graph.width,0,graph.depth));
					pivotPoint = RoundVector3 ( pivotPoint );
					diff = pivotPoint-graph.center;
					pivotPoint = EditorGUILayout.Vector3Field ("Top-Right",pivotPoint);
					graph.center = pivotPoint-diff;
					break;
				case GridPivot.BottomLeft:
					pivotPoint = graph.matrix.MultiplyPoint3x4 (new Vector3 (0,0,0));
					pivotPoint = RoundVector3 ( pivotPoint );
					diff = pivotPoint-graph.center;
					pivotPoint = EditorGUILayout.Vector3Field ("Bottom-Left",pivotPoint);
					graph.center = pivotPoint-diff;
					break;
				case GridPivot.BottomRight:
					pivotPoint = graph.matrix.MultiplyPoint3x4 (new Vector3 (graph.width,0,0));
					pivotPoint = RoundVector3 ( pivotPoint );
					diff = pivotPoint-graph.center;
					pivotPoint = EditorGUILayout.Vector3Field ("Bottom-Right",pivotPoint);
					graph.center = pivotPoint-diff;
					break;
			}

			graph.GenerateMatrix ();

			pivot = PivotPointSelector (pivot);

			GUILayout.EndHorizontal ();
		}
		protected virtual void DrawMiddleSection (GridGraph graph) {
			DrawNeighbours(graph);
			DrawMaxClimb(graph);
			DrawMaxSlope(graph);
			DrawErosion(graph);
		}
		void DrawIsometricField (GridGraph graph) {

			var isometricGUIContent = new GUIContent ("Isometric Angle", "For an isometric 2D game, you can use this parameter to scale the graph correctly.\nIt can also be used to create a hexagon grid.");
			var isometricOptions = new [] {new GUIContent ("None (0°)"), new GUIContent ("Isometric (≈54.74°)"), new GUIContent("Custom")};
			var isometricValues = new [] {0f, standardIsometric};
			var isometricOption = 2;

			for (int i = 0; i < isometricValues.Length; i++) {
				if (Mathf.Approximately (graph.isometricAngle, isometricValues[i])) {
					isometricOption = i;
				}
			}

			var prevIsometricOption = isometricOption;
			isometricOption = EditorGUILayout.IntPopup (isometricGUIContent, isometricOption, isometricOptions, new [] {0, 1, 2});
			if (prevIsometricOption != isometricOption) {
				// Change to something that will not match the predefined values above
				graph.isometricAngle = 45;
			}

			if (isometricOption < 2) {
				graph.isometricAngle = isometricValues[isometricOption];
			} else {
				// Custom
				graph.isometricAngle = EditorGUILayout.FloatField (isometricGUIContent, graph.isometricAngle);
			}
		}
		void DrawWidthDepthFields (GridGraph graph) {
			lockStyle = lockStyle ?? AstarPathEditor.astarSkin.FindStyle ("GridSizeLock") ?? new GUIStyle ();

			GUILayout.BeginHorizontal ();
			GUILayout.BeginVertical ();
			int newWidth = EditorGUILayout.IntField (new GUIContent ("Width (nodes)","Width of the graph in nodes"), graph.width);
			int newDepth = EditorGUILayout.IntField (new GUIContent ("Depth (nodes)","Depth (or height you might also call it) of the graph in nodes"), graph.depth);
			GUILayout.EndVertical ();

			Rect lockRect = GUILayoutUtility.GetRect (lockStyle.fixedWidth,lockStyle.fixedHeight);

			GUILayout.EndHorizontal ();

			// All the layouts mess up the margin to the next control, so add it manually
			GUILayout.Space (2);

			// Add a small offset to make it better centred around the controls
			lockRect.y += 3;
			lockRect.width = lockStyle.fixedWidth;
			lockRect.height = lockStyle.fixedHeight;
			lockRect.x += lockStyle.margin.left;
			lockRect.y += lockStyle.margin.top;

			locked = GUI.Toggle (lockRect,locked,
			                     new GUIContent ("", "If the width and depth values are locked, " +
			                "changing the node size will scale the grid which keeping the number of nodes consistent " +
			                "instead of keeping the size the same and changing the number of nodes in the graph"), lockStyle);

			if (newWidth != graph.width || newDepth != graph.depth) {
				SnapSizeToNodes (newWidth,newDepth,graph);
			}
		}
Esempio n. 26
0
 public void UpdateShortcuts()
 {
     navmesh = (NavMeshGraph)FindGraphOfType (typeof(NavMeshGraph));
     gridGraph = (GridGraph)FindGraphOfType (typeof(GridGraph));
     listGraph = (ListGraph)FindGraphOfType (typeof(ListGraph));
 }
Esempio n. 27
0
        /** Returns randomly selected points on the specified nodes with each point being separated by \a clearanceRadius from each other.
         * Selecting points ON the nodes only works for TriangleMeshNode (used by Recast Graph and Navmesh Graph) and GridNode (used by GridGraph).
         * For other node types, only the positions of the nodes will be used.
         *
         * clearanceRadius will be reduced if no valid points can be found.
         */
        public static List <Vector3> GetPointsOnNodes(List <GraphNode> nodes, int count, float clearanceRadius = 0)
        {
            if (nodes == null)
            {
                throw new System.ArgumentNullException("nodes");
            }
            if (nodes.Count == 0)
            {
                throw new System.ArgumentException("no nodes passed");
            }

            var rnd = new System.Random();

            List <Vector3> pts = ListPool <Vector3> .Claim(count);

            // Square
            clearanceRadius *= clearanceRadius;

            if (nodes[0] is TriangleMeshNode
#if !ASTAR_NO_GRID_GRAPH
                || nodes[0] is GridNode
#endif
                )
            {
                //Assume all nodes are triangle nodes or grid nodes

                List <float> accs = ListPool <float> .Claim(nodes.Count);

                float tot = 0;

                for (int i = 0; i < nodes.Count; i++)
                {
                    var tnode = nodes[i] as TriangleMeshNode;
                    if (tnode != null)
                    {
                        /** \bug Doesn't this need to be divided by 2? */
                        float a = System.Math.Abs(Polygon.TriangleArea2(tnode.GetVertex(0), tnode.GetVertex(1), tnode.GetVertex(2)));
                        tot += a;
                        accs.Add(tot);
                    }
#if !ASTAR_NO_GRID_GRAPH
                    else
                    {
                        var gnode = nodes[i] as GridNode;

                        if (gnode != null)
                        {
                            GridGraph gg = GridNode.GetGridGraph(gnode.GraphIndex);
                            float     a  = gg.nodeSize * gg.nodeSize;
                            tot += a;
                            accs.Add(tot);
                        }
                        else
                        {
                            accs.Add(tot);
                        }
                    }
#endif
                }

                for (int i = 0; i < count; i++)
                {
                    //Pick point
                    int  testCount = 0;
                    int  testLimit = 10;
                    bool worked    = false;

                    while (!worked)
                    {
                        worked = true;

                        //If no valid points can be found, progressively lower the clearance radius until such a point is found
                        if (testCount >= testLimit)
                        {
                            clearanceRadius *= 0.8f;
                            testLimit       += 10;
                            if (testLimit > 100)
                            {
                                clearanceRadius = 0;
                            }
                        }

                        float tg = (float)rnd.NextDouble() * tot;
                        int   v  = accs.BinarySearch(tg);
                        if (v < 0)
                        {
                            v = ~v;
                        }

                        if (v >= nodes.Count)
                        {
                            // This shouldn't happen, due to NextDouble being smaller than 1... but I don't trust floating point arithmetic.
                            worked = false;
                            continue;
                        }

                        var node = nodes[v] as TriangleMeshNode;

                        Vector3 p;

                        if (node != null)
                        {
                            // Find a random point inside the triangle
                            float v1;
                            float v2;
                            do
                            {
                                v1 = (float)rnd.NextDouble();
                                v2 = (float)rnd.NextDouble();
                            } while (v1 + v2 > 1);

                            p = ((Vector3)(node.GetVertex(1) - node.GetVertex(0))) * v1 + ((Vector3)(node.GetVertex(2) - node.GetVertex(0))) * v2 + (Vector3)node.GetVertex(0);
                        }
                        else
                        {
#if !ASTAR_NO_GRID_GRAPH
                            var gnode = nodes[v] as GridNode;

                            if (gnode != null)
                            {
                                GridGraph gg = GridNode.GetGridGraph(gnode.GraphIndex);

                                float v1 = (float)rnd.NextDouble();
                                float v2 = (float)rnd.NextDouble();
                                p = (Vector3)gnode.position + new Vector3(v1 - 0.5f, 0, v2 - 0.5f) * gg.nodeSize;
                            }
                            else
#endif
                            {
                                //Point nodes have no area, so we break directly instead
                                pts.Add((Vector3)nodes[v].position);
                                break;
                            }
                        }

                        // Test if it is some distance away from the other points
                        if (clearanceRadius > 0)
                        {
                            for (int j = 0; j < pts.Count; j++)
                            {
                                if ((pts[j] - p).sqrMagnitude < clearanceRadius)
                                {
                                    worked = false;
                                    break;
                                }
                            }
                        }

                        if (worked)
                        {
                            pts.Add(p);
                            break;
                        }
                        testCount++;
                    }
                }

                ListPool <float> .Release(accs);
            }
            else
            {
                for (int i = 0; i < count; i++)
                {
                    pts.Add((Vector3)nodes[rnd.Next(nodes.Count)].position);
                }
            }

            return(pts);
        }
Esempio n. 28
0
        /** Opens a node using Jump Point Search.
         * \see http://en.wikipedia.org/wiki/Jump_point_search
         */
        public void JPSOpen(Path path, PathNode pathNode, PathHandler handler)
        {
            GridGraph gg = GetGridGraph(GraphIndex);

            int[]      neighbourOffsets = gg.neighbourOffsets;
            GridNode[] nodes            = gg.nodes;
            ushort     pid = handler.PathID;

            int noncyclic = gridFlags & 0xFF;
            int cyclic    = 0;

            for (int i = 0; i < 8; i++)
            {
                cyclic |= ((noncyclic >> i) & 0x1) << JPSCyclic[i];
            }

            var parent    = pathNode.parent != null ? pathNode.parent.node as GridNode : null;
            int parentDir = -1;

            if (parent != null)
            {
                int diff = parent != null ? parent.nodeInGridIndex - nodeInGridIndex : 0;

                int x2 = nodeInGridIndex % gg.width;
                int x1 = parent.nodeInGridIndex % gg.width;
                if (diff < 0)
                {
                    if (x1 == x2)
                    {
                        parentDir = 0;
                    }
                    else if (x1 < x2)
                    {
                        parentDir = 7;
                    }
                    else
                    {
                        parentDir = 4;
                    }
                }
                else
                {
                    if (x1 == x2)
                    {
                        parentDir = 1;
                    }
                    else if (x1 < x2)
                    {
                        parentDir = 6;
                    }
                    else
                    {
                        parentDir = 5;
                    }
                }
            }
            int cyclicParentDir = 0;
            // Check for -1

            int forced = 0;

            if (parentDir != -1)
            {
                cyclicParentDir = JPSCyclic[parentDir];
                // Loop around to be able to assume -X is where we came from
                cyclic = ((cyclic >> cyclicParentDir) | ((cyclic << 8) >> cyclicParentDir)) & 0xFF;
            }
            else
            {
                forced = 0xFF;
                //parentDir = 0;
            }

            bool diagonal = parentDir >= 4;
            int  natural;

            if (diagonal)
            {
                for (int i = 0; i < 8; i++)
                {
                    if (((cyclic >> i) & 1) == 0)
                    {
                        forced |= JPSForcedDiagonal[i];
                    }
                }

                natural = JPSNaturalDiagonalNeighbours;
            }
            else
            {
                for (int i = 0; i < 8; i++)
                {
                    if (((cyclic >> i) & 1) == 0)
                    {
                        forced |= JPSForced[i];
                    }
                }

                natural = JPSNaturalStraightNeighbours;
            }

            // Don't force nodes we cannot reach anyway
            forced  &= cyclic;
            natural &= cyclic;

            int nb = forced | natural;


            /*if ( ((Vector3)position - new Vector3(0.5f,0,3.5f)).magnitude < 0.5f ) {
             * EB.Debug.Log (noncyclic + " " + parentDir + " " + cyclicParentDir);
             * EB.Debug.Log (System.Convert.ToString (cyclic, 2)+"\n"+System.Convert.ToString (noncyclic, 2)+"\n"+System.Convert.ToString (natural, 2)+"\n"+System.Convert.ToString (forced, 2));
             * }*/

            for (int i = 0; i < 8; i++)
            {
                if (((nb >> i) & 1) != 0)
                {
                    int      oi    = JPSInverseCyclic[(i + cyclicParentDir) % 8];
                    GridNode other = nodes[nodeInGridIndex + neighbourOffsets[oi]];

#if ASTARDEBUG
                    if (((forced >> i) & 1) != 0)
                    {
                        Debug.DrawLine((Vector3)position, Vector3.Lerp((Vector3)other.position, (Vector3)position, 0.6f), Color.red);
                    }
                    if (((natural >> i) & 1) != 0)
                    {
                        Debug.DrawLine((Vector3)position + Vector3.up * 0.2f, Vector3.Lerp((Vector3)other.position, (Vector3)position, 0.6f) + Vector3.up * 0.2f, Color.green);
                    }
#endif

                    if (oi < 4)
                    {
                        other = JPSJumpStraight(other, path, handler, JPSInverseCyclic[(i + 4 + cyclicParentDir) % 8]);
                    }
                    else
                    {
                        other = other.JPSJumpDiagonal(path, handler, JPSInverseCyclic[(i + 4 + cyclicParentDir) % 8]);
                    }

                    if (other != null)
                    {
                        //Debug.DrawLine ( (Vector3)position + Vector3.up*0.0f, (Vector3)other.position + Vector3.up*0.3f, Color.cyan);
                        //Debug.DrawRay ( (Vector3)other.position, Vector3.up, Color.cyan);
                        //GridNode other = nodes[nodeInGridIndex + neighbourOffsets[i]];
                        //if (!path.CanTraverse (other)) continue;

                        PathNode otherPN = handler.GetPathNode(other);

                        if (otherPN.pathID != pid)
                        {
                            otherPN.parent = pathNode;
                            otherPN.pathID = pid;

                            otherPN.cost = (uint)(other.position - position).costMagnitude;                            //neighbourCosts[i];

                            otherPN.H = path.CalculateHScore(other);
                            other.UpdateG(path, otherPN);

                            //Debug.Log ("G " + otherPN.G + " F " + otherPN.F);
                            handler.PushNode(otherPN);
                            //Debug.DrawRay ((Vector3)otherPN.node.Position, Vector3.up,Color.blue);
                        }
                        else
                        {
                            //If not we can test if the path from the current node to this one is a better one then the one already used
                            uint tmpCost = (uint)(other.position - position).costMagnitude;                            //neighbourCosts[i];

                            if (pathNode.G + tmpCost + path.GetTraversalCost(other) < otherPN.G)
                            {
                                //Debug.Log ("Path better from " + NodeIndex + " to " + otherPN.node.NodeIndex + " " + (pathNode.G+tmpCost+path.GetTraversalCost(other)) + " < " + otherPN.G);
                                otherPN.cost = tmpCost;

                                otherPN.parent = pathNode;

                                other.UpdateRecursiveG(path, otherPN, handler);

                                //Or if the path from this node ("other") to the current ("current") is better
                            }
                            else if (otherPN.G + tmpCost + path.GetTraversalCost(this) < pathNode.G)
                            {
                                //Debug.Log ("Path better from " + otherPN.node.NodeIndex + " to " + NodeIndex + " " + (otherPN.G+tmpCost+path.GetTraversalCost (this)) + " < " + pathNode.G);
                                pathNode.parent = otherPN;
                                pathNode.cost   = tmpCost;

                                UpdateRecursiveG(path, pathNode, handler);
                            }
                        }
                    }
                }

#if ASTARDEBUG
                if (i == 0 && parentDir != -1 && this.nodeInGridIndex > 10)
                {
                    int oi = JPSInverseCyclic[(i + cyclicParentDir) % 8];

                    if (nodeInGridIndex + neighbourOffsets[oi] < 0 || nodeInGridIndex + neighbourOffsets[oi] >= nodes.Length)
                    {
                        //Debug.LogError ("ERR: " + (nodeInGridIndex + neighbourOffsets[oi]) + " " + cyclicParentDir + " " + parentDir + " Reverted " + oi);
                        //Debug.DrawRay ((Vector3)position, Vector3.up, Color.red);
                    }
                    else
                    {
                        GridNode other = nodes[nodeInGridIndex + neighbourOffsets[oi]];
                        Debug.DrawLine((Vector3)position - Vector3.up * 0.2f, Vector3.Lerp((Vector3)other.position, (Vector3)position, 0.6f) - Vector3.up * 0.2f, Color.blue);
                    }
                }
#endif
            }
        }
		protected virtual void DrawCutCorners (GridGraph graph) {
			graph.cutCorners = EditorGUILayout.Toggle (new GUIContent ("Cut Corners","Enables or disables cutting corners. See docs for image example"),graph.cutCorners);
		}
Esempio n. 30
0
		protected virtual void DrawCutCorners (GridGraph graph) {
			graph.cutCorners = EditorGUILayout.Toggle(new GUIContent("Cut Corners", "Enables or disables cutting corners. See docs for image example"), graph.cutCorners);
			if (!graph.cutCorners && graph.useJumpPointSearch) {
				EditorGUILayout.HelpBox("Jump Point Search only works if 'Cut Corners' is enabled.", MessageType.Error);
			}
		}
Esempio n. 31
0
        public override void Open(Path path, PathNode pathNode, PathHandler handler)
        {
            GridGraph gg = GetGridGraph(GraphIndex);

            ushort pid = handler.PathID;

            {
                int[]      neighbourOffsets = gg.neighbourOffsets;
                uint[]     neighbourCosts   = gg.neighbourCosts;
                GridNode[] nodes            = gg.nodes;
                var        index            = NodeInGridIndex;

                for (int i = 0; i < 8; i++)
                {
                    if (HasConnectionInDirection(i))
                    {
                        GridNode other = nodes[index + neighbourOffsets[i]];
                        if (!path.CanTraverse(other))
                        {
                            continue;
                        }

                        PathNode otherPN = handler.GetPathNode(other);

                        uint tmpCost = neighbourCosts[i];

                        // Check if the other node has not yet been visited by this path
                        if (otherPN.pathID != pid)
                        {
                            otherPN.parent = pathNode;
                            otherPN.pathID = pid;

                            otherPN.cost = tmpCost;

                            otherPN.H = path.CalculateHScore(other);
                            otherPN.UpdateG(path);

                            handler.heap.Add(otherPN);
                        }
                        else
                        {
                            // Sorry for the huge number of #ifs

                            //If not we can test if the path from the current node to this one is a better one then the one already used

#if ASTAR_NO_TRAVERSAL_COST
                            if (pathNode.G + tmpCost < otherPN.G)
#else
                            if (pathNode.G + tmpCost + path.GetTraversalCost(other) < otherPN.G)
#endif
                            {
                                //Debug.Log ("Path better from " + NodeIndex + " to " + otherPN.node.NodeIndex + " " + (pathNode.G+tmpCost+path.GetTraversalCost(other)) + " < " + otherPN.G);
                                otherPN.cost = tmpCost;

                                otherPN.parent = pathNode;

                                other.UpdateRecursiveG(path, otherPN, handler);
                            }
                        }
                    }
                }
            }

#if !ASTAR_GRID_NO_CUSTOM_CONNECTIONS
            base.Open(path, pathNode, handler);
#endif
        }
		protected virtual void DrawNeighbours (GridGraph graph) {
			graph.neighbours = (NumNeighbours)EditorGUILayout.EnumPopup (new GUIContent ("Connections","Sets how many connections a node should have to it's neighbour nodes."),graph.neighbours);

			EditorGUI.indentLevel++;

			if (graph.neighbours == NumNeighbours.Eight) {
				DrawCutCorners(graph);
			}

			if (graph.neighbours == NumNeighbours.Six) {
				graph.uniformEdgeCosts = EditorGUILayout.Toggle (new GUIContent ("Hexagon connection costs", "Tweak the edge costs in the graph to be more suitable for hexagon graphs"), graph.uniformEdgeCosts);
				if ((!Mathf.Approximately(graph.isometricAngle, standardIsometric) || !graph.uniformEdgeCosts) && GUILayout.Button ("Configure as hexagon graph")) {
					graph.isometricAngle = standardIsometric;
					graph.uniformEdgeCosts = true;
				}
			} else {
				graph.uniformEdgeCosts = false;
			}

			EditorGUI.indentLevel--;

		}
Esempio n. 33
0
        /** Executes a diagonal jump search.
         * \see http://en.wikipedia.org/wiki/Jump_point_search
         */
        GridNode JPSJumpDiagonal(Path path, PathHandler handler, int parentDir, int depth = 0)
        {
            // Indexing into the cache arrays from multiple threads like this should cause
            // a lot of false sharing and cache trashing, but after profiling it seems
            // that this is not a major concern
            int threadID     = handler.threadID;
            int threadOffset = 8 * handler.threadID;

            // This is needed to make sure different threads don't overwrite each others results
            // It doesn't matter if we throw away some caching done by other threads as this will only
            // happen during the first few path requests
            if (JPSLastCacheID == null || JPSLastCacheID.Length < handler.totalThreadCount)
            {
                lock (this) {
                    // Check again in case another thread has already created the array
                    if (JPSLastCacheID == null || JPSLastCacheID.Length < handler.totalThreadCount)
                    {
                        JPSCache       = new GridNode[8 * handler.totalThreadCount];
                        JPSDead        = new byte[handler.totalThreadCount];
                        JPSLastCacheID = new ushort[handler.totalThreadCount];
                    }
                }
            }
            if (JPSLastCacheID[threadID] != path.pathID)
            {
                for (int i = 0; i < 8; i++)
                {
                    JPSCache[i + threadOffset] = null;
                }
                JPSLastCacheID[threadID] = path.pathID;
                JPSDead[threadID]        = 0;
            }

            // Cache earlier results, major optimization
            // It is important to read from it once and then return the same result,
            // if we read from it twice, we might get different results due to other threads clearing the array sometimes
            GridNode cachedResult = JPSCache[parentDir + threadOffset];

            if (cachedResult != null)
            {
                //return cachedResult;
            }

            //if ( ((JPSDead[threadID] >> parentDir)&1) != 0 ) return null;

            // Special node (e.g end node), take care of
            if (handler.GetPathNode(this).flag2)
            {
                //Debug.Log ("Found end Node!");
                //Debug.DrawRay ((Vector3)position, Vector3.up*2, Color.green);
                JPSCache[parentDir + threadOffset] = this;
                return(this);
            }

#if !ASTAR_GRID_NO_CUSTOM_CONNECTIONS
            // Special node which has custom connections, take care of
            if (connections != null && connections.Length > 0)
            {
                JPSCache[parentDir] = this;
                return(this);
            }
#endif

            int noncyclic = gridFlags;            //We don't actually need to & with this because we don't use the other bits. & 0xFF;
            int cyclic    = 0;
            for (int i = 0; i < 8; i++)
            {
                cyclic |= ((noncyclic >> i) & 0x1) << JPSCyclic[i];
            }


            int forced          = 0;
            int cyclicParentDir = JPSCyclic[parentDir];
            // Loop around to be able to assume -X is where we came from
            cyclic = ((cyclic >> cyclicParentDir) | ((cyclic << 8) >> cyclicParentDir)) & 0xFF;

            int natural;

            for (int i = 0; i < 8; i++)
            {
                if (((cyclic >> i) & 1) == 0)
                {
                    forced |= JPSForcedDiagonal[i];
                }
            }

            natural = JPSNaturalDiagonalNeighbours;

            /*
             * if ( ((Vector3)position - new Vector3(1.5f,0,-1.5f)).magnitude < 0.5f ) {
             * EB.Debug.Log (noncyclic + " " + parentDir + " " + cyclicParentDir);
             * EB.Debug.Log (System.Convert.ToString (cyclic, 2)+"\n"+System.Convert.ToString (noncyclic, 2)+"\n"+System.Convert.ToString (natural, 2)+"\n"+System.Convert.ToString (forced, 2));
             * }*/

            // Don't force nodes we cannot reach anyway
            forced  &= cyclic;
            natural &= cyclic;

            if ((forced & (~natural)) != 0)
            {
                // Some of the neighbour nodes are forced
                JPSCache[parentDir + threadOffset] = this;
                return(this);
            }

            int forwardDir;

            GridGraph  gg = GetGridGraph(GraphIndex);
            int[]      neighbourOffsets = gg.neighbourOffsets;
            GridNode[] nodes            = gg.nodes;

            {
                // Rotate 180 degrees - 1 node
                forwardDir = 3;
                if (((cyclic >> forwardDir) & 1) != 0)
                {
                    int      oi    = JPSInverseCyclic[(forwardDir + cyclicParentDir) % 8];
                    GridNode other = nodes[nodeInGridIndex + neighbourOffsets[oi]];

                    //Debug.DrawLine ( (Vector3)position + Vector3.up*0.2f*(depth), (Vector3)other.position + Vector3.up*0.2f*(depth+1), Color.black);
                    GridNode v;
                    if (oi < 4)
                    {
                        v = JPSJumpStraight(other, path, handler, JPSInverseCyclic[(cyclicParentDir - 1 + 8) % 8], depth + 1);
                    }
                    else
                    {
                        v = other.JPSJumpDiagonal(path, handler, JPSInverseCyclic[(cyclicParentDir - 1 + 8) % 8], depth + 1);
                    }
                    if (v != null)
                    {
                        JPSCache[parentDir + threadOffset] = this;
                        return(this);
                    }
                }

                // Rotate 180 degrees + 1 node
                forwardDir = 5;
                if (((cyclic >> forwardDir) & 1) != 0)
                {
                    int      oi    = JPSInverseCyclic[(forwardDir + cyclicParentDir) % 8];
                    GridNode other = nodes[nodeInGridIndex + neighbourOffsets[oi]];

                    //Debug.DrawLine ( (Vector3)position + Vector3.up*0.2f*(depth), (Vector3)other.position + Vector3.up*0.2f*(depth+1), Color.grey);
                    GridNode v;
                    if (oi < 4)
                    {
                        v = JPSJumpStraight(other, path, handler, JPSInverseCyclic[(cyclicParentDir + 1 + 8) % 8], depth + 1);
                    }
                    else
                    {
                        v = other.JPSJumpDiagonal(path, handler, JPSInverseCyclic[(cyclicParentDir + 1 + 8) % 8], depth + 1);
                    }

                    if (v != null)
                    {
                        JPSCache[parentDir + threadOffset] = this;
                        return(this);
                    }
                }
            }

            // Rotate 180 degrees
            forwardDir = 4;
            if (((cyclic >> forwardDir) & 1) != 0)
            {
                int      oi    = JPSInverseCyclic[(forwardDir + cyclicParentDir) % 8];
                GridNode other = nodes[nodeInGridIndex + neighbourOffsets[oi]];

                //Debug.DrawLine ( (Vector3)position + Vector3.up*0.2f*(depth), (Vector3)other.position + Vector3.up*0.2f*(depth+1), Color.magenta);

                var v = other.JPSJumpDiagonal(path, handler, parentDir, depth + 1);
                if (v != null)
                {
                    JPSCache[parentDir + threadOffset] = v;
                    return(v);
                }
            }
            JPSDead[threadID] |= (byte)(1 << parentDir);
            return(null);
        }
		protected virtual void DrawMaxClimb (GridGraph graph) {
			graph.maxClimb = EditorGUILayout.FloatField (new GUIContent ("Max Climb","How high in world units, relative to the graph, should a climbable level be. A zero (0) indicates infinity"),graph.maxClimb);
			if ( graph.maxClimb < 0 ) graph.maxClimb = 0;
			EditorGUI.indentLevel++;
			graph.maxClimbAxis = EditorGUILayout.IntPopup (new GUIContent ("Climb Axis","Determines which axis the above setting should test on"),graph.maxClimbAxis,new [] {new GUIContent ("X"),new GUIContent ("Y"),new GUIContent ("Z")},new [] {0,1,2});
			EditorGUI.indentLevel--;

			if ( graph.maxClimb > 0 && Mathf.Abs((Quaternion.Euler (graph.rotation) * new Vector3 (graph.nodeSize,0,graph.nodeSize))[graph.maxClimbAxis]) > graph.maxClimb ) {
				EditorGUILayout.HelpBox ("Nodes are spaced further apart than this in the grid. You might want to increase this value or change the axis", MessageType.Warning );
			}
		}
Esempio n. 35
0
        public override void Open(Path path, PathNode pathNode, PathHandler handler)
        {
            GridGraph gg = GetGridGraph(GraphIndex);

            ushort pid = handler.PathID;

            {
                int[]      neighbourOffsets = gg.neighbourOffsets;
                uint[]     neighbourCosts   = gg.neighbourCosts;
                GridNode[] nodes            = gg.nodes;

                for (int i = 0; i < 8; i++)
                {
                    if (GetConnectionInternal(i))
                    {
                        GridNode other = nodes[nodeInGridIndex + neighbourOffsets[i]];
                        if (!path.CanTraverse(other))
                        {
                            continue;
                        }

                        PathNode otherPN = handler.GetPathNode(other);

                        // Multiply the connection cost with 1 + the average of the traversal costs for the two nodes
                        uint tmpCost = (neighbourCosts[i] * (256 + path.GetTraversalCost(this) + path.GetTraversalCost(other))) / 128;

                        if (otherPN.pathID != pid)
                        {
                            otherPN.parent = pathNode;
                            otherPN.pathID = pid;

                            otherPN.cost = tmpCost;

                            otherPN.H = path.CalculateHScore(other);
                            other.UpdateG(path, otherPN);

                            //Debug.Log ("G " + otherPN.G + " F " + otherPN.F);
                            handler.PushNode(otherPN);
                            //Debug.DrawRay ((Vector3)otherPN.node.Position, Vector3.up,Color.blue);
                        }
                        else
                        {
                            // Sorry for the huge number of #ifs

                            //If not we can test if the path from the current node to this one is a better one then the one already used

                            if (pathNode.G + tmpCost < otherPN.G)
                            {
                                //Debug.Log ("Path better from " + NodeIndex + " to " + otherPN.node.NodeIndex + " " + (pathNode.G+tmpCost+path.GetTraversalCost(other)) + " < " + otherPN.G);
                                otherPN.cost = tmpCost;

                                otherPN.parent = pathNode;

                                other.UpdateRecursiveG(path, otherPN, handler);

                                //Or if the path from this node ("other") to the current ("current") is better
                            }
                            else if (otherPN.G + tmpCost < pathNode.G)
                            {
                                //Debug.Log ("Path better from " + otherPN.node.NodeIndex + " to " + NodeIndex + " " + (otherPN.G+tmpCost+path.GetTraversalCost (this)) + " < " + pathNode.G);
                                pathNode.parent = otherPN;
                                pathNode.cost   = tmpCost;

                                UpdateRecursiveG(path, pathNode, handler);
                            }
                        }
                    }
                }
            }

            if (connections != null)
            {
                for (int i = 0; i < connections.Length; i++)
                {
                    GraphNode other = connections[i];
                    if (!path.CanTraverse(other))
                    {
                        continue;
                    }

                    PathNode otherPN = handler.GetPathNode(other);

                    uint tmpCost = (connectionCosts[i] * (256 + path.GetTraversalCost(this) + path.GetTraversalCost(other))) / 128;

                    if (otherPN.pathID != pid)
                    {
                        otherPN.parent = pathNode;
                        otherPN.pathID = pid;

                        otherPN.cost = tmpCost;

                        otherPN.H = path.CalculateHScore(other);
                        other.UpdateG(path, otherPN);

                        //Debug.Log ("G " + otherPN.G + " F " + otherPN.F);
                        handler.PushNode(otherPN);
                        //Debug.DrawRay ((Vector3)otherPN.node.Position, Vector3.up,Color.blue);
                    }
                    else
                    {
                        // Sorry for the huge number of #ifs

                        //If not we can test if the path from the current node to this one is a better one then the one already used

                        if (pathNode.G + tmpCost < otherPN.G)
                        {
                            //Debug.Log ("Path better from " + NodeIndex + " to " + otherPN.node.NodeIndex + " " + (pathNode.G+tmpCost+path.GetTraversalCost(other)) + " < " + otherPN.G);
                            otherPN.cost = tmpCost;

                            otherPN.parent = pathNode;

                            other.UpdateRecursiveG(path, otherPN, handler);

                            //Or if the path from this node ("other") to the current ("current") is better
                        }
                        else if (otherPN.G + tmpCost < pathNode.G && other.ContainsConnection(this))
                        {
                            //Debug.Log ("Path better from " + otherPN.node.NodeIndex + " to " + NodeIndex + " " + (otherPN.G+tmpCost+path.GetTraversalCost (this)) + " < " + pathNode.G);
                            pathNode.parent = otherPN;
                            pathNode.cost   = tmpCost;

                            UpdateRecursiveG(path, pathNode, handler);
                        }
                    }
                }
            }
        }
		protected void DrawMaxSlope (GridGraph graph) {
			graph.maxSlope = EditorGUILayout.Slider (new GUIContent ("Max Slope","Sets the max slope in degrees for a point to be walkable. Only enabled if Height Testing is enabled."),graph.maxSlope,0,90F);
		}
Esempio n. 37
0
        /** Draws settings for using a texture as source for a grid.
         * \astarpro */
        public void DrawTextureData(GridGraph.TextureData data, GridGraph graph)
        {
            if (data == null)
            {
                return;
            }

            data.enabled = ToggleGroup("Use Texture", data.enabled);
            //EditorGUILayout.Toggle ("Use Texture",data.enabled);
            //data.enabled = ToggleGroup ("Use Texture",data.enabled);
            if (!data.enabled)
            {
                return;
            }

            bool preGUI = GUI.enabled;

            GUI.enabled = data.enabled && GUI.enabled;

            EditorGUI.indentLevel++;
            //data.source = EditorGUILayout.ObjectField ("Source",data.source,typeof(Texture2D),false) as Texture2D;
            data.source = ObjectField("Source", data.source, typeof(Texture2D), false) as Texture2D;

            if (data.source != null)
            {
                string path = AssetDatabase.GetAssetPath(data.source);

                if (path != "")
                {
                    TextureImporter importer = AssetImporter.GetAtPath(path) as TextureImporter;
                    if (!importer.isReadable)
                    {
                        if (FixLabel("Texture is not readable"))
                        {
                            importer.isReadable = true;
                            EditorUtility.SetDirty(importer);
                            AssetDatabase.ImportAsset(path);
                        }
                    }
                }
            }

            for (int i = 0; i < 3; i++)
            {
                string channelName = i == 0 ? "R" : (i == 1 ? "G" : "B");
                data.channels[i] = (GridGraph.TextureData.ChannelUse)EditorGUILayout.Popup(channelName, (int)data.channels[i], ChannelUseNames);

                if (data.channels[i] != GridGraph.TextureData.ChannelUse.None)
                {
                    EditorGUI.indentLevel++;
                    data.factors[i] = EditorGUILayout.FloatField("Factor", data.factors[i]);

                    string help = "";
                    switch (data.channels[i])
                    {
                    case GridGraph.TextureData.ChannelUse.Penalty:
                        help = "Nodes are applied penalty according to channel '" + channelName + "', multiplied with factor";
                        break;

                    case GridGraph.TextureData.ChannelUse.Position:
                        help = "Nodes Y position is changed according to channel '" + channelName + "', multiplied with factor";

                        if (graph.collision.heightCheck)
                        {
                            HelpBox("Getting position both from raycast and from texture. You should disable one of them");
                        }
                        break;

                    case GridGraph.TextureData.ChannelUse.WalkablePenalty:
                        help = "If channel '" + channelName + "' is 0, the node is made unwalkable. Otherwise the node is applied penalty multiplied with factor";
                        break;
                    }

                    HelpBox(help);

                    EditorGUI.indentLevel--;
                }
            }

            if (GUILayout.Button("Generate Reference"))
            {
                SaveReferenceTexture(graph);
            }

            GUI.enabled = preGUI;
            EditorGUI.indentLevel--;
        }
		protected void DrawErosion (GridGraph graph) {
			graph.erodeIterations = EditorGUILayout.IntField (new GUIContent ("Erosion iterations","Sets how many times the graph should be eroded. This adds extra margin to objects."),graph.erodeIterations);
			graph.erodeIterations = graph.erodeIterations < 0 ? 0 : (graph.erodeIterations > 16 ? 16 : graph.erodeIterations); //Clamp iterations to [0,16]

			if ( graph.erodeIterations > 0 ) {
				EditorGUI.indentLevel++;
				graph.erosionUseTags = EditorGUILayout.Toggle (new GUIContent ("Erosion Uses Tags","Instead of making nodes unwalkable, " +
				"nodes will have their tag set to a value corresponding to their erosion level, " +
				"which is a quite good measurement of their distance to the closest wall.\nSee online documentation for more info."),
			                                               graph.erosionUseTags);
				if (graph.erosionUseTags) {
					EditorGUI.indentLevel++;
					graph.erosionFirstTag = EditorGUILayoutx.TagField ("First Tag",graph.erosionFirstTag);
					EditorGUI.indentLevel--;
				}
				EditorGUI.indentLevel--;
			}
		}
Esempio n. 39
0
        protected virtual void DrawRules(GridGraph graph)
        {
            var rules = graph.rules.GetRules();

            for (int i = 0; i < rules.Count; i++)
            {
                var rule = rules[i];
                if (rule != null)
                {
                    var ruleEditor = GetEditor(rule);
                    var ruleType   = rule.GetType();
                    GUILayout.BeginHorizontal();
                    rule.enabled = ToggleGroup(ruleHeaders.ContainsKey(ruleType) ? ruleHeaders[ruleType] : ruleType.Name, rule.enabled);
                    if (GUILayout.Button("", AstarPathEditor.astarSkin.FindStyle("SimpleDeleteButton")))
                    {
                        graph.rules.RemoveRule(rule);
                        ruleEditorInstances.Remove(rule);
                        rule.enabled = false;
                        rule.DisposeUnmanagedData();
                    }
                    GUILayout.EndHorizontal();

                    if (rule.enabled)
                    {
                        if (ruleEditor != null)
                        {
                            EditorGUI.indentLevel++;
                            EditorGUI.BeginChangeCheck();
                            ruleEditor.OnInspectorGUI(graph, rule);
                            if (EditorGUI.EndChangeCheck())
                            {
                                rule.SetDirty();
                            }
                            EditorGUI.indentLevel--;
                        }
                        else
                        {
                            EditorGUILayout.HelpBox("No editor found for " + rule.GetType().Name, MessageType.Error);
                        }
                    }
                }
            }

            EditorGUILayout.Separator();

            GUILayout.BeginHorizontal();
            GUILayout.Space(10);
            if (GUILayout.Button("Add Rule"))
            {
                if (ruleEditors == null)
                {
                    FindRuleEditors();
                }
                GenericMenu menu = new GenericMenu();
                foreach (var type in ruleTypes)
                {
                    menu.AddItem(new GUIContent(ruleHeaders.ContainsKey(type) ? ruleHeaders[type] : type.Name), false, ruleType => graph.rules.AddRule(System.Activator.CreateInstance((System.Type)ruleType) as GridGraphRule), type);
                }
                menu.ShowAsContext();
            }
            GUILayout.Space(10);
            GUILayout.EndHorizontal();
        }
		void DrawLastSection (GridGraph graph) {
			GUILayout.Label (new GUIContent ("Advanced"), EditorStyles.boldLabel);

			DrawPenaltyModifications (graph);
			DrawJPS (graph);
		}
        void DrawFirstSection(GridGraph graph)
        {
            float prevRatio = graph.aspectRatio;

            DrawInspectorMode(graph);

            Draw2DMode(graph);

            var normalizedPivotPoint = NormalizedPivotPoint(graph, pivot);
            var worldPoint = graph.CalculateTransform().Transform(normalizedPivotPoint);
            int newWidth, newDepth;

            DrawWidthDepthFields(graph, out newWidth, out newDepth);

            EditorGUI.BeginChangeCheck();
            float newNodeSize;

            if (graph.inspectorGridMode == InspectorGridMode.Hexagonal)
            {
                graph.inspectorHexagonSizeMode = (InspectorGridHexagonNodeSize)EditorGUILayout.EnumPopup(new GUIContent("Hexagon dimension"), graph.inspectorHexagonSizeMode);
                float hexagonSize = GridGraph.ConvertNodeSizeToHexagonSize(graph.inspectorHexagonSizeMode, graph.nodeSize);
                hexagonSize = (float)System.Math.Round(hexagonSize, 5);
                newNodeSize = GridGraph.ConvertHexagonSizeToNodeSize(graph.inspectorHexagonSizeMode, EditorGUILayout.FloatField(hexagonSizeContents[(int)graph.inspectorHexagonSizeMode], hexagonSize));
            }
            else
            {
                newNodeSize = EditorGUILayout.FloatField(new GUIContent("Node size", "The size of a single node. The size is the side of the node square in world units"), graph.nodeSize);
            }
            bool nodeSizeChanged = EditorGUI.EndChangeCheck();

            newNodeSize = newNodeSize <= 0.01F ? 0.01F : newNodeSize;

            if (graph.inspectorGridMode == InspectorGridMode.IsometricGrid || graph.inspectorGridMode == InspectorGridMode.Advanced)
            {
                graph.aspectRatio = EditorGUILayout.FloatField(new GUIContent("Aspect Ratio", "Scaling of the nodes width/depth ratio. Good for isometric games"), graph.aspectRatio);

                DrawIsometricField(graph);
            }

            if ((nodeSizeChanged && locked) || (newWidth != graph.width || newDepth != graph.depth) || prevRatio != graph.aspectRatio)
            {
                graph.nodeSize = newNodeSize;
                graph.SetDimensions(newWidth, newDepth, newNodeSize);

                normalizedPivotPoint = NormalizedPivotPoint(graph, pivot);
                var newWorldPoint = graph.CalculateTransform().Transform(normalizedPivotPoint);
                // Move the center so that the pivot point stays at the same point in the world
                graph.center += worldPoint - newWorldPoint;
                graph.center  = RoundVector3(graph.center);
                graph.UpdateTransform();
                AutoScan();
            }

            if ((nodeSizeChanged && !locked))
            {
                graph.nodeSize = newNodeSize;
                graph.UpdateTransform();
            }

            DrawPositionField(graph);

            DrawRotationField(graph);
        }
		void DrawPenaltyModifications (GridGraph graph) {
			showExtra = EditorGUILayout.Foldout (showExtra, "Penalty Modifications");

			if (showExtra) {
				EditorGUI.indentLevel+=2;

				graph.penaltyAngle = ToggleGroup (new GUIContent ("Angle Penalty","Adds a penalty based on the slope of the node"),graph.penaltyAngle);
				if (graph.penaltyAngle) {
					EditorGUI.indentLevel++;
					graph.penaltyAngleFactor = EditorGUILayout.FloatField (new GUIContent ("Factor","Scale of the penalty. A negative value should not be used"),graph.penaltyAngleFactor);
					graph.penaltyAnglePower = EditorGUILayout.Slider ("Power", graph.penaltyAnglePower, 0.1f, 10f);
					HelpBox ("Applies penalty to nodes based on the angle of the hit surface during the Height Testing\nPenalty applied is: P=(1-cos(angle)^power)*factor.");

					EditorGUI.indentLevel--;
				}

				graph.penaltyPosition = ToggleGroup ("Position Penalty",graph.penaltyPosition);
				if (graph.penaltyPosition) {
					EditorGUI.indentLevel++;
					graph.penaltyPositionOffset = EditorGUILayout.FloatField ("Offset",graph.penaltyPositionOffset);
					graph.penaltyPositionFactor = EditorGUILayout.FloatField ("Factor",graph.penaltyPositionFactor);
					HelpBox ("Applies penalty to nodes based on their Y coordinate\nSampled in Int3 space, i.e it is multiplied with Int3.Precision first ("+Int3.Precision+")\n" +
						"Be very careful when using negative values since a negative penalty will underflow and instead get really high");
					EditorGUI.indentLevel--;
				}

				GUI.enabled = false;
				ToggleGroup (new GUIContent ("Use Texture",AstarPathEditor.AstarProTooltip),false);
				GUI.enabled = true;
				EditorGUI.indentLevel-=2;
			}
		}
Esempio n. 43
0
        public override float SurfaceArea()
        {
            GridGraph gg = GridNode.GetGridGraph(GraphIndex);

            return(gg.nodeSize * gg.nodeSize);
        }
		protected virtual void DrawJPS (GridGraph graph) {
			// Jump point search is a pro only feature
		}
Esempio n. 45
0
 protected virtual void DrawCutCorners(GridGraph graph)
 {
     graph.cutCorners = EditorGUILayout.Toggle(new GUIContent("Cut Corners", "Enables or disables cutting corners. See docs for image example"), graph.cutCorners);
 }
		public void SnapSizeToNodes (int newWidth, int newDepth, GridGraph graph) {
			graph.unclampedSize = new Vector2 (newWidth*graph.nodeSize,newDepth*graph.nodeSize);
			Vector3 newCenter = graph.matrix.MultiplyPoint3x4 (new Vector3 (newWidth/2F,0,newDepth/2F));
			graph.center = newCenter;
			graph.GenerateMatrix ();
			AutoScan ();

			GUI.changed = true;
		}
Esempio n. 47
0
 protected virtual void DrawJPS(GridGraph graph)
 {
     // Jump point search is a pro only feature
 }
Esempio n. 48
0
		public void SaveReferenceTexture (GridGraph graph) {
			//GridGraph graph = target as GridGraph;
			
			if (graph.nodes == null || graph.nodes.Length != graph.width * graph.depth) {
				AstarPath.active.Scan ();
			}
			
			if (graph.nodes.Length != graph.width * graph.depth) {
				Debug.LogError ("Couldn't create reference image since width*depth != nodes.Length");
				return;
			}
			
			if (graph.nodes.Length == 0) {
				Debug.LogError ("Couldn't create reference image since the graph is too small (0*0)");
				return;
			}
			
			Texture2D tex = new Texture2D (graph.width,graph.depth);
			
			float maxY = float.NegativeInfinity;
			for (int i=0;i<graph.nodes.Length;i++) {
				Vector3 p = graph.inverseMatrix.MultiplyPoint ((Vector3)graph.nodes[i].position);
				maxY = p.y > maxY ? p.y : maxY;
			}
			
			Color[] cols = new Color[graph.width*graph.depth];
			
			for (int z=0;z<graph.depth;z++) {
				for (int x=0;x<graph.width;x++) {
					GraphNode node = graph.nodes[z*graph.width+x];
					float v = node.Walkable ? 1F : 0.0F;
					Vector3 p = graph.inverseMatrix.MultiplyPoint ((Vector3)node.position);
					float q = p.y / maxY;
					cols[z*graph.width+x] = new Color (v,q,0);
				}
			}
			tex.SetPixels (cols);
			tex.Apply ();
			
			string path = AssetDatabase.GenerateUniqueAssetPath ("Assets/gridReference.png");
			
			using (System.IO.StreamWriter outstream = new System.IO.StreamWriter (path)) {
				using (System.IO.BinaryWriter outfile = new System.IO.BinaryWriter (outstream.BaseStream)) {
					outfile.Write (tex.EncodeToPNG ());
				}
			}
			AssetDatabase.Refresh ();
			Object obj = AssetDatabase.LoadAssetAtPath (path,typeof (Texture));
			
			EditorGUIUtility.PingObject (obj);
		}
Esempio n. 49
0
 /** Updates shortcuts to the first graph of different types.
  * Hard coding references to some graph types is not really a good thing imo. I want to keep it dynamic and flexible.
  * But these references ease the use of the system, so I decided to keep them. It is the only reference to specific graph types in the pathfinding core.\n
  */
 public void UpdateShortcuts()
 {
     navmesh    = (NavMeshGraph)FindGraphOfType(typeof(NavMeshGraph));
     gridGraph  = (GridGraph)FindGraphOfType(typeof(GridGraph));
     pointGraph = (PointGraph)FindGraphOfType(typeof(PointGraph));
 }
Esempio n. 50
0
		public void SnapSizeToNodes (int newWidth, int newDepth, GridGraph graph) {
			//Vector2 preSize = graph.unclampedSize;
			
			/*if (locked) {
				graph.unclampedSize = new Vector2 (newWidth*newNodeSize,newDepth*newNodeSize);
				graph.nodeSize = newNodeSize;
				graph.GenerateMatrix ();
				Vector3 newCenter = graph.matrix.MultiplyPoint3x4 (new Vector3 (newWidth/2F,0,newDepth/2F));
				graph.center = newCenter;
				AstarPath.active.AutoScan ();
			} else {*/
				graph.unclampedSize = new Vector2 (newWidth*graph.nodeSize,newDepth*graph.nodeSize);
				Vector3 newCenter = graph.matrix.MultiplyPoint3x4 (new Vector3 (newWidth/2F,0,newDepth/2F));
				graph.center = newCenter;
				graph.GenerateMatrix ();
				AstarPath.active.AutoScan ();
			//}
			
			GUI.changed = true;
		}
Esempio n. 51
0
        /// <summary>
        /// Check if a straight path between v1 and v2 is valid.
        /// If both n1 and n2 are supplied it is assumed that the line goes from the center of n1 to the center of n2 and a more optimized graph linecast may be done.
        /// </summary>
        protected bool ValidateLine(GraphNode n1, GraphNode n2, Vector3 v1, Vector3 v2)
        {
            if (useRaycasting)
            {
                // Use raycasting to check if a straight path between v1 and v2 is valid
                if (use2DPhysics)
                {
                    if (thickRaycast && thickRaycastRadius > 0 && Physics2D.CircleCast(v1 + raycastOffset, thickRaycastRadius, v2 - v1, (v2 - v1).magnitude, mask))
                    {
                        return(false);
                    }

                    if (Physics2D.Linecast(v1 + raycastOffset, v2 + raycastOffset, mask))
                    {
                        return(false);
                    }
                }
                else
                {
                    // Perform a thick raycast (if enabled)
                    if (thickRaycast && thickRaycastRadius > 0 && Physics.SphereCast(new Ray(v1 + raycastOffset, v2 - v1), thickRaycastRadius, (v2 - v1).magnitude, mask))
                    {
                        return(false);
                    }

                    // Perform a normal raycast
                    // This is done even if a thick raycast is also done because thick raycasts do not report collisions for
                    // colliders that overlapped the (imaginary) sphere at the origin of the thick raycast.
                    // If this raycast was not done then some obstacles could be missed.
                    if (Physics.Linecast(v1 + raycastOffset, v2 + raycastOffset, mask))
                    {
                        return(false);
                    }
                }
            }

            if (useGraphRaycasting)
            {
#if !ASTAR_NO_GRID_GRAPH
                bool betweenNodeCenters = n1 != null && n2 != null;
#endif
                if (n1 == null)
                {
                    n1 = AstarPath.active.GetNearest(v1).node;
                }
                if (n2 == null)
                {
                    n2 = AstarPath.active.GetNearest(v2).node;
                }

                if (n1 != null && n2 != null)
                {
                    // Use graph raycasting to check if a straight path between v1 and v2 is valid
                    NavGraph graph  = n1.Graph;
                    NavGraph graph2 = n2.Graph;

                    if (graph != graph2)
                    {
                        return(false);
                    }

                    var rayGraph = graph as IRaycastableGraph;
#if !ASTAR_NO_GRID_GRAPH
                    GridGraph gg = graph as GridGraph;
                    if (betweenNodeCenters && gg != null)
                    {
                        // If the linecast is exactly between the centers of two nodes on a grid graph then a more optimized linecast can be used.
                        // This method is also more stable when raycasting along a diagonal when the line just touches an obstacle.
                        // The normal linecast method may or may not detect that as a hit depending on floating point errors
                        // however this method never detect it as an obstacle (and that is very good for this component as it improves the simplification).
                        return(!gg.Linecast(n1 as GridNodeBase, n2 as GridNodeBase));
                    }
                    else
#endif
                    if (rayGraph != null)
                    {
                        return(!rayGraph.Linecast(v1, v2, n1));
                    }
                }
            }
            return(true);
        }
Esempio n. 52
0
        public override void Open(Path path, PathNode pathNode, PathHandler handler)
        {
            GridGraph gg = GetGridGraph(GraphIndex);

            ushort pid = handler.PathID;

#if ASTAR_JPS
            if (gg.useJumpPointSearch && !path.FloodingPath)
            {
                JPSOpen(path, pathNode, handler);
            }
            else
#endif
            {
                int[]      neighbourOffsets = gg.neighbourOffsets;
                uint[]     neighbourCosts   = gg.neighbourCosts;
                GridNode[] nodes            = gg.nodes;

                for (int i = 0; i < 8; i++)
                {
                    if (GetConnectionInternal(i))
                    {
                        GridNode other = nodes[nodeInGridIndex + neighbourOffsets[i]];
                        if (!path.CanTraverse(other))
                        {
                            continue;
                        }

                        PathNode otherPN = handler.GetPathNode(other);

                        uint tmpCost = neighbourCosts[i];

                        if (otherPN.pathID != pid)
                        {
                            otherPN.parent = pathNode;
                            otherPN.pathID = pid;

                            otherPN.cost = tmpCost;

                            otherPN.H = path.CalculateHScore(other);
                            other.UpdateG(path, otherPN);

                            //Debug.Log ("G " + otherPN.G + " F " + otherPN.F);
                            handler.PushNode(otherPN);
                            //Debug.DrawRay ((Vector3)otherPN.node.Position, Vector3.up,Color.blue);
                        }
                        else
                        {
                            // Sorry for the huge number of #ifs

                            //If not we can test if the path from the current node to this one is a better one then the one already used

#if ASTAR_NO_TRAVERSAL_COST
                            if (pathNode.G + tmpCost < otherPN.G)
#else
                            if (pathNode.G + tmpCost + path.GetTraversalCost(other) < otherPN.G)
#endif
                            {
                                //Debug.Log ("Path better from " + NodeIndex + " to " + otherPN.node.NodeIndex + " " + (pathNode.G+tmpCost+path.GetTraversalCost(other)) + " < " + otherPN.G);
                                otherPN.cost = tmpCost;

                                otherPN.parent = pathNode;

                                other.UpdateRecursiveG(path, otherPN, handler);

                                //Or if the path from this node ("other") to the current ("current") is better
                            }
#if ASTAR_NO_TRAVERSAL_COST
                            else if (otherPN.G + tmpCost < pathNode.G)
#else
                            else if (otherPN.G + tmpCost + path.GetTraversalCost(this) < pathNode.G)
#endif
                            {
                                //Debug.Log ("Path better from " + otherPN.node.NodeIndex + " to " + NodeIndex + " " + (otherPN.G+tmpCost+path.GetTraversalCost (this)) + " < " + pathNode.G);
                                pathNode.parent = otherPN;
                                pathNode.cost   = tmpCost;

                                UpdateRecursiveG(path, pathNode, handler);
                            }
                        }
                    }
                }
            }

#if !ASTAR_GRID_NO_CUSTOM_CONNECTIONS
            if (connections != null)
            {
                for (int i = 0; i < connections.Length; i++)
                {
                    GraphNode other = connections[i];
                    if (!path.CanTraverse(other))
                    {
                        continue;
                    }

                    PathNode otherPN = handler.GetPathNode(other);

                    uint tmpCost = connectionCosts[i];

                    if (otherPN.pathID != pid)
                    {
                        otherPN.parent = pathNode;
                        otherPN.pathID = pid;

                        otherPN.cost = tmpCost;

                        otherPN.H = path.CalculateHScore(other);
                        other.UpdateG(path, otherPN);

                        //Debug.Log ("G " + otherPN.G + " F " + otherPN.F);
                        handler.PushNode(otherPN);
                        //Debug.DrawRay ((Vector3)otherPN.node.Position, Vector3.up,Color.blue);
                    }
                    else
                    {
                        // Sorry for the huge number of #ifs

                        //If not we can test if the path from the current node to this one is a better one then the one already used

#if ASTAR_NO_TRAVERSAL_COST
                        if (pathNode.G + tmpCost < otherPN.G)
#else
                        if (pathNode.G + tmpCost + path.GetTraversalCost(other) < otherPN.G)
#endif
                        {
                            //Debug.Log ("Path better from " + NodeIndex + " to " + otherPN.node.NodeIndex + " " + (pathNode.G+tmpCost+path.GetTraversalCost(other)) + " < " + otherPN.G);
                            otherPN.cost = tmpCost;

                            otherPN.parent = pathNode;

                            other.UpdateRecursiveG(path, otherPN, handler);

                            //Or if the path from this node ("other") to the current ("current") is better
                        }
#if ASTAR_NO_TRAVERSAL_COST
                        else if (otherPN.G + tmpCost < pathNode.G && other.ContainsConnection(this))
#else
                        else if (otherPN.G + tmpCost + path.GetTraversalCost(this) < pathNode.G && other.ContainsConnection(this))
#endif
                        {
                            //Debug.Log ("Path better from " + otherPN.node.NodeIndex + " to " + NodeIndex + " " + (otherPN.G+tmpCost+path.GetTraversalCost (this)) + " < " + pathNode.G);
                            pathNode.parent = otherPN;
                            pathNode.cost   = tmpCost;

                            UpdateRecursiveG(path, pathNode, handler);
                        }
                    }
                }
            }
#endif
        }
Esempio n. 53
0
        public override bool GetPortal(GraphNode other, List <Vector3> left, List <Vector3> right, bool backwards)
        {
            if (backwards)
            {
                return(true);
            }

            GridGraph gg = GetGridGraph(GraphIndex);

            int[]      neighbourOffsets = gg.neighbourOffsets;
            GridNode[] nodes            = gg.nodes;

            for (int i = 0; i < 4; i++)
            {
                if (HasConnectionInDirection(i) && other == nodes[NodeInGridIndex + neighbourOffsets[i]])
                {
                    Vector3 middle = ((Vector3)(position + other.position)) * 0.5f;
                    Vector3 cross  = Vector3.Cross(gg.collision.up, (Vector3)(other.position - position));
                    cross.Normalize();
                    cross *= gg.nodeSize * 0.5f;
                    left.Add(middle - cross);
                    right.Add(middle + cross);
                    return(true);
                }
            }

            for (int i = 4; i < 8; i++)
            {
                if (HasConnectionInDirection(i) && other == nodes[NodeInGridIndex + neighbourOffsets[i]])
                {
                    bool rClear = false;
                    bool lClear = false;
                    if (HasConnectionInDirection(i - 4))
                    {
                        GridNode n2 = nodes[NodeInGridIndex + neighbourOffsets[i - 4]];
                        if (n2.Walkable && n2.HasConnectionInDirection((i - 4 + 1) % 4))
                        {
                            rClear = true;
                        }
                    }

                    if (HasConnectionInDirection((i - 4 + 1) % 4))
                    {
                        GridNode n2 = nodes[NodeInGridIndex + neighbourOffsets[(i - 4 + 1) % 4]];
                        if (n2.Walkable && n2.HasConnectionInDirection(i - 4))
                        {
                            lClear = true;
                        }
                    }

                    Vector3 middle = ((Vector3)(position + other.position)) * 0.5f;
                    Vector3 cross  = Vector3.Cross(gg.collision.up, (Vector3)(other.position - position));
                    cross.Normalize();
                    cross *= gg.nodeSize * 1.4142f;
                    left.Add(middle - (lClear ? cross : Vector3.zero));
                    right.Add(middle + (rClear ? cross : Vector3.zero));
                    return(true);
                }
            }

            return(false);
        }
Esempio n. 54
0
        /** Executes a straight jump search.
         * \see http://en.wikipedia.org/wiki/Jump_point_search
         */
        static GridNode JPSJumpStraight(GridNode node, Path path, PathHandler handler, int parentDir, int depth = 0)
        {
            GridGraph gg = GetGridGraph(node.GraphIndex);

            int[]      neighbourOffsets = gg.neighbourOffsets;
            GridNode[] nodes            = gg.nodes;

            GridNode origin = node;
            // Indexing into the cache arrays from multiple threads like this should cause
            // a lot of false sharing and cache trashing, but after profiling it seems
            // that this is not a major concern
            int threadID     = handler.threadID;
            int threadOffset = 8 * handler.threadID;

            int cyclicParentDir = JPSCyclic[parentDir];

            GridNode result = null;

            // Rotate 180 degrees
            const int forwardDir    = 4;
            int       forwardOffset = neighbourOffsets[JPSInverseCyclic[(forwardDir + cyclicParentDir) % 8]];

            // Move forwards in the same direction
            // until a node is encountered which we either
            // * know the result for (memoization)
            // * is a special node (flag2 set)
            // * has custom connections
            // * the node has a forced neighbour
            // Then break out of the loop
            // and start another loop which goes through the same nodes and sets the
            // memoization caches to avoid expensive calls in the future
            while (true)
            {
                // This is needed to make sure different threads don't overwrite each others results
                // It doesn't matter if we throw away some caching done by other threads as this will only
                // happen during the first few path requests
                if (node.JPSLastCacheID == null || node.JPSLastCacheID.Length < handler.totalThreadCount)
                {
                    lock (node) {
                        // Check again in case another thread has already created the array
                        if (node.JPSLastCacheID == null || node.JPSLastCacheID.Length < handler.totalThreadCount)
                        {
                            node.JPSCache       = new GridNode[8 * handler.totalThreadCount];
                            node.JPSDead        = new byte[handler.totalThreadCount];
                            node.JPSLastCacheID = new ushort[handler.totalThreadCount];
                        }
                    }
                }
                if (node.JPSLastCacheID[threadID] != path.pathID)
                {
                    for (int i = 0; i < 8; i++)
                    {
                        node.JPSCache[i + threadOffset] = null;
                    }
                    node.JPSLastCacheID[threadID] = path.pathID;
                    node.JPSDead[threadID]        = 0;
                }

                // Cache earlier results, major optimization
                // It is important to read from it once and then return the same result,
                // if we read from it twice, we might get different results due to other threads clearing the array sometimes
                GridNode cachedResult = node.JPSCache[parentDir + threadOffset];
                if (cachedResult != null)
                {
                    result = cachedResult;
                    break;
                }

                if (((node.JPSDead[threadID] >> parentDir) & 1) != 0)
                {
                    return(null);
                }

                // Special node (e.g end node), take care of
                if (handler.GetPathNode(node).flag2)
                {
                    //Debug.Log ("Found end Node!");
                    //Debug.DrawRay ((Vector3)position, Vector3.up*2, Color.green);
                    result = node;
                    break;
                }

                                #if !ASTAR_GRID_NO_CUSTOM_CONNECTIONS
                // Special node which has custom connections, take care of
                if (node.connections != null && node.connections.Length > 0)
                {
                    result = node;
                    break;
                }
                                #endif


                // These are the nodes this node is connected to, one bit for each of the 8 directions
                int noncyclic = node.gridFlags;                //We don't actually need to & with this because we don't use the other bits. & 0xFF;
                int cyclic    = 0;
                for (int i = 0; i < 8; i++)
                {
                    cyclic |= ((noncyclic >> i) & 0x1) << JPSCyclic[i];
                }


                int forced = 0;
                // Loop around to be able to assume -X is where we came from
                cyclic = ((cyclic >> cyclicParentDir) | ((cyclic << 8) >> cyclicParentDir)) & 0xFF;

                //for ( int i = 0; i < 8; i++ ) if ( ((cyclic >> i)&1) == 0 ) forced |= JPSForced[i];
                if ((cyclic & (1 << 2)) == 0)
                {
                    forced |= (1 << 3);
                }
                if ((cyclic & (1 << 6)) == 0)
                {
                    forced |= (1 << 5);
                }

                int natural = JPSNaturalStraightNeighbours;

                // Check if there are any forced neighbours which we can reach that are not natural neighbours
                //if ( ((forced & cyclic) & (~(natural & cyclic))) != 0 ) {
                if ((forced & (~natural) & cyclic) != 0)
                {
                    // Some of the neighbour nodes are forced
                    result = node;
                    break;
                }

                // Make sure we can reach the next node
                if ((cyclic & (1 << forwardDir)) != 0)
                {
                    node = nodes[node.nodeInGridIndex + forwardOffset];

                    //Debug.DrawLine ( (Vector3)position + Vector3.up*0.2f*(depth), (Vector3)other.position + Vector3.up*0.2f*(depth+1), Color.magenta);
                }
                else
                {
                    result = null;
                    break;
                }
            }

            if (result == null)
            {
                while (origin != node)
                {
                    origin.JPSDead[threadID] |= (byte)(1 << parentDir);
                    origin = nodes[origin.nodeInGridIndex + forwardOffset];
                }
            }
            else
            {
                while (origin != node)
                {
                    origin.JPSCache[parentDir + threadOffset] = result;
                    origin = nodes[origin.nodeInGridIndex + forwardOffset];
                }
            }

            return(result);
        }
Esempio n. 55
0
 public static void SetGridGraph(int graphIndex, GridGraph graph)
 {
     if (GridNode._gridGraphs.Length <= graphIndex)
     {
         GridGraph[] array = new GridGraph[graphIndex + 1];
         for (int i = 0; i < GridNode._gridGraphs.Length; i++)
         {
             array[i] = GridNode._gridGraphs[i];
         }
         GridNode._gridGraphs = array;
     }
     GridNode._gridGraphs[graphIndex] = graph;
 }
		protected override void DrawCutCorners (GridGraph graph) {
			// No corner cutting since only 4 neighbours are possible
		}
Esempio n. 57
0
		/** Draws settings for using a texture as source for a grid.
		 * \astarpro */
		public void DrawTextureData (GridGraph.TextureData data, GridGraph graph) {
			if (data == null) {
				return;
			}
			
			data.enabled = ToggleGroup ("Use Texture",data.enabled);
				//EditorGUILayout.Toggle ("Use Texture",data.enabled);
			//data.enabled = ToggleGroup ("Use Texture",data.enabled);
			if (!data.enabled) {
				return;
			}
			
			bool preGUI = GUI.enabled;
			GUI.enabled = data.enabled && GUI.enabled;
			
			EditorGUI.indentLevel++;
			//data.source = EditorGUILayout.ObjectField ("Source",data.source,typeof(Texture2D),false) as Texture2D;
			data.source = ObjectField ("Source",data.source,typeof(Texture2D),false) as Texture2D;
			
			if (data.source != null) {
				string path = AssetDatabase.GetAssetPath (data.source);
				
				if (path != "") {
					TextureImporter importer = AssetImporter.GetAtPath (path) as TextureImporter;
					if (!importer.isReadable) {
						if (FixLabel ("Texture is not readable")) {
							importer.isReadable = true;
							EditorUtility.SetDirty (importer);
							AssetDatabase.ImportAsset (path);
						}
					}
				}
			}
			
			for (int i=0;i<3;i++) {
				string channelName = i == 0 ? "R" : (i == 1 ? "G" : "B");
				data.channels[i] = (GridGraph.TextureData.ChannelUse)EditorGUILayout.Popup (channelName, (int)data.channels[i], ChannelUseNames);
				
				if (data.channels[i] != GridGraph.TextureData.ChannelUse.None) {
					EditorGUI.indentLevel++;
					data.factors[i] = EditorGUILayout.FloatField ("Factor",data.factors[i]);
					
					string help = "";
					switch (data.channels[i]) {
					case GridGraph.TextureData.ChannelUse.Penalty:
						help = "Nodes are applied penalty according to channel '"+channelName+"', multiplied with factor";
						break;
					case GridGraph.TextureData.ChannelUse.Position:
						help = "Nodes Y position is changed according to channel '"+channelName+"', multiplied with factor";
						
						if (graph.collision.heightCheck) {
							HelpBox ("Getting position both from raycast and from texture. You should disable one of them");
						}
						break;
					case GridGraph.TextureData.ChannelUse.WalkablePenalty:
						help = "If channel '"+channelName+"' is 0, the node is made unwalkable. Otherwise the node is applied penalty multiplied with factor";
						break;
					}
					
					HelpBox (help);
					
					EditorGUI.indentLevel--;
				}
				
			}
			
			if (GUILayout.Button ("Generate Reference")) {
				SaveReferenceTexture (graph);
			}
			
			GUI.enabled = preGUI;
			EditorGUI.indentLevel--;
		}
Esempio n. 58
0
        /// <summary>
        /// Finds all contours of a collection of nodes in a grid graph.
        ///
        /// <code>
        /// var grid = AstarPath.active.data.gridGraph;
        ///
        /// // Find all contours in the graph and draw them using debug lines
        /// GraphUtilities.GetContours(grid, vertices => {
        ///     for (int i = 0; i < vertices.Length; i++) {
        ///         Debug.DrawLine(vertices[i], vertices[(i+1)%vertices.Length], Color.red, 4);
        ///     }
        /// }, 0);
        /// </code>
        ///
        /// In the image below you can see the contour of a graph.
        /// [Open online documentation to see images]
        ///
        /// In the image below you can see the contour of just a part of a grid graph (when the nodes parameter is supplied)
        /// [Open online documentation to see images]
        ///
        /// Contour of a hexagon graph
        /// [Open online documentation to see images]
        ///
        /// See: <see cref="GetContours(NavGraph)"/>
        /// </summary>
        /// <param name="grid">The grid to find the contours of</param>
        /// <param name="callback">The callback will be called once for every contour that is found with the vertices of the contour. The contour always forms a cycle.</param>
        /// <param name="yMergeThreshold">Contours will be simplified if the y coordinates for adjacent vertices differ by no more than this value.</param>
        /// <param name="nodes">Only these nodes will be searched. If this parameter is null then all nodes in the grid graph will be searched.</param>
        public static void GetContours(GridGraph grid, System.Action <Vector3[]> callback, float yMergeThreshold, GridNodeBase[] nodes = null)
        {
            // Set of all allowed nodes or null if all nodes are allowed
            HashSet <GridNodeBase> nodeSet = nodes != null ? new HashSet <GridNodeBase>(nodes) : null;

            // Use all nodes if the nodes parameter is null
            if (grid is LayerGridGraph)
            {
                nodes = nodes ?? (grid as LayerGridGraph).nodes;
            }
            nodes = nodes ?? grid.nodes;
            int[] neighbourXOffsets = grid.neighbourXOffsets;
            int[] neighbourZOffsets = grid.neighbourZOffsets;
            var   neighbourIndices  = grid.neighbours == NumNeighbours.Six ? GridGraph.hexagonNeighbourIndices : new [] { 0, 1, 2, 3 };
            var   offsetMultiplier  = grid.neighbours == NumNeighbours.Six ? 1 / 3f : 0.5f;

            if (nodes != null)
            {
                var trace = ListPool <Vector3> .Claim();

                var seenStates = new HashSet <int>();

                for (int i = 0; i < nodes.Length; i++)
                {
                    var startNode = nodes[i];
                    // The third check is a fast check for if the node has connections in all grid directions, if it has then we can skip processing it (unless the nodes parameter was used in which case we have to handle the edge cases)
                    if (startNode != null && startNode.Walkable && (!startNode.HasConnectionsToAllEightNeighbours || nodeSet != null))
                    {
                        for (int startDir = 0; startDir < neighbourIndices.Length; startDir++)
                        {
                            int startState = (startNode.NodeIndex << 4) | startDir;

                            // Check if there is an obstacle in that direction
                            var startNeighbour = startNode.GetNeighbourAlongDirection(neighbourIndices[startDir]);
                            if ((startNeighbour == null || (nodeSet != null && !nodeSet.Contains(startNeighbour))) && !seenStates.Contains(startState))
                            {
                                // Start tracing a contour here
                                trace.ClearFast();
                                int          dir  = startDir;
                                GridNodeBase node = startNode;

                                while (true)
                                {
                                    int state = (node.NodeIndex << 4) | dir;
                                    if (state == startState && trace.Count > 0)
                                    {
                                        break;
                                    }

                                    seenStates.Add(state);

                                    var neighbour = node.GetNeighbourAlongDirection(neighbourIndices[dir]);
                                    if (neighbour == null || (nodeSet != null && !nodeSet.Contains(neighbour)))
                                    {
                                        // Draw edge
                                        var d0 = neighbourIndices[dir];
                                        dir = (dir + 1) % neighbourIndices.Length;
                                        var d1 = neighbourIndices[dir];

                                        // Position in graph space of the vertex
                                        Vector3 graphSpacePos = new Vector3(node.XCoordinateInGrid + 0.5f, 0, node.ZCoordinateInGrid + 0.5f);
                                        // Offset along diagonal to get the correct XZ coordinates
                                        graphSpacePos.x += (neighbourXOffsets[d0] + neighbourXOffsets[d1]) * offsetMultiplier;
                                        graphSpacePos.z += (neighbourZOffsets[d0] + neighbourZOffsets[d1]) * offsetMultiplier;
                                        graphSpacePos.y  = grid.transform.InverseTransform((Vector3)node.position).y;

                                        if (trace.Count >= 2)
                                        {
                                            var v0  = trace[trace.Count - 2];
                                            var v1  = trace[trace.Count - 1];
                                            var v1d = v1 - v0;
                                            var v2d = graphSpacePos - v0;
                                            // Replace the previous point if it is colinear with the point just before it and just after it (the current point), because that point wouldn't add much information, but it would add CPU overhead
                                            if (((Mathf.Abs(v1d.x) > 0.01f || Mathf.Abs(v2d.x) > 0.01f) && (Mathf.Abs(v1d.z) > 0.01f || Mathf.Abs(v2d.z) > 0.01f)) || (Mathf.Abs(v1d.y) > yMergeThreshold || Mathf.Abs(v2d.y) > yMergeThreshold))
                                            {
                                                trace.Add(graphSpacePos);
                                            }
                                            else
                                            {
                                                trace[trace.Count - 1] = graphSpacePos;
                                            }
                                        }
                                        else
                                        {
                                            trace.Add(graphSpacePos);
                                        }
                                    }
                                    else
                                    {
                                        // Move
                                        node = neighbour;
                                        dir  = (dir + neighbourIndices.Length / 2 + 1) % neighbourIndices.Length;
                                    }
                                }

                                // Simplify the contour a bit around the start point.
                                // Otherwise we might return a cycle which was not as simplified as possible and the number of vertices
                                // would depend on where in the cycle the algorithm started to traverse the contour.
                                if (trace.Count >= 3)
                                {
                                    var v0  = trace[trace.Count - 2];
                                    var v1  = trace[trace.Count - 1];
                                    var v1d = v1 - v0;
                                    var v2d = trace[0] - v0;
                                    // Replace the previous point if it is colinear with the point just before it and just after it (the current point), because that point wouldn't add much information, but it would add CPU overhead
                                    if (!(((Mathf.Abs(v1d.x) > 0.01f || Mathf.Abs(v2d.x) > 0.01f) && (Mathf.Abs(v1d.z) > 0.01f || Mathf.Abs(v2d.z) > 0.01f)) || (Mathf.Abs(v1d.y) > yMergeThreshold || Mathf.Abs(v2d.y) > yMergeThreshold)))
                                    {
                                        trace.RemoveAt(trace.Count - 1);
                                    }
                                }

                                if (trace.Count >= 3)
                                {
                                    var v0  = trace[trace.Count - 1];
                                    var v1  = trace[0];
                                    var v1d = v1 - v0;
                                    var v2d = trace[1] - v0;
                                    // Replace the previous point if it is colinear with the point just before it and just after it (the current point), because that point wouldn't add much information, but it would add CPU overhead
                                    if (!(((Mathf.Abs(v1d.x) > 0.01f || Mathf.Abs(v2d.x) > 0.01f) && (Mathf.Abs(v1d.z) > 0.01f || Mathf.Abs(v2d.z) > 0.01f)) || (Mathf.Abs(v1d.y) > yMergeThreshold || Mathf.Abs(v2d.y) > yMergeThreshold)))
                                    {
                                        trace.RemoveAt(0);
                                    }
                                }
                                var result = trace.ToArray();
                                grid.transform.Transform(result);
                                callback(result);
                            }
                        }
                    }
                }

                ListPool <Vector3> .Release(ref trace);
            }
        }
Esempio n. 59
0
		/** Updates shortcuts to the first graph of different types.
		 * Hard coding references to some graph types is not really a good thing imo. I want to keep it dynamic and flexible.
		 * But these references ease the use of the system, so I decided to keep them. It is the only reference to specific graph types in the pathfinding core.\n
		 */
		public void UpdateShortcuts () {
			navmesh = (NavMeshGraph)FindGraphOfType (typeof(NavMeshGraph));
			gridGraph = (GridGraph)FindGraphOfType (typeof(GridGraph));
			pointGraph = (PointGraph)FindGraphOfType (typeof(PointGraph));
			recastGraph = (RecastGraph)FindGraphOfType (typeof(RecastGraph));
		}
Esempio n. 60
0
		/** Updates shortcuts to the first graph of different types.
		 * Hard coding references to some graph types is not really a good thing imo. I want to keep it dynamic and flexible.
		 * But these references ease the use of the system, so I decided to keep them. It is the only reference to specific graph types in the pathfinding core.\n
		 */
		public void UpdateShortcuts () {
			navmesh = (NavMeshGraph)FindGraphOfType (typeof(NavMeshGraph));

#if !ASTAR_NO_GRID_GRAPH
			gridGraph = (GridGraph)FindGraphOfType (typeof(GridGraph));
#endif

#if !ASTAR_NO_POINT_GRAPH
			pointGraph = (PointGraph)FindGraphOfType (typeof(PointGraph));
#endif

			recastGraph = (RecastGraph)FindGraphOfType (typeof(RecastGraph));
		}