153 lines
2.9 KiB
TypeScript
153 lines
2.9 KiB
TypeScript
|
|
type Vec2 = [number, number];
|
|
type Rad = number;
|
|
|
|
interface Graphics {
|
|
clear(): void;
|
|
drawCar(pos: Vec2, angle: Rad): void;
|
|
}
|
|
|
|
|
|
class CanvasGraphics implements Graphics {
|
|
private canvas = document.querySelector<HTMLCanvasElement>("#canvas")!;
|
|
private ctx = this.canvas.getContext("2d")!;
|
|
private alpha = 1;
|
|
private trans: Vec2 = [100, 350];
|
|
|
|
public setup() {
|
|
this.canvas.width = 500;
|
|
this.canvas.height = 500;
|
|
}
|
|
|
|
public clear() {
|
|
this.setFill(100, 170, 255);
|
|
this.fillRect([0, 0], [this.canvas.width, this.canvas.height]);
|
|
|
|
// Draw ground
|
|
this.setFill(50, 155, 50);
|
|
this.fillRect([0, 350], [this.canvas.width, 150]);
|
|
}
|
|
|
|
public drawCar(pos: Vec2, angle: Rad) {
|
|
const [x, y] = pos;
|
|
this.ctx.save();
|
|
this.ctx.translate(...this.trans);
|
|
|
|
|
|
|
|
this.ctx.save();
|
|
this.ctx.translate(60 + x, 0 + y);
|
|
this.ctx.rotate(angle);
|
|
|
|
// Draw car body
|
|
this.setFill(200, 0, 0);
|
|
this.fillRect([-20, -40], [80, 21]);
|
|
this.fillRect([-20, -20], [100, 20]);
|
|
|
|
// Draw rear wheel
|
|
this.setFill(0, 0, 0);
|
|
this.fillCircle([0, 0], 10);
|
|
|
|
// Draw front wheel
|
|
this.fillCircle([60, 0], 10);
|
|
|
|
this.ctx.restore();
|
|
|
|
|
|
this.ctx.restore();
|
|
|
|
}
|
|
|
|
private setFill(red: number, green: number, blue: number): void {
|
|
this.ctx.fillStyle = `rgba(${red}, ${green}, ${blue}, ${this.alpha})`;
|
|
}
|
|
|
|
private fillRect(pos: Vec2, size: Vec2): void {
|
|
const [x, y] = pos;
|
|
const [width, height] = size;
|
|
this.ctx.fillRect(x, y, width, height);
|
|
}
|
|
|
|
private fillCircle(pos: Vec2, radius: number) {
|
|
const [x, y] = pos;
|
|
this.ctx.beginPath();
|
|
this.ctx.arc(x, y, radius, 0, Math.PI * 2);
|
|
this.ctx.fill();
|
|
}
|
|
}
|
|
|
|
interface Entity {
|
|
render(graphics: Graphics): void;
|
|
update(delta: number): void;
|
|
}
|
|
|
|
class Car implements Entity {
|
|
private pos: Vec2 = [0, 0];
|
|
private angle: Rad = 0;
|
|
private speeder = 1.0;
|
|
|
|
public render(graphics: Graphics): void {
|
|
graphics.drawCar(this.pos, this.angle);
|
|
}
|
|
|
|
public update(delta: number): void {
|
|
if (this.angle > Math.PI / -2) {
|
|
this.angle += this.speeder * -0.005 * Math.PI;
|
|
this.pos[0] += this.speeder * delta * 100;
|
|
}
|
|
}
|
|
|
|
public setSpeeder(speeder: number): void {
|
|
this.speeder = speeder;
|
|
}
|
|
|
|
public getAngle(): number {
|
|
return this.angle;
|
|
}
|
|
}
|
|
|
|
class Matrix {
|
|
private entities: Entity[] = []
|
|
private graphics = new CanvasGraphics();
|
|
|
|
public setup() {
|
|
this.graphics.setup();
|
|
}
|
|
|
|
public start() {
|
|
const looped = (before: number) => {
|
|
const now = Date.now();
|
|
const delta = (now - before) / 1000;
|
|
for (const entity of this.entities) {
|
|
entity.update(delta);
|
|
}
|
|
this.graphics.clear();
|
|
for (const entity of this.entities) {
|
|
entity.render(this.graphics);
|
|
}
|
|
requestAnimationFrame(() => looped(now));
|
|
}
|
|
looped(Date.now());
|
|
}
|
|
|
|
public addEntity(entity: Entity) {
|
|
this.entities.push(entity);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
function main() {
|
|
const matricen = new Matrix();
|
|
matricen.setup();
|
|
|
|
const car = new Car();
|
|
matricen.addEntity(car);
|
|
matricen.start();
|
|
}
|
|
|
|
|
|
main();
|
|
|