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
|
||||
- StorageCenterLocation.w * StorageCenterLocation.h)
|
||||
|
||||
const AgentMoveSpeed = 20 /* 1 - slowest, 89 - fastest */
|
||||
const AgentRotationSpeed = 20 /* 1 - slowest, 89 - fastest */
|
||||
const AgentMoveSpeed = 40 /* 1 - slowest, 89 - fastest */
|
||||
const AgentRotationSpeed = 40 /* 1 - slowest, 89 - fastest */
|
||||
const AgentWaitTime = 500 /* in miliseconds */
|
||||
|
@ -18,10 +18,12 @@
|
||||
<script src="configuration.js"></script>
|
||||
<script src="utilities.js"></script>
|
||||
<script src="logic/product.js"></script>
|
||||
<script src="logic/time.js"></script>
|
||||
|
||||
<script src="view/floor.js"></script>
|
||||
<script src="view/grid.js"></script>
|
||||
<script src="logic/pathfinding.js"></script>
|
||||
<script src="view/timeController.js"></script>
|
||||
<script src="view/agentController.js"></script>
|
||||
<script src="logic/agent.js"></script>
|
||||
<script src="view/products.js"></script>
|
||||
@ -43,7 +45,34 @@
|
||||
<main>
|
||||
|
||||
<div class="header">
|
||||
<div class="header-line"></div>
|
||||
<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 class="logs-label">
|
||||
|
@ -1,21 +1,27 @@
|
||||
class Agent extends AgentController {
|
||||
|
||||
static instance;
|
||||
|
||||
constructor(canvas) {
|
||||
super(canvas);
|
||||
|
||||
Agent.instance = this;
|
||||
|
||||
const cycle = async () => {
|
||||
const jobRequest = Products.instance.getJobRequest();
|
||||
if (jobRequest) {
|
||||
const requiredAmount = 50 - jobRequest.amount;
|
||||
await this.takeFromStore(jobRequest.product, requiredAmount);
|
||||
await this.deliver(jobRequest.x, jobRequest.y);
|
||||
} else {
|
||||
await waitFor(1000);
|
||||
}
|
||||
|
||||
await waitFor(AgentWaitTime);
|
||||
await waitFor(this.waitTime);
|
||||
cycle();
|
||||
};
|
||||
|
||||
setTimeout(() => cycle(), 2000);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
@ -34,8 +40,9 @@ class Agent extends AgentController {
|
||||
*/
|
||||
async deliver(x, y) {
|
||||
await this.moveTo(x, y);
|
||||
await waitFor(AgentWaitTime);
|
||||
await waitFor(this.waitTime);
|
||||
Products.instance.exchange(x, y, this.ownedProduct, 50);
|
||||
|
||||
this.ownedProductAmount = 0;
|
||||
this.ownedProduct = Product.REGISTRY.empty;
|
||||
}
|
||||
@ -46,7 +53,7 @@ class Agent extends AgentController {
|
||||
*/
|
||||
async takeFromStore(product, amount) {
|
||||
await this.moveTo(9, 8);
|
||||
await waitFor(AgentWaitTime);
|
||||
await waitFor(this.waitTime);
|
||||
this.ownedProductAmount = amount;
|
||||
this.ownedProduct = product;
|
||||
}
|
||||
|
@ -34,10 +34,12 @@ class Pathfinding {
|
||||
|
||||
for (const successor of this.successor(elem)) {
|
||||
if (!Pathfinding.isNodeInArr(successor, explored) && !Pathfinding.isNodeInArr(successor, fringe)) {
|
||||
Pathfinding.insertWithPriority(successor, fringe, expectedNode);
|
||||
Pathfinding.insertWithPriority(successor, fringe);
|
||||
} else if (Pathfinding.isNodeInArr(successor, fringe)) {
|
||||
const index = Pathfinding.findIndefOf(successor, fringe);
|
||||
fringe.splice(index, 1, successor);
|
||||
const index = Pathfinding.findIndexOf(successor, fringe);
|
||||
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))
|
||||
}
|
||||
|
||||
static findIndefOf(node, arr) {
|
||||
static findIndexOf(node, arr) {
|
||||
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()) {
|
||||
if (node.totalCost < n.totalCost) {
|
||||
arr.splice(i, 0, node);
|
||||
@ -108,7 +110,6 @@ class Pathfinding {
|
||||
currentElement = currentElement.parent;
|
||||
}
|
||||
|
||||
console.log(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 costMap = new CostMap();
|
||||
const time = new Time();
|
||||
const timeController = new TimeController();
|
||||
const costMapVisualisation = new CostMapVisualisation(costCanvas);
|
||||
const floor = new Floor(floorCanvas);
|
||||
const grid = new Grid(gridCanvas);
|
||||
const agent = new Agent(agentCanvas);
|
||||
const products = new Products(productsCanvas);
|
||||
|
||||
|
||||
const fpsElement = document.getElementById('fps');
|
||||
if (window.location.hash == '#debug') {
|
||||
displayFPS(fpsElement);
|
||||
|
@ -41,6 +41,49 @@ main {
|
||||
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 {
|
||||
margin: 0 20px 30px 10px;
|
||||
}
|
||||
|
@ -15,14 +15,24 @@ class AgentController {
|
||||
}
|
||||
this.currentAction = this.actions.STATIONARY;
|
||||
|
||||
// Pozycja i poruszanie się
|
||||
// Pozycja i rotacja
|
||||
this.position = { x: 6, y: 0 };
|
||||
this.rotation = { z: 0 };
|
||||
this.speed = 90 - AgentMoveSpeed;
|
||||
this.rotationSpeed = 90 / ( 90 - AgentRotationSpeed);
|
||||
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) {
|
||||
canvas.width = 2000;
|
||||
canvas.height = 900;
|
||||
@ -35,7 +45,7 @@ class AgentController {
|
||||
}
|
||||
this.drawAgent();
|
||||
|
||||
requestAnimationFrame(this.update.bind(this));
|
||||
Time.instance.requestAnimationFrame(this.update.bind(this));
|
||||
}
|
||||
|
||||
updateAgentPosition() {
|
||||
@ -78,6 +88,11 @@ class AgentController {
|
||||
* @param {{ x: number, y: number }} position
|
||||
*/
|
||||
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) => {
|
||||
const cycle = () => {
|
||||
let { speed } = this;
|
||||
@ -89,14 +104,20 @@ class AgentController {
|
||||
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 = {
|
||||
x: Math.round(this.position.x),
|
||||
y: Math.round(this.position.y)
|
||||
x: Math.round(position.x),
|
||||
y: Math.round(position.y)
|
||||
}
|
||||
resolve();
|
||||
} else {
|
||||
requestAnimationFrame(() => cycle());
|
||||
Time.instance.requestAnimationFrame(() => cycle());
|
||||
}
|
||||
}
|
||||
|
||||
@ -146,6 +167,8 @@ class AgentController {
|
||||
const sign = (() => {
|
||||
if (((this.rotation.z > rotation.z) || (this.rotation.z == 0 && rotation.z == 270)) && !(this.rotation.z == 270 && rotation.z == 0)) {
|
||||
return -1;
|
||||
} else if (this.rotation.z == rotation.z) {
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
})();
|
||||
@ -154,7 +177,6 @@ class AgentController {
|
||||
this.currentAction = this.actions.IN_ROTATION;
|
||||
|
||||
const oldZRotation = this.rotation.z;
|
||||
const newZRotation = rotation.z;
|
||||
|
||||
const clampRotation = (rot) => (rot + 360) % 360;
|
||||
let { rotationSpeed } = this;
|
||||
@ -162,11 +184,17 @@ class AgentController {
|
||||
|
||||
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();
|
||||
this.rotation = { z: clampRotation(newZRotation) }
|
||||
this.rotation = { z: clampRotation(rotation.z) }
|
||||
} 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