Spazer/src/starfield/starfield.ts

124 lines
3.0 KiB
TypeScript

import { reference } from "./reference.ts"
const canvas = document.querySelector("#mainCanvas");
const ctx = canvas.getContext("2d");
const dpr = window.devicePixelRatio;
const cw = window.innerWidth;
const ch = window.innerHeight;
canvas.width = cw * dpr;
canvas.height = ch * dpr;
ctx.scale(dpr, dpr);
function resize() {
canvas.width = window.innerWidth * dpr;
canvas.height = window.innerHeight * dpr;
}
window.addEventListener('resize', resize, false);
class Star {
// Star x and y are offsets from center of screen
constructor(x: number, y: number, multiplier: number) {
this.x = x;
this.y = y;
this.multiplier = multiplier;
}
canvasPos() {
return {
x: (canvas.width / 2) + this.x,
y: (canvas.height / 2) + this.y,
};
}
size() {
// Size is proportional to distance from the middle
//const dist = Math.max(this.x, this.y);
//return Math.max(1.5, dist/100);
return 1.0;
}
render(ctx) {
const { x, y } = this.canvasPos();
const r = this.size();
ctx.fillStyle = "red";
ctx.beginPath();
ctx.arc(x, y, r, 0, 2*Math.PI)
ctx.fill();
}
static make() {
const angle = Math.random() * 2*Math.PI
const x = Math.cos(angle);
const y = Math.sin(angle);
// The multiplier affects how quickly the star moves.
// Varying this makes some stars appear closer (faster
// movement), some further (slower movement).
const multiplier = 1.01 + Math.random() * 0.04;
return new Star(x, y, multiplier);
}
};
const state = {
start: null,
stars: [],
timeSinceLastStar: Infinity,
};
let start = null;
let stars = [];
let timeSinceLastStar = Infinity;
const starIntervalms = 2000;
const fadeout = 8 / 100;
function clear(ctx, alpha) {
ctx.globalCompositeOperation = "destination-out";
ctx.fillStyle = `rgba(0,0,0, ${alpha})`;
ctx.fillRect( 0, 0, canvas.width, canvas.height );
ctx.globalCompositeOperation = "lighter";
}
function loop(timestamp) {
if (state.start === null) {
state.start = timestamp;
}
const progress = timestamp - state.start
// Create a new star if it's been long enough since
// the previous one
state.timeSinceLastStar += progress;
if (state.timeSinceLastStar > starIntervalms) {
state.timeSinceLastStar = 0
state.stars.push(Star.make());
}
// Clear the screen.
// If you want the hyperspace effect, skip this.
clear(ctx, fadeout);
state.stars.forEach((star) => {
// Increase the star's distance from the middle
// proportionally to its current distance
const multiplier = star.multiplier;
star.x *= multiplier
star.y *= multiplier
star.render(ctx);
})
// Remove stars outside the view boundary
let i = state.stars.length;
while (--i) {
const star = state.stars[i];
let {x, y} = star.canvasPos();
if (x < 0 || x > canvas.width || y < 0 || y > canvas.height) {
state.stars.splice(i, 1)
}
}
window.requestAnimationFrame(loop)
}
window.requestAnimationFrame(loop)
//reference(canvas, ctx);