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

Add custom condition #40

Closed
5 changes: 5 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,11 @@ easystar.enableSync();
```javascript
easystar.setDirectionalCondition(x, y, [EasyStar.TOP, EasyStar.BOTTOM]); // only accessible from the top and left
```
```javascript
easystar.setCustomCondition(x, y, function(sourceNode, thisNode, grid) {
return grid[sourceNode.y][sourceNode.x] === 2 // only allow '2' nodes to access the node a [x, y]
})
```

## Usage

Expand Down
24 changes: 23 additions & 1 deletion index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,9 @@ export const LEFT: 'LEFT'
export const TOP_LEFT: 'TOP_LEFT'

type Direction = 'TOP' | 'TOP_RIGHT' | 'RIGHT' | 'BOTTOM_RIGHT' | 'BOTTOM' | 'BOTTOM_LEFT' | 'LEFT' | 'TOP_LEFT'
type CustomCheck = (source?: { x: number, y: number }, thisNode?: { x: number, y: number}, grid?: number[][]) => boolean

export class js {

/**
* Sets the collision grid that EasyStar uses.
*
Expand Down Expand Up @@ -158,4 +158,26 @@ export class js {
* Remove all directional conditions
*/
removeAllDirectionalConditions(): void

/**
* Sets a custom condition on a tile
*
* @param {Number} x The x value of the point.
* @param {Number} y The y value of the point.
* @param {Function} customCheck Function to check whether a movement onto a tile is valid
*/
setCustomCondition(x: number, y: number, customCheck: CustomCheck): void

/**
* Remove all custom conditions
*/
removeAllCustomConditions(): void
}

/**
* Calculate the direction to a node
*
* @param {Object} sourceNode The source node
* @param {Object} destinationNode The destination node
*/
export function calculateDirection(sourceNode: { x: number, y: number }, destinationNode: { x: number, y: number }): Direction
65 changes: 47 additions & 18 deletions src/easystar.js
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ EasyStar.js = function() {
var costMap = {};
var pointsToCost = {};
var directionalConditions = {};
var customConditions = {};
var allowCornerCutting = true;
var iterationsSoFar;
var instances = [];
Expand Down Expand Up @@ -155,6 +156,25 @@ EasyStar.js = function() {
directionalConditions = {};
};

/**
* Sets a custom condition on a tile
*
* @param {Number} x The x value of the point.
* @param {Number} y The y value of the point.
* @param {Function} customCheck Function that takes the sourceNode and the grid as an argument
* and returns a boolean.
**/
this.setCustomCondition = function(x, y, customCheck) {
customConditions[x + '_' + y] = customCheck;
};

/**
* Remove all custom conditions
**/
this.removeAllCustomConditions = function () {
customConditions = {}
};

/**
* Sets the number of search iterations per calculation.
* A lower number provides a slower result, but more practical if you
Expand Down Expand Up @@ -443,7 +463,7 @@ EasyStar.js = function() {
// Helpers
var isTileWalkable = function(collisionGrid, acceptableTiles, x, y, sourceNode) {
if (directionalConditions[x + "_" + y]) {
var direction = calculateDirection(sourceNode.x - x, sourceNode.y - y)
var direction = EasyStar.calculateDirection(sourceNode, { x: x, y: y })
var directionIncluded = function () {
for (var i = 0; i < directionalConditions[x + "_" + y].length; i++) {
if (directionalConditions[x + "_" + y][i] === direction) return true
Expand All @@ -452,6 +472,12 @@ EasyStar.js = function() {
}
if (!directionIncluded()) return false
}

if (customConditions[x + "_" + y] &&
!customConditions[x + "_" + y](sourceNode, { x: x, y: y}, collisionGrid)) {
return false
}

for (var i = 0; i < acceptableTiles.length; i++) {
if (collisionGrid[y][x] === acceptableTiles[i]) {
return true;
Expand All @@ -461,23 +487,6 @@ EasyStar.js = function() {
return false;
};

/**
* -1, -1 | 0, -1 | 1, -1
* -1, 0 | SOURCE | 1, 0
* -1, 1 | 0, 1 | 1, 1
*/
var calculateDirection = function (diffX, diffY) {
if (diffX === 0, diffY === -1) return EasyStar.BOTTOM
else if (diffX === 1, diffY === -1) return EasyStar.BOTTOM_LEFT
else if (diffX === 1, diffY === 0) return EasyStar.LEFT
else if (diffX === 1, diffY === 1) return EasyStar.TOP_LEFT
else if (diffX === 0, diffY === 1) return EasyStar.TOP
else if (diffX === -1, diffY === 1) return EasyStar.TOP_RIGHT
else if (diffX === -1, diffY === 0) return EasyStar.RIGHT
else if (diffX === -1, diffY === -1) return EasyStar.BOTTOM_RIGHT
throw new Error('These differences are not valid: ' + diffX + ', ' + diffY)
};

var getTileCost = function(x, y) {
return pointsToCost[x + '_' + y] || costMap[collisionGrid[y][x]]
};
Expand Down Expand Up @@ -516,6 +525,26 @@ EasyStar.js = function() {
};
}


/**
* -1, -1 | 0, -1 | 1, -1
* -1, 0 | SOURCE | 1, 0
* -1, 1 | 0, 1 | 1, 1
*/
EasyStar.calculateDirection = function (sourceNode, destinationNode) {
var diffX = sourceNode.x - destinationNode.x
var diffY = sourceNode.y - destinationNode.y
if (diffX === 0, diffY === -1) return EasyStar.BOTTOM
else if (diffX === 1, diffY === -1) return EasyStar.BOTTOM_LEFT
else if (diffX === 1, diffY === 0) return EasyStar.LEFT
else if (diffX === 1, diffY === 1) return EasyStar.TOP_LEFT
else if (diffX === 0, diffY === 1) return EasyStar.TOP
else if (diffX === -1, diffY === 1) return EasyStar.TOP_RIGHT
else if (diffX === -1, diffY === 0) return EasyStar.RIGHT
else if (diffX === -1, diffY === -1) return EasyStar.BOTTOM_RIGHT
throw new Error('These differences are not valid: ' + diffX + ', ' + diffY)
};

EasyStar.TOP = 'TOP'
EasyStar.TOP_RIGHT = 'TOP_RIGHT'
EasyStar.RIGHT = 'RIGHT'
Expand Down
25 changes: 25 additions & 0 deletions test/easystartest.js
Original file line number Diff line number Diff line change
Expand Up @@ -266,6 +266,31 @@ describe("EasyStar.js", function() {
done();
});

easyStar.calculate();
})
it("It should handle tiles with a custom condition", function (done) {
var easyStar = new EasyStar.js();
var grid = [
[0, 1, 0],
[0, 0, 4],
[4, 0, 0],
];
easyStar.setGrid(grid);
easyStar.setAcceptableTiles([0, 4, 5]);
easyStar.setCustomCondition(1, 1, function(source, thisNode, grid) {
return grid[source.y][source.x] === 4
})
easyStar.setCustomCondition(1, 2, function (source, thisNode, grid) {
return EasyStar.calculateDirection(source, thisNode) === 'LEFT' && grid[source.y][source.x] === 4
})

easyStar.findPath(0, 0, 2, 0, function (path) {
expect(path).not.toBeNull();
expect(path[3]).toEqual({ x: 1, y: 2 })
expect(path.length).toEqual(7);
done();
});

easyStar.calculate();
})
});