feat: Time management

This commit is contained in:
Marcin Czerniak 2021-05-10 18:39:21 +02:00
parent c31c838e55
commit 49a12b1b92
9 changed files with 217 additions and 25 deletions

View File

@ -6,6 +6,6 @@ const StorageCenterLocation = { x: 7, y: 8, w: UnitsInGroupCount, h: 1 }
const UnitsCount = ((ColumnsOfGroupsCount * RowsOfGroupsCount) * UnitsInGroupCount const UnitsCount = ((ColumnsOfGroupsCount * RowsOfGroupsCount) * UnitsInGroupCount
- StorageCenterLocation.w * StorageCenterLocation.h) - StorageCenterLocation.w * StorageCenterLocation.h)
const AgentMoveSpeed = 20 /* 1 - slowest, 89 - fastest */ const AgentMoveSpeed = 40 /* 1 - slowest, 89 - fastest */
const AgentRotationSpeed = 20 /* 1 - slowest, 89 - fastest */ const AgentRotationSpeed = 40 /* 1 - slowest, 89 - fastest */
const AgentWaitTime = 500 /* in miliseconds */ const AgentWaitTime = 500 /* in miliseconds */

View File

@ -18,10 +18,12 @@
<script src="configuration.js"></script> <script src="configuration.js"></script>
<script src="utilities.js"></script> <script src="utilities.js"></script>
<script src="logic/product.js"></script> <script src="logic/product.js"></script>
<script src="logic/time.js"></script>
<script src="view/floor.js"></script> <script src="view/floor.js"></script>
<script src="view/grid.js"></script> <script src="view/grid.js"></script>
<script src="logic/pathfinding.js"></script> <script src="logic/pathfinding.js"></script>
<script src="view/timeController.js"></script>
<script src="view/agentController.js"></script> <script src="view/agentController.js"></script>
<script src="logic/agent.js"></script> <script src="logic/agent.js"></script>
<script src="view/products.js"></script> <script src="view/products.js"></script>
@ -43,7 +45,34 @@
<main> <main>
<div class="header"> <div class="header">
<div class="header-line"></div>
<img src="img/logo.png" alt="logo"> <img src="img/logo.png" alt="logo">
<div class="header-line">
<fieldset>
<legend>Time management</legend>
<div class="button" onClick="Time.instance.pause()">
<i class="fas fa-pause"></i>
</div>
<div class="button" onClick="Time.instance.resume()">
<i class="fas fa-play"></i>
</div>
<div class="button" onClick="Time.instance.setMultiplier(2)">
<i class="fas fa-forward"></i>
</div>
<div class="button" onClick="Time.instance.setMultiplier(4)">
<i class="fas fa-fast-forward"></i>
</div>
</fieldset>
<fieldset>
<legend>Day: <span class="bind-day"></span></legend>
<input id="dayInput" type="number" value="1">
<div class="button" onClick="TimeController.instance.readFromDayInput()">
<i class="fas fa-step-forward"></i>
</div>
</div>
</div> </div>
<div class="logs-label"> <div class="logs-label">

View File

@ -1,21 +1,27 @@
class Agent extends AgentController { class Agent extends AgentController {
static instance;
constructor(canvas) { constructor(canvas) {
super(canvas); super(canvas);
Agent.instance = this;
const cycle = async () => { const cycle = async () => {
const jobRequest = Products.instance.getJobRequest(); const jobRequest = Products.instance.getJobRequest();
if (jobRequest) { if (jobRequest) {
const requiredAmount = 50 - jobRequest.amount; const requiredAmount = 50 - jobRequest.amount;
await this.takeFromStore(jobRequest.product, requiredAmount); await this.takeFromStore(jobRequest.product, requiredAmount);
await this.deliver(jobRequest.x, jobRequest.y); await this.deliver(jobRequest.x, jobRequest.y);
} else {
await waitFor(1000);
} }
await waitFor(AgentWaitTime); await waitFor(this.waitTime);
cycle(); cycle();
}; };
setTimeout(() => cycle(), 2000); setTimeout(() => cycle(), 2000);
} }
/** /**
@ -34,8 +40,9 @@ class Agent extends AgentController {
*/ */
async deliver(x, y) { async deliver(x, y) {
await this.moveTo(x, y); await this.moveTo(x, y);
await waitFor(AgentWaitTime); await waitFor(this.waitTime);
Products.instance.exchange(x, y, this.ownedProduct, 50); Products.instance.exchange(x, y, this.ownedProduct, 50);
this.ownedProductAmount = 0; this.ownedProductAmount = 0;
this.ownedProduct = Product.REGISTRY.empty; this.ownedProduct = Product.REGISTRY.empty;
} }
@ -46,7 +53,7 @@ class Agent extends AgentController {
*/ */
async takeFromStore(product, amount) { async takeFromStore(product, amount) {
await this.moveTo(9, 8); await this.moveTo(9, 8);
await waitFor(AgentWaitTime); await waitFor(this.waitTime);
this.ownedProductAmount = amount; this.ownedProductAmount = amount;
this.ownedProduct = product; this.ownedProduct = product;
} }

View File

@ -34,10 +34,12 @@ class Pathfinding {
for (const successor of this.successor(elem)) { for (const successor of this.successor(elem)) {
if (!Pathfinding.isNodeInArr(successor, explored) && !Pathfinding.isNodeInArr(successor, fringe)) { if (!Pathfinding.isNodeInArr(successor, explored) && !Pathfinding.isNodeInArr(successor, fringe)) {
Pathfinding.insertWithPriority(successor, fringe, expectedNode); Pathfinding.insertWithPriority(successor, fringe);
} else if (Pathfinding.isNodeInArr(successor, fringe)) { } else if (Pathfinding.isNodeInArr(successor, fringe)) {
const index = Pathfinding.findIndefOf(successor, fringe); const index = Pathfinding.findIndexOf(successor, fringe);
fringe.splice(index, 1, successor); if (successor.totalCost < fringe[index].totalCost) {
fringe.splice(index, 1, successor);
}
} }
} }
} }
@ -47,11 +49,11 @@ class Pathfinding {
return !arr.every(n => !Pathfinding.reached(n.state, node.state)) return !arr.every(n => !Pathfinding.reached(n.state, node.state))
} }
static findIndefOf(node, arr) { static findIndexOf(node, arr) {
return arr.findIndex(n => Pathfinding.reached(n.state, node.state)); return arr.findIndex(n => Pathfinding.reached(n.state, node.state));
} }
static insertWithPriority(node, arr, destination) { static insertWithPriority(node, arr) {
for (const [i, n] of arr.entries()) { for (const [i, n] of arr.entries()) {
if (node.totalCost < n.totalCost) { if (node.totalCost < n.totalCost) {
arr.splice(i, 0, node); arr.splice(i, 0, node);
@ -108,7 +110,6 @@ class Pathfinding {
currentElement = currentElement.parent; currentElement = currentElement.parent;
} }
console.log(result);
return result; return result;
} }

64
src/logic/time.js Normal file
View File

@ -0,0 +1,64 @@
class Time {
isPaused = false;
timeMultiplier = 1;
day = 0;
static instance;
constructor() {
Time.instance = this;
}
/**
* Pause app
*/
pause() {
this.isPaused = true;
}
/**
* Resume from pause state
*/
resume() {
this.setMultiplier(1);
}
/**
* Get animation frame base on pase state
*/
requestAnimationFrame(func) {
if (!this.isPaused) {
return window.requestAnimationFrame(func);
} else {
return window.requestAnimationFrame(() => {
Time.instance.requestAnimationFrame(func);
})
}
}
/**
* multiply agent action speed
*/
setMultiplier(multiplier) {
this.isPaused = false;
this.timeMultiplier = multiplier;
}
/**
* Set day
*/
setDay(day) {
this.day = Number(day);
TimeController.instance.bindTime();
}
/**
* Add days
*/
addDays(days) {
this.setDay(this.day += Number(days));
}
}

View File

@ -6,13 +6,14 @@ window.addEventListener('DOMContentLoaded', () => document.fonts.load('900 14px
const costCanvas = document.getElementById('canvas-costmap'); const costCanvas = document.getElementById('canvas-costmap');
const costMap = new CostMap(); const costMap = new CostMap();
const time = new Time();
const timeController = new TimeController();
const costMapVisualisation = new CostMapVisualisation(costCanvas); const costMapVisualisation = new CostMapVisualisation(costCanvas);
const floor = new Floor(floorCanvas); const floor = new Floor(floorCanvas);
const grid = new Grid(gridCanvas); const grid = new Grid(gridCanvas);
const agent = new Agent(agentCanvas); const agent = new Agent(agentCanvas);
const products = new Products(productsCanvas); const products = new Products(productsCanvas);
const fpsElement = document.getElementById('fps'); const fpsElement = document.getElementById('fps');
if (window.location.hash == '#debug') { if (window.location.hash == '#debug') {
displayFPS(fpsElement); displayFPS(fpsElement);

View File

@ -41,6 +41,49 @@ main {
align-items: flex-end; align-items: flex-end;
} }
.header-line {
flex-grow: 1;
display: flex;
padding: 32px;
flex: 1;
}
.header-line fieldset {
display: flex;
gap: 5px;
justify-content: center;
border-radius: 10px;
border-color: #E9F116;
}
.header-line div {
padding: 0 20px 0 0;
}
.header-line .button {
cursor: pointer;
padding: 5px;
border-radius: 50%;
width: 20px;
height: 20px;
display: flex;
justify-content: center;
align-items: center;
}
.header-line .button:hover {
background-color: #0A0A0A;
}
.header-line input {
background-color: transparent;
border: 0;
border-bottom: 1px solid yellow;
width: 50px;
color: yellow;
outline: 0;
}
.logs-label { .logs-label {
margin: 0 20px 30px 10px; margin: 0 20px 30px 10px;
} }

View File

@ -15,14 +15,24 @@ class AgentController {
} }
this.currentAction = this.actions.STATIONARY; this.currentAction = this.actions.STATIONARY;
// Pozycja i poruszanie się // Pozycja i rotacja
this.position = { x: 6, y: 0 }; this.position = { x: 6, y: 0 };
this.rotation = { z: 0 }; this.rotation = { z: 0 };
this.speed = 90 - AgentMoveSpeed;
this.rotationSpeed = 90 / ( 90 - AgentRotationSpeed);
this.update(); this.update();
} }
get speed() {
return 90 - clamp(AgentMoveSpeed * Time.instance.timeMultiplier, 0, 89);
}
get rotationSpeed() {
return 90 / ( 90 - clamp(AgentRotationSpeed * Time.instance.timeMultiplier, 0, 88));
}
get waitTime() {
return AgentWaitTime / (Time.instance.timeMultiplier * 2);
}
setCanvasSize (canvas) { setCanvasSize (canvas) {
canvas.width = 2000; canvas.width = 2000;
canvas.height = 900; canvas.height = 900;
@ -35,7 +45,7 @@ class AgentController {
} }
this.drawAgent(); this.drawAgent();
requestAnimationFrame(this.update.bind(this)); Time.instance.requestAnimationFrame(this.update.bind(this));
} }
updateAgentPosition() { updateAgentPosition() {
@ -78,6 +88,11 @@ class AgentController {
* @param {{ x: number, y: number }} position * @param {{ x: number, y: number }} position
*/ */
moveInLine(position, actionCost) { moveInLine(position, actionCost) {
const vector = {
x: Math.sign(position.x - this.position.x),
y: Math.sign(position.y - this.position.y)
}
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
const cycle = () => { const cycle = () => {
let { speed } = this; let { speed } = this;
@ -89,14 +104,20 @@ class AgentController {
y: this.position.y + (Math.sign(position.y - this.position.y)/speed) y: this.position.y + (Math.sign(position.y - this.position.y)/speed)
} }
if (Math.abs(position.x - this.position.x) < 0.001 && Math.abs(position.y - this.position.y) < 0.001) { if (
(vector.x > 0 && this.position.x > position.x) ||
(vector.x < 0 && this.position.x < position.x) ||
(vector.y > 0 && this.position.y > position.y) ||
(vector.y < 0 && this.position.y < position.y) ||
(Math.sign(position.y - this.position.y) == 0 && Math.sign(position.x - this.position.x) == 0)
) {
this.position = { this.position = {
x: Math.round(this.position.x), x: Math.round(position.x),
y: Math.round(this.position.y) y: Math.round(position.y)
} }
resolve(); resolve();
} else { } else {
requestAnimationFrame(() => cycle()); Time.instance.requestAnimationFrame(() => cycle());
} }
} }
@ -146,6 +167,8 @@ class AgentController {
const sign = (() => { const sign = (() => {
if (((this.rotation.z > rotation.z) || (this.rotation.z == 0 && rotation.z == 270)) && !(this.rotation.z == 270 && rotation.z == 0)) { if (((this.rotation.z > rotation.z) || (this.rotation.z == 0 && rotation.z == 270)) && !(this.rotation.z == 270 && rotation.z == 0)) {
return -1; return -1;
} else if (this.rotation.z == rotation.z) {
return 0;
} }
return 1; return 1;
})(); })();
@ -154,7 +177,6 @@ class AgentController {
this.currentAction = this.actions.IN_ROTATION; this.currentAction = this.actions.IN_ROTATION;
const oldZRotation = this.rotation.z; const oldZRotation = this.rotation.z;
const newZRotation = rotation.z;
const clampRotation = (rot) => (rot + 360) % 360; const clampRotation = (rot) => (rot + 360) % 360;
let { rotationSpeed } = this; let { rotationSpeed } = this;
@ -162,11 +184,17 @@ class AgentController {
this.rotation = { z: clampRotation(oldZRotation + (rotationSpeed * sign)) }; this.rotation = { z: clampRotation(oldZRotation + (rotationSpeed * sign)) };
if (Math.abs(oldZRotation - newZRotation) < 5) { if (
(sign > 0 && rotation.z != 0 && this.rotation.z > rotation.z) ||
(sign > 0 && rotation.z == 0 && this.rotation.z < 90) ||
(sign < 0 && this.rotation.z < rotation.z) ||
(sign < 0 && rotation.z == 0 && this.rotation.z > 270) ||
sign == 0
) {
resolve(); resolve();
this.rotation = { z: clampRotation(newZRotation) } this.rotation = { z: clampRotation(rotation.z) }
} else { } else {
requestAnimationFrame(() => cycle()); Time.instance.requestAnimationFrame(() => cycle());
} }
} }

View File

@ -0,0 +1,19 @@
class TimeController {
static instance;
constructor() {
TimeController.instance = this;
this.bindTime();
}
bindTime() {
for(const elem of document.getElementsByClassName('bind-day')) {
elem.innerHTML = Time.instance.day;
}
}
readFromDayInput() {
Time.instance.addDays(document.getElementById('dayInput').value);
}
}