diff --git a/src/frontend/app.js b/src/frontend/app.js
index 11d18ba..1f7f94a 100644
--- a/src/frontend/app.js
+++ b/src/frontend/app.js
@@ -1,13 +1,15 @@
import Game from './utilities/Game.js';
import Player from './utilities/Player.js';
-const canvas = document.querySelector('canvas');
+const foregroundCanvas = document.getElementById('foreground-layer');
+const playerCanvas = document.getElementById('player-layer');
+
const movementKeys = ['w', 'a', 's', 'd', 'ArrowUp', 'ArrowLeft', 'ArrowDown', 'ArrowRight'];
-const game = new Game(canvas);
+const game = new Game(foregroundCanvas, playerCanvas);
const player = new Player();
-await game.loadGameBoard('./maps/dev.json'); // load the gameboard/map from json file
+await game.loadGameBoard('./assets/map.json'); // load the gameboard/map from json file
game.addPlayer(player);
game.start();
diff --git a/src/frontend/assets/map.json b/src/frontend/assets/map.json
new file mode 100644
index 0000000..4f210d6
--- /dev/null
+++ b/src/frontend/assets/map.json
@@ -0,0 +1,566 @@
+{
+ "intersections": [
+ {
+ "x": 48,
+ "y": 48
+ },
+ {
+ "x": 208,
+ "y": 48
+ },
+ {
+ "x": 400,
+ "y": 48
+ },
+ {
+ "x": 496,
+ "y": 48
+ },
+ {
+ "x": 688,
+ "y": 48
+ },
+ {
+ "x": 848,
+ "y": 48
+ },
+ {
+ "x": 48,
+ "y": 176
+ },
+ {
+ "x": 208,
+ "y": 176
+ },
+ {
+ "x": 304,
+ "y": 176
+ },
+ {
+ "x": 400,
+ "y": 176
+ },
+ {
+ "x": 496,
+ "y": 176
+ },
+ {
+ "x": 592,
+ "y": 176
+ },
+ {
+ "x": 688,
+ "y": 176
+ },
+ {
+ "x": 848,
+ "y": 176
+ },
+ {
+ "x": 48,
+ "y": 272
+ },
+ {
+ "x": 208,
+ "y": 272
+ },
+ {
+ "x": 304,
+ "y": 272
+ },
+ {
+ "x": 400,
+ "y": 272
+ },
+ {
+ "x": 496,
+ "y": 272
+ },
+ {
+ "x": 592,
+ "y": 272
+ },
+ {
+ "x": 688,
+ "y": 272
+ },
+ {
+ "x": 848,
+ "y": 272
+ },
+ {
+ "x": 304,
+ "y": 368
+ },
+ {
+ "x": 400,
+ "y": 368
+ },
+ {
+ "x": 448,
+ "y": 368
+ },
+ {
+ "x": 496,
+ "y": 368
+ },
+ {
+ "x": 592,
+ "y": 368
+ },
+ {
+ "x": 20,
+ "y": 464
+ },
+ {
+ "x": 208,
+ "y": 464
+ },
+ {
+ "x": 304,
+ "y": 464
+ },
+ {
+ "x": 376,
+ "y": 464
+ },
+ {
+ "x": 412,
+ "y": 464
+ },
+ {
+ "x": 448,
+ "y": 464
+ },
+ {
+ "x": 484,
+ "y": 464
+ },
+ {
+ "x": 520,
+ "y": 464
+ },
+ {
+ "x": 592,
+ "y": 464
+ },
+ {
+ "x": 688,
+ "y": 464
+ },
+ {
+ "x": 868,
+ "y": 464
+ },
+ {
+ "x": 304,
+ "y": 560
+ },
+ {
+ "x": 592,
+ "y": 560
+ },
+ {
+ "x": 48,
+ "y": 656
+ },
+ {
+ "x": 208,
+ "y": 656
+ },
+ {
+ "x": 304,
+ "y": 656
+ },
+ {
+ "x": 400,
+ "y": 656
+ },
+ {
+ "x": 496,
+ "y": 656
+ },
+ {
+ "x": 592,
+ "y": 656
+ },
+ {
+ "x": 688,
+ "y": 656
+ },
+ {
+ "x": 848,
+ "y": 656
+ },
+ {
+ "x": 48,
+ "y": 752
+ },
+ {
+ "x": 112,
+ "y": 752
+ },
+ {
+ "x": 208,
+ "y": 752
+ },
+ {
+ "x": 304,
+ "y": 752
+ },
+ {
+ "x": 400,
+ "y": 752
+ },
+ {
+ "x": 496,
+ "y": 752
+ },
+ {
+ "x": 592,
+ "y": 752
+ },
+ {
+ "x": 688,
+ "y": 752
+ },
+ {
+ "x": 784,
+ "y": 752
+ },
+ {
+ "x": 848,
+ "y": 752
+ },
+ {
+ "x": 48,
+ "y": 848
+ },
+ {
+ "x": 112,
+ "y": 848
+ },
+ {
+ "x": 208,
+ "y": 848
+ },
+ {
+ "x": 304,
+ "y": 848
+ },
+ {
+ "x": 400,
+ "y": 848
+ },
+ {
+ "x": 496,
+ "y": 848
+ },
+ {
+ "x": 592,
+ "y": 848
+ },
+ {
+ "x": 688,
+ "y": 848
+ },
+ {
+ "x": 784,
+ "y": 848
+ },
+ {
+ "x": 848,
+ "y": 848
+ },
+ {
+ "x": 48,
+ "y": 944
+ },
+ {
+ "x": 400,
+ "y": 944
+ },
+ {
+ "x": 496,
+ "y": 944
+ },
+ {
+ "x": 848,
+ "y": 944
+ }
+ ],
+ "portals": [
+ [
+ {
+ "x": 20,
+ "y": 464
+ },
+ {
+ "x": 868,
+ "y": 464
+ }
+ ]
+ ],
+ "inaccessiblePaths": [
+ [
+ {
+ "x": 400,
+ "y": 48
+ },
+ {
+ "x": 496,
+ "y": 48
+ }
+ ],
+ [
+ {
+ "x": 208,
+ "y": 272
+ },
+ {
+ "x": 304,
+ "y": 272
+ }
+ ],
+ [
+ {
+ "x": 400,
+ "y": 272
+ },
+ {
+ "x": 496,
+ "y": 272
+ }
+ ],
+ [
+ {
+ "x": 592,
+ "y": 272
+ },
+ {
+ "x": 688,
+ "y": 272
+ }
+ ],
+ [
+ {
+ "x": 400,
+ "y": 176
+ },
+ {
+ "x": 400,
+ "y": 272
+ }
+ ],
+ [
+ {
+ "x": 496,
+ "y": 176
+ },
+ {
+ "x": 496,
+ "y": 272
+ }
+ ],
+ [
+ {
+ "x": 304,
+ "y": 272
+ },
+ {
+ "x": 304,
+ "y": 368
+ }
+ ],
+ [
+ {
+ "x": 592,
+ "y": 272
+ },
+ {
+ "x": 592,
+ "y": 368
+ }
+ ],
+ [
+ {
+ "x": 304,
+ "y": 464
+ },
+ {
+ "x": 376,
+ "y": 464
+ }
+ ],
+ [
+ {
+ "x": 520,
+ "y": 464
+ },
+ {
+ "x": 592,
+ "y": 464
+ }
+ ],
+ [
+ {
+ "x": 400,
+ "y": 656
+ },
+ {
+ "x": 496,
+ "y": 656
+ }
+ ],
+ [
+ {
+ "x": 400,
+ "y": 368
+ },
+ {
+ "x": 400,
+ "y": 656
+ }
+ ],
+ [
+ {
+ "x": 496,
+ "y": 368
+ },
+ {
+ "x": 496,
+ "y": 656
+ }
+ ],
+ [
+ {
+ "x": 112,
+ "y": 752
+ },
+ {
+ "x": 208,
+ "y": 752
+ }
+ ],
+ [
+ {
+ "x": 688,
+ "y": 752
+ },
+ {
+ "x": 784,
+ "y": 752
+ }
+ ],
+ [
+ {
+ "x": 304,
+ "y": 656
+ },
+ {
+ "x": 304,
+ "y": 752
+ }
+ ],
+ [
+ {
+ "x": 592,
+ "y": 656
+ },
+ {
+ "x": 592,
+ "y": 752
+ }
+ ],
+ [
+ {
+ "x": 208,
+ "y": 848
+ },
+ {
+ "x": 304,
+ "y": 848
+ }
+ ],
+ [
+ {
+ "x": 400,
+ "y": 848
+ },
+ {
+ "x": 496,
+ "y": 848
+ }
+ ],
+ [
+ {
+ "x": 592,
+ "y": 848
+ },
+ {
+ "x": 688,
+ "y": 848
+ }
+ ],
+ [
+ {
+ "x": 48,
+ "y": 752
+ },
+ {
+ "x": 48,
+ "y": 848
+ }
+ ],
+ [
+ {
+ "x": 400,
+ "y": 752
+ },
+ {
+ "x": 400,
+ "y": 848
+ }
+ ],
+ [
+ {
+ "x": 496,
+ "y": 752
+ },
+ {
+ "x": 496,
+ "y": 848
+ }
+ ],
+ [
+ {
+ "x": 848,
+ "y": 752
+ },
+ {
+ "x": 848,
+ "y": 848
+ }
+ ],
+ [
+ {
+ "x": 48,
+ "y": 272
+ },
+ {
+ "x": 48,
+ "y": 656
+ }
+ ],
+ [
+ {
+ "x": 848,
+ "y": 272
+ },
+ {
+ "x": 848,
+ "y": 656
+ }
+ ]
+ ]
+}
diff --git a/src/frontend/assets/map.png b/src/frontend/assets/map.png
new file mode 100644
index 0000000..b6b2f04
Binary files /dev/null and b/src/frontend/assets/map.png differ
diff --git a/src/frontend/index.html b/src/frontend/index.html
index fc5d87b..464ff25 100644
--- a/src/frontend/index.html
+++ b/src/frontend/index.html
@@ -9,7 +9,11 @@
Multiplayer Pacman
-
+
+
+
+
+
diff --git a/src/frontend/maps/dev.json b/src/frontend/maps/dev.json
deleted file mode 100644
index fc6dc4a..0000000
--- a/src/frontend/maps/dev.json
+++ /dev/null
@@ -1,36 +0,0 @@
-{
- "intersections": [
- {
- "x": 20,
- "y": 20
- },
- {
- "x": 250,
- "y": 20
- },
- {
- "x": 480,
- "y": 20
- },
- {
- "x": 20,
- "y": 250
- },
- {
- "x": 250,
- "y": 250
- },
- {
- "x": 120,
- "y": 280
- },
- {
- "x": 20,
- "y": 480
- },
- {
- "x": 480,
- "y": 480
- }
- ]
-}
diff --git a/src/frontend/utilities/Game.js b/src/frontend/utilities/Game.js
index adfbc87..b8d4238 100644
--- a/src/frontend/utilities/Game.js
+++ b/src/frontend/utilities/Game.js
@@ -1,41 +1,48 @@
import Intersection from './Intersection.js';
import Path from './Path.js';
+import Portal from './Portal.js';
export default class Game {
- constructor(canvas) {
- this.canvas = canvas;
- this.ctx = canvas.getContext('2d');
+ constructor(foregroundCanvas, playerCanvas) {
+ this.foregroundCtx = foregroundCanvas.getContext('2d');
+ this.playerCtx = playerCanvas.getContext('2d');
this.players = [];
this.intersections = [];
this.paths = [];
this.interval = undefined;
- this.ctx.fillStyle = '#FFFFFF';
- }
-
- addPlayer(player) {
- this.players.push(player);
+ this.board = {
+ width: foregroundCanvas.width,
+ height: foregroundCanvas.height
+ };
- // Spawn the player at the first safe path
- for (const path of this.paths) {
- if (path.isSafe) {
- player.spawn(path);
- }
- }
+ // TODO: change this
+ this.foregroundCtx.fillStyle = '#FFFFFF';
+ this.playerCtx.fillStyle = '#FFFFFF';
}
async loadGameBoard(path) {
const res = await fetch(path);
const map = await res.json();
- for (const position of map.intersections) {
- this.intersections.push(new Intersection(position));
+ for (const configuration of map.intersections) {
+ this.intersections.push(new Intersection(configuration));
+ }
+
+ this.#generatePaths(map);
+
+ // draw intersections (dev purposes only, will change)
+ for (const intersection of this.intersections) {
+ intersection.draw(this.foregroundCtx);
}
- this.generatePaths();
+ // draw paths (dev purposes only, will change)
+ for (const path of this.paths) {
+ path.draw(this.foregroundCtx);
+ }
}
- generatePaths() {
+ #generatePaths({ inaccessiblePaths, portals }) {
for (const start of this.intersections) {
for (const end of this.intersections) {
if (start === end || start.position.x > end.position.x || start.position.y > end.position.y) continue;
@@ -53,16 +60,48 @@ export default class Game {
});
}
- if (isBestPath) {
- const path = new Path(start, end);
- start.addPath(path);
- end.addPath(path);
- this.paths.push(path);
+ const isPortal = portals.find((intersections) => {
+ const startPortal = (intersections[0].x === start.position.x && intersections[0].y === start.position.y);
+ let endPortal = (intersections[1].x === end.position.x && intersections[1].y === end.position.y);
+ return startPortal && endPortal;
+ });
+
+ if (isBestPath && !isPortal) {
+ const isInaccessiblePath = inaccessiblePaths.find((intersections) => {
+ const containsStart = intersections.find((intersection) => {
+ return intersection.x === start.position.x && intersection.y === start.position.y;
+ });
+
+ const containsEnd = intersections.find((intersection) => {
+ return intersection.x === end.position.x && intersection.y === end.position.y;
+ });
+
+ return containsStart && containsEnd;
+ });
+
+ if (!isInaccessiblePath) {
+ this.paths.push(new Path(start, end));
+ }
+ }
+
+ if (isPortal) {
+ this.paths.push(new Portal(start, end));
}
}
}
}
+ addPlayer(player) {
+ this.players.push(player);
+
+ // Spawn the player at the first safe path
+ for (const path of this.paths) {
+ if (path.isSafe) {
+ player.spawn(path);
+ }
+ }
+ }
+
removePlayer(playerToRemove) {
this.players = this.players.filter((player) => player.id !== playerToRemove.id);
}
@@ -80,23 +119,13 @@ export default class Game {
}
update() {
- this.ctx.clearRect(0, 0, this.canvas.width, this.canvas.height);
-
- // draw intersections (dev purposes only, will change)
- for (const intersection of this.intersections) {
- intersection.draw(this.ctx);
- }
-
- // draw paths (dev purposes only, will change)
- for (const path of this.paths) {
- path.draw(this.ctx);
- }
+ this.playerCtx.clearRect(0, 0, this.board.width, this.board.height);
- // draw players
+ // move and draw players
for (let i = 0; i < this.players.length; i++) {
const player = this.players[i];
player.move();
- player.draw(this.ctx);
+ player.draw(this.playerCtx);
}
}
}
diff --git a/src/frontend/utilities/Intersection.js b/src/frontend/utilities/Intersection.js
index c3aee3c..bb801f5 100644
--- a/src/frontend/utilities/Intersection.js
+++ b/src/frontend/utilities/Intersection.js
@@ -1,3 +1,5 @@
+import Portal from './Portal.js';
+
export default class Intersection {
constructor(position) {
this.position = position;
@@ -5,20 +7,40 @@ export default class Intersection {
}
addPath(path) {
- if (path.isHorizontal) {
- if (path.start === this) {
- this.paths.right = path;
+ if (path instanceof Portal) {
+ if (path.isHorizontal) {
+ if (path.start === this) {
+ this.paths.left = path;
+ }
+ else if (path.end === this) {
+ this.paths.right = path;
+ }
}
- else if (path.end === this) {
- this.paths.left = path;
+ else {
+ if (path.start === this) {
+ this.paths.up = path;
+ }
+ else if (path.end === this) {
+ this.paths.down = path;
+ }
}
}
- else {
- if (path.start === this) {
- this.paths.down = path;
+ else {
+ if (path.isHorizontal) {
+ if (path.start === this) {
+ this.paths.right = path;
+ }
+ else if (path.end === this) {
+ this.paths.left = path;
+ }
}
- else if (path.end === this) {
- this.paths.up = path;
+ else {
+ if (path.start === this) {
+ this.paths.down = path;
+ }
+ else if (path.end === this) {
+ this.paths.up = path;
+ }
}
}
}
@@ -43,6 +65,7 @@ export default class Intersection {
}
draw(ctx) {
+ ctx.strokeStyle = '#FFFFFF'; // TODO: revert
ctx.beginPath();
ctx.arc(this.position.x, this.position.y, 8, 0, 2 * Math.PI);
ctx.stroke();
diff --git a/src/frontend/utilities/Player.js b/src/frontend/utilities/Player.js
index 995cca6..ef1bf40 100644
--- a/src/frontend/utilities/Player.js
+++ b/src/frontend/utilities/Player.js
@@ -1,5 +1,6 @@
import Path from './Path.js';
import Intersection from './Intersection.js';
+import Portal from './Portal.js';
export default class Player {
constructor() {
@@ -44,6 +45,7 @@ export default class Player {
...this.movement,
...movement
};
+ this.nextMovement = {}; // clear next movement
}
else {
this.nextMovement = movement;
@@ -70,6 +72,10 @@ export default class Player {
const newPath = this.currentPath.traverse(this.movement);
if (newPath) {
+ if (newPath instanceof Portal) {
+ return newPath.travel(this); // travel through the portal
+ }
+
this.currentPath = newPath;
}
else return this.stop();
@@ -82,7 +88,6 @@ export default class Player {
if (this.currentPath && this.currentPath instanceof Path) {
if (this.currentPath.start.position.x === this.position.x && this.currentPath.start.position.y === this.position.y) {
this.currentPath = this.currentPath.start;
-
}
else if (this.currentPath.end.position.x === this.position.x && this.currentPath.end.position.y === this.position.y) {
this.currentPath = this.currentPath.end;
@@ -92,6 +97,11 @@ export default class Player {
}
}
+ teleport(intersection) {
+ this.position = { ...intersection.position };
+ this.currentPath = intersection;
+ }
+
stop() {
this.movement = { x: 0, y: 0 };
}
diff --git a/src/frontend/utilities/Portal.js b/src/frontend/utilities/Portal.js
new file mode 100644
index 0000000..20566c8
--- /dev/null
+++ b/src/frontend/utilities/Portal.js
@@ -0,0 +1,26 @@
+import Path from './Path.js';
+
+export default class Portal extends Path {
+ constructor(start, end) {
+ super(start, end);
+ }
+
+ travel(player) {
+ if (this.isHorizontal) {
+ if (player.position.x === this.start.position.x) {
+ player.teleport(this.end);
+ }
+ else {
+ player.teleport(this.start);
+ }
+ }
+ else {
+ if (player.position.y === this.start.position.y) {
+ player.teleport(this.end);
+ }
+ else {
+ player.teleport(this.start);
+ }
+ }
+ }
+}
diff --git a/test/frontend/utilities/Game.test.js b/test/frontend/utilities/Game.test.js
index 313f988..f6f12d0 100644
--- a/test/frontend/utilities/Game.test.js
+++ b/test/frontend/utilities/Game.test.js
@@ -4,31 +4,43 @@ import Chance from 'chance';
const chance = new Chance();
+
describe('Game', () => {
- let game, ctxMock;
+ let game, foregroundCtxMock, playerCtxMock;
beforeEach(() => {
- ctxMock = {
+ foregroundCtxMock = {
fillStyle: '#000000',
clearRect: jest.fn(),
fillRect: jest.fn()
};
- const mockCanvas = {
+ playerCtxMock = {
+ fillStyle: '#000000',
+ clearRect: jest.fn(),
+ fillRect: jest.fn()
+ };
+
+ const generateMockCanvas = (ctxMock) => ({
getContext: () => ctxMock,
width: chance.integer({ min: 100 }),
height: chance.integer({ min: 100 })
- };
+ });
- game = new Game(mockCanvas);
+ game = new Game(generateMockCanvas(foregroundCtxMock), generateMockCanvas(playerCtxMock));
});
it('creates a game with all default values', () => {
- expect(game.ctx).toMatchObject(ctxMock);
+ expect(game.foregroundCtx).toMatchObject(foregroundCtxMock);
+ expect(game.playerCtx).toMatchObject(playerCtxMock);
expect(game.players).toEqual([]);
+ expect(game.paths).toEqual([]);
+ expect(game.intersections).toEqual([]);
expect(game.interval).toBeUndefined();
});
+ describe('loadGameBoard()', () => {});
+
describe('addPlayer() and removePlayer()', () => {
let player;
@@ -73,7 +85,7 @@ describe('Game', () => {
});
it('clears the canvas', () => {
- expect(ctxMock.clearRect).toBeCalled();
+ expect(playerCtxMock.clearRect).toBeCalled();
});
it('moves all players', () => {
diff --git a/test/frontend/utilities/Intersection.test.js b/test/frontend/utilities/Intersection.test.js
index 51367f1..0e0361b 100644
--- a/test/frontend/utilities/Intersection.test.js
+++ b/test/frontend/utilities/Intersection.test.js
@@ -1,4 +1,5 @@
import Intersection from '@/frontend/utilities/Intersection.js';
+import Portal from '@/frontend/utilities/Portal.js';
import Chance from 'chance';
const chance = new Chance();
@@ -22,43 +23,93 @@ describe('Intersection', () => {
describe('addPath()', () => {
let path;
- describe('given a horizontal path', () => {
- beforeEach(() => {
- path = { isHorizontal: true };
- });
-
- it('it properly configures the left path', () => {
- path.end = intersection;
- intersection.addPath(path);
- expect(intersection.paths.left).toMatchObject(path);
+ describe('given a regular (non-portal) path', () => {
+ describe('given a horizontal path', () => {
+ beforeEach(() => {
+ path = { isHorizontal: true };
+ });
+
+ it('it properly configures the left path', () => {
+ path.end = intersection;
+
+ intersection.addPath(path);
+ expect(intersection.paths.left).toMatchObject(path);
+ });
+
+ it('it properly configures the right path', () => {
+ path.start = intersection;
+
+ intersection.addPath(path);
+ expect(intersection.paths.right).toMatchObject(path);
+ });
});
-
- it('it properly configures the right path', () => {
- path.start = intersection;
-
- intersection.addPath(path);
- expect(intersection.paths.right).toMatchObject(path);
+
+ describe('given a vertical path', () => {
+ beforeEach(() => {
+ path = { isVertical: true };
+ });
+
+ it('it properly configures the up path', () => {
+ path.end = intersection;
+
+ intersection.addPath(path);
+ expect(intersection.paths.up).toMatchObject(path);
+ });
+
+ it('it properly configures the down path', () => {
+ path.end = intersection;
+
+ intersection.addPath(path);
+ expect(intersection.paths.up).toMatchObject(path);
+ });
});
});
-
- describe('given a vertical path', () => {
- beforeEach(() => {
- path = { isVertical: true };
- });
-
- it('it properly configures the up path', () => {
- path.end = intersection;
- intersection.addPath(path);
- expect(intersection.paths.up).toMatchObject(path);
+ describe('given a portal path', () => {
+ let start, end;
+ describe('given a horizontal path', () => {
+ beforeEach(() => {
+ start = new Intersection({ x: chance.integer({ min: 0, max: 99 }), y: 10 });
+ end = new Intersection({ x: chance.integer({ min: 100, max: 500 }), y: 10 });
+ path = new Portal(start, end);
+ });
+
+ it('it properly configures the left path', () => {
+ path.start = intersection;
+
+ intersection.addPath(path);
+ expect(intersection.paths.left).toMatchObject(path);
+ });
+
+ it('it properly configures the right path', () => {
+ path.end = intersection;
+
+ intersection.addPath(path);
+ expect(intersection.paths.right).toMatchObject(path);
+ });
});
-
- it('it properly configures the down path', () => {
- path.end = intersection;
-
- intersection.addPath(path);
- expect(intersection.paths.up).toMatchObject(path);
+
+ describe('given a vertical path', () => {
+ beforeEach(() => {
+ start = new Intersection({ x: 10, y: chance.integer({ min: 0, max: 99 }) });
+ end = new Intersection({ x: 10, y: chance.integer({ min: 100, max: 500 }) });
+ path = new Portal(start, end);
+ });
+
+ it('it properly configures the up path', () => {
+ path.start = intersection;
+
+ intersection.addPath(path);
+ expect(intersection.paths.up).toMatchObject(path);
+ });
+
+ it('it properly configures the down path', () => {
+ path.start = intersection;
+
+ intersection.addPath(path);
+ expect(intersection.paths.up).toMatchObject(path);
+ });
});
});
});
diff --git a/test/frontend/utilities/Player.test.js b/test/frontend/utilities/Player.test.js
index 279cb33..e2a549e 100644
--- a/test/frontend/utilities/Player.test.js
+++ b/test/frontend/utilities/Player.test.js
@@ -138,6 +138,27 @@ describe('Player', () => {
});
});
+ describe('teleport()', () => {
+ let intersection;
+
+ beforeEach(() => {
+ intersection = new Intersection({
+ x: chance.integer(),
+ y: chance.integer()
+ });
+
+ player.teleport(intersection);
+ });
+
+ it('changes the player position to that of the intersection provided', () => {
+ expect(player.position).toMatchObject(intersection.position);
+ });
+
+ it('changes the player currentPath to that of the intersection provided', () => {
+ expect(player.currentPath).toMatchObject(intersection);
+ });
+ });
+
describe('draw()', () => {
let ctxMock;
diff --git a/test/frontend/utilities/Portal.test.js b/test/frontend/utilities/Portal.test.js
new file mode 100644
index 0000000..cb5ae3c
--- /dev/null
+++ b/test/frontend/utilities/Portal.test.js
@@ -0,0 +1,53 @@
+import Player from '@/frontend/utilities/Player.js';
+import Portal from '@/frontend/utilities/Portal.js';
+import Intersection from '@/frontend/utilities/Intersection.js';
+import Chance from 'chance';
+
+const chance = new Chance();
+
+describe('Portal', () => {
+ let portal, start, end;
+
+ beforeEach(() => {
+ start = new Intersection({ x: chance.integer({ min: 0, max: 100 }), y: 10 });
+ end = new Intersection({ x: chance.integer({ min: 0, max: 100 }), y: 10 });
+
+
+ start.addPath = jest.fn();
+ end.addPath = jest.fn();
+
+ portal = new Portal(start, end);
+ });
+
+ it('creates a portal correctly', () => {
+ expect(portal.isHorizontal).toBeTruthy();
+ expect(portal.isVertical).not.toBeTruthy();
+ expect(portal.isSafe).toBeTruthy();
+ expect(portal.start).toBe(start);
+ expect(portal.end).toBe(end);
+ });
+
+ it('adds itself to both intersections list of paths', () => {
+ expect(start.addPath).toBeCalled();
+ expect(end.addPath).toBeCalled();
+
+ expect(start.addPath).toBeCalledWith(portal);
+ expect(end.addPath).toBeCalledWith(portal);
+ });
+
+ describe('travel()', () => {
+ let player;
+
+ beforeEach(() => {
+ player = new Player();
+ player.spawn(portal);
+ player.teleport = jest.fn();
+
+ portal.travel(player);
+ });
+
+ it('teleports the player', () => {
+ expect(player.teleport).toBeCalled();
+ });
+ });
+});