init
This commit is contained in:
@@ -0,0 +1,36 @@
|
||||
import { loadImage } from "#/lib/loadImage.ts";
|
||||
import { createSprite, type Sprite } from "#/lib/Sprite.ts";
|
||||
import { createVector, type Vector } from "#/lib/Vector.ts";
|
||||
|
||||
export type Entity = {
|
||||
id: string;
|
||||
src: string;
|
||||
width: number;
|
||||
height: number;
|
||||
};
|
||||
|
||||
export type EntityInstance = {
|
||||
position: Vector;
|
||||
width: number;
|
||||
height: number;
|
||||
sprite: Sprite;
|
||||
};
|
||||
|
||||
export function createEntity(
|
||||
id: string,
|
||||
src: string,
|
||||
width: number = 16,
|
||||
height: number = 16,
|
||||
): Entity {
|
||||
return { id, width, height, src };
|
||||
}
|
||||
|
||||
export async function loadEntity(name: string): Promise<EntityInstance> {
|
||||
const entity = (await import(`#/entities/${name}/index.ts`)).default;
|
||||
|
||||
const { width, height } = entity;
|
||||
const sprite = createSprite(await loadImage(entity.src), 2, 4);
|
||||
const position = createVector();
|
||||
|
||||
return { position, width, height, sprite };
|
||||
}
|
||||
@@ -0,0 +1,62 @@
|
||||
export type SceneData = {
|
||||
id: string;
|
||||
width: number;
|
||||
height: number;
|
||||
entities: string[];
|
||||
};
|
||||
|
||||
export type Scene = {
|
||||
data: SceneData;
|
||||
process: Process;
|
||||
};
|
||||
|
||||
export type Process = (ctx: CanvasRenderingContext2D, delta: number) => void;
|
||||
|
||||
export type SceneChangeCallback = (from: Scene, to: Scene) => void;
|
||||
|
||||
let sceneChangeCallback: SceneChangeCallback = (): void => {};
|
||||
|
||||
const sceneDataMap = new Map<string, SceneData>();
|
||||
const sceneProcessMap = new Map<string, Process>();
|
||||
|
||||
export const currentScene: Scene = {
|
||||
data: {
|
||||
id: "",
|
||||
width: 0,
|
||||
height: 0,
|
||||
entities: [],
|
||||
},
|
||||
process: () => {},
|
||||
};
|
||||
|
||||
export function useScene(data: SceneData): {
|
||||
process: (fn: Process) => void;
|
||||
} {
|
||||
sceneDataMap.set(data.id, data);
|
||||
|
||||
return {
|
||||
process(fn: Process): void {
|
||||
sceneProcessMap.set(data.id, fn);
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
export function setSceneChangeCallback(callback: SceneChangeCallback) {
|
||||
sceneChangeCallback = callback;
|
||||
}
|
||||
|
||||
export function changeScene(scene: Scene): void {
|
||||
sceneChangeCallback(currentScene, scene);
|
||||
currentScene.data = scene.data;
|
||||
currentScene.process = scene.process;
|
||||
}
|
||||
|
||||
export async function loadScene(name: string): Promise<void> {
|
||||
await import(`#/scenes/${name}/index.ts`);
|
||||
|
||||
const data = sceneDataMap.get(name)!;
|
||||
currentScene.data = data;
|
||||
|
||||
const process = sceneProcessMap.get(name)!;
|
||||
currentScene.process = process;
|
||||
}
|
||||
@@ -0,0 +1,86 @@
|
||||
import { createVector, type Vector } from "#/lib/Vector.ts";
|
||||
|
||||
export type Viewport = {
|
||||
initialScale: number;
|
||||
imageSmoothing: CanvasImageSmoothing;
|
||||
translation: Vector;
|
||||
ctx: CanvasRenderingContext2D;
|
||||
canvas: HTMLCanvasElement;
|
||||
gameContainer: HTMLElement;
|
||||
canvasContainer: HTMLElement;
|
||||
};
|
||||
|
||||
export const viewport: Viewport = {
|
||||
initialScale: 4,
|
||||
imageSmoothing: {
|
||||
imageSmoothingEnabled: false,
|
||||
imageSmoothingQuality: "low",
|
||||
},
|
||||
translation: createVector(),
|
||||
ctx: null as unknown as CanvasRenderingContext2D,
|
||||
canvas: null as unknown as HTMLCanvasElement,
|
||||
gameContainer: null as unknown as HTMLElement,
|
||||
canvasContainer: null as unknown as HTMLElement,
|
||||
};
|
||||
|
||||
export function initViewport(): void {
|
||||
const gameContainer = document.createElement("div");
|
||||
gameContainer.id = "gameContainer";
|
||||
|
||||
const canvasContainer = document.createElement("div");
|
||||
canvasContainer.id = "canvasContainer";
|
||||
|
||||
const canvas = document.createElement("canvas");
|
||||
viewport.ctx = canvas.getContext("2d", {
|
||||
alpha: false,
|
||||
}) as CanvasRenderingContext2D;
|
||||
|
||||
viewport.canvas = canvas;
|
||||
viewport.canvasContainer = canvasContainer;
|
||||
viewport.gameContainer = gameContainer;
|
||||
|
||||
canvasContainer.appendChild(canvas);
|
||||
gameContainer.appendChild(canvasContainer);
|
||||
document.body.appendChild(gameContainer);
|
||||
}
|
||||
|
||||
export function setScale(scale: number): void {
|
||||
viewport.initialScale = scale;
|
||||
self.dispatchEvent(new Event("resize"));
|
||||
}
|
||||
|
||||
export function resizeCanvas(width: number, height: number): void {
|
||||
const {
|
||||
initialScale,
|
||||
imageSmoothing,
|
||||
ctx,
|
||||
canvas,
|
||||
canvasContainer,
|
||||
gameContainer,
|
||||
} = viewport;
|
||||
|
||||
const containerWidth = (gameContainer.offsetWidth / initialScale) | 0;
|
||||
const containerHeight = (gameContainer.offsetHeight / initialScale) | 0;
|
||||
|
||||
canvas.width = Math.min(width, containerWidth);
|
||||
canvas.height = Math.min(height, containerHeight);
|
||||
|
||||
ctx.imageSmoothingEnabled = imageSmoothing.imageSmoothingEnabled;
|
||||
ctx.imageSmoothingQuality = imageSmoothing.imageSmoothingQuality;
|
||||
|
||||
const canvasWidth =
|
||||
canvas.width * initialScale - (containerWidth % initialScale);
|
||||
const canvasHeight =
|
||||
canvas.height * initialScale - (containerHeight % initialScale);
|
||||
|
||||
canvasContainer.style = `width: ${canvasWidth}px; height: ${canvasHeight}px;`;
|
||||
}
|
||||
|
||||
export function resetCtx() {
|
||||
const { ctx, canvas, translation } = viewport;
|
||||
|
||||
ctx.restore();
|
||||
ctx.clearRect(0, 0, canvas.width, canvas.height);
|
||||
ctx.save();
|
||||
ctx.translate(-(translation.x | 0), -(translation.y | 0));
|
||||
}
|
||||
Reference in New Issue
Block a user