It works
This commit is contained in:
+29
-20
@@ -2,7 +2,6 @@ import SandPainter from "./sand-painter"
|
|||||||
import State from "./state"
|
import State from "./state"
|
||||||
|
|
||||||
export default class Crack {
|
export default class Crack {
|
||||||
private static padding = .66
|
|
||||||
private x: number = 0
|
private x: number = 0
|
||||||
private y: number = 0
|
private y: number = 0
|
||||||
private angle: number = 0
|
private angle: number = 0
|
||||||
@@ -10,29 +9,17 @@ export default class Crack {
|
|||||||
private state: State
|
private state: State
|
||||||
|
|
||||||
constructor(state: State) {
|
constructor(state: State) {
|
||||||
this.painter = new SandPainter(state)
|
this.painter = new SandPainter(state.getRandomColor())
|
||||||
this.state = state
|
this.state = state
|
||||||
this.init()
|
this.init()
|
||||||
}
|
}
|
||||||
|
|
||||||
init() {
|
init() {
|
||||||
let x = 0, y = 0, found = false, tries = 0
|
const index = Math.floor(Math.random() * this.state.seeds.length)
|
||||||
while (!found && tries++ < 1000) {
|
const {x, y} = this.state.seeds.splice(index, 1)[0]
|
||||||
x = Math.random() * this.state.width
|
const flip = Math.random() < 0.5
|
||||||
y = Math.random() * this.state.height
|
let angle = this.state.grid[x][y]
|
||||||
found = this.state.crackGrid[y * this.state.height + x] < 10000
|
this.start(x, y, angle + (90 + Math.floor(Math.random() * 4.1 - 2)) * (flip ? -1 : 1))
|
||||||
}
|
|
||||||
|
|
||||||
if (!found) {
|
|
||||||
console.warn("Unable to start crack due to timeout")
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
const negative = Math.random() < 0.5
|
|
||||||
let value = this.state.crackGrid[y * this.state.height + x]
|
|
||||||
|
|
||||||
if (negative) value -= 90 + Math.floor(Math.random() * 4.1 - 2)
|
|
||||||
else value += 90 + Math.floor(Math.random() * 4.1 - 2)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
start(x: number, y: number, angle: number) {
|
start(x: number, y: number, angle: number) {
|
||||||
@@ -41,8 +28,30 @@ export default class Crack {
|
|||||||
this.angle = angle
|
this.angle = angle
|
||||||
}
|
}
|
||||||
|
|
||||||
continue() {
|
draw() {
|
||||||
this.x += .42 * Math.cos(this.angle * Math.PI / 180)
|
this.x += .42 * Math.cos(this.angle * Math.PI / 180)
|
||||||
this.y += .42 * Math.sin(this.angle * Math.PI / 180)
|
this.y += .42 * Math.sin(this.angle * Math.PI / 180)
|
||||||
|
|
||||||
|
const context = this.state.canvas.getContext("2d")
|
||||||
|
context.fillStyle = "#000"
|
||||||
|
context.fillRect(this.x, this.y, 1, 1)
|
||||||
|
|
||||||
|
const x = Math.floor(this.x)
|
||||||
|
const y = Math.floor(this.y)
|
||||||
|
const height = this.state.canvas.height
|
||||||
|
const width = this.state.canvas.width
|
||||||
|
if (x >= 0 && x < width && y >= 0 && y < height) {
|
||||||
|
const seed = this.state.grid[x][y]
|
||||||
|
if (seed > 10000 || Math.abs(seed - this.angle) < 5) {
|
||||||
|
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 {
|
||||||
|
this.init()
|
||||||
|
this.state.addCrack()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
+7
-1
@@ -1,10 +1,16 @@
|
|||||||
import Substrate from "./substrate"
|
import Substrate from "./substrate"
|
||||||
import Weather from "./weather"
|
import Weather from "./weather"
|
||||||
|
|
||||||
const background = new Substrate("substrate-canvas", 20)
|
const ready = (func: () => void) => document.readyState !== "loading" ? func() : document.addEventListener("DOMContentLoaded", func)
|
||||||
|
ready(() => {
|
||||||
|
new Substrate(20)
|
||||||
|
})
|
||||||
|
|
||||||
|
/*
|
||||||
let weather: Weather
|
let weather: Weather
|
||||||
navigator.geolocation.getCurrentPosition(position => {
|
navigator.geolocation.getCurrentPosition(position => {
|
||||||
weather = new Weather(position.coords.latitude, position.coords.longitude)
|
weather = new Weather(position.coords.latitude, position.coords.longitude)
|
||||||
}, () => {
|
}, () => {
|
||||||
weather = new Weather()
|
weather = new Weather()
|
||||||
})
|
})
|
||||||
|
*/
|
||||||
+6
-2
@@ -4,8 +4,12 @@ export default class SandPainter {
|
|||||||
private color: number
|
private color: number
|
||||||
private gain: number
|
private gain: number
|
||||||
|
|
||||||
constructor(state: State) {
|
constructor(color: number) {
|
||||||
this.color = state.getRandomColor()
|
this.color = color
|
||||||
this.gain = Math.random() / 10
|
this.gain = Math.random() / 10
|
||||||
}
|
}
|
||||||
|
|
||||||
|
render() {
|
||||||
|
|
||||||
|
}
|
||||||
}
|
}
|
||||||
+37
-12
@@ -1,26 +1,51 @@
|
|||||||
export default class State {
|
import Crack from "./crack"
|
||||||
colors: number[]
|
|
||||||
maxCracks: number
|
|
||||||
crackGrid: number[]
|
|
||||||
height: number
|
|
||||||
width: number
|
|
||||||
|
|
||||||
constructor(colors: number[], maxCracks: number, height: number, width: number) {
|
export default class State {
|
||||||
|
readonly canvas: HTMLCanvasElement
|
||||||
|
readonly colors: number[]
|
||||||
|
readonly maxCracks: number
|
||||||
|
readonly grid: number[][]
|
||||||
|
seeds: {x: number, y: number}[]
|
||||||
|
cracks: Crack[]
|
||||||
|
|
||||||
|
constructor(colors: number[], maxCracks: number, canvas: HTMLCanvasElement) {
|
||||||
|
this.canvas = canvas
|
||||||
this.colors = colors
|
this.colors = colors
|
||||||
this.maxCracks = maxCracks
|
this.maxCracks = maxCracks
|
||||||
this.height = height
|
this.grid = []
|
||||||
this.width = width
|
this.cracks = []
|
||||||
this.crackGrid = []
|
|
||||||
|
this.init()
|
||||||
|
}
|
||||||
|
|
||||||
|
init() {
|
||||||
|
this.seeds = []
|
||||||
|
const height = this.canvas.height
|
||||||
|
const width = this.canvas.width
|
||||||
|
const context = this.canvas.getContext("2d")
|
||||||
|
context.fillStyle = "rgb(255 255 255 / 95%)"
|
||||||
|
context.fillRect(0, 0, width, height)
|
||||||
|
|
||||||
for (let x = 0; x < width; x++) {
|
for (let x = 0; x < width; x++) {
|
||||||
|
if (!this.grid[x]) this.grid[x] = []
|
||||||
|
|
||||||
for (let y = 0; y < height; y++) {
|
for (let y = 0; y < height; y++) {
|
||||||
this.crackGrid[y * width + x] = 10000
|
this.grid[x][y] = 10001
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for (let i = 0; i < 16; i++) {
|
for (let i = 0; i < 16; i++) {
|
||||||
this.crackGrid[Math.floor(Math.random() * (height * width))] = Math.ceil(Math.random() * 360)
|
const x = Math.floor(Math.random() * width)
|
||||||
|
const y = Math.floor(Math.random() * height)
|
||||||
|
this.grid[x][y] = Math.floor(Math.random() * 360)
|
||||||
|
this.seeds.push({x, y})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
this.cracks = [new Crack(this), new Crack(this), new Crack(this)]
|
||||||
|
}
|
||||||
|
|
||||||
|
addCrack() {
|
||||||
|
if (this.cracks.length < this.maxCracks) this.cracks.push(new Crack(this))
|
||||||
}
|
}
|
||||||
|
|
||||||
getRandomColor(): number {
|
getRandomColor(): number {
|
||||||
|
|||||||
@@ -5,10 +5,3 @@ body {
|
|||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
padding: 0;
|
padding: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
body {
|
|
||||||
canvas {
|
|
||||||
height: 100%;
|
|
||||||
width: 100%;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
+19
-12
@@ -2,27 +2,34 @@
|
|||||||
import State from "./state"
|
import State from "./state"
|
||||||
|
|
||||||
export default class Substrate {
|
export default class Substrate {
|
||||||
private readonly canvas: HTMLCanvasElement
|
|
||||||
private readonly state: State
|
private readonly state: State
|
||||||
|
|
||||||
constructor(id: string, maxCracks: number, colors?: number[]) {
|
constructor(maxCracks: number, colors?: number[]) {
|
||||||
if (!colors?.length) colors = [ 0x3a1e3e, 0x7c2d3b, 0xb94f3c, 0xf4a462, 0xf9c54e ] // https://colormagic.app/palette/671eeb6c42273fc4c1bb1ac7
|
if (!colors?.length) colors = [ 0x3a1e3e, 0x7c2d3b, 0xb94f3c, 0xf4a462, 0xf9c54e ] // https://colormagic.app/palette/671eeb6c42273fc4c1bb1ac7
|
||||||
|
|
||||||
let canvas = document.getElementById(id) as HTMLCanvasElement
|
const canvas = document.createElement("canvas")
|
||||||
if (!canvas) {
|
canvas.width = document.body.clientWidth
|
||||||
canvas = document.createElement("canvas")
|
canvas.height = document.body.clientHeight
|
||||||
document.body.appendChild(canvas)
|
document.body.appendChild(canvas)
|
||||||
}
|
|
||||||
|
|
||||||
this.canvas = canvas
|
|
||||||
this.state = new State(colors, maxCracks, canvas.clientHeight, canvas.clientWidth)
|
|
||||||
|
|
||||||
|
this.state = new State(colors, maxCracks, canvas)
|
||||||
this.init()
|
this.init()
|
||||||
}
|
}
|
||||||
|
|
||||||
init() {
|
init() {
|
||||||
const context = this.canvas.getContext("2d")
|
const me = this
|
||||||
context.fillStyle = "#fff"
|
let request: number
|
||||||
context.fillRect(0, 0, this.canvas.width, this.canvas.height)
|
const draw = () => {
|
||||||
|
for (const crack of me.state.cracks) crack.draw()
|
||||||
|
request = requestAnimationFrame(draw)
|
||||||
|
}
|
||||||
|
|
||||||
|
setInterval(() => {
|
||||||
|
cancelAnimationFrame(request)
|
||||||
|
me.state.init()
|
||||||
|
request = requestAnimationFrame(draw)
|
||||||
|
}, 60 * 1000)
|
||||||
|
|
||||||
|
request = requestAnimationFrame(draw)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -6,7 +6,6 @@
|
|||||||
<link rel="stylesheet" href="styles.css" />
|
<link rel="stylesheet" href="styles.css" />
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<canvas id="substrate-canvas"></canvas>
|
|
||||||
<div id="weather-panel"></div>
|
<div id="weather-panel"></div>
|
||||||
<script src="main.js"></script>
|
<script src="main.js"></script>
|
||||||
</body>
|
</body>
|
||||||
|
|||||||
+13
-165
File diff suppressed because one or more lines are too long
@@ -5,7 +5,3 @@ body {
|
|||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
padding: 0;
|
padding: 0;
|
||||||
}
|
}
|
||||||
body canvas {
|
|
||||||
height: 100%;
|
|
||||||
width: 100%;
|
|
||||||
}
|
|
||||||
|
|||||||
Reference in New Issue
Block a user