1
0
포크 0
Scene-Starlight/Starlight-Renderer.js

152 lines
3.9 KiB
JavaScript

"use strict";
import random from './Random'; // Bounded random number generation
import Vector from './Vector'; // 2D vector class
import Range from './Range'; // Range representation
// Subclasses
import Star from './Star';
// ~~~
class StarlightRenderer
{
constructor(canvas)
{
// The colour of the sky in the background.
this.skyColour1 = "hsla(248, 100%, 23%, 1)";
this.skyColour2 = "hsla(248, 100%, 5%, 1)";
this.starCount = 1000;
this.starSize = new Range(2, 10);
this.twinkleDuration = new Range(0.5, 1.5);
this.twinkleSize = new Range(1.2, 2);
// ~~~
this.canvas = canvas;
this.context = canvas.getContext("2d");
this.trackWindowSize();
this.lastFrame = +new Date() / 1000;
// ~~~
this.stars = [];
for(let i = 0; i < this.starCount; i++)
{
let nextStar = new Star(
this.canvas,
new Vector(
random(0, this.canvas.width),
random(0, this.canvas.height)
),
random(this.starSize.min, this.starSize.max)
);
nextStar.pointCount = random(4, 8);
// Make larger stars tend towards having longer points
nextStar.innerRingRatio = random(0.2, 0.8, true);
nextStar.innerRingRatio = (nextStar.innerRingRatio + nextStar.innerRingRatio*(1 - (nextStar.size / this.starSize.max))) / 2;
nextStar.rotation = random(0, Math.PI*2, true);
nextStar.rotationStep = random(0.1, 1, true);
if(random(0, 2) == 0)
nextStar.rotationStep *= -1;
nextStar.alpha = random(0.2, 0.9, true);
nextStar.twinkleDuration = random(this.twinkleDuration.min, this.twinkleDuration.max, true);
nextStar.twinkleSize = random(this.twinkleSize.min, this.twinkleSize.max, true);
this.stars.push(nextStar);
}
}
generateGradients(canvas, context)
{
this.generateBackgroundGradient(canvas, context);
this.generateOverlayGradient(canvas, context);
}
generateBackgroundGradient(canvas, context)
{
this.backgroundGradient = context.createRadialGradient(
canvas.width / 2, canvas.height, canvas.height / 5,
canvas.width / 2, canvas.height, canvas.height * 1.2
);
this.backgroundGradient.addColorStop(0, this.skyColour1);
this.backgroundGradient.addColorStop(1, this.skyColour2);
}
generateOverlayGradient(canvas, context)
{
this.overlayGradient = context.createRadialGradient(
canvas.width / 2, canvas.height, canvas.height / 5,
canvas.width / 2, canvas.height, canvas.height * 1.2
);
this.overlayGradient.addColorStop(0, "hsla(248, 100%, 7%, 0.6)");
this.overlayGradient.addColorStop(1, "hsla(248, 100%, 2%, 0.01)");
}
nextFrame()
{
this.update();
this.render(this.canvas, this.context);
requestAnimationFrame(this.nextFrame.bind(this));
}
update()
{
// Calculate the time between this frame and the last one
this.currentFrame = (+new Date()) / 1000;
this.currentDt = this.currentFrame - this.lastFrame;
// Update all the stars
for(let star of this.stars)
star.update(this.currentDt);
this.lastFrame = this.currentFrame;
}
render(canvas, context)
{
// Background
context.fillStyle = this.backgroundGradient;
context.fillRect(0, 0, this.canvas.width, this.canvas.height);
// Stars
for(let star of this.stars)
star.render(context);
// Overlay
context.fillStyle = this.overlayGradient;
context.fillRect(0, 0, this.canvas.width, this.canvas.height);
}
/**
* Updates the canvas size to match the current viewport size.
*/
matchWindowSize() {
this.canvas.width = window.innerWidth;
this.canvas.height = window.innerHeight;
this.generateGradients(this.canvas, this.context);
//this.render(this.context);
}
/**
* Makes the canvas size track the window size.
*/
trackWindowSize() {
this.matchWindowSize();
window.addEventListener("resize", this.matchWindowSize.bind(this));
}
}
window.addEventListener("load", function (event) {
var canvas = document.getElementById("canvas-main"),
renderer = new StarlightRenderer(canvas);
renderer.nextFrame();
window.renderer = renderer;
});