Reviewed-on: #9
This commit is contained in:
		
						commit
						1cac9b90bc
					
				
					 11 changed files with 368 additions and 105 deletions
				
			
		
							
								
								
									
										163
									
								
								index.js
									
										
									
									
									
								
							
							
						
						
									
										163
									
								
								index.js
									
										
									
									
									
								
							| 
						 | 
					@ -1,111 +1,78 @@
 | 
				
			||||||
import { CanvasResizer } from "./modules/canvas-resizer.js";
 | 
					import { GAME_HEIGHT, GAME_WIDTH } from "./modules/constants.js";
 | 
				
			||||||
import { getLevel } from "./modules/utils.js";
 | 
					import {
 | 
				
			||||||
 | 
					  Camera,
 | 
				
			||||||
 | 
					  CanvasResizer,
 | 
				
			||||||
 | 
					  FpsCounter,
 | 
				
			||||||
 | 
					  GameObject,
 | 
				
			||||||
 | 
					  MapManagement,
 | 
				
			||||||
 | 
					} from "./modules/game-objects/index.js";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const maps = [
 | 
				
			||||||
 | 
					  {
 | 
				
			||||||
 | 
					    name: "overworld",
 | 
				
			||||||
 | 
					    imageId: "overworld",
 | 
				
			||||||
 | 
					    elementId: "level1",
 | 
				
			||||||
 | 
					    selected: true,
 | 
				
			||||||
 | 
					  },
 | 
				
			||||||
 | 
					  { name: "ocean", imageId: "overworld", elementId: "level2" },
 | 
				
			||||||
 | 
					];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const clicableObjects = ["debug", "level1", "level2"];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class Game extends GameObject {
 | 
				
			||||||
 | 
					  constructor({ canvas }) {
 | 
				
			||||||
 | 
					    super();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const TILE_SIZE = 16;
 | 
					 | 
				
			||||||
    const canvasResizer = new CanvasResizer({
 | 
					    const canvasResizer = new CanvasResizer({
 | 
				
			||||||
  canvas: document.getElementById("game"),
 | 
					      canvas: canvas,
 | 
				
			||||||
  width: 320 / 2,
 | 
					      width: GAME_WIDTH,
 | 
				
			||||||
  height: 240 / 2,
 | 
					      height: GAME_HEIGHT,
 | 
				
			||||||
      percentage: 0.9,
 | 
					      percentage: 0.9,
 | 
				
			||||||
    });
 | 
					    });
 | 
				
			||||||
 | 
					    const camera = new Camera({
 | 
				
			||||||
 | 
					      gameObjects: [new MapManagement({ maps: maps })],
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					    const fpsCounter = new FpsCounter({ debug: false });
 | 
				
			||||||
 | 
					    this.gameObjects = [canvasResizer, camera, fpsCounter];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const cols = canvasResizer.width / TILE_SIZE;
 | 
					    this.canvas = canvas;
 | 
				
			||||||
const rows = canvasResizer.height / TILE_SIZE;
 | 
					    this.ctx = this.canvas.getContext("2d");
 | 
				
			||||||
const ctx = canvasResizer.canvas.getContext("2d");
 | 
					    this.lastTime = 0;
 | 
				
			||||||
let debug = false;
 | 
					 | 
				
			||||||
let cameraX = 0;
 | 
					 | 
				
			||||||
let cameraY = 0;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
async function drawLevel({ levelName, imageName }) {
 | 
					 | 
				
			||||||
  const levelImage = document.getElementById(imageName);
 | 
					 | 
				
			||||||
  const level = await getLevel(levelName);
 | 
					 | 
				
			||||||
  const layer = level.layers[0];
 | 
					 | 
				
			||||||
  const { data, width, height } = layer; // Obtenemos la capa del tilemap, con su numero de columnas y filas
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  const endCol = cameraX + cols;
 | 
					 | 
				
			||||||
  const endRow = cameraY + rows;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  for (let row = cameraY; row <= endRow; row++) {
 | 
					 | 
				
			||||||
    for (let col = cameraX; col <= endCol; col++) {
 | 
					 | 
				
			||||||
      if (row < 0 || col < 0 || row >= height || col >= width) continue; // Omitimos tiles fuera del rango del tilemap
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
      if (debug) {
 | 
					 | 
				
			||||||
        ctx.strokeRect(
 | 
					 | 
				
			||||||
          (col - cameraX) * TILE_SIZE,
 | 
					 | 
				
			||||||
          (row - cameraY) * TILE_SIZE,
 | 
					 | 
				
			||||||
          TILE_SIZE,
 | 
					 | 
				
			||||||
          TILE_SIZE
 | 
					 | 
				
			||||||
        );
 | 
					 | 
				
			||||||
      }
 | 
					 | 
				
			||||||
      const tile = data[row * width + col];
 | 
					 | 
				
			||||||
      ctx.drawImage(
 | 
					 | 
				
			||||||
        levelImage,
 | 
					 | 
				
			||||||
        ((tile - 1) * TILE_SIZE) % levelImage.width,
 | 
					 | 
				
			||||||
        Math.floor(((tile - 1) * TILE_SIZE) / levelImage.width) * TILE_SIZE,
 | 
					 | 
				
			||||||
        TILE_SIZE,
 | 
					 | 
				
			||||||
        TILE_SIZE,
 | 
					 | 
				
			||||||
        (col - cameraX) * TILE_SIZE,
 | 
					 | 
				
			||||||
        (row - cameraY) * TILE_SIZE,
 | 
					 | 
				
			||||||
        TILE_SIZE,
 | 
					 | 
				
			||||||
        TILE_SIZE
 | 
					 | 
				
			||||||
      );
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
function moveCamera(dx, dy) {
 | 
					  async load() {
 | 
				
			||||||
  cameraX = Math.min(
 | 
					    await super.load();
 | 
				
			||||||
    Math.max(cameraX + dx, 0),
 | 
					    clicableObjects.forEach((elementId) => {
 | 
				
			||||||
    Math.floor((320 - canvasResizer.width) / TILE_SIZE)
 | 
					      document.getElementById(elementId).addEventListener("click", () => {
 | 
				
			||||||
  );
 | 
					        this.onMouseClick(elementId);
 | 
				
			||||||
  cameraY = Math.min(
 | 
					      });
 | 
				
			||||||
    Math.max(cameraY + dy, 0),
 | 
					    });
 | 
				
			||||||
    Math.floor((240 - canvasResizer.height) / TILE_SIZE)
 | 
					    document.addEventListener("keydown", (event) => {
 | 
				
			||||||
  );
 | 
					      this.onKeyPressed(event.key);
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					    document.addEventListener("keyup", (event) => {
 | 
				
			||||||
 | 
					      this.onKeyReleased(event.key);
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  clear(ctx) {
 | 
				
			||||||
 | 
					    ctx.clearRect(0, 0, this.canvas.width, this.canvas.height);
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  loop(time) {
 | 
				
			||||||
 | 
					    const delta = (time - this.lastTime) / 1000;
 | 
				
			||||||
 | 
					    this.lastTime = time;
 | 
				
			||||||
 | 
					    this.update(delta);
 | 
				
			||||||
 | 
					    this.clear(this.ctx);
 | 
				
			||||||
 | 
					    this.render(this.ctx);
 | 
				
			||||||
 | 
					    requestAnimationFrame(this.loop.bind(this));
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
async function run() {
 | 
					async function run() {
 | 
				
			||||||
  await canvasResizer.load();
 | 
					  const game = new Game({ canvas: document.getElementById("game") });
 | 
				
			||||||
 | 
					  await game.load();
 | 
				
			||||||
  let selectedLevel = { levelName: "overworld", imageName: "overworld" };
 | 
					  game.loop(0);
 | 
				
			||||||
 | 
					 | 
				
			||||||
  const debugButton = document.getElementById("debug");
 | 
					 | 
				
			||||||
  debugButton.addEventListener("click", async () => {
 | 
					 | 
				
			||||||
    debug = !debug;
 | 
					 | 
				
			||||||
    await drawLevel(selectedLevel);
 | 
					 | 
				
			||||||
  });
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  const level1Button = document.getElementById("level1");
 | 
					 | 
				
			||||||
  level1Button.addEventListener("click", async () => {
 | 
					 | 
				
			||||||
    selectedLevel = { levelName: "overworld", imageName: "overworld" };
 | 
					 | 
				
			||||||
    await drawLevel(selectedLevel);
 | 
					 | 
				
			||||||
  });
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  const level2Button = document.getElementById("level2");
 | 
					 | 
				
			||||||
  level2Button.addEventListener("click", async () => {
 | 
					 | 
				
			||||||
    selectedLevel = { levelName: "ocean", imageName: "overworld" };
 | 
					 | 
				
			||||||
    await drawLevel(selectedLevel);
 | 
					 | 
				
			||||||
  });
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  window.addEventListener("keydown", (event) => {
 | 
					 | 
				
			||||||
    switch (event.key) {
 | 
					 | 
				
			||||||
      case "ArrowUp":
 | 
					 | 
				
			||||||
        moveCamera(0, -1);
 | 
					 | 
				
			||||||
        break;
 | 
					 | 
				
			||||||
      case "ArrowDown":
 | 
					 | 
				
			||||||
        moveCamera(0, 1);
 | 
					 | 
				
			||||||
        break;
 | 
					 | 
				
			||||||
      case "ArrowLeft":
 | 
					 | 
				
			||||||
        moveCamera(-1, 0);
 | 
					 | 
				
			||||||
        break;
 | 
					 | 
				
			||||||
      case "ArrowRight":
 | 
					 | 
				
			||||||
        moveCamera(1, 0);
 | 
					 | 
				
			||||||
        break;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    drawLevel(selectedLevel);
 | 
					 | 
				
			||||||
  });
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  await drawLevel(selectedLevel);
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
run();
 | 
					run();
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										5
									
								
								modules/constants.js
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										5
									
								
								modules/constants.js
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,5 @@
 | 
				
			||||||
 | 
					export const TILE_SIZE = 16;
 | 
				
			||||||
 | 
					export const GAME_WIDTH = 160;
 | 
				
			||||||
 | 
					export const GAME_HEIGHT = 120;
 | 
				
			||||||
 | 
					export const COLS = GAME_WIDTH / TILE_SIZE;
 | 
				
			||||||
 | 
					export const ROWS = GAME_HEIGHT / TILE_SIZE;
 | 
				
			||||||
							
								
								
									
										68
									
								
								modules/game-objects/camera.js
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										68
									
								
								modules/game-objects/camera.js
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,68 @@
 | 
				
			||||||
 | 
					import { TILE_SIZE } from "../constants.js";
 | 
				
			||||||
 | 
					import { GameObject } from "./game-object.js";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export class Camera extends GameObject {
 | 
				
			||||||
 | 
					  constructor({
 | 
				
			||||||
 | 
					    gameObjects = [],
 | 
				
			||||||
 | 
					    x = 0,
 | 
				
			||||||
 | 
					    y = 0,
 | 
				
			||||||
 | 
					    width = 160,
 | 
				
			||||||
 | 
					    height = 120,
 | 
				
			||||||
 | 
					    speed = 1,
 | 
				
			||||||
 | 
					  }) {
 | 
				
			||||||
 | 
					    super({ x, y });
 | 
				
			||||||
 | 
					    this.gameObjects = gameObjects;
 | 
				
			||||||
 | 
					    this.x = x;
 | 
				
			||||||
 | 
					    this.y = y;
 | 
				
			||||||
 | 
					    this.width = width;
 | 
				
			||||||
 | 
					    this.height = height;
 | 
				
			||||||
 | 
					    this.speed = speed;
 | 
				
			||||||
 | 
					    this.keys = [
 | 
				
			||||||
 | 
					      { key: "ArrowUp", pressed: false, value: [0, -1] },
 | 
				
			||||||
 | 
					      { key: "ArrowDown", pressed: false, value: [0, 1] },
 | 
				
			||||||
 | 
					      { key: "ArrowLeft", pressed: false, value: [-1, 0] },
 | 
				
			||||||
 | 
					      { key: "ArrowRight", pressed: false, value: [1, 0] },
 | 
				
			||||||
 | 
					    ];
 | 
				
			||||||
 | 
					    this.availableKeys = this.keys.reduce(
 | 
				
			||||||
 | 
					      (acc, item) => ({ ...acc, [item.key]: item }),
 | 
				
			||||||
 | 
					      {}
 | 
				
			||||||
 | 
					    );
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  update(delta) {
 | 
				
			||||||
 | 
					    this.keys.forEach((item) => {
 | 
				
			||||||
 | 
					      if (item.pressed) {
 | 
				
			||||||
 | 
					        this.moveCamera(...item.value, delta);
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  onKeyPressed(key) {
 | 
				
			||||||
 | 
					    if (!this.availableKeys[key]) return;
 | 
				
			||||||
 | 
					    this.availableKeys[key].pressed = true;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  onKeyReleased(key) {
 | 
				
			||||||
 | 
					    if (!this.availableKeys[key]) return;
 | 
				
			||||||
 | 
					    this.availableKeys[key].pressed = false;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  render(ctx) {
 | 
				
			||||||
 | 
					    this.gameObjects.forEach((item) =>
 | 
				
			||||||
 | 
					      item.render(ctx, this.x, this.y, this.width, this.height)
 | 
				
			||||||
 | 
					    );
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  moveCamera(dx, dy, delta) {
 | 
				
			||||||
 | 
					    const [item] = this.gameObjects;
 | 
				
			||||||
 | 
					    const { height, width } = item.selected ?? item;
 | 
				
			||||||
 | 
					    this.x = Math.min(
 | 
				
			||||||
 | 
					      Math.max(this.x + dx * Math.floor(delta * this.speed * 100), 0),
 | 
				
			||||||
 | 
					      width * TILE_SIZE - this.width
 | 
				
			||||||
 | 
					    );
 | 
				
			||||||
 | 
					    this.y = Math.min(
 | 
				
			||||||
 | 
					      Math.max(this.y + dy * Math.floor(delta * this.speed * 100), 0),
 | 
				
			||||||
 | 
					      height * TILE_SIZE - this.height
 | 
				
			||||||
 | 
					    );
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -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.
 | 
					   * Creates a new instance of `CanvasResizer` class.
 | 
				
			||||||
   * @param {Object} config - The configuration options for the 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.
 | 
					   * @param {number} config.percentage - The percentage of the screen size to use for the canvas.
 | 
				
			||||||
   */
 | 
					   */
 | 
				
			||||||
  constructor({ canvas, width, height, percentage }) {
 | 
					  constructor({ canvas, width, height, percentage }) {
 | 
				
			||||||
 | 
					    super();
 | 
				
			||||||
    this.canvas = canvas;
 | 
					    this.canvas = canvas;
 | 
				
			||||||
    this.width = width;
 | 
					    this.width = width;
 | 
				
			||||||
    this.height = height;
 | 
					    this.height = height;
 | 
				
			||||||
| 
						 | 
					@ -18,12 +21,16 @@ export class CanvasResizer {
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  load() {
 | 
					  load() {
 | 
				
			||||||
 | 
					    if (this.loaded) {
 | 
				
			||||||
 | 
					      return;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
    return new Promise((resolve) => {
 | 
					    return new Promise((resolve) => {
 | 
				
			||||||
      ["load", "resize"].map((item) =>
 | 
					      ["load", "resize"].map((item) =>
 | 
				
			||||||
        window.addEventListener(item, () => {
 | 
					        window.addEventListener(item, () => {
 | 
				
			||||||
          this._resize();
 | 
					          this._resize();
 | 
				
			||||||
          if (item === "load") {
 | 
					          if (item === "load") {
 | 
				
			||||||
            resolve();
 | 
					            resolve();
 | 
				
			||||||
 | 
					            this.loaded = true;
 | 
				
			||||||
          }
 | 
					          }
 | 
				
			||||||
        })
 | 
					        })
 | 
				
			||||||
      );
 | 
					      );
 | 
				
			||||||
							
								
								
									
										21
									
								
								modules/game-objects/fps-counter.js
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										21
									
								
								modules/game-objects/fps-counter.js
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,21 @@
 | 
				
			||||||
 | 
					import { GameObject } from "./game-object.js";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export class FpsCounter extends GameObject {
 | 
				
			||||||
 | 
					  constructor({ debug = false }) {
 | 
				
			||||||
 | 
					    super({ debug });
 | 
				
			||||||
 | 
					    this.fps = 0;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  update(delta) {
 | 
				
			||||||
 | 
					    this.fps = Math.floor(1 / delta);
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  render(ctx) {
 | 
				
			||||||
 | 
					    if (!this.debug) {
 | 
				
			||||||
 | 
					      return;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    ctx.fillStyle = "Red";
 | 
				
			||||||
 | 
					    ctx.font = "normal 12pt Arial";
 | 
				
			||||||
 | 
					    ctx.fillText(this.fps + " fps", 5, 15);
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										61
									
								
								modules/game-objects/game-object.js
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										61
									
								
								modules/game-objects/game-object.js
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,61 @@
 | 
				
			||||||
 | 
					export class GameObject {
 | 
				
			||||||
 | 
					  constructor(options = {}) {
 | 
				
			||||||
 | 
					    const {
 | 
				
			||||||
 | 
					      x = 0,
 | 
				
			||||||
 | 
					      y = 0,
 | 
				
			||||||
 | 
					      width = 0,
 | 
				
			||||||
 | 
					      height = 0,
 | 
				
			||||||
 | 
					      debug = false,
 | 
				
			||||||
 | 
					      gameObjects = [],
 | 
				
			||||||
 | 
					    } = options;
 | 
				
			||||||
 | 
					    this.x = x;
 | 
				
			||||||
 | 
					    this.y = y;
 | 
				
			||||||
 | 
					    this.width = width;
 | 
				
			||||||
 | 
					    this.height = height;
 | 
				
			||||||
 | 
					    this.gameObjects = gameObjects;
 | 
				
			||||||
 | 
					    this.debug = debug;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  async load() {
 | 
				
			||||||
 | 
					    await Promise.all(
 | 
				
			||||||
 | 
					      this.gameObjects.map((item) => {
 | 
				
			||||||
 | 
					        item.load();
 | 
				
			||||||
 | 
					      })
 | 
				
			||||||
 | 
					    );
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  update(delta) {
 | 
				
			||||||
 | 
					    this.gameObjects.forEach((item) => {
 | 
				
			||||||
 | 
					      item.update(delta);
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  render(ctx, ...args) {
 | 
				
			||||||
 | 
					    this.gameObjects.forEach((item) => {
 | 
				
			||||||
 | 
					      item.render(ctx, ...args);
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  onKeyPressed(key) {
 | 
				
			||||||
 | 
					    this.gameObjects.forEach((item) => {
 | 
				
			||||||
 | 
					      item.onKeyPressed(key);
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  onKeyReleased(key) {
 | 
				
			||||||
 | 
					    this.gameObjects.forEach((item) => {
 | 
				
			||||||
 | 
					      item.onKeyReleased(key);
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  onMouseClick(elementId) {
 | 
				
			||||||
 | 
					    if (elementId === "debug") {
 | 
				
			||||||
 | 
					      this.debug = !this.debug;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    this.gameObjects.forEach((item) => {
 | 
				
			||||||
 | 
					      item.onMouseClick(elementId);
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  onCollide() {}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										6
									
								
								modules/game-objects/index.js
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										6
									
								
								modules/game-objects/index.js
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,6 @@
 | 
				
			||||||
 | 
					export { Camera } from "./camera.js";
 | 
				
			||||||
 | 
					export { CanvasResizer } from "./canvas-resizer.js";
 | 
				
			||||||
 | 
					export { FpsCounter } from "./fps-counter.js";
 | 
				
			||||||
 | 
					export { GameObject } from "./game-object.js";
 | 
				
			||||||
 | 
					export { MapManagement } from "./map-management.js";
 | 
				
			||||||
 | 
					export { Map } from "./map.js";
 | 
				
			||||||
							
								
								
									
										32
									
								
								modules/game-objects/map-management.js
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										32
									
								
								modules/game-objects/map-management.js
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,32 @@
 | 
				
			||||||
 | 
					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;
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  onMouseClick(elementId) {
 | 
				
			||||||
 | 
					    super.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;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										93
									
								
								modules/game-objects/map.js
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										93
									
								
								modules/game-objects/map.js
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,93 @@
 | 
				
			||||||
 | 
					import { TILE_SIZE } from "../constants.js";
 | 
				
			||||||
 | 
					import { createCanvas } from "../utils.js";
 | 
				
			||||||
 | 
					import { GameObject } from "./game-object.js";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export class Map extends GameObject {
 | 
				
			||||||
 | 
					  constructor({ name, imageId, elementId, selected = false, debug = false }) {
 | 
				
			||||||
 | 
					    super({ debug });
 | 
				
			||||||
 | 
					    this.name = name;
 | 
				
			||||||
 | 
					    this.imageId = imageId;
 | 
				
			||||||
 | 
					    this.image = document.getElementById(imageId);
 | 
				
			||||||
 | 
					    this.imageWidth = this.image.width;
 | 
				
			||||||
 | 
					    this.imageHeight = this.image.height;
 | 
				
			||||||
 | 
					    this.selected = selected;
 | 
				
			||||||
 | 
					    this.elementId = elementId;
 | 
				
			||||||
 | 
					    this.debug = debug;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  async load() {
 | 
				
			||||||
 | 
					    const levelConfig = await fetch("/resources/" + this.name + ".json");
 | 
				
			||||||
 | 
					    this.levelConfig = await levelConfig.json();
 | 
				
			||||||
 | 
					    const layer = this.levelConfig.layers[0];
 | 
				
			||||||
 | 
					    const { data, height, width } = layer;
 | 
				
			||||||
 | 
					    this.width = width;
 | 
				
			||||||
 | 
					    this.height = height;
 | 
				
			||||||
 | 
					    this.data = data;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  get level() {
 | 
				
			||||||
 | 
					    if (this._level) {
 | 
				
			||||||
 | 
					      return this._level;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    const { ctx, canvas } = createCanvas(
 | 
				
			||||||
 | 
					      this.width * TILE_SIZE,
 | 
				
			||||||
 | 
					      this.height * TILE_SIZE
 | 
				
			||||||
 | 
					    );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    for (let row = 0; row < this.height; row++) {
 | 
				
			||||||
 | 
					      for (let col = 0; col < this.width; col++) {
 | 
				
			||||||
 | 
					        if (row < 0 || col < 0 || row >= this.height || col >= this.width)
 | 
				
			||||||
 | 
					          continue;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if (this.debug) {
 | 
				
			||||||
 | 
					          ctx.strokeRect(
 | 
				
			||||||
 | 
					            col * TILE_SIZE,
 | 
				
			||||||
 | 
					            row * TILE_SIZE,
 | 
				
			||||||
 | 
					            TILE_SIZE,
 | 
				
			||||||
 | 
					            TILE_SIZE
 | 
				
			||||||
 | 
					          );
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        const tile = this.data[row * this.width + col] - 1;
 | 
				
			||||||
 | 
					        ctx.drawImage(
 | 
				
			||||||
 | 
					          this.image,
 | 
				
			||||||
 | 
					          (tile * TILE_SIZE) % this.imageWidth,
 | 
				
			||||||
 | 
					          Math.floor((tile * TILE_SIZE) / this.imageWidth) * TILE_SIZE,
 | 
				
			||||||
 | 
					          TILE_SIZE,
 | 
				
			||||||
 | 
					          TILE_SIZE,
 | 
				
			||||||
 | 
					          col * TILE_SIZE,
 | 
				
			||||||
 | 
					          row * TILE_SIZE,
 | 
				
			||||||
 | 
					          TILE_SIZE,
 | 
				
			||||||
 | 
					          TILE_SIZE
 | 
				
			||||||
 | 
					        );
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return (this._level = canvas);
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  onMouseClick(elementId) {
 | 
				
			||||||
 | 
					    if (elementId === "debug") {
 | 
				
			||||||
 | 
					      this.debug = !this.debug;
 | 
				
			||||||
 | 
					      this._level = null;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  render(ctx, sourceX, sourceY, width, height) {
 | 
				
			||||||
 | 
					    if (!this.levelConfig || !this.selected) {
 | 
				
			||||||
 | 
					      return;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    ctx.drawImage(
 | 
				
			||||||
 | 
					      this.level,
 | 
				
			||||||
 | 
					      sourceX,
 | 
				
			||||||
 | 
					      sourceY,
 | 
				
			||||||
 | 
					      width,
 | 
				
			||||||
 | 
					      height,
 | 
				
			||||||
 | 
					      0,
 | 
				
			||||||
 | 
					      0,
 | 
				
			||||||
 | 
					      width,
 | 
				
			||||||
 | 
					      height
 | 
				
			||||||
 | 
					    );
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -1,4 +1,7 @@
 | 
				
			||||||
export async function getLevel(name) {
 | 
					export function createCanvas(width, height) {
 | 
				
			||||||
  const level = await fetch("/resources/" + name + ".json");
 | 
					  const canvas = document.createElement("canvas");
 | 
				
			||||||
  return await level.json();
 | 
					  canvas.width = width;
 | 
				
			||||||
 | 
					  canvas.height = height;
 | 
				
			||||||
 | 
					  const ctx = canvas.getContext("2d");
 | 
				
			||||||
 | 
					  return { ctx, canvas };
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -3,7 +3,7 @@
 | 
				
			||||||
  "version": "1.0.0",
 | 
					  "version": "1.0.0",
 | 
				
			||||||
  "main": "src/index.js",
 | 
					  "main": "src/index.js",
 | 
				
			||||||
  "scripts": {
 | 
					  "scripts": {
 | 
				
			||||||
    "start": "serve ."
 | 
					    "start": "serve . -n"
 | 
				
			||||||
  },
 | 
					  },
 | 
				
			||||||
  "repository": "git@git.jusemon.com:jusemon/evolver.git",
 | 
					  "repository": "git@git.jusemon.com:jusemon/evolver.git",
 | 
				
			||||||
  "author": "Jusemon <juansmm@outlook.com>",
 | 
					  "author": "Jusemon <juansmm@outlook.com>",
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue