feat: Time management
This commit is contained in:
parent
c31c838e55
commit
49a12b1b92
@ -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 */
|
||||||
|
@ -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">
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
|
@ -34,24 +34,26 @@ 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);
|
||||||
|
if (successor.totalCost < fringe[index].totalCost) {
|
||||||
fringe.splice(index, 1, successor);
|
fringe.splice(index, 1, successor);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static isNodeInArr(node, arr) {
|
static isNodeInArr(node, arr) {
|
||||||
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
64
src/logic/time.js
Normal 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));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -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);
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
|
@ -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());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
19
src/view/timeController.js
Normal file
19
src/view/timeController.js
Normal 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);
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user