Compare commits
No commits in common. "d96aefd3f2779073684baeb59149b470caeaee02" and "757e85bbcf3c10aa72566f57af981861b41856c2" have entirely different histories.
d96aefd3f2
...
757e85bbcf
11
config.js
11
config.js
@ -1,14 +1,5 @@
|
|||||||
export const MASS_CREATION_RATE = 0.001;
|
export const MASS_CREATION_RATE = 0.001;
|
||||||
export const DISPLAY_OBJECTS_INFO = false;
|
export const DISPLAY_OBJECTS_INFO = false;
|
||||||
|
export const DISPLAY_CURSOR_INFO = false;
|
||||||
export const DISPLAY_VELOCITY_VECTORS = true;
|
export const DISPLAY_VELOCITY_VECTORS = true;
|
||||||
export const POINTER_HISTORY_SIZE = 20;
|
export const POINTER_HISTORY_SIZE = 20;
|
||||||
export const VELOCITY_VECTOR_SCALE = 0.2;
|
|
||||||
export const VELOCITY_VECTOR_COLOR = 'rgb(150, 150, 150)'; // optionally set to 'object color'
|
|
||||||
export const VELOCITY_VECTOR_WIDTH = 1.5;
|
|
||||||
export const VELOCITY_VECTOR_ARROWHEAD = true;
|
|
||||||
export const ARROWHEAD_LENGTH = 10;
|
|
||||||
export const ARROWHEAD_WIDTH = 7;
|
|
||||||
export const MOTION_TIME_SCALE = 0.001;
|
|
||||||
export const OFFSCREEN_OBJECT_LINE_SCALE = 5;
|
|
||||||
export const OFFSCREEN_OBJECT_LINE_WIDTH = 1.5;
|
|
||||||
export const OFFSCREEN_OBJECT_ARROWHEAD_LENGTH = 15;
|
|
||||||
|
|||||||
152
display.js
152
display.js
@ -1,19 +1,7 @@
|
|||||||
import {
|
|
||||||
VELOCITY_VECTOR_SCALE,
|
|
||||||
VELOCITY_VECTOR_COLOR,
|
|
||||||
VELOCITY_VECTOR_WIDTH,
|
|
||||||
VELOCITY_VECTOR_ARROWHEAD,
|
|
||||||
ARROWHEAD_LENGTH,
|
|
||||||
ARROWHEAD_WIDTH,
|
|
||||||
OFFSCREEN_OBJECT_LINE_SCALE,
|
|
||||||
OFFSCREEN_OBJECT_LINE_WIDTH,
|
|
||||||
OFFSCREEN_OBJECT_ARROWHEAD_LENGTH,
|
|
||||||
} from './config.js';
|
|
||||||
|
|
||||||
export class Display {
|
export class Display {
|
||||||
sim = undefined;
|
sim = undefined;
|
||||||
scale = 1;
|
|
||||||
viewOrigin = {x: 0, y: 0};
|
VELOCITY_VECTOR_SCALE = 0.2;
|
||||||
|
|
||||||
constructor(sim) {
|
constructor(sim) {
|
||||||
this.sim = sim;
|
this.sim = sim;
|
||||||
@ -21,6 +9,7 @@ export class Display {
|
|||||||
// If the window resizes, also resize the canvas
|
// If the window resizes, also resize the canvas
|
||||||
const canvas = document.createElement('canvas')
|
const canvas = document.createElement('canvas')
|
||||||
this.canvas = canvas;
|
this.canvas = canvas;
|
||||||
|
this.ctx = canvas.getContext("2d");
|
||||||
this.sim.div.appendChild(canvas);
|
this.sim.div.appendChild(canvas);
|
||||||
canvas.style.position = 'absolute';
|
canvas.style.position = 'absolute';
|
||||||
canvas.style.top = 0;
|
canvas.style.top = 0;
|
||||||
@ -29,29 +18,6 @@ export class Display {
|
|||||||
window.addEventListener('resize', () => this.fullscreen());
|
window.addEventListener('resize', () => this.fullscreen());
|
||||||
}
|
}
|
||||||
|
|
||||||
get ctx() {
|
|
||||||
const ctx = this.canvas.getContext("2d");
|
|
||||||
ctx.resetTransform();
|
|
||||||
ctx.scale(this.scale, this.scale);
|
|
||||||
ctx.translate(-this.viewOrigin.x, -this.viewOrigin.y);
|
|
||||||
return ctx;
|
|
||||||
}
|
|
||||||
|
|
||||||
get width() {
|
|
||||||
return this.canvas.width / this.scale;
|
|
||||||
}
|
|
||||||
|
|
||||||
get height() {
|
|
||||||
return this.canvas.height / this.scale;
|
|
||||||
}
|
|
||||||
|
|
||||||
screenToSim(x, y) {
|
|
||||||
return {
|
|
||||||
x: x / this.scale + this.viewOrigin.x,
|
|
||||||
y: y / this.scale + this.viewOrigin.y,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
fullscreen() {
|
fullscreen() {
|
||||||
this.canvas.width = document.documentElement.clientWidth;
|
this.canvas.width = document.documentElement.clientWidth;
|
||||||
this.canvas.height = document.documentElement.clientHeight;
|
this.canvas.height = document.documentElement.clientHeight;
|
||||||
@ -61,7 +27,7 @@ export class Display {
|
|||||||
fillCanvas() {
|
fillCanvas() {
|
||||||
const ctx = this.ctx;
|
const ctx = this.ctx;
|
||||||
ctx.fillStyle = '#000';
|
ctx.fillStyle = '#000';
|
||||||
ctx.fillRect(this.viewOrigin.x, this.viewOrigin.y, this.width, this.height);
|
ctx.fillRect(0, 0, this.canvas.width, this.canvas.height);
|
||||||
}
|
}
|
||||||
|
|
||||||
drawObject(idx) {
|
drawObject(idx) {
|
||||||
@ -71,57 +37,6 @@ export class Display {
|
|||||||
const {x, y} = obj.position;
|
const {x, y} = obj.position;
|
||||||
const {x: vx, y: vy} = obj.velocity;
|
const {x: vx, y: vy} = obj.velocity;
|
||||||
const radius = obj.radius;
|
const radius = obj.radius;
|
||||||
const {height: H, width: W} = this;
|
|
||||||
const ox = this.viewOrigin.x;
|
|
||||||
const oy = this.viewOrigin.y;
|
|
||||||
const cx = ox + W / 2;
|
|
||||||
const cy = oy + H / 2;
|
|
||||||
// If the object is outside the display area, draw an arrow at the edge of the display
|
|
||||||
if (Math.abs(x - cx) - radius >= W / 2 ||
|
|
||||||
Math.abs(y - cy) - radius >= H / 2) {
|
|
||||||
// Find where a line from center of display to object intersects display edge
|
|
||||||
let px, py;
|
|
||||||
if (y <= cy) {
|
|
||||||
// Line intersects y = 0:
|
|
||||||
const y0px = cx + (H / 2) / (cy - y) * (x - cx);
|
|
||||||
if (Math.abs(y0px - cx) <= W / 2) {
|
|
||||||
px = y0px;
|
|
||||||
py = this.viewOrigin.y;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// Line intersects y = H
|
|
||||||
const yHpx = cx + (H / 2) / (y - cy) * (x - cx);
|
|
||||||
if (Math.abs(yHpx - cx) <= W / 2) {
|
|
||||||
px = yHpx;
|
|
||||||
py = this.viewOrigin.y + H;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (px === undefined) {
|
|
||||||
if (x <= cx) {
|
|
||||||
// Line intersects x = 0:
|
|
||||||
px = this.viewOrigin.x;
|
|
||||||
py = cy + (W / 2) / (cx - x) * (y - cy);
|
|
||||||
} else {
|
|
||||||
// Line intersects x = W:
|
|
||||||
px = this.viewOrigin.x + W;
|
|
||||||
py = cy + (W / 2) / (x - cx) * (y - cy);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const arrowDirection = Math.atan2(py - cy, px - cx);
|
|
||||||
// Length of arrow based on distance (logarithmic scale)
|
|
||||||
const distance = Math.sqrt((x - px)**2, (y - py)**2);
|
|
||||||
const arrowLength = Math.log(distance) * OFFSCREEN_OBJECT_LINE_SCALE / this.scale;
|
|
||||||
const startAx = px - arrowLength * Math.cos(arrowDirection);
|
|
||||||
const startAy = py - arrowLength * Math.sin(arrowDirection);
|
|
||||||
this.drawArrow(startAx, startAy, px, py, {
|
|
||||||
style: `rgb(${r}, ${g}, ${b})`,
|
|
||||||
width: OFFSCREEN_OBJECT_LINE_WIDTH,
|
|
||||||
arrowheadLength: OFFSCREEN_OBJECT_ARROWHEAD_LENGTH
|
|
||||||
});
|
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Draw filled circle for the object
|
// Draw filled circle for the object
|
||||||
ctx.fillStyle = `rgb(${r}, ${g}, ${b})`;
|
ctx.fillStyle = `rgb(${r}, ${g}, ${b})`;
|
||||||
@ -129,17 +44,16 @@ export class Display {
|
|||||||
ctx.arc(x, y, radius, 0, 2*Math.PI);
|
ctx.arc(x, y, radius, 0, 2*Math.PI);
|
||||||
ctx.fill();
|
ctx.fill();
|
||||||
|
|
||||||
// Draw arrow for the velocity
|
// Draw line for the velocity
|
||||||
const endVx = x + VELOCITY_VECTOR_SCALE * vx;
|
// TODO: Arrow
|
||||||
const endVy = y + VELOCITY_VECTOR_SCALE * vy;
|
ctx.strokeStyle = ctx.fillStyle;
|
||||||
const style = VELOCITY_VECTOR_COLOR === 'object color' ? ctx.fillStyle : VELOCITY_VECTOR_COLOR;
|
ctx.lineWidth = 2.0;
|
||||||
this.drawArrow(x, y, endVx, endVy, {
|
ctx.beginPath();
|
||||||
style,
|
ctx.moveTo(x, y);
|
||||||
width: VELOCITY_VECTOR_WIDTH,
|
ctx.lineTo(x + this.VELOCITY_VECTOR_SCALE * vx, y + this.VELOCITY_VECTOR_SCALE * vy);
|
||||||
arrowhead: VELOCITY_VECTOR_ARROWHEAD
|
ctx.stroke();
|
||||||
});
|
|
||||||
|
|
||||||
// TODO: Draw arrow for acceleration
|
// TODO: Draw line for acceleration
|
||||||
}
|
}
|
||||||
|
|
||||||
drawObjects() {
|
drawObjects() {
|
||||||
@ -147,44 +61,4 @@ export class Display {
|
|||||||
this.drawObject(i);
|
this.drawObject(i);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
drawArrow(startX, startY, endX, endY, {style, width, arrowhead, arrowheadLength}) {
|
|
||||||
arrowhead = arrowhead ?? true;
|
|
||||||
arrowheadLength = arrowheadLength ?? ARROWHEAD_LENGTH;
|
|
||||||
const ctx = this.ctx;
|
|
||||||
ctx.strokeStyle = style;
|
|
||||||
// Keep arrows at normal scale
|
|
||||||
ctx.lineWidth = width / this.scale;
|
|
||||||
const scaledArrowheadLength = arrowheadLength / this.scale;
|
|
||||||
const arrowDirection = Math.atan2(endY - startY, endX - startX);
|
|
||||||
const endAx = arrowhead ? endX - (scaledArrowheadLength - 1) * Math.cos(arrowDirection) : endX;
|
|
||||||
const endAy = arrowhead ? endY - (scaledArrowheadLength - 1) * Math.sin(arrowDirection) : endY;
|
|
||||||
ctx.beginPath();
|
|
||||||
ctx.moveTo(startX, startY);
|
|
||||||
ctx.lineTo(endAx, endAy);
|
|
||||||
ctx.stroke();
|
|
||||||
if (arrowhead) {
|
|
||||||
this.drawArrowHead(endX, endY, arrowDirection, {style, length: arrowheadLength});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
drawArrowHead(x, y, direction, {style, length}) {
|
|
||||||
const arrowheadLength = length ?? ARROWHEAD_LENGTH;
|
|
||||||
const arrowheadWidth = arrowheadLength / ARROWHEAD_LENGTH * ARROWHEAD_WIDTH;
|
|
||||||
const ctx = this.ctx;
|
|
||||||
ctx.fillStyle = style;
|
|
||||||
// To make this simple, draw the arrowhead and then rotate and translate it as needed.
|
|
||||||
// Keep arrows at normal scale
|
|
||||||
const scaledArrowheadLength = arrowheadLength / this.scale;
|
|
||||||
const scaledArrowheadWidth = arrowheadWidth / this.scale;
|
|
||||||
ctx.beginPath();
|
|
||||||
ctx.moveTo(x, y);
|
|
||||||
ctx.translate(x, y);
|
|
||||||
ctx.rotate(direction);
|
|
||||||
ctx.lineTo(-scaledArrowheadLength, -scaledArrowheadWidth / 2);
|
|
||||||
ctx.lineTo(-scaledArrowheadLength, scaledArrowheadWidth / 2);
|
|
||||||
ctx.closePath();
|
|
||||||
ctx.fill();
|
|
||||||
ctx.resetTransform();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,5 +1,4 @@
|
|||||||
export class MassObject {
|
export class MassObject {
|
||||||
index = undefined;
|
|
||||||
mass = 0;
|
mass = 0;
|
||||||
density = 1;
|
density = 1;
|
||||||
position = {x: undefined, y: undefined};
|
position = {x: undefined, y: undefined};
|
||||||
@ -7,8 +6,7 @@ export class MassObject {
|
|||||||
color = {r: undefined, g: undefined, b: undefined};
|
color = {r: undefined, g: undefined, b: undefined};
|
||||||
created = undefined;
|
created = undefined;
|
||||||
|
|
||||||
constructor(x, y, index) {
|
constructor(x, y) {
|
||||||
this.index = index;
|
|
||||||
this.position.x = x;
|
this.position.x = x;
|
||||||
this.position.y = y;
|
this.position.y = y;
|
||||||
this.color.r = Math.random() * 256;
|
this.color.r = Math.random() * 256;
|
||||||
|
|||||||
15
objects.js
15
objects.js
@ -1,9 +1,5 @@
|
|||||||
import { MassObject } from './object.js';
|
import { MassObject } from './object.js';
|
||||||
import {
|
import { MASS_CREATION_RATE, DISPLAY_OBJECTS_INFO } from './config.js';
|
||||||
MASS_CREATION_RATE,
|
|
||||||
DISPLAY_OBJECTS_INFO,
|
|
||||||
MOTION_TIME_SCALE,
|
|
||||||
} from './config.js';
|
|
||||||
|
|
||||||
export class Objects {
|
export class Objects {
|
||||||
objects = [];
|
objects = [];
|
||||||
@ -16,8 +12,8 @@ export class Objects {
|
|||||||
|
|
||||||
// Create an object with mass that grows as pointer is held down
|
// Create an object with mass that grows as pointer is held down
|
||||||
createObject(x, y) {
|
createObject(x, y) {
|
||||||
|
const obj = new MassObject(x, y);
|
||||||
const idx = this.objects.length;
|
const idx = this.objects.length;
|
||||||
const obj = new MassObject(x, y, idx);
|
|
||||||
this.creatingObject = idx;
|
this.creatingObject = idx;
|
||||||
this.objects.push(obj);
|
this.objects.push(obj);
|
||||||
}
|
}
|
||||||
@ -69,13 +65,6 @@ export class Objects {
|
|||||||
obj.mass += rate * elapsedTime;
|
obj.mass += rate * elapsedTime;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Update positions. Simple Euler method for now.
|
|
||||||
for (let i = 0; i < this.objects.length; i++) {
|
|
||||||
const obj = this.objects[i];
|
|
||||||
obj.position.x += obj.velocity.x * MOTION_TIME_SCALE;
|
|
||||||
obj.position.y += obj.velocity.y * MOTION_TIME_SCALE;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Display objects info
|
// Display objects info
|
||||||
if (DISPLAY_OBJECTS_INFO) {
|
if (DISPLAY_OBJECTS_INFO) {
|
||||||
for (let i = 0; i < this.objects.length; i++) {
|
for (let i = 0; i < this.objects.length; i++) {
|
||||||
|
|||||||
45
pointer.js
45
pointer.js
@ -1,4 +1,4 @@
|
|||||||
import { POINTER_HISTORY_SIZE } from './config.js';
|
import { DISPLAY_CURSOR_INFO, POINTER_HISTORY_SIZE } from './config.js';
|
||||||
|
|
||||||
export class Pointer {
|
export class Pointer {
|
||||||
sim = undefined;
|
sim = undefined;
|
||||||
@ -11,31 +11,38 @@ export class Pointer {
|
|||||||
// Monitor mouse movements
|
// Monitor mouse movements
|
||||||
const el = window;
|
const el = window;
|
||||||
el.addEventListener('mousemove', e => {
|
el.addEventListener('mousemove', e => {
|
||||||
this.handlePointerMove(this.sim.screenToSim(e.clientX, e.clientY));
|
if (DISPLAY_CURSOR_INFO) {
|
||||||
|
this.sim.info['Mouse move'] = [`${e.clientX}, `, `${e.clientY}`];
|
||||||
|
}
|
||||||
|
this.handlePointerMove(e.clientX, e.clientY);
|
||||||
});
|
});
|
||||||
|
|
||||||
// Monitor touch events
|
// Monitor touch events
|
||||||
el.addEventListener('touchmove', e => {
|
el.addEventListener('touchmove', e => {
|
||||||
const {pageX, pageY} = e.touches[0];
|
if (DISPLAY_CURSOR_INFO) {
|
||||||
this.handlePointerMove(this.sim.screenToSim(pageX, pageY));
|
this.sim.info['Touch move'] = [`${e.touches[0].pageX}, `, `${e.touches[0].pageY}`];
|
||||||
|
}
|
||||||
|
this.handlePointerMove(e.touches[0].pageX, e.touches[0].pageY);
|
||||||
});
|
});
|
||||||
|
|
||||||
el.addEventListener('pointerdown', e => {
|
el.addEventListener('pointerdown', e => {
|
||||||
this.handlePointerDown(this.sim.screenToSim(e.clientX, e.clientY));
|
if (DISPLAY_CURSOR_INFO) {
|
||||||
|
this.sim.info['Pointer down'] = [`${e.clientX}, `, `${e.clientY}`];
|
||||||
|
}
|
||||||
|
this.handlePointerDown(e.clientX, e.clientY);
|
||||||
});
|
});
|
||||||
|
|
||||||
el.addEventListener('pointerup', e => {
|
el.addEventListener('pointerup', e => {
|
||||||
this.handlePointerUp(this.sim.screenToSim(e.clientX, e.clientY));
|
if (DISPLAY_CURSOR_INFO) {
|
||||||
|
this.sim.info['Pointer up'] = [`${e.clientX}, `, `${e.clientY}`];
|
||||||
|
}
|
||||||
|
this.handlePointerUp(e.clientX, e.clientY);
|
||||||
});
|
});
|
||||||
|
|
||||||
el.addEventListener('click', e => {
|
el.addEventListener('click', e => {
|
||||||
});
|
if (DISPLAY_CURSOR_INFO) {
|
||||||
|
this.sim.info['Click'] = [`${e.clientX}, `, `${e.clientY}`];
|
||||||
// Monitor wheel events
|
}
|
||||||
el.addEventListener('wheel', e => {
|
|
||||||
// Wheel scroll down => positive deltaY => ZOOM IN
|
|
||||||
const factor = e.deltaY > 0 ? 2 : 0.5;
|
|
||||||
this.sim.scheduleZoom(this.sim.screenToSim(e.clientX, e.clientY), factor);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
}
|
}
|
||||||
@ -58,7 +65,7 @@ export class Pointer {
|
|||||||
this.pointerHistory = [];
|
this.pointerHistory = [];
|
||||||
}
|
}
|
||||||
|
|
||||||
updatePointer({x, y}) {
|
updatePointer(x, y) {
|
||||||
const t = document.timeline.currentTime;
|
const t = document.timeline.currentTime;
|
||||||
this.pointerHistory.push({x, y, t});
|
this.pointerHistory.push({x, y, t});
|
||||||
if (this.pointerHistory.length > POINTER_HISTORY_SIZE) {
|
if (this.pointerHistory.length > POINTER_HISTORY_SIZE) {
|
||||||
@ -66,9 +73,9 @@ export class Pointer {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
handlePointerDown({x, y}) {
|
handlePointerDown(x, y) {
|
||||||
this.clearPointerHistory();
|
this.clearPointerHistory();
|
||||||
this.updatePointer({x, y});
|
this.updatePointer(x, y);
|
||||||
|
|
||||||
// If pointer is touching an object, select the object
|
// If pointer is touching an object, select the object
|
||||||
const touchingObject = this.sim.objects.objectAtLocation(x, y);
|
const touchingObject = this.sim.objects.objectAtLocation(x, y);
|
||||||
@ -81,20 +88,20 @@ export class Pointer {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
handlePointerUp({x, y}) {
|
handlePointerUp(x, y) {
|
||||||
this.sim.objects.doneCreatingObject();
|
this.sim.objects.doneCreatingObject();
|
||||||
this.sim.objects.deselect();
|
this.sim.objects.deselect();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Handle cursor (mouse or touch) movement
|
// Handle cursor (mouse or touch) movement
|
||||||
handlePointerMove({x, y}) {
|
handlePointerMove(x, y) {
|
||||||
// TODO: If e.touches.length > 1, user may be engaging pinch to zoom
|
// TODO: If e.touches.length > 1, user may be engaging pinch to zoom
|
||||||
|
|
||||||
// If the cursor moves while creating an object, or while an object is selected,
|
// If the cursor moves while creating an object, or while an object is selected,
|
||||||
// update the position and velocity of the object
|
// update the position and velocity of the object
|
||||||
const obj = this.sim.objects.getSelectedOrCreating();
|
const obj = this.sim.objects.getSelectedOrCreating();
|
||||||
if (obj !== undefined) {
|
if (obj !== undefined) {
|
||||||
this.updatePointer({x, y});
|
this.updatePointer(x, y);
|
||||||
const {x: vx, y: vy} = this.getPointerVelocity();
|
const {x: vx, y: vy} = this.getPointerVelocity();
|
||||||
obj.position.x = x;
|
obj.position.x = x;
|
||||||
obj.position.y = y;
|
obj.position.y = y;
|
||||||
|
|||||||
28
simulator.js
28
simulator.js
@ -7,7 +7,6 @@ export class Sim {
|
|||||||
info = {};
|
info = {};
|
||||||
frame = 0;
|
frame = 0;
|
||||||
time = undefined;
|
time = undefined;
|
||||||
nextZoom = undefined;
|
|
||||||
|
|
||||||
display = undefined;
|
display = undefined;
|
||||||
overlay = undefined;
|
overlay = undefined;
|
||||||
@ -29,37 +28,14 @@ export class Sim {
|
|||||||
requestAnimationFrame(t => this.loop(t));
|
requestAnimationFrame(t => this.loop(t));
|
||||||
}
|
}
|
||||||
|
|
||||||
scheduleZoom({x, y}, factor) {
|
|
||||||
this.nextZoom = {x, y, factor};
|
|
||||||
}
|
|
||||||
|
|
||||||
zoom({x, y, factor}) {
|
|
||||||
// x, y are the mouse coordinates, which should be the center of the new view frame
|
|
||||||
// the new view origin should be x, y minus half the new view width and height
|
|
||||||
// compute new scale
|
|
||||||
this.display.scale = this.display.scale * factor;
|
|
||||||
// compute coordinates of new view frame
|
|
||||||
this.display.viewOrigin.x = x - this.display.width / 2;
|
|
||||||
this.display.viewOrigin.y = y - this.display.height / 2;
|
|
||||||
}
|
|
||||||
|
|
||||||
screenToSim(x, y) {
|
|
||||||
return this.display.screenToSim(x, y);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Main loop
|
// Main loop
|
||||||
loop(currentTime) {
|
loop(currentTime) {
|
||||||
const elapsedTime = currentTime - this.time;
|
const elapsedTime = currentTime - this.time;
|
||||||
this.time = currentTime;
|
this.time = currentTime;
|
||||||
if (this.nextZoom) {
|
|
||||||
this.zoom(this.nextZoom);
|
|
||||||
this.nextZoom = undefined;
|
|
||||||
}
|
|
||||||
this.display.fillCanvas();
|
|
||||||
this.objects.computeFrame(elapsedTime);
|
this.objects.computeFrame(elapsedTime);
|
||||||
|
|
||||||
this.info['scale'] = this.display.scale;
|
this.display.fillCanvas();
|
||||||
|
|
||||||
this.display.drawObjects();
|
this.display.drawObjects();
|
||||||
this.overlay.renderInfo();
|
this.overlay.renderInfo();
|
||||||
|
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user