animation basics

This commit is contained in:
James Turk 2024-07-07 03:09:26 -05:00
parent 627ce43e4f
commit ff593dcd92
4 changed files with 131 additions and 1 deletions

View File

@ -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) {

34
artworld/timer.js Normal file
View File

@ -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);
}
}
}

View File

@ -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) {

63
examples/balls.html Normal file
View File

@ -0,0 +1,63 @@
<html>
<head> </head>
<body>
<canvas id="mainCanvas" width="500" height="500"></canvas>
<script type="module">
import {
artworld,
Color,
Pico8,
Group,
Circle,
Random,
Vector2,
degToRad,
} from "../artworld/index.js";
artworld.bindCanvas("mainCanvas");
window.artworld = artworld;
class Ball extends Circle {
constructor() {
super();
this.speed = new Vector2(0, Random.between(9, 15));
}
update() {
this.move(this.speed);
if (this.worldPos.y > artworld.height + 20) {
this.y(-20);
}
}
}
class GravityBall extends Circle {
constructor() {
super();
this.accel = new Vector2(0, 0.5);
this.speed = Vector2.random(0, 5);
}
update() {
this.speed = this.speed.add(this.accel);
this.move(this.speed);
if (this.worldPos.y > artworld.height - 10) {
this.speed = this.speed.scale(-0.98); // bounce w/ dampening
this.y(artworld.height - 10.01);
}
}
}
for (let i = 0; i < 21; i++) {
new Ball()
.pos(new Vector2(40 * i, 0))
.radius(10)
.fill(Pico8.BLUE);
new GravityBall()
.pos(new Vector2(20 + 40 * i, 0))
.radius(10)
.fill(Pico8.PURPLE);
}
artworld.loopStep();
</script>
</body>
</html>