Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Adds option to 'find nearest' when target tile is unacceptable #95

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
20 changes: 16 additions & 4 deletions bin/easystar-0.4.4.js
Expand Up @@ -116,7 +116,7 @@ var EasyStar=
*
* Implementation By Bryce Neal (@prettymuchbryce)
**/
var EasyStar={},Instance=__webpack_require__(1),Node=__webpack_require__(2),Heap=__webpack_require__(3);module.exports=EasyStar;var nextInstanceId=1;EasyStar.js=function(){var collisionGrid,iterationsSoFar,acceptableTiles,syncEnabled=!1,pointsToAvoid={},costMap={},pointsToCost={},directionalConditions={},allowCornerCutting=!0,instances={},instanceQueue=[],iterationsPerCalculation=Number.MAX_VALUE,diagonalsEnabled=!1;
var EasyStar={},Instance=__webpack_require__(1),Node=__webpack_require__(2),Heap=__webpack_require__(3);module.exports=EasyStar;var nextInstanceId=1;EasyStar.js=function(){var collisionGrid,iterationsSoFar,acceptableTiles,syncEnabled=!1,pointsToAvoid={},costMap={},pointsToCost={},directionalConditions={},allowCornerCutting=!0,instances={},instanceQueue=[],iterationsPerCalculation=Number.MAX_VALUE,diagonalsEnabled=!1,findNearestEnabled=!1;
/**
* Sets the collision grid that EasyStar uses.
*
Expand Down Expand Up @@ -146,6 +146,14 @@ this.enableDiagonals=function(){diagonalsEnabled=!0},
* Disable diagonal pathfinding.
*/
this.disableDiagonals=function(){diagonalsEnabled=!1},
/**
* Enable pathfinder to find 'nearest' tile when non acceptable tile is selected.
*/
this.enableFindNearest=function(){findNearestEnabled=!0},
/**
* Enable find nearest.
*/
this.disableFindNearest=function(){findNearestEnabled=!1},
/**
* Sets the collision grid that EasyStar uses.
*
Expand Down Expand Up @@ -249,7 +257,7 @@ if(void 0===acceptableTiles)throw new Error("You can't set a path without first
if(void 0===collisionGrid)throw new Error("You can't set a path without first calling setGrid() on EasyStar.");// Start or endpoint outside of scope.
if(startX<0||startY<0||endX<0||endY<0||startX>collisionGrid[0].length-1||startY>collisionGrid.length-1||endX>collisionGrid[0].length-1||endY>collisionGrid.length-1)throw new Error("Your start or end point is outside the scope of your grid.");// Start and end are the same tile.
if(startX!==endX||startY!==endY){for(// End point is not an acceptable tile.
var endTile=collisionGrid[endY][endX],isAcceptable=!1,i=0;i<acceptableTiles.length;i++)if(endTile===acceptableTiles[i]){isAcceptable=!0;break}if(!1!==isAcceptable){// Create the instance
var endTile=collisionGrid[endY][endX],isAcceptable=!1,i=0;i<acceptableTiles.length;i++)if(endTile===acceptableTiles[i]){isAcceptable=!0;break}if(!1!==isAcceptable||findNearestEnabled){// Create the instance
var instance=new Instance;instance.openList=new Heap((function(nodeA,nodeB){return nodeA.bestGuessDistance()-nodeB.bestGuessDistance()})),instance.isDoneCalculating=!1,instance.nodeHash={},instance.startX=startX,instance.startY=startY,instance.endX=endX,instance.endY=endY,instance.callback=callbackWrapper,instance.openList.push(coordinateToNode(instance,instance.startX,instance.startY,null,1));var instanceId=nextInstanceId++;return instances[instanceId]=instance,instanceQueue.push(instanceId),instanceId}callbackWrapper(null)}else callbackWrapper([])},
/**
* Cancel a path calculation.
Expand All @@ -269,10 +277,14 @@ this.calculate=function(){if(0!==instanceQueue.length&&void 0!==collisionGrid&&v
// If this is a sync instance, we want to make sure that it calculates synchronously.
iterationsSoFar=0);var instanceId=instanceQueue[0],instance=instances[instanceId];if(void 0!==instance)// Couldn't find a path.
if(0!==instance.openList.size()){var searchNode=instance.openList.pop();// Handles the case where we have found the destination
if(instance.endX!==searchNode.x||instance.endY!==searchNode.y)searchNode.list=0,searchNode.y>0&&checkAdjacentNode(instance,searchNode,0,-1,1*getTileCost(searchNode.x,searchNode.y-1)),searchNode.x<collisionGrid[0].length-1&&checkAdjacentNode(instance,searchNode,1,0,1*getTileCost(searchNode.x+1,searchNode.y)),searchNode.y<collisionGrid.length-1&&checkAdjacentNode(instance,searchNode,0,1,1*getTileCost(searchNode.x,searchNode.y+1)),searchNode.x>0&&checkAdjacentNode(instance,searchNode,-1,0,1*getTileCost(searchNode.x-1,searchNode.y)),diagonalsEnabled&&(searchNode.x>0&&searchNode.y>0&&(allowCornerCutting||isTileWalkable(collisionGrid,acceptableTiles,searchNode.x,searchNode.y-1,searchNode)&&isTileWalkable(collisionGrid,acceptableTiles,searchNode.x-1,searchNode.y,searchNode))&&checkAdjacentNode(instance,searchNode,-1,-1,1.4*getTileCost(searchNode.x-1,searchNode.y-1)),searchNode.x<collisionGrid[0].length-1&&searchNode.y<collisionGrid.length-1&&(allowCornerCutting||isTileWalkable(collisionGrid,acceptableTiles,searchNode.x,searchNode.y+1,searchNode)&&isTileWalkable(collisionGrid,acceptableTiles,searchNode.x+1,searchNode.y,searchNode))&&checkAdjacentNode(instance,searchNode,1,1,1.4*getTileCost(searchNode.x+1,searchNode.y+1)),searchNode.x<collisionGrid[0].length-1&&searchNode.y>0&&(allowCornerCutting||isTileWalkable(collisionGrid,acceptableTiles,searchNode.x,searchNode.y-1,searchNode)&&isTileWalkable(collisionGrid,acceptableTiles,searchNode.x+1,searchNode.y,searchNode))&&checkAdjacentNode(instance,searchNode,1,-1,1.4*getTileCost(searchNode.x+1,searchNode.y-1)),searchNode.x>0&&searchNode.y<collisionGrid.length-1&&(allowCornerCutting||isTileWalkable(collisionGrid,acceptableTiles,searchNode.x,searchNode.y+1,searchNode)&&isTileWalkable(collisionGrid,acceptableTiles,searchNode.x-1,searchNode.y,searchNode))&&checkAdjacentNode(instance,searchNode,-1,1,1.4*getTileCost(searchNode.x-1,searchNode.y+1)));else{var path=[];path.push({x:searchNode.x,y:searchNode.y});for(var parent=searchNode.parent;null!=parent;)path.push({x:parent.x,y:parent.y}),parent=parent.parent;path.reverse();var ip=path;instance.callback(ip),delete instances[instanceId],instanceQueue.shift()}}else instance.callback(null),delete instances[instanceId],instanceQueue.shift();else
if(instance.endX!==searchNode.x||instance.endY!==searchNode.y)searchNode.list=0,searchNode.y>0&&checkAdjacentNode(instance,searchNode,0,-1,1*getTileCost(searchNode.x,searchNode.y-1)),searchNode.x<collisionGrid[0].length-1&&checkAdjacentNode(instance,searchNode,1,0,1*getTileCost(searchNode.x+1,searchNode.y)),searchNode.y<collisionGrid.length-1&&checkAdjacentNode(instance,searchNode,0,1,1*getTileCost(searchNode.x,searchNode.y+1)),searchNode.x>0&&checkAdjacentNode(instance,searchNode,-1,0,1*getTileCost(searchNode.x-1,searchNode.y)),diagonalsEnabled&&(searchNode.x>0&&searchNode.y>0&&(allowCornerCutting||isTileWalkable(collisionGrid,acceptableTiles,searchNode.x,searchNode.y-1,searchNode)&&isTileWalkable(collisionGrid,acceptableTiles,searchNode.x-1,searchNode.y,searchNode))&&checkAdjacentNode(instance,searchNode,-1,-1,1.4*getTileCost(searchNode.x-1,searchNode.y-1)),searchNode.x<collisionGrid[0].length-1&&searchNode.y<collisionGrid.length-1&&(allowCornerCutting||isTileWalkable(collisionGrid,acceptableTiles,searchNode.x,searchNode.y+1,searchNode)&&isTileWalkable(collisionGrid,acceptableTiles,searchNode.x+1,searchNode.y,searchNode))&&checkAdjacentNode(instance,searchNode,1,1,1.4*getTileCost(searchNode.x+1,searchNode.y+1)),searchNode.x<collisionGrid[0].length-1&&searchNode.y>0&&(allowCornerCutting||isTileWalkable(collisionGrid,acceptableTiles,searchNode.x,searchNode.y-1,searchNode)&&isTileWalkable(collisionGrid,acceptableTiles,searchNode.x+1,searchNode.y,searchNode))&&checkAdjacentNode(instance,searchNode,1,-1,1.4*getTileCost(searchNode.x+1,searchNode.y-1)),searchNode.x>0&&searchNode.y<collisionGrid.length-1&&(allowCornerCutting||isTileWalkable(collisionGrid,acceptableTiles,searchNode.x,searchNode.y+1,searchNode)&&isTileWalkable(collisionGrid,acceptableTiles,searchNode.x-1,searchNode.y,searchNode))&&checkAdjacentNode(instance,searchNode,-1,1,1.4*getTileCost(searchNode.x-1,searchNode.y+1)));else{(path=[]).push({x:searchNode.x,y:searchNode.y});for(var parent=searchNode.parent;null!=parent;)path.push({x:parent.x,y:parent.y}),parent=parent.parent;path.reverse();var ip=path;instance.callback(ip),delete instances[instanceId],instanceQueue.shift()}}else{
// if nearest target is rdesired
if(findNearestEnabled)
// does instance have a 'nearest target'
if(instance.nearestTarget){for(var path=[],targetNode=instance.nearestTarget;targetNode;)path.push({x:targetNode.x,y:targetNode.y}),targetNode=targetNode.parent;instance.callback(path.reverse())}else instance.callback(null);else instance.callback(null);delete instances[instanceId],instanceQueue.shift()}else
// This instance was cancelled
instanceQueue.shift()}};// Private methods follow
var checkAdjacentNode=function(instance,searchNode,x,y,cost){var adjacentCoordinateX=searchNode.x+x,adjacentCoordinateY=searchNode.y+y;if((void 0===pointsToAvoid[adjacentCoordinateY]||void 0===pointsToAvoid[adjacentCoordinateY][adjacentCoordinateX])&&isTileWalkable(collisionGrid,acceptableTiles,adjacentCoordinateX,adjacentCoordinateY,searchNode)){var node=coordinateToNode(instance,adjacentCoordinateX,adjacentCoordinateY,searchNode,cost);void 0===node.list?(node.list=1,instance.openList.push(node)):searchNode.costSoFar+cost<node.costSoFar&&(node.costSoFar=searchNode.costSoFar+cost,node.parent=searchNode,instance.openList.updateItem(node))}},isTileWalkable=function(collisionGrid,acceptableTiles,x,y,sourceNode){var directionalCondition=directionalConditions[y]&&directionalConditions[y][x];if(directionalCondition){var direction=calculateDirection(sourceNode.x-x,sourceNode.y-y);if(!function(){for(var i=0;i<directionalCondition.length;i++)if(directionalCondition[i]===direction)return!0;return!1}())return!1}for(var i=0;i<acceptableTiles.length;i++)if(collisionGrid[y][x]===acceptableTiles[i])return!0;return!1},calculateDirection=function(diffX,diffY){if(0===diffX&&-1===diffY)return EasyStar.TOP;if(1===diffX&&-1===diffY)return EasyStar.TOP_RIGHT;if(1===diffX&&0===diffY)return EasyStar.RIGHT;if(1===diffX&&1===diffY)return EasyStar.BOTTOM_RIGHT;if(0===diffX&&1===diffY)return EasyStar.BOTTOM;if(-1===diffX&&1===diffY)return EasyStar.BOTTOM_LEFT;if(-1===diffX&&0===diffY)return EasyStar.LEFT;if(-1===diffX&&-1===diffY)return EasyStar.TOP_LEFT;throw new Error("These differences are not valid: "+diffX+", "+diffY)},getTileCost=function(x,y){return pointsToCost[y]&&pointsToCost[y][x]||costMap[collisionGrid[y][x]]},coordinateToNode=function(instance,x,y,parent,cost){if(void 0!==instance.nodeHash[y]){if(void 0!==instance.nodeHash[y][x])return instance.nodeHash[y][x]}else instance.nodeHash[y]={};var simpleDistanceToTarget=getDistance(x,y,instance.endX,instance.endY);if(null!==parent)var costSoFar=parent.costSoFar+cost;else costSoFar=0;var node=new Node(parent,x,y,costSoFar,simpleDistanceToTarget);return instance.nodeHash[y][x]=node,node},getDistance=function(x1,y1,x2,y2){
var checkAdjacentNode=function(instance,searchNode,x,y,cost){var adjacentCoordinateX=searchNode.x+x,adjacentCoordinateY=searchNode.y+y;if((void 0===pointsToAvoid[adjacentCoordinateY]||void 0===pointsToAvoid[adjacentCoordinateY][adjacentCoordinateX])&&isTileWalkable(collisionGrid,acceptableTiles,adjacentCoordinateX,adjacentCoordinateY,searchNode)){var node=coordinateToNode(instance,adjacentCoordinateX,adjacentCoordinateY,searchNode,cost);void 0===node.list?(node.list=1,instance.openList.push(node)):searchNode.costSoFar+cost<node.costSoFar?(node.costSoFar=searchNode.costSoFar+cost,node.parent=searchNode,instance.openList.updateItem(node)):findNearestEnabled&&(instance.nearestTarget?(node.simpleDistanceToTarget<instance.nearestTarget.simpleDistanceToTarget||node.simpleDistanceToTarget===instance.nearestTarget.simpleDistanceToTarget&&node.costSoFar<instance.nearestTarget.costSoFar)&&(instance.nearestTarget=node):instance.nearestTarget=searchNode)}},isTileWalkable=function(collisionGrid,acceptableTiles,x,y,sourceNode){var directionalCondition=directionalConditions[y]&&directionalConditions[y][x];if(directionalCondition){var direction=calculateDirection(sourceNode.x-x,sourceNode.y-y);if(!function(){for(var i=0;i<directionalCondition.length;i++)if(directionalCondition[i]===direction)return!0;return!1}())return!1}for(var i=0;i<acceptableTiles.length;i++)if(collisionGrid[y][x]===acceptableTiles[i])return!0;return!1},calculateDirection=function(diffX,diffY){if(0===diffX&&-1===diffY)return EasyStar.TOP;if(1===diffX&&-1===diffY)return EasyStar.TOP_RIGHT;if(1===diffX&&0===diffY)return EasyStar.RIGHT;if(1===diffX&&1===diffY)return EasyStar.BOTTOM_RIGHT;if(0===diffX&&1===diffY)return EasyStar.BOTTOM;if(-1===diffX&&1===diffY)return EasyStar.BOTTOM_LEFT;if(-1===diffX&&0===diffY)return EasyStar.LEFT;if(-1===diffX&&-1===diffY)return EasyStar.TOP_LEFT;throw new Error("These differences are not valid: "+diffX+", "+diffY)},getTileCost=function(x,y){return pointsToCost[y]&&pointsToCost[y][x]||costMap[collisionGrid[y][x]]},coordinateToNode=function(instance,x,y,parent,cost){if(void 0!==instance.nodeHash[y]){if(void 0!==instance.nodeHash[y][x])return instance.nodeHash[y][x]}else instance.nodeHash[y]={};var simpleDistanceToTarget=getDistance(x,y,instance.endX,instance.endY);if(null!==parent)var costSoFar=parent.costSoFar+cost;else costSoFar=0;var node=new Node(parent,x,y,costSoFar,simpleDistanceToTarget);return instance.nodeHash[y][x]=node,node},getDistance=function(x1,y1,x2,y2){
// Octile distance
var dx,dy;return diagonalsEnabled?(dx=Math.abs(x1-x2))<(dy=Math.abs(y1-y2))?1.4*dx+dy:1.4*dy+dx:(dx=Math.abs(x1-x2))+(dy=Math.abs(y1-y2))};// Helpers
},EasyStar.TOP="TOP",EasyStar.TOP_RIGHT="TOP_RIGHT",EasyStar.RIGHT="RIGHT",EasyStar.BOTTOM_RIGHT="BOTTOM_RIGHT",EasyStar.BOTTOM="BOTTOM",EasyStar.BOTTOM_LEFT="BOTTOM_LEFT",EasyStar.LEFT="LEFT",EasyStar.TOP_LEFT="TOP_LEFT"},
Expand Down