feat(#8): modularizing

This commit is contained in:
Juan Sebastián Montoya 2024-09-13 21:45:59 -05:00
parent f300fe1be7
commit 32dd2ad599
11 changed files with 271 additions and 94 deletions

5
modules/constants.js Normal file
View file

@ -0,0 +1,5 @@
export const TILE_SIZE = 16;
export const GAME_WIDTH = 320;
export const GAME_HEIGHT = 240;
export const COLS = GAME_WIDTH / TILE_SIZE;
export const ROWS = GAME_HEIGHT / TILE_SIZE;

View file

@ -0,0 +1,12 @@
import { GameObject } from "./game-object.js";
export class Camera extends GameObject {
constructor({ map, x = 0, y = 0, width = 320, height = 240 }) {
super({ x, y });
this.map = map;
this.x = x;
this.y = y;
this.width = width;
this.height = height;
}
}

View file

@ -1,4 +1,6 @@
export class CanvasResizer {
import { GameObject } from "./game-object.js";
export class CanvasResizer extends GameObject {
/**
* Creates a new instance of `CanvasResizer` class.
* @param {Object} config - The configuration options for the class.
@ -8,6 +10,7 @@ export class CanvasResizer {
* @param {number} config.percentage - The percentage of the screen size to use for the canvas.
*/
constructor({ canvas, width, height, percentage }) {
super();
this.canvas = canvas;
this.width = width;
this.height = height;
@ -18,12 +21,16 @@ export class CanvasResizer {
}
load() {
if (this.loaded) {
return;
}
return new Promise((resolve) => {
["load", "resize"].map((item) =>
window.addEventListener(item, () => {
this._resize();
if (item === "load") {
resolve();
this.loaded = true;
}
})
);

View file

@ -0,0 +1,40 @@
import { COLS, ROWS, TILE_SIZE } from "../constants.js";
import { GameObject } from "./game-object.js";
export class Debug extends GameObject {
constructor({ debug = false }) {
super();
this.debug = debug;
this.fps = 0;
}
toggle() {
this.debug = !this.debug;
}
update(delta) {
this.fps = Math.floor(1 / delta);
}
render(ctx) {
if (!this.debug) {
return;
}
for (let row = 0; row < ROWS; row++) {
for (let col = 0; col < COLS; col++) {
ctx.strokeRect(col * TILE_SIZE, row * TILE_SIZE, TILE_SIZE, TILE_SIZE);
}
}
ctx.fillStyle = "Red";
ctx.font = "normal 16pt Arial";
ctx.fillText(this.fps + " fps", 10, 26);
}
onMouseClick(elementId) {
if (elementId === "debug") {
this.toggle();
}
}
}

View file

@ -0,0 +1,50 @@
export class GameObject {
/**
* Initializes a new instance of the GameObject class.
*
* @param {Object} options - An object containing the initial properties of the game object.
* @param {number} [options.x=0] - The initial x-coordinate of the game object.
* @param {number} [options.y=0] - The initial y-coordinate of the game object.
* @param {GameObject[]} [options.gameObjects=[]] - An array of child game objects.
*/
constructor(options = {}) {
const { x = 0, y = 0, gameObjects = [] } = options;
this.x = x;
this.y = y;
this.gameObjects = gameObjects;
}
async load() {
await Promise.all(
this.gameObjects.map((item) => {
item.load();
})
);
}
update(delta) {
this.gameObjects.forEach((item) => {
item.update(delta);
});
}
render(ctx) {
this.gameObjects.forEach((item) => {
item.render(ctx);
});
}
onKeyReleased(key) {
this.gameObjects.forEach((item) => {
item.onKeyReleased(key);
});
}
onMouseClick(elementId) {
this.gameObjects.forEach((item) => {
item.onMouseClick(elementId);
});
}
onCollide() {}
}

View file

@ -0,0 +1,6 @@
export { Camera } from "./camera.js";
export { CanvasResizer } from "./canvas-resizer.js";
export { Debug } from "./debug.js";
export { GameObject } from "./game-object.js";
export { MapManagement } from "./map-management.js";
export { Map } from "./map.js";

View file

@ -0,0 +1,47 @@
import { GameObject } from "./game-object.js";
import { Map } from "./map.js";
export class MapManagement extends GameObject {
constructor({ maps = [] }) {
super();
this.gameObjects = maps.map((item) => new Map(item));
this.elementsId = this.gameObjects.map((item) => item.elementId);
}
get selected() {
return this.gameObjects.find((item) => item.selected);
}
set selected(name) {
this.gameObjects.forEach((item) => {
item.selected = item.name === name;
});
}
update(delta) {
this.gameObjects.forEach((item) => {
if (item.selected) {
item.update(delta);
}
});
}
render(ctx) {
this.gameObjects.forEach((item) => {
if (item.selected) {
item.render(ctx);
}
});
}
onMouseClick(elementId) {
if (
!this.elementsId.includes(elementId) ||
this.selected.elementId === elementId
) {
return;
}
const map = this.gameObjects.find((item) => item.elementId === elementId);
this.selected = map.name;
}
}

View file

@ -0,0 +1,46 @@
import { COLS, ROWS, TILE_SIZE } from "../constants.js";
import { GameObject } from "./game-object.js";
export class Map extends GameObject {
constructor({ name, imageId, elementId, selected = false }) {
super();
this.name = name;
this.imageId = imageId;
this.image = document.getElementById(imageId);
this.selected = selected;
this.elementId = elementId;
}
async load() {
const level = await fetch("/resources/" + this.name + ".json");
this.level = await level.json();
return true;
}
render(ctx) {
if (!this.level) {
return;
}
const levelImage = this.image;
const level = this.level;
const layer = level.layers[0];
const data = layer.data;
for (let row = 0; row < ROWS; row++) {
for (let col = 0; col < COLS; col++) {
const tile = data[row * COLS + col] - 1;
ctx.drawImage(
levelImage,
(tile * TILE_SIZE) % levelImage.width,
Math.floor((tile * TILE_SIZE) / levelImage.width) * TILE_SIZE,
TILE_SIZE,
TILE_SIZE,
col * TILE_SIZE,
row * TILE_SIZE,
TILE_SIZE,
TILE_SIZE
);
}
}
}
}

View file

@ -1,4 +0,0 @@
export async function getLevel(name) {
const level = await fetch("/resources/" + name + ".json");
return await level.json();
}