diff --git a/src/index.html b/src/index.html
index 2742d86..8585e1f 100644
--- a/src/index.html
+++ b/src/index.html
@@ -13,6 +13,8 @@
+
+
diff --git a/src/main.js b/src/main.js
index 532bfa5..18eccc7 100644
--- a/src/main.js
+++ b/src/main.js
@@ -6,4 +6,5 @@ window.addEventListener('DOMContentLoaded', () => {
const floor = new Floor(floorCanvas);
const grid = new Grid(gridCanvas);
+ const agent = new Agent(agentCanvas);
});
\ No newline at end of file
diff --git a/src/modules/agent.js b/src/modules/agent.js
new file mode 100644
index 0000000..e2b5be2
--- /dev/null
+++ b/src/modules/agent.js
@@ -0,0 +1,13 @@
+class Agent extends AgentController {
+ constructor(canvas) {
+ super(canvas);
+
+ let { x, y } = Grid.instance.randomPlace();
+ this.moveTo(x, y);
+
+ this.onDestinationReached(() => {
+ let { x, y } = Grid.instance.randomPlace();
+ this.moveTo(x, y);
+ })
+ }
+}
\ No newline at end of file
diff --git a/src/modules/agentController.js b/src/modules/agentController.js
new file mode 100644
index 0000000..a6a0501
--- /dev/null
+++ b/src/modules/agentController.js
@@ -0,0 +1,146 @@
+class AgentController {
+ constructor(canvas) {
+ this.ctx = canvas.getContext('2d');
+ this.events = {
+ 'ON_DESTINATION_REACHED': [],
+ };
+
+ this.setCanvasSize(canvas);
+
+ this.position = { x: 6, y: 0 };
+
+ this.update();
+ }
+
+ setCanvasSize (canvas) {
+ canvas.width = 2000;
+ canvas.height = 900;
+ }
+
+ update() {
+ this.clearCanvas();
+ if (this.currentPath) {
+ this.drawPath(this.currentPath);
+ this.updateAgentPosition();
+ }
+ this.drawAgent();
+
+ requestAnimationFrame(this.update.bind(this));
+ }
+
+ updateAgentPosition() {
+ const speed = 30;
+ if (!this.currentPathIndex) {
+ this.currentPathIndex = 0;
+ }
+
+ let nearestPoint = this.currentPath[this.currentPathIndex];
+
+ if (nearestPoint) {
+ this.position = {
+ x: this.position.x + (Math.sign(nearestPoint.x - this.position.x)/speed),
+ y: this.position.y + (Math.sign(nearestPoint.y - this.position.y)/speed)
+ }
+ if (Math.abs(nearestPoint.x - this.position.x) < 0.001 && Math.abs(nearestPoint.y - this.position.y) < 0.001) {
+ nearestPoint = this.currentPath[++this.currentPathIndex];
+ if (!nearestPoint) {
+ this.position = {
+ x: Math.round(this.position.x),
+ y: Math.round(this.position.y)
+ }
+ this.currentPath = [];
+ this.currentPathIndex = 0;
+ this.events.ON_DESTINATION_REACHED.forEach(func => func());
+ }
+ }
+ }
+ }
+
+ moveTo(x, y) {
+ this.currentPath = this.findPathTo(x, y, this.position.x, this.position.y);
+ }
+
+ drawPath(path) {
+ for(let i = 0; i < path.length - 1; i++) {
+ this.ctx.beginPath();
+ this.ctx.strokeWidth = 5;
+ this.ctx.strokeStyle = 'red';
+ this.ctx.moveTo(path[i].x * 100 + 50, path[i].y * 100 + 50);
+ this.ctx.lineTo(path[i + 1].x * 100 + 50, path[i + 1].y * 100 + 50);
+ this.ctx.stroke();
+ }
+ }
+
+ drawAgent() {
+ const {x, y} = this.position;
+ const offset = 5;
+ this.ctx.clearRect((x * 100) + (offset), (y * 100) + (offset), 100 - (offset * 2), 100 - (offset * 2));
+ this.roundRect((x * 100) + (offset), (y * 100) + (offset), 100 - (offset * 2), 100 - (offset * 2));
+ }
+
+ findPathTo(dx, dy, sx, sy) {
+ const grid = JSON.parse(JSON.stringify(Grid.instance.grid));
+ const queue = [];
+ const lastPoint = [];
+
+ if (grid[dx][dy] === GRID_FIELD_TYPE.SHELF) {
+ if(grid[dx][dy + 1] === GRID_FIELD_TYPE.PATH) {
+ lastPoint.push({ x: dx, y: dy, options: { isShelf: true } });
+ dy++;
+ } else if(grid[dx][dy - 1] === GRID_FIELD_TYPE.PATH) {
+ lastPoint.push({ x: dx, y: dy, options: { isShelf: true } });
+ dy--;
+ }
+ }
+
+ queue.push({ x: sx, y: sy, path: [] });
+
+ while(queue.length) {
+ const { x, y, path } = queue.shift();
+ path.push({ x, y });
+
+ if (x === dx && y === dy) {
+ return [...path, ...lastPoint];
+ }
+ if (grid[x][y - 1] === GRID_FIELD_TYPE.PATH) {
+ queue.push({ x, y: y - 1, path: [...path] });
+ }
+ if (grid[x][y + 1] === GRID_FIELD_TYPE.PATH) {
+ queue.push({ x, y: y + 1, path: [...path] });
+ }
+ if (grid[x - 1] && grid[x - 1][y] === GRID_FIELD_TYPE.PATH) {
+ queue.push({ x: x - 1, y, path: [...path] });
+ }
+ if (grid[x + 1] && grid[x + 1][y] === GRID_FIELD_TYPE.PATH) {
+ queue.push({ x: x + 1, y, path: [...path] });
+ }
+
+ grid[x][y] = -1;
+ }
+ }
+
+ onDestinationReached(func) {
+ this.events.ON_DESTINATION_REACHED.push(func);
+ }
+
+ clearCanvas() {
+ this.ctx.clearRect(0, 0, 2000, 900);
+ }
+
+ roundRect(x, y, w, h, r = 20) {
+ this.ctx.lineWidth = 5;
+ this.ctx.strokeStyle = 'red';
+ this.ctx.beginPath();
+ this.ctx.moveTo(x + r, y);
+ this.ctx.lineTo(x + w - r, y);
+ this.ctx.quadraticCurveTo(x + w, y, x + w, y + r);
+ this.ctx.lineTo(x + w, y + h - r);
+ this.ctx.quadraticCurveTo(x + w, y + h, x + w - r, y + h);
+ this.ctx.lineTo(x + r, y + h);
+ this.ctx.quadraticCurveTo(x, y + h, x, y + h - r);
+ this.ctx.lineTo(x, y + r);
+ this.ctx.quadraticCurveTo(x, y, x + r, y);
+ this.ctx.closePath();
+ this.ctx.stroke();
+ }
+}
\ No newline at end of file
diff --git a/src/modules/grid.js b/src/modules/grid.js
index f08dfdb..f15ea2a 100644
--- a/src/modules/grid.js
+++ b/src/modules/grid.js
@@ -5,6 +5,8 @@ const GRID_FIELD_TYPE = Object.freeze({
});
class Grid {
+ static instance;
+
constructor(canvas) {
this.grid = [[]];
this.ctx;
@@ -15,6 +17,8 @@ class Grid {
this.processGrid();
this.drawShelfs();
this.drawStorages();
+
+ Grid.instance = this;
}
getGrid () {
@@ -39,7 +43,6 @@ class Grid {
for (let i = 0; i < 20; i++) {
this.grid[i] = [...this.grid[i], lastLine[i]];
}
- console.log(this.grid);
}
drawShelfs () {
@@ -52,6 +55,16 @@ class Grid {
}
}
+ randomPlace() {
+ const x = Math.floor(Math.random() * this.grid.length);
+ const y = Math.floor(Math.random() * this.grid[0].length);
+ const rand = this.grid[x][y];
+ if (rand === GRID_FIELD_TYPE.SHELF || rand === GRID_FIELD_TYPE.PATH) {
+ return { x, y };
+ }
+ return this.randomPlace();
+ }
+
drawStorages () {
let isFirstOfType = true;
let isLastOfType = false;