public List<Vector3D> FindPath(Actor actor, Vector3D Start, Vector3D Destination) { _baseX = 0; _baseY = 0; // reset to 0 // Should only be null first time a path is requested. if (_curScene == null) { _curScene = actor.CurrentScene; if(!listOfPathFinderInstances.TryGetValue(_curScene.SceneSNO.Id,out mPathFinder)) // Attempts to pull the pathfinder which matches the scenes SNO from the patherlist { mPathFinder = new PathFinderFast(_curScene.NavMesh.WalkGrid); // Create a new pather, using the current scenes grid. listOfPathFinderInstances.TryAdd(_curScene.SceneSNO.Id, mPathFinder); // add it to our patherlist, with the SNO as key. } InitPathFinder(); } // Checks if our path start location is inside current scene, if it isnt, we reset curScene and set mPathfinder to the corrent grid. if (!_curScene.Bounds.IntersectsWith(new System.Windows.Rect(Start.X, Start.Y, 1, 1))) { _curScene = actor.CurrentScene;// TODO- THIS CAN RETURN PARENT RATHER THAN SUBSCENE - DarkLotus if (!listOfPathFinderInstances.TryGetValue(_curScene.SceneSNO.Id, out mPathFinder)) { mPathFinder = new PathFinderFast(_curScene.NavMesh.WalkGrid); listOfPathFinderInstances.TryAdd(_curScene.SceneSNO.Id, mPathFinder); } InitPathFinder(); } _baseX = _curScene.Position.X; //Our base location for working out world > SceneLocal coordinates. _baseY = _curScene.Position.Y; // Path's start and destination are both in same scene. if (_curScene.Bounds.IntersectsWith(new System.Windows.Rect(Destination.X, Destination.Y, 1, 1))) { _destScene = _curScene; } else { //Builds a new grid on the fly containing both the start and destination scenes. This is not really optimal, but its a trade off. // Keeping grids Scene based means they can be used cross game even when laid out different in a seperate world. This keeps memory usage down substantially. // Also limited to a max distance of scene > scene. Again this keeps memory usage low. _destScene = _curScene.World.QuadTree.Query<Scene>(new System.Windows.Rect(Destination.X, Destination.Y, 1, 1)).FirstOrDefault(); mPathFinder = new PathFinderFast(BuildOutOfSceneGrid(_curScene, _destScene, ref _baseX, ref _baseY)); InitPathFinder(); } //2.5f is because Scene navmesh's are based on 96x96 for a 240x240 scene - Darklotus _startSceneLocal.X = (int)((Start.X - _baseX) / 2.5f); _startSceneLocal.Y = (int)((Start.Y - _baseY) / 2.5f); _destinationSceneLocal.X = (int)((Destination.X - _baseX) / 2.5f); _destinationSceneLocal.Y = (int)((Destination.Y - _baseY) / 2.5f); //Possibily add a check to ensure start/dest local coords are valid. Unneeded so far. nodePathList = mPathFinder.FindPath(_startSceneLocal, _destinationSceneLocal); // The actual pathfind request, the path is found here. vectorPathList.Clear(); // Clear the previous path. if (nodePathList == null) { //TODO: Sometimes Mobs are require to spawn outside current walkable boundaries, with the current implementation //Pathfinder is unable to return a valid path if the mob is outside this boundaries. //This is just a hackish way to force a path over the mob. Logger.Debug("Pathfinding forced hack activated due Mob outside walkable area"); vectorPathList.Insert(0, new Vector3D(Destination.X,Destination.Y,Destination.Z)); return vectorPathList; }// No Path Found. if (nodePathList.Count < 1) { return vectorPathList; } // Safety net Incase start/dest are the same. for (int i = 0; i < nodePathList.Count; i++) { // Convert the path into world coordinates for use in Movement. // TODO Objectpool maybe? vectorPathList.Insert(0, new Vector3D(nodePathList[i].X * 2.5f + _baseX, nodePathList[i].Y * 2.5f + _baseY, 0)); } //new System.Threading.Thread(c => System.Windows.Forms.Application.Run(new PatherDebug.PatherDebug(actor, vectorPathList))).Start(); return vectorPathList; }
public List <Vector3D> FindPath(Actor actor, Vector3D Start, Vector3D Destination) { _baseX = 0; _baseY = 0; // reset to 0 // Should only be null first time a path is requested. if (_curScene == null) { _curScene = actor.CurrentScene; if (!listOfPathFinderInstances.TryGetValue(_curScene.SceneSNO.Id, out mPathFinder)) // Attempts to pull the pathfinder which matches the scenes SNO from the patherlist { mPathFinder = new PathFinderFast(_curScene.NavMesh.WalkGrid); // Create a new pather, using the current scenes grid. listOfPathFinderInstances.TryAdd(_curScene.SceneSNO.Id, mPathFinder); // add it to our patherlist, with the SNO as key. } InitPathFinder(); } // Checks if our path start location is inside current scene, if it isnt, we reset curScene and set mPathfinder to the corrent grid. if (!_curScene.Bounds.IntersectsWith(new System.Windows.Rect(Start.X, Start.Y, 1, 1))) { _curScene = actor.CurrentScene; if (!listOfPathFinderInstances.TryGetValue(_curScene.SceneSNO.Id, out mPathFinder)) { mPathFinder = new PathFinderFast(_curScene.NavMesh.WalkGrid); listOfPathFinderInstances.TryAdd(_curScene.SceneSNO.Id, mPathFinder); } InitPathFinder(); } _baseX = _curScene.Position.X; //Our base location for working out world > SceneLocal coordinates. _baseY = _curScene.Position.Y; // Path's start and destination are both in same scene. if (_curScene.Bounds.IntersectsWith(new System.Windows.Rect(Destination.X, Destination.Y, 1, 1))) { _destScene = _curScene; } else { //Builds a new grid on the fly containing both the start and destination scenes. This is not really optimal, but its a trade off. // Keeping grids Scene based means they can be used cross game even when laid out different in a seperate world. This keeps memory usage down substantially. // Also limited to a max distance of scene > scene. Again this keeps memory usage low. _destScene = _curScene.World.QuadTree.Query <Scene>(new System.Windows.Rect(Destination.X, Destination.Y, 1, 1)).FirstOrDefault(); mPathFinder = new PathFinderFast(BuildOutOfSceneGrid(_curScene, _destScene, ref _baseX, ref _baseY)); InitPathFinder(); } //2.5f is because Scene navmesh's are based on 96x96 for a 240x240 scene - Darklotus _startSceneLocal.X = (int)((Start.X - _baseX) / 2.5f); _startSceneLocal.Y = (int)((Start.Y - _baseY) / 2.5f); _destinationSceneLocal.X = (int)((Destination.X - _baseX) / 2.5f); _destinationSceneLocal.Y = (int)((Destination.Y - _baseY) / 2.5f); //Possibily add a check to ensure start/dest local coords are valid. Unneeded so far. nodePathList = mPathFinder.FindPath(_startSceneLocal, _destinationSceneLocal); // The actual pathfind request, the path is found here. vectorPathList.Clear(); // Clear the previous path. if (nodePathList == null) { return(vectorPathList); } // No Path Found. if (nodePathList.Count < 1) { return(vectorPathList); } // Safety net Incase start/dest are the same. for (int i = 0; i < nodePathList.Count; i++) { // Convert the path into world coordinates for use in Movement. // TODO Objectpool maybe? vectorPathList.Insert(0, new Vector3D(nodePathList[i].X * 2.5f + _baseX, nodePathList[i].Y * 2.5f + _baseY, 0)); } return(vectorPathList); }