kill the singleton

This commit is contained in:
James Turk 2025-03-09 22:57:34 -05:00
parent c44252a14c
commit 90256f617e
6 changed files with 60 additions and 52 deletions

View File

@ -1,4 +1,3 @@
import { artworld } from "./world.js";
import { Vector2 } from "./math.js"; import { Vector2 } from "./math.js";
import { Color } from "./color.js"; import { Color } from "./color.js";
import { Random } from "./random.js"; import { Random } from "./random.js";
@ -10,13 +9,12 @@ export class Drawable {
this._fill = parent ? parent._fill : null; this._fill = parent ? parent._fill : null;
this._stroke = parent ? parent._stroke : null; this._stroke = parent ? parent._stroke : null;
this._strokeWeight = parent ? parent._strokeWeight : null; this._strokeWeight = parent ? parent._strokeWeight : null;
this._z_index = parent ? parent._z_index : null; this._zIndex = parent ? parent._zIndex : null;
this._posVec = new Vector2(0, 0); this._posVec = new Vector2(0, 0);
this._animations = []; this._animations = [];
if (this._parent) { if (this._parent) {
this._parent.addChild(this); this._parent.addChild(this);
} }
artworld.register(this);
} }
copy() { copy() {
@ -71,7 +69,7 @@ export class Drawable {
} }
z(scalar) { z(scalar) {
this._z_index = scalar; this._zIndex = scalar;
return this; return this;
} }
@ -83,10 +81,7 @@ export class Drawable {
} }
random() { random() {
this._posVec = new Vector2( this._posVec = new Vector2(Random.under(100), Random.under(100));
Random.under(artworld.width),
Random.under(artworld.height),
);
this._stroke = new Color( this._stroke = new Color(
Random.under(360), Random.under(360),
Random.between(30, 60), Random.between(30, 60),
@ -137,11 +132,16 @@ export class Group extends Drawable {
return newGroup; return newGroup;
} }
draw() {} draw() {
for (let c of this._children) {
c.draw();
}
}
addChild(drawable) { addChild(drawable) {
this._children.push(drawable); this._children.push(drawable);
drawable._parent = this; drawable._parent = this;
drawable._world = this._world;
return this; return this;
} }

View File

@ -1,7 +1,7 @@
export { artworld } from "./world.js";
export { Color, Pico8 } from "./color.js"; export { Color, Pico8 } from "./color.js";
export { Vector2, degToRad, radToDeg } from "./math.js"; export { Vector2, degToRad, radToDeg } from "./math.js";
export { Line, Rect, Circle, Arc, Polygon } from "./shapes.js"; export { Line, Rect, Circle, Arc, Polygon } from "./shapes.js";
export { Group } from "./drawable.js"; export { Group } from "./drawable.js";
export { Random } from "./random.js"; export { Random } from "./random.js";
export { Var } from "./variables.js"; export { Var } from "./variables.js";
export { World } from "./world.js";

View File

@ -32,8 +32,8 @@ export class Line extends Drawable {
} }
draw() { draw() {
artworld.prepareDraw(this); this._world.prepareDraw(this);
artworld.drawLine( this._world.drawLine(
this.worldPos, this.worldPos,
this.worldPos.add(getVal(this._offsetVec)), this.worldPos.add(getVal(this._offsetVec)),
); );
@ -70,8 +70,13 @@ export class Arc extends Drawable {
return this; return this;
} }
draw() { draw() {
artworld.prepareDraw(this); this._world.prepareDraw(this);
artworld.drawArc(this.worldPos, this._r, this._startAngle, this._endAngle); this._world.drawArc(
this.worldPos,
this._r,
this._startAngle,
this._endAngle,
);
} }
radius(scalar) { radius(scalar) {
@ -104,8 +109,8 @@ export class Circle extends Drawable {
} }
draw() { draw() {
artworld.prepareDraw(this); this._world.prepareDraw(this);
artworld.drawArc(this.worldPos, this._r, 0, 2 * Math.PI); this._world.drawArc(this.worldPos, this._r, 0, 2 * Math.PI);
} }
radius(scalar) { radius(scalar) {
@ -132,8 +137,8 @@ export class Rect extends Drawable {
} }
draw() { draw() {
artworld.prepareDraw(this); this._world.prepareDraw(this);
artworld.drawRect(this.worldPos, this._width, this._height); this._world.drawRect(this.worldPos, this._width, this._height);
} }
size(w, h) { size(w, h) {
@ -204,8 +209,8 @@ export class Polygon extends Drawable {
} }
draw() { draw() {
artworld.prepareDraw(this); this._world.prepareDraw(this);
artworld.drawPolygon(this.worldPos, this._points); this._world.drawPolygon(this.worldPos, this._points);
} }
point(vector, to_modify = null) { point(vector, to_modify = null) {

View File

@ -1,5 +1,3 @@
import { artworld } from "./world.js";
export function getVal(x) { export function getVal(x) {
return x && x.getValue ? x.getValue() : x; return x && x.getValue ? x.getValue() : x;
} }
@ -13,7 +11,6 @@ export class Var {
this._value = value; this._value = value;
this._updateFunc = null; this._updateFunc = null;
} }
artworld.register(this);
} }
updateFunc(func) { updateFunc(func) {

View File

@ -2,7 +2,7 @@ import { Timer } from "./timer.js";
import { getVal, Var } from "./variables.js"; import { getVal, Var } from "./variables.js";
export class World { export class World {
constructor() { constructor(canvasId) {
this.ctx = null; this.ctx = null;
this.drawables = []; this.drawables = [];
this.variables = []; this.variables = [];
@ -12,10 +12,7 @@ export class World {
this.stepSize = 1000 / this.targetFrameRate; this.stepSize = 1000 / this.targetFrameRate;
this.lastTick = this.timer.time(); this.lastTick = this.timer.time();
this.numTicks = 0; this.numTicks = 0;
} this.ctx = document.getElementById(canvasId).getContext("2d");
bindCanvas(id) {
this.ctx = document.getElementById(id).getContext("2d");
} }
get width() { get width() {
@ -26,22 +23,24 @@ export class World {
return this.ctx.canvas.height; return this.ctx.canvas.height;
} }
// TODO rename var(value) {
register(thing) { let v = new Var(value);
if (thing instanceof Var) { this.variables.push(v);
this.variables.push(thing); return v;
} else { }
// TODO: check drawable?
this.drawables.push(thing); drawable(thing) {
} this.drawables.push(thing);
thing._world = this; // set world for access to renderer (TODO: revisit)
return thing;
} }
draw() { draw() {
this.ctx.fillStyle = "white"; this.ctx.fillStyle = this.backgroundColor;
this.ctx.beginPath(); this.ctx.beginPath();
this.ctx.fillRect(0, 0, this.width, this.height); this.ctx.fillRect(0, 0, this.width, this.height);
this.ctx.fill(); this.ctx.fill();
for (let d of this.drawables.sort((a, b) => a._z_index - b._z_index)) { for (let d of this.drawables.sort((a, b) => a._zIndex - b._zIndex)) {
d.draw(); d.draw();
} }
} }
@ -134,6 +133,3 @@ export class World {
if (this._fill) this.ctx.fill(); if (this._fill) this.ctx.fill();
} }
} }
// singleton (for now)
export const artworld = new World();

View File

@ -4,7 +4,7 @@
<canvas id="mainCanvas" width="500" height="500"></canvas> <canvas id="mainCanvas" width="500" height="500"></canvas>
<script type="module"> <script type="module">
import { import {
artworld, World,
Color, Color,
Pico8, Pico8,
Group, Group,
@ -16,32 +16,42 @@
Var, Var,
degToRad, degToRad,
} from "../artworld/index.js"; } from "../artworld/index.js";
artworld.bindCanvas("mainCanvas");
window.artworld = artworld;
// declare some time-fluctuation variables let world = new World("mainCanvas");
let color = new Var( window.world = world;
// This is an experiment to separate the declaration of
// "what the data does" from "what it looks like".
// First we use `Var` to define "what the data does"
// variables are expected to regularly *vary*!
// Variables are defined as functions that update with time.
// It is also possible to define static variables.
let color = world.var(
(t) => (t) =>
[Pico8.RED, Pico8.ORANGE, Pico8.GREEN, Pico8.BLUE][ [Pico8.RED, Pico8.ORANGE, Pico8.GREEN, Pico8.BLUE][
Math.floor(t / 60) % 4 Math.floor(t / 60) % 4
], ],
); );
let outerR = new Var((t) => Math.sin(t / 100) * 50 + 200); // We can create dependencies between them: here the inner & outer
// simple dependency // radii should be 10 pixels apart.
let innerR = new Var(() => outerR.getValue() - 10); let outerR = world.var((t) => Math.sin(t / 100) * 50 + 200);
// example of a more complex Var that uses other vars let innerR = world.var(() => outerR.getValue() - 10);
let lineTo = new Var((t) => { // We take this composition a bit further here, the radius of the clock
// hand grows & shrinks with the edge.
let lineTo = world.var((t) => {
let angle = (t / 6000) * Math.PI * 2; let angle = (t / 6000) * Math.PI * 2;
return Vector2.polar(innerR.getValue(), angle); return Vector2.polar(innerR.getValue(), angle);
}); });
let g = new Group().pos(new Vector2(250, 250)); let g = new Group().pos(new Vector2(250, 250));
world.drawable(g);
new Circle(g).fill(Pico8.BLACK).z(1).radius(outerR); new Circle(g).fill(Pico8.BLACK).z(1).radius(outerR);
new Circle(g).z(10).fill(color).radius(innerR); new Circle(g).z(10).fill(color).radius(innerR);
new Circle(g).radius(20).fill(Pico8.BLACK).z(50); new Circle(g).radius(20).fill(Pico8.BLACK).z(50);
new Line(g).to(lineTo).z(100); new Line(g).to(lineTo).z(100);
artworld.loopStep(); world.loopStep();
</script> </script>
</body> </body>
</html> </html>