Much better consistency and I finally figured out that substrate was multiplying draw calls

This commit is contained in:
Lani Aung
2025-06-05 22:07:26 -07:00
parent 0b16629878
commit 5e9039efad
5 changed files with 71 additions and 42 deletions
+11 -17
View File
@@ -9,23 +9,16 @@ export default class Crack {
private state: State
constructor(state: State, x: number, y: number, angle: number) {
this.painter = new SandPainter(state.getRandomColor(), state.isWithinBoundary.bind(state))
this.painter = new SandPainter(state.getRandomColor())
this.state = state
this.x = x
this.y = y
this.angle = angle
this.init()
}
init() {
const flip = Math.random() < 0.5
this.start(this.x, this.y, this.angle + (90 + Math.floor(Math.random() * 4.1 - 2)) * (flip ? -1 : 1))
this.start(x, y, angle)
}
start(x: number, y: number, angle: number) {
this.x = x + .61 * Math.cos(angle * Math.PI / 180)
this.y = y + .61 * Math.sin(angle * Math.PI / 180)
this.angle = angle
const flip = Math.random() < 0.5
this.angle = angle + (90 + Math.floor(Math.random() * 4.1 - 2)) * (flip ? -1 : 1)
}
draw() {
@@ -39,16 +32,17 @@ export default class Crack {
const x = Math.floor(this.x)
const y = Math.floor(this.y)
if (this.state.isWithinBoundary(x, y)) {
const seed = this.state.grid[x][y]
if (seed > 10000 || Math.abs(seed - this.angle) < 5) {
const angle = this.state.grid[x][y]
if (angle > 10000) {
this.state.grid[x][y] = Math.floor(this.angle)
this.state.seeds.push({x, y})
} else if (Math.abs(seed - this.angle) > 2) {
this.init()
this.state.addCrack()
} else if (this.state.grid[x][y] != Math.floor(this.angle)) {
const entry = this.state.getNewEntry()
this.start(entry.x, entry.y, entry.angle)
}
} else {
this.init()
const entry = this.state.getNewEntry()
this.start(entry.x, entry.y, entry.angle)
this.state.addCrack()
}
}
+21 -11
View File
@@ -3,25 +3,35 @@ import State from "./state"
export default class SandPainter {
private color: number
private gain: number
private readonly boundaryCheck: (x: number, y: number) => boolean
constructor(color: number, boundaryCheck: (x: number, y: number) => boolean) {
constructor(color: number) {
this.color = color
this.boundaryCheck = boundaryCheck
this.gain = Math.random() / 10
}
render(x: number, y: number, angle: number) {
let open = true, paintX: number, paintY: number
render(x: number, y: number, angle: number, state: State) {
let open = true, endX = x, endY = y
while (open) {
paintX = x + .81 * Math.sin(angle * Math.PI / 180)
paintY = y - .81 * Math.cos(angle * Math.PI / 180)
const gridX = Math.floor(paintX)
const gridY = Math.floor(paintY)
if (this.boundaryCheck(gridX, gridY)) {
endX += .81 * Math.sin(angle * Math.PI / 180)
endY -= .81 * Math.cos(angle * Math.PI / 180)
const gridX = Math.floor(endX)
const gridY = Math.floor(endY)
if (state.isWithinBoundary(gridX, gridY)) {
open = state.grid[gridX][gridY] > 10000
} else {
open = false
}
}
const grains = 64
const hex = this.color.toString(16)
const w = this.gain / (grains - 1) // some kind of multiplier
const context = state.canvas.getContext("2d")
for (let i = 0; i < grains; i++) {
const alpha = (.1 - i / (grains * 10)) * 255
context.fillStyle = `#${hex.padStart(6, "0")}${alpha.toString(16).padStart(2, "0")}`
}
}
}
+33 -4
View File
@@ -14,13 +14,16 @@ export default class State {
this.maxCracks = maxCracks
this.grid = []
this.cracks = []
this.seeds = []
this.init()
}
init() {
this.seeds = []
this.cracks = []
this.cracks.length = 0
this.grid.length = 0
this.seeds.length = 0
const height = this.canvas.height
const width = this.canvas.width
const context = this.canvas.getContext("2d")
@@ -28,7 +31,7 @@ export default class State {
context.fillRect(0, 0, width, height)
for (let x = 0; x < width; x++) {
if (!this.grid[x]) this.grid[x] = []
this.grid[x] = []
for (let y = 0; y < height; y++) {
this.grid[x][y] = 10001
@@ -45,7 +48,10 @@ export default class State {
}
addCrack() {
if (this.cracks.length < this.maxCracks) this.cracks.push(new Crack(this))
if (this.cracks.length >= this.maxCracks) return
const {x, y, angle} = this.getNewEntry()
this.cracks.push(new Crack(this, x, y, angle))
}
getRandomColor(): number {
@@ -55,4 +61,27 @@ export default class State {
isWithinBoundary(x: number, y: number): boolean {
return x >= 0 && x < this.canvas.width && y >= 0 && y < this.canvas.height
}
getNewEntry(): {x: number, y: number, angle: number} {
if (!this.seeds.length) {
const x = Math.floor(Math.random() * this.canvas.width)
const y = Math.floor(Math.random() * this.canvas.height)
let angle = this.grid[x][y]
if (angle > 10000) {
angle = Math.floor(Math.random() * 360)
this.grid[x][y] = angle
}
return {x, y, angle}
}
const randomIndex = Math.floor(Math.random() * this.seeds.length)
const entry = this.seeds.splice(randomIndex, 1)[0]
return {
x: entry.x,
y: entry.y,
angle: this.grid[entry.x][entry.y]
}
}
}
+2 -6
View File
@@ -23,11 +23,7 @@ export default class Substrate {
requestAnimationFrame(draw)
}
setInterval(() => {
me.state.init()
requestAnimationFrame(draw)
}, 120 * 1000)
requestAnimationFrame(draw)
setInterval(() => me.state.init(), 120 * 1000)
draw()
}
}