diff --git a/index.js b/index.js index 70bb826..97d31b4 100644 --- a/index.js +++ b/index.js @@ -29,10 +29,11 @@ class Game extends GameObject { height: GAME_HEIGHT, percentage: 0.9, }); - const mapManagement = new MapManagement({ maps: maps }); - const camera = new Camera({ map: mapManagement.selected }); + const camera = new Camera({ + mapManagement: new MapManagement({ maps: maps }), + }); const debug = new Debug({ debug: false }); - this.gameObjects = [canvasResizer, mapManagement, camera, debug]; + this.gameObjects = [canvasResizer, camera, debug]; this.canvas = canvas; this.ctx = this.canvas.getContext("2d"); @@ -42,6 +43,12 @@ class Game extends GameObject { document.getElementById(elementId).addEventListener("click", () => { this.onMouseClick(elementId); }); + document.addEventListener("keydown", (event) => { + this.onKeyPressed(event.key); + }); + document.addEventListener("keyup", (event) => { + this.onKeyReleased(event.key); + }); }); } @@ -59,17 +66,6 @@ class Game extends GameObject { } } -function moveCamera(dx, dy) { - cameraX = Math.min( - Math.max(cameraX + dx, 0), - Math.floor((320 - canvasResizer.width) / TILE_SIZE) - ); - cameraY = Math.min( - Math.max(cameraY + dy, 0), - Math.floor((240 - canvasResizer.height) / TILE_SIZE) - ); -} - async function run() { const game = new Game({ canvas: document.getElementById("game") }); await game.load(); diff --git a/modules/constants.js b/modules/constants.js index 0538b2e..950ec2c 100644 --- a/modules/constants.js +++ b/modules/constants.js @@ -1,5 +1,5 @@ export const TILE_SIZE = 16; -export const GAME_WIDTH = 320; -export const GAME_HEIGHT = 240; +export const GAME_WIDTH = 160; +export const GAME_HEIGHT = 120; export const COLS = GAME_WIDTH / TILE_SIZE; export const ROWS = GAME_HEIGHT / TILE_SIZE; diff --git a/modules/game-objects/camera.js b/modules/game-objects/camera.js index e360dde..24cacb5 100644 --- a/modules/game-objects/camera.js +++ b/modules/game-objects/camera.js @@ -1,12 +1,67 @@ +import { TILE_SIZE } from "../constants.js"; import { GameObject } from "./game-object.js"; +import { MapManagement } from "./map-management.js"; export class Camera extends GameObject { - constructor({ map, x = 0, y = 0, width = 320, height = 240 }) { + constructor({ mapManagement, x = 0, y = 0, width = 160, height = 120 }) { super({ x, y }); - this.map = map; + this.mapManagement = mapManagement; + this.gameObjects = [mapManagement]; this.x = x; this.y = y; this.width = width; this.height = height; + 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 { levelConfig } = this.mapManagement.selected; + const layer = levelConfig.layers[0]; + const { height, width } = layer; + + const floorX = dx > 0 ? Math.floor : Math.ceil; + const floorY = dy > 0 ? Math.floor : Math.ceil; + + this.x = Math.min( + Math.max(this.x + floorX(dx * (delta * 100)), 0), + width * TILE_SIZE - this.width + ); + this.y = Math.min( + Math.max(this.y + floorY(dy * (delta * 100)), 0), + height * TILE_SIZE - this.height + ); } } diff --git a/modules/game-objects/game-object.js b/modules/game-objects/game-object.js index b7ba42b..73d1713 100644 --- a/modules/game-objects/game-object.js +++ b/modules/game-objects/game-object.js @@ -28,9 +28,15 @@ export class GameObject { }); } - render(ctx) { + render(ctx, ...args) { this.gameObjects.forEach((item) => { - item.render(ctx); + item.render(ctx, ...args); + }); + } + + onKeyPressed(key) { + this.gameObjects.forEach((item) => { + item.onKeyPressed(key); }); } diff --git a/modules/game-objects/map.js b/modules/game-objects/map.js index 8fd93d6..c12209e 100644 --- a/modules/game-objects/map.js +++ b/modules/game-objects/map.js @@ -1,4 +1,4 @@ -import { COLS, ROWS, TILE_SIZE } from "../constants.js"; +import { TILE_SIZE } from "../constants.js"; import { createCanvas } from "../utils.js"; import { GameObject } from "./game-object.js"; @@ -22,22 +22,20 @@ export class Map extends GameObject { if (this._level) { return this._level; } + const levelConfig = this.levelConfig; + const layer = levelConfig.layers[0]; + const { data, height, width } = layer; + const { ctx, canvas } = createCanvas(width * TILE_SIZE, height * TILE_SIZE); - const { ctx, canvas } = createCanvas(COLS * TILE_SIZE, ROWS * TILE_SIZE); + for (let row = 0; row < height; row++) { + for (let col = 0; col < width; col++) { + if (row < 0 || col < 0 || row >= height || col >= width) continue; - const image = this.image; - const width = this.width; - const level = this.levelConfig; - 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; + const tile = data[row * width + col] - 1; ctx.drawImage( - image, - (tile * TILE_SIZE) % width, - Math.floor((tile * TILE_SIZE) / width) * TILE_SIZE, + this.image, + (tile * TILE_SIZE) % this.width, + Math.floor((tile * TILE_SIZE) / this.width) * TILE_SIZE, TILE_SIZE, TILE_SIZE, col * TILE_SIZE, @@ -47,13 +45,25 @@ export class Map extends GameObject { ); } } + return (this._level = canvas); } - render(ctx) { + render(ctx, sourceX, sourceY, width, height) { if (!this.levelConfig || !this.selected) { return; } - ctx.drawImage(this.level, 0, 0); + + ctx.drawImage( + this.level, + sourceX, + sourceY, + width, + height, + 0, + 0, + width, + height + ); } }