mirror of
https://github.com/Heretek-AI/GDevelop.git
synced 2026-07-22 01:55:25 -04:00
3846a1553b
Co-authored-by: Davy Hélard <davy.helard@gmail.com> Don't show in changelog
804 lines
25 KiB
JavaScript
804 lines
25 KiB
JavaScript
// @ts-check
|
|
describe('gdjs.PathfindingRuntimeBehavior', function () {
|
|
// limit tests cases on the legacy collision methods.
|
|
// Note that the legacy collision mode is still the only mode that exists
|
|
// because the new one were never merged.
|
|
let doLegacyPathFindingTests = (
|
|
cellSize,
|
|
objectCenteredOnCells,
|
|
direction
|
|
) => {
|
|
const pathFindingName = 'auto1';
|
|
|
|
let createScene = () => {
|
|
const runtimeGame = gdjs.getPixiRuntimeGame();
|
|
const runtimeScene = new gdjs.RuntimeScene(runtimeGame);
|
|
runtimeScene.loadFromScene({
|
|
sceneData: {
|
|
layers: [
|
|
{
|
|
name: '',
|
|
visibility: true,
|
|
effects: [],
|
|
cameras: [],
|
|
|
|
ambientLightColorR: 0,
|
|
ambientLightColorG: 0,
|
|
ambientLightColorB: 0,
|
|
isLightingLayer: false,
|
|
followBaseLayerCamera: true,
|
|
},
|
|
],
|
|
variables: [],
|
|
r: 0,
|
|
v: 0,
|
|
b: 0,
|
|
mangledName: 'Scene1',
|
|
name: 'Scene1',
|
|
stopSoundsOnStartup: false,
|
|
title: '',
|
|
behaviorsSharedData: [],
|
|
objects: [],
|
|
instances: [],
|
|
usedResources: [],
|
|
uiSettings: {
|
|
grid: false,
|
|
gridType: 'rectangular',
|
|
gridWidth: 10,
|
|
gridHeight: 10,
|
|
gridDepth: 10,
|
|
gridOffsetX: 0,
|
|
gridOffsetY: 0,
|
|
gridOffsetZ: 0,
|
|
gridColor: 0,
|
|
gridAlpha: 1,
|
|
snap: false,
|
|
},
|
|
},
|
|
usedExtensionsWithVariablesData: [],
|
|
});
|
|
runtimeScene._timeManager.getElapsedTime = function () {
|
|
return (1 / 60) * 1000;
|
|
};
|
|
return runtimeScene;
|
|
};
|
|
|
|
let addPlayer = (runtimeScene) => {
|
|
const player = new gdjs.SpriteRuntimeObject(runtimeScene, {
|
|
name: 'player',
|
|
type: '',
|
|
animations: [
|
|
{
|
|
name: 'animation',
|
|
directions: [
|
|
{
|
|
sprites: [
|
|
{
|
|
originPoint: objectCenteredOnCells
|
|
? { name: 'Origin', x: 80, y: 80 }
|
|
: { name: 'Origin', x: 87, y: 87 },
|
|
centerPoint: {
|
|
name: 'Center',
|
|
x: 80,
|
|
y: 80,
|
|
automatic: false,
|
|
},
|
|
points: [
|
|
{ name: 'Center', x: 80, y: 80 },
|
|
objectCenteredOnCells
|
|
? { name: 'Origin', x: 80, y: 80 }
|
|
: { name: 'Origin', x: 87, y: 87 },
|
|
],
|
|
hasCustomCollisionMask: false,
|
|
customCollisionMask: [],
|
|
image: '',
|
|
},
|
|
],
|
|
timeBetweenFrames: 0,
|
|
looping: false,
|
|
},
|
|
],
|
|
useMultipleDirections: false,
|
|
},
|
|
],
|
|
behaviors: [
|
|
{
|
|
type: 'PathfindingBehavior::PathfindingBehavior',
|
|
name: 'auto1',
|
|
allowDiagonals: false,
|
|
acceleration: 400,
|
|
maxSpeed: 200,
|
|
angularMaxSpeed: 180,
|
|
rotateObject: false,
|
|
angleOffset: 0,
|
|
cellWidth: cellSize,
|
|
cellHeight: cellSize,
|
|
extraBorder: 0,
|
|
},
|
|
],
|
|
variables: [],
|
|
effects: [],
|
|
updateIfNotVisible: true,
|
|
});
|
|
player.getWidth = function () {
|
|
return 160;
|
|
};
|
|
player.getHeight = function () {
|
|
return 160;
|
|
};
|
|
runtimeScene.addObject(player);
|
|
return player;
|
|
};
|
|
|
|
let addObstacle = (runtimeScene) => {
|
|
const obstacle = new gdjs.SpriteRuntimeObject(runtimeScene, {
|
|
name: 'obstacle',
|
|
type: '',
|
|
animations: [
|
|
{
|
|
name: 'animation',
|
|
directions: [
|
|
{
|
|
sprites: [
|
|
{
|
|
originPoint: objectCenteredOnCells
|
|
? { name: 'Origin', x: 80, y: 80 }
|
|
: { name: 'Origin', x: 87, y: 87 },
|
|
centerPoint: {
|
|
name: 'Center',
|
|
x: 80,
|
|
y: 80,
|
|
automatic: false,
|
|
},
|
|
points: [
|
|
{ name: 'Center', x: 80, y: 80 },
|
|
objectCenteredOnCells
|
|
? { name: 'Origin', x: 80, y: 80 }
|
|
: { name: 'Origin', x: 87, y: 87 },
|
|
],
|
|
hasCustomCollisionMask: false,
|
|
customCollisionMask: [],
|
|
image: '',
|
|
},
|
|
],
|
|
timeBetweenFrames: 0,
|
|
looping: false,
|
|
},
|
|
],
|
|
useMultipleDirections: false,
|
|
},
|
|
],
|
|
behaviors: [
|
|
{
|
|
type: 'PathfindingBehavior::PathfindingObstacleBehavior',
|
|
impassable: true,
|
|
cost: 2,
|
|
},
|
|
],
|
|
variables: [],
|
|
effects: [],
|
|
updateIfNotVisible: true,
|
|
});
|
|
obstacle.getWidth = function () {
|
|
return 160;
|
|
};
|
|
obstacle.getHeight = function () {
|
|
return 160;
|
|
};
|
|
runtimeScene.addObject(obstacle);
|
|
|
|
return obstacle;
|
|
};
|
|
|
|
let playerLeftBorder;
|
|
let playerRightBorder;
|
|
let playerTopBorder;
|
|
let playerBottomBorder;
|
|
|
|
let obstacleLeftBorder;
|
|
let obstacleRightBorder;
|
|
let obstacleTopBorder;
|
|
let obstacleBottomBorder;
|
|
|
|
if (cellSize == 160) {
|
|
if (objectCenteredOnCells) {
|
|
playerLeftBorder = 80;
|
|
playerRightBorder = 80;
|
|
playerTopBorder = 80;
|
|
playerBottomBorder = 80;
|
|
} else {
|
|
playerLeftBorder = 87;
|
|
playerRightBorder = 73;
|
|
playerTopBorder = 87;
|
|
playerBottomBorder = 73;
|
|
}
|
|
} else {
|
|
// The player radius is at most 2 cells
|
|
playerLeftBorder = 2 * cellSize;
|
|
playerRightBorder = 2 * cellSize;
|
|
playerTopBorder = 2 * cellSize;
|
|
playerBottomBorder = 2 * cellSize;
|
|
}
|
|
|
|
if (objectCenteredOnCells) {
|
|
obstacleLeftBorder = 80;
|
|
obstacleRightBorder = 80;
|
|
obstacleTopBorder = 80;
|
|
obstacleBottomBorder = 80;
|
|
} else {
|
|
obstacleLeftBorder = 87;
|
|
obstacleRightBorder = 73;
|
|
obstacleTopBorder = 87;
|
|
obstacleBottomBorder = 73;
|
|
}
|
|
|
|
let inclusiveMargin;
|
|
if (cellSize == 160) {
|
|
// The collision is strict
|
|
inclusiveMargin = 0;
|
|
} else {
|
|
// The collision is not strict
|
|
inclusiveMargin = 1;
|
|
}
|
|
|
|
// multiple of 20 and 160
|
|
const playerX = 480;
|
|
const playerY = 320;
|
|
|
|
let runtimeScene;
|
|
let player;
|
|
beforeEach(function () {
|
|
runtimeScene = createScene();
|
|
player = addPlayer(runtimeScene);
|
|
});
|
|
|
|
it('can find a path with an obstacle near the start', function () {
|
|
const obstacle = addObstacle(runtimeScene);
|
|
|
|
let obstacleX;
|
|
let obstacleY;
|
|
let targetX;
|
|
let targetY;
|
|
switch (direction) {
|
|
case 'right':
|
|
// right on the player right
|
|
obstacleX = playerX + playerRightBorder + obstacleLeftBorder;
|
|
obstacleY = playerY;
|
|
targetX = playerX - 2 * cellSize;
|
|
targetY = playerY;
|
|
break;
|
|
case 'left':
|
|
obstacleX = playerX - playerLeftBorder - obstacleRightBorder;
|
|
obstacleY = playerY;
|
|
targetX = playerX + 2 * cellSize;
|
|
targetY = playerY;
|
|
break;
|
|
case 'up':
|
|
obstacleX = playerX;
|
|
obstacleY = playerY - playerTopBorder - obstacleBottomBorder;
|
|
targetX = playerX;
|
|
targetY = playerY + 2 * cellSize;
|
|
break;
|
|
case 'down':
|
|
obstacleX = playerX;
|
|
obstacleY = playerY + playerBottomBorder + obstacleTopBorder;
|
|
targetX = playerX;
|
|
targetY = playerY - 2 * cellSize;
|
|
break;
|
|
default:
|
|
throw new Error('Invalid direction for the test');
|
|
}
|
|
|
|
obstacle.setPosition(obstacleX, obstacleY);
|
|
// To ensure obstacles are registered.
|
|
runtimeScene.renderAndStep(1000 / 60);
|
|
|
|
// move away from the obstacle
|
|
player.setPosition(playerX, playerY);
|
|
player
|
|
.getBehavior(pathFindingName)
|
|
.moveTo(runtimeScene, targetX, targetY);
|
|
expect(player.getBehavior(pathFindingName).pathFound()).to.be(true);
|
|
expect(player.getBehavior(pathFindingName).getNodeCount()).to.be(3);
|
|
});
|
|
|
|
it('can find a path when an obstacle is overlapping only at the start', function () {
|
|
const obstacle = addObstacle(runtimeScene);
|
|
|
|
let obstacleX;
|
|
let obstacleY;
|
|
let targetX;
|
|
let targetY;
|
|
switch (direction) {
|
|
case 'right':
|
|
// The obstacle will be right on the player right after the first step.
|
|
// So, it's overlapping the player by one cell length at start.
|
|
obstacleX =
|
|
playerX +
|
|
playerRightBorder +
|
|
obstacleLeftBorder -
|
|
cellSize +
|
|
inclusiveMargin;
|
|
obstacleY = playerY;
|
|
targetX = playerX - 2 * cellSize;
|
|
targetY = playerY;
|
|
break;
|
|
case 'left':
|
|
obstacleX =
|
|
playerX -
|
|
playerLeftBorder -
|
|
obstacleRightBorder +
|
|
cellSize -
|
|
inclusiveMargin;
|
|
obstacleY = playerY;
|
|
targetX = playerX + 2 * cellSize;
|
|
targetY = playerY;
|
|
break;
|
|
case 'up':
|
|
obstacleX = playerX;
|
|
obstacleY =
|
|
playerY -
|
|
playerTopBorder -
|
|
obstacleBottomBorder +
|
|
cellSize -
|
|
inclusiveMargin;
|
|
targetX = playerX;
|
|
targetY = playerY + 2 * cellSize;
|
|
break;
|
|
case 'down':
|
|
obstacleX = playerX;
|
|
obstacleY =
|
|
playerY +
|
|
playerBottomBorder +
|
|
obstacleTopBorder -
|
|
cellSize +
|
|
inclusiveMargin;
|
|
targetX = playerX;
|
|
targetY = playerY - 2 * cellSize;
|
|
break;
|
|
default:
|
|
throw new Error('Invalid direction for the test');
|
|
}
|
|
|
|
obstacle.setPosition(obstacleX, obstacleY);
|
|
// To ensure obstacles are registered.
|
|
runtimeScene.renderAndStep(1000 / 60);
|
|
|
|
// move away from the obstacle
|
|
player.setPosition(playerX, playerY);
|
|
player
|
|
.getBehavior(pathFindingName)
|
|
.moveTo(runtimeScene, targetX, targetY);
|
|
expect(player.getBehavior(pathFindingName).pathFound()).to.be(true);
|
|
expect(player.getBehavior(pathFindingName).getNodeCount()).to.be(3);
|
|
});
|
|
|
|
it("mustn't find a path when an obstacle is slightly overlapping the only first cell to go", function () {
|
|
const obstacle = addObstacle(runtimeScene);
|
|
|
|
let obstacleX;
|
|
let obstacleY;
|
|
let targetX;
|
|
let targetY;
|
|
switch (direction) {
|
|
case 'right':
|
|
// The obstacle will be right on the player right after the first step.
|
|
// So, it's overlapping the player by one cell length at start.
|
|
obstacleX =
|
|
playerX +
|
|
playerRightBorder +
|
|
obstacleLeftBorder -
|
|
cellSize +
|
|
inclusiveMargin -
|
|
1;
|
|
obstacleY = playerY;
|
|
targetX = playerX - 2 * cellSize;
|
|
targetY = playerY;
|
|
break;
|
|
case 'left':
|
|
obstacleX =
|
|
playerX -
|
|
playerLeftBorder -
|
|
obstacleRightBorder +
|
|
cellSize -
|
|
inclusiveMargin +
|
|
1;
|
|
obstacleY = playerY;
|
|
targetX = playerX + 2 * cellSize;
|
|
targetY = playerY;
|
|
break;
|
|
case 'up':
|
|
obstacleX = playerX;
|
|
obstacleY =
|
|
playerY -
|
|
playerTopBorder -
|
|
obstacleBottomBorder +
|
|
cellSize -
|
|
inclusiveMargin +
|
|
1;
|
|
targetX = playerX;
|
|
targetY = playerY + 2 * cellSize;
|
|
break;
|
|
case 'down':
|
|
obstacleX = playerX;
|
|
obstacleY =
|
|
playerY +
|
|
playerBottomBorder +
|
|
obstacleTopBorder -
|
|
cellSize +
|
|
inclusiveMargin -
|
|
1;
|
|
targetX = playerX;
|
|
targetY = playerY - 2 * cellSize;
|
|
break;
|
|
default:
|
|
throw new Error('Invalid direction for the test');
|
|
}
|
|
|
|
obstacle.setPosition(obstacleX, obstacleY);
|
|
// To ensure obstacles are registered.
|
|
runtimeScene.renderAndStep(1000 / 60);
|
|
|
|
// move away from the obstacle
|
|
player.setPosition(playerX, playerY);
|
|
player
|
|
.getBehavior(pathFindingName)
|
|
.moveTo(runtimeScene, targetX, targetY);
|
|
if (cellSize == 160) {
|
|
// The obstacle is the size of the cell so the player can bypass it.
|
|
expect(player.getBehavior(pathFindingName).getNodeCount()).to.be.above(
|
|
3
|
|
);
|
|
} else {
|
|
expect(player.getBehavior(pathFindingName).pathFound()).to.be(false);
|
|
}
|
|
});
|
|
|
|
it('can find a path with an obstacle adjacent to the target', function () {
|
|
const obstacle = addObstacle(runtimeScene);
|
|
|
|
let obstacleX;
|
|
let obstacleY;
|
|
let targetX;
|
|
let targetY;
|
|
switch (direction) {
|
|
case 'right':
|
|
targetX = playerX + 2 * cellSize;
|
|
targetY = playerY;
|
|
// will be right on the player right at the end
|
|
obstacleX =
|
|
targetX + playerRightBorder + obstacleLeftBorder + inclusiveMargin;
|
|
obstacleY = playerY;
|
|
break;
|
|
case 'left':
|
|
targetX = playerX - 2 * cellSize;
|
|
targetY = playerY;
|
|
obstacleX =
|
|
targetX - playerRightBorder - obstacleLeftBorder - inclusiveMargin;
|
|
obstacleY = playerY;
|
|
break;
|
|
case 'up':
|
|
targetX = playerX;
|
|
targetY = playerY - 2 * cellSize;
|
|
obstacleX = playerX;
|
|
obstacleY =
|
|
targetY - playerTopBorder - obstacleBottomBorder - inclusiveMargin;
|
|
break;
|
|
case 'down':
|
|
targetX = playerX;
|
|
targetY = playerY + 2 * cellSize;
|
|
obstacleX = playerX;
|
|
obstacleY =
|
|
targetY + playerBottomBorder + obstacleTopBorder + inclusiveMargin;
|
|
break;
|
|
default:
|
|
throw new Error('Invalid direction for the test');
|
|
}
|
|
|
|
obstacle.setPosition(obstacleX, obstacleY);
|
|
// so obstacles register
|
|
runtimeScene.renderAndStep(1000 / 60);
|
|
|
|
// move as close as possible to the obstacle
|
|
player.setPosition(playerX, playerY);
|
|
player
|
|
.getBehavior(pathFindingName)
|
|
.moveTo(runtimeScene, targetX, targetY);
|
|
expect(player.getBehavior(pathFindingName).pathFound()).to.be(true);
|
|
expect(player.getBehavior(pathFindingName).getNodeCount()).to.be(3);
|
|
});
|
|
|
|
it("mustn't find a path with an obstacle slightly overlapping to the target", function () {
|
|
const obstacle = addObstacle(runtimeScene);
|
|
|
|
let obstacleX;
|
|
let obstacleY;
|
|
let targetX;
|
|
let targetY;
|
|
switch (direction) {
|
|
case 'right':
|
|
targetX = playerX + 2 * cellSize;
|
|
targetY = playerY;
|
|
obstacleX =
|
|
targetX +
|
|
playerRightBorder +
|
|
obstacleLeftBorder +
|
|
inclusiveMargin -
|
|
1;
|
|
obstacleY = playerY;
|
|
break;
|
|
case 'left':
|
|
targetX = playerX - 2 * cellSize;
|
|
targetY = playerY;
|
|
obstacleX =
|
|
targetX -
|
|
playerLeftBorder -
|
|
obstacleRightBorder -
|
|
inclusiveMargin +
|
|
1;
|
|
obstacleY = playerY;
|
|
break;
|
|
case 'up':
|
|
targetX = playerX;
|
|
targetY = playerY - 2 * cellSize;
|
|
obstacleX = playerX;
|
|
obstacleY =
|
|
targetY -
|
|
playerTopBorder -
|
|
obstacleBottomBorder -
|
|
inclusiveMargin +
|
|
1;
|
|
break;
|
|
case 'down':
|
|
targetX = playerX;
|
|
targetY = playerY + 2 * cellSize;
|
|
obstacleX = playerX;
|
|
obstacleY =
|
|
targetY +
|
|
playerBottomBorder +
|
|
obstacleTopBorder +
|
|
inclusiveMargin -
|
|
1;
|
|
break;
|
|
default:
|
|
throw new Error('Invalid direction for the test');
|
|
}
|
|
|
|
obstacle.setPosition(obstacleX, obstacleY);
|
|
// To ensure obstacles are registered.
|
|
runtimeScene.renderAndStep(1000 / 60);
|
|
|
|
// move as close as possible to the obstacle
|
|
player.setPosition(playerX, playerY);
|
|
player
|
|
.getBehavior(pathFindingName)
|
|
.moveTo(runtimeScene, targetX, targetY);
|
|
expect(player.getBehavior(pathFindingName).pathFound()).to.be(false);
|
|
});
|
|
|
|
it('can find a path between 2 obstacles making a path perfectly adjusted to the object', function () {
|
|
const obstacleTop = addObstacle(runtimeScene);
|
|
const obstacleBottom = addObstacle(runtimeScene);
|
|
|
|
let topObstacleX;
|
|
let bottomObstacleX;
|
|
let topObstacleY;
|
|
let bottomObstacleY;
|
|
let targetX;
|
|
let targetY;
|
|
let straightLineCellCount;
|
|
switch (direction) {
|
|
case 'right': {
|
|
const obstacleX =
|
|
playerX + playerRightBorder + 2 * cellSize + obstacleLeftBorder;
|
|
topObstacleX = obstacleX;
|
|
bottomObstacleX = obstacleX;
|
|
topObstacleY =
|
|
playerY - playerTopBorder - obstacleBottomBorder - inclusiveMargin;
|
|
bottomObstacleY =
|
|
playerY + playerBottomBorder + obstacleTopBorder + inclusiveMargin;
|
|
targetX =
|
|
obstacleX + obstacleRightBorder + playerLeftBorder + 2 * cellSize;
|
|
targetY = playerY;
|
|
straightLineCellCount = (targetX - playerX) / cellSize + 1;
|
|
break;
|
|
}
|
|
case 'left': {
|
|
const obstacleX =
|
|
playerX - playerLeftBorder - 2 * cellSize - obstacleRightBorder;
|
|
topObstacleX = obstacleX;
|
|
bottomObstacleX = obstacleX;
|
|
topObstacleY =
|
|
playerY - playerTopBorder - obstacleBottomBorder - inclusiveMargin;
|
|
bottomObstacleY =
|
|
playerY + playerBottomBorder + obstacleTopBorder + inclusiveMargin;
|
|
targetX =
|
|
obstacleX - obstacleLeftBorder - playerRightBorder - 2 * cellSize;
|
|
targetY = playerY;
|
|
straightLineCellCount = (playerX - targetX) / cellSize + 1;
|
|
break;
|
|
}
|
|
case 'up': {
|
|
// topObstacle and bottomObstacle are actually left and right but for convenience...
|
|
const obstacleY =
|
|
playerY - playerTopBorder - 2 * cellSize - obstacleBottomBorder;
|
|
topObstacleY = obstacleY;
|
|
bottomObstacleY = obstacleY;
|
|
topObstacleX =
|
|
playerX - playerLeftBorder - obstacleRightBorder - inclusiveMargin;
|
|
bottomObstacleX =
|
|
playerX + playerRightBorder + obstacleLeftBorder + inclusiveMargin;
|
|
targetY =
|
|
obstacleY - obstacleTopBorder - playerBottomBorder - 2 * cellSize;
|
|
targetX = playerX;
|
|
straightLineCellCount = (playerY - targetY) / cellSize + 1;
|
|
break;
|
|
}
|
|
case 'down': {
|
|
// topObstacle and bottomObstacle are actually left and right but for convenience...
|
|
const obstacleY =
|
|
playerY + playerBottomBorder + 2 * cellSize + obstacleTopBorder;
|
|
topObstacleY = obstacleY;
|
|
bottomObstacleY = obstacleY;
|
|
topObstacleX =
|
|
playerX - playerLeftBorder - obstacleRightBorder - inclusiveMargin;
|
|
bottomObstacleX =
|
|
playerX + playerRightBorder + obstacleLeftBorder + inclusiveMargin;
|
|
targetY =
|
|
obstacleY + obstacleBottomBorder + playerTopBorder + 2 * cellSize;
|
|
targetX = playerX;
|
|
straightLineCellCount = (targetY - playerY) / cellSize + 1;
|
|
break;
|
|
}
|
|
default:
|
|
throw new Error('Invalid direction for the test');
|
|
}
|
|
|
|
obstacleTop.setPosition(topObstacleX, topObstacleY);
|
|
obstacleBottom.setPosition(bottomObstacleX, bottomObstacleY);
|
|
// To ensure obstacles are registered.
|
|
runtimeScene.renderAndStep(1000 / 60);
|
|
|
|
player.setPosition(playerX, playerY);
|
|
player
|
|
.getBehavior(pathFindingName)
|
|
.moveTo(runtimeScene, targetX, targetY);
|
|
expect(player.getBehavior(pathFindingName).pathFound()).to.be(true);
|
|
expect(player.getBehavior(pathFindingName).getNodeCount()).to.be(
|
|
straightLineCellCount
|
|
);
|
|
});
|
|
|
|
it("mustn't find a direct path between 2 slightly too much tighten obstacles", function () {
|
|
const obstacleTop = addObstacle(runtimeScene);
|
|
const obstacleBottom = addObstacle(runtimeScene);
|
|
|
|
let topObstacleX;
|
|
let bottomObstacleX;
|
|
let topObstacleY;
|
|
let bottomObstacleY;
|
|
let targetX;
|
|
let targetY;
|
|
let straightLineCellCount;
|
|
switch (direction) {
|
|
case 'right': {
|
|
const obstacleX =
|
|
playerX + playerRightBorder + 2 * cellSize + obstacleLeftBorder;
|
|
topObstacleX = obstacleX;
|
|
bottomObstacleX = obstacleX;
|
|
topObstacleY =
|
|
playerY - playerTopBorder - obstacleBottomBorder - inclusiveMargin;
|
|
bottomObstacleY =
|
|
playerY +
|
|
playerBottomBorder +
|
|
obstacleTopBorder +
|
|
inclusiveMargin -
|
|
1;
|
|
targetX =
|
|
obstacleX + obstacleRightBorder + playerLeftBorder + 2 * cellSize;
|
|
targetY = playerY;
|
|
straightLineCellCount = (targetX - playerX) / cellSize + 1;
|
|
break;
|
|
}
|
|
case 'left': {
|
|
const obstacleX =
|
|
playerX - playerLeftBorder - 2 * cellSize - obstacleRightBorder;
|
|
topObstacleX = obstacleX;
|
|
bottomObstacleX = obstacleX;
|
|
topObstacleY =
|
|
playerY - playerTopBorder - obstacleBottomBorder - inclusiveMargin;
|
|
bottomObstacleY =
|
|
playerY +
|
|
playerBottomBorder +
|
|
obstacleTopBorder +
|
|
inclusiveMargin -
|
|
1;
|
|
targetX =
|
|
obstacleX - obstacleLeftBorder - playerRightBorder - 2 * cellSize;
|
|
targetY = playerY;
|
|
straightLineCellCount = (playerX - targetX) / cellSize + 1;
|
|
break;
|
|
}
|
|
case 'up': {
|
|
// topObstacle and bottomObstacle are actually left and right but for convenience...
|
|
const obstacleY =
|
|
playerY - playerTopBorder - 2 * cellSize - obstacleBottomBorder;
|
|
topObstacleY = obstacleY;
|
|
bottomObstacleY = obstacleY;
|
|
topObstacleX =
|
|
playerX - playerLeftBorder - obstacleRightBorder - inclusiveMargin;
|
|
bottomObstacleX =
|
|
playerX +
|
|
playerRightBorder +
|
|
obstacleLeftBorder +
|
|
inclusiveMargin -
|
|
1;
|
|
targetY =
|
|
obstacleY - obstacleTopBorder - playerBottomBorder - 2 * cellSize;
|
|
targetX = playerX;
|
|
straightLineCellCount = (playerY - targetY) / cellSize + 1;
|
|
break;
|
|
}
|
|
case 'down': {
|
|
// topObstacle and bottomObstacle are actually left and right but for convenience...
|
|
const obstacleY =
|
|
playerY + playerBottomBorder + 2 * cellSize + obstacleTopBorder;
|
|
topObstacleY = obstacleY;
|
|
bottomObstacleY = obstacleY;
|
|
topObstacleX =
|
|
playerX - playerLeftBorder - obstacleRightBorder - inclusiveMargin;
|
|
bottomObstacleX =
|
|
playerX +
|
|
playerRightBorder +
|
|
obstacleLeftBorder +
|
|
inclusiveMargin -
|
|
1;
|
|
targetY =
|
|
obstacleY + obstacleBottomBorder + playerTopBorder + 2 * cellSize;
|
|
targetX = playerX;
|
|
straightLineCellCount = (targetY - playerY) / cellSize + 1;
|
|
break;
|
|
}
|
|
default:
|
|
throw new Error('Invalid direction for the test');
|
|
}
|
|
|
|
obstacleTop.setPosition(topObstacleX, topObstacleY);
|
|
obstacleBottom.setPosition(bottomObstacleX, bottomObstacleY);
|
|
// To ensure obstacles are registered.
|
|
runtimeScene.renderAndStep(1000 / 60);
|
|
|
|
player.setPosition(playerX, playerY);
|
|
player
|
|
.getBehavior(pathFindingName)
|
|
.moveTo(runtimeScene, targetX, targetY);
|
|
expect(player.getBehavior(pathFindingName).pathFound()).to.be(true);
|
|
// had to do a little detour
|
|
expect(player.getBehavior(pathFindingName).getNodeCount()).to.be.above(
|
|
straightLineCellCount
|
|
);
|
|
});
|
|
};
|
|
|
|
describe('(collisionMethod: Legacy,', function () {
|
|
// Small cells and cells the object size
|
|
[20, 160].forEach((cellSize) => {
|
|
describe(`cellSize: ${cellSize},`, function () {
|
|
[false, true].forEach((objectCenteredOnCells) => {
|
|
describe(`centered: ${objectCenteredOnCells},`, function () {
|
|
['left', 'right', 'down', 'up'].forEach((direction) => {
|
|
describe(`direction: ${direction})`, function () {
|
|
doLegacyPathFindingTests(
|
|
cellSize,
|
|
objectCenteredOnCells,
|
|
direction
|
|
);
|
|
});
|
|
});
|
|
});
|
|
});
|
|
});
|
|
});
|
|
});
|
|
});
|