diff --git a/artworld/drawable.js b/artworld/drawable.js index 3ab659f..bd50e4f 100644 --- a/artworld/drawable.js +++ b/artworld/drawable.js @@ -26,6 +26,9 @@ export class Drawable { throw new Error("draw() must be implemented on child class"); } + // do nothing by default + update() {} + // setters fill(color) { diff --git a/artworld/timer.js b/artworld/timer.js new file mode 100644 index 0000000..09a49fe --- /dev/null +++ b/artworld/timer.js @@ -0,0 +1,34 @@ +export class Timer { + constructor() { + this._pausedAt = null; + this._elapsed = 0; + this._lastStarted = performance.now(); + } + + pause() { + if (!this.isPaused) { + this._pausedAt = performance.now(); + // store time since last pause + this._elapsed += this._pausedAt - this._lastStarted; + } + } + + unpause() { + if (this.isPaused) { + this.lastStarted = performance.now(); + this._pausedAt = null; + } + } + + get isPaused() { + return this._pausedAt !== null; + } + + time() { + if (this.isPaused) { + return this._elapsed; + } else { + return this._elapsed + (performance.now() - this._lastStarted); + } + } +} diff --git a/artworld/world.js b/artworld/world.js index 1b7323b..24eefff 100644 --- a/artworld/world.js +++ b/artworld/world.js @@ -1,7 +1,14 @@ +import { Timer } from "./timer.js"; + export class World { constructor() { - this.drawables = []; this.ctx = null; + this.drawables = []; + this.backgroundColor = "white"; + this.timer = new Timer(); + this.targetFrameRate = 60; + this.stepSize = 1000 / this.targetFrameRate; + this.lastTick = this.timer.time(); } bindCanvas(id) { @@ -16,16 +23,39 @@ export class World { return this.ctx.canvas.height; } + // TODO rename register(drawable) { this.drawables.push(drawable); } draw() { + this.ctx.fillStyle = "white"; + this.ctx.beginPath(); + this.ctx.fillRect(0, 0, this.width, this.height); + this.ctx.fill(); for (let d of this.drawables.sort((a, b) => a._z_index - b._z_index)) { d.draw(); } } + tick() { + for (let d of this.drawables) { + d.update(); + } + } + + loopStep() { + window.requestAnimationFrame(() => this.loopStep()); + + let curTime = this.timer.time(); + // tick appropriate number of times + while (curTime - this.lastTick > this.stepSize) { + this.lastTick += this.stepSize; + this.tick(); + } + this.draw(); + } + // Canvas 2D ///////////////// prepareDraw(drawable) { diff --git a/examples/balls.html b/examples/balls.html new file mode 100644 index 0000000..4f85eea --- /dev/null +++ b/examples/balls.html @@ -0,0 +1,63 @@ + +
+ + + + +