Start creating zombies
This commit is contained in:
parent
63760d4cb8
commit
efba557e96
|
|
@ -0,0 +1,49 @@
|
|||
import { createCanvas } from "@common/display/canvas";
|
||||
import Spinner from "./spinner";
|
||||
|
||||
const canvas = createCanvas(1024, 1024);
|
||||
const spinner = new Spinner();
|
||||
|
||||
async function update(dt: number) {
|
||||
spinner.update(dt);
|
||||
}
|
||||
|
||||
async function render(ctx: CanvasRenderingContext2D) {
|
||||
ctx.fillStyle = 'green';
|
||||
ctx.fillRect(0, 0, canvas.width, canvas.height);
|
||||
|
||||
ctx.save();
|
||||
|
||||
ctx.translate(100, 100);
|
||||
ctx.scale(200, 200);
|
||||
|
||||
spinner.render(ctx);
|
||||
|
||||
ctx.restore();
|
||||
}
|
||||
|
||||
export default async function main() {
|
||||
document.body.style.background = 'green';
|
||||
canvas.style.imageRendering = 'auto';
|
||||
|
||||
const ctx = canvas.getContext('2d');
|
||||
|
||||
spinner.addListener(console.log);
|
||||
canvas.addEventListener('click', () => {
|
||||
spinner.spin();
|
||||
})
|
||||
|
||||
if (ctx) {
|
||||
let prevFrame = performance.now();
|
||||
const loop = () => {
|
||||
const now = performance.now()
|
||||
const dt = (now - prevFrame) / 1000;
|
||||
prevFrame = now;
|
||||
|
||||
update(dt);
|
||||
render(ctx);
|
||||
requestAnimationFrame(loop);
|
||||
};
|
||||
loop();
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,116 @@
|
|||
export type SpinnerListener = (angle: number) => void;
|
||||
|
||||
export default class Spinner {
|
||||
private readonly probabilities = [0.3, 0.3, 0.2, 0.2];
|
||||
private readonly colors = ['yellow', 'green', 'blue', 'red'];
|
||||
private readonly startAngle = -Math.PI / 2 - this.probabilities[0] * 2 * Math.PI;
|
||||
|
||||
private angle = this.startAngle;
|
||||
private speed = 0;
|
||||
private friction = 0.3;
|
||||
private fired = true;
|
||||
private listeners = new Set<SpinnerListener>();
|
||||
|
||||
public render(ctx: CanvasRenderingContext2D) {
|
||||
ctx.fillStyle = 'white';
|
||||
|
||||
ctx.beginPath();
|
||||
ctx.arc(0.5, 0.5, 0.5, 0, Math.PI * 2);
|
||||
ctx.fill();
|
||||
|
||||
|
||||
ctx.lineCap = 'butt';
|
||||
ctx.fillStyle = 'black';
|
||||
ctx.font = '0.1px Arial';
|
||||
ctx.textAlign = 'center';
|
||||
ctx.textBaseline = 'middle';
|
||||
ctx.lineWidth = 0.2;
|
||||
|
||||
let angle = this.startAngle;
|
||||
for (let i = 0; i < this.probabilities.length; i++) {
|
||||
ctx.strokeStyle = this.colors[i];
|
||||
ctx.beginPath();
|
||||
const nextAngle = angle + this.probabilities[i] * 2 * Math.PI;
|
||||
ctx.arc(0.5, 0.5, 0.4, angle, nextAngle);
|
||||
ctx.stroke();
|
||||
|
||||
const center = (angle + nextAngle) / 2;
|
||||
ctx.fillText(`${i + 1}`, 0.5 + Math.cos(center) * 0.4, 0.5 + Math.sin(center) * 0.4);
|
||||
|
||||
angle = nextAngle;
|
||||
}
|
||||
|
||||
ctx.lineCap = 'round';
|
||||
ctx.strokeStyle = 'black';
|
||||
ctx.lineWidth = 0.01;
|
||||
|
||||
angle = this.startAngle;
|
||||
for (let i = 0; i < this.probabilities.length; i++) {
|
||||
const nextAngle = angle + this.probabilities[i] * 2 * Math.PI;
|
||||
|
||||
ctx.beginPath();
|
||||
ctx.moveTo(0.5, 0.5);
|
||||
ctx.lineTo(0.5 + Math.cos(angle) * 0.5, 0.5 + Math.sin(angle) * 0.5)
|
||||
ctx.stroke();
|
||||
|
||||
angle = nextAngle;
|
||||
}
|
||||
|
||||
ctx.lineWidth = 0.02;
|
||||
ctx.beginPath();
|
||||
ctx.arc(0.5, 0.5, 0.5, 0, Math.PI * 2);
|
||||
ctx.moveTo(0.5, 0.5);
|
||||
ctx.lineTo(0.5 + Math.cos(this.angle) * 0.4, 0.5 + Math.sin(this.angle) * 0.4);
|
||||
ctx.stroke();
|
||||
}
|
||||
|
||||
public update(dt: number) {
|
||||
if (this.fired) return;
|
||||
if (this.speed < 0.1) {
|
||||
this.fire();
|
||||
return;
|
||||
}
|
||||
|
||||
this.angle += this.speed * dt;
|
||||
this.speed *= 1.0 - this.friction * dt;
|
||||
this.friction += 0.7 * dt;
|
||||
}
|
||||
|
||||
public spin() {
|
||||
if (!this.fired) return;
|
||||
|
||||
this.fired = false;
|
||||
this.speed = 25 + Math.random() * 25;
|
||||
this.friction = 0.3 + Math.random() * 0.3;
|
||||
}
|
||||
|
||||
public addListener(listener: SpinnerListener) {
|
||||
this.listeners.add(listener);
|
||||
}
|
||||
|
||||
public removeListener(listener: SpinnerListener) {
|
||||
this.listeners.delete(listener);
|
||||
}
|
||||
|
||||
private fire() {
|
||||
if (this.fired) return;
|
||||
this.fired = true;
|
||||
|
||||
let checkAngle = this.angle % (Math.PI * 2);
|
||||
|
||||
for (let a = 0; a < 2; a++) {
|
||||
let angle = (this.startAngle + Math.PI * 2) % (Math.PI * 2);
|
||||
for (let i = 0; i < this.probabilities.length; i++) {
|
||||
const nextAngle = angle + this.probabilities[i] * 2 * Math.PI;
|
||||
|
||||
if (angle <= checkAngle && checkAngle <= nextAngle) {
|
||||
this.listeners.forEach(l => l(i + 1));
|
||||
return;
|
||||
}
|
||||
|
||||
angle = nextAngle;
|
||||
}
|
||||
checkAngle += Math.PI * 2;
|
||||
}
|
||||
}
|
||||
}
|
||||
Loading…
Reference in New Issue