import {Game} from "./Game.js"; export class Tile { /** * A tile of the game grid * @param {int} x * @param {int} y * @param {tiles} type * @param {Game} game */ constructor(x, y, type = tiles.EMPTY, game) { if (typeof x === "number" && x >= 0 && x % 1 === 0) this.x = x; else throw new InvalidTileOption("x"); if (typeof y === "number" && y >= 0 && y % 1 === 0) this.y = y; else throw new InvalidTileOption("y"); if (type && Object.values(tiles).find(t => t === type)) this.type = type; else throw new InvalidTileOption("type"); if (game && game instanceof Game) this.game = game; else throw new InvalidTileOption("game"); } /** * Draw the tile on the grid */ draw() { const canvasPos = this.getCanvasPos(), size = this.getSize(); this.game.ctx.beginPath(); this.game.ctx.globalCompositeOperation = "destination-out"; this.game.ctx.fillRect(...canvasPos, ...size); this.game.ctx.globalCompositeOperation = "source-over"; switch (this.type) { case tiles.EMPTY: this.game.ctx.strokeStyle = "#999999"; this.game.ctx.rect(...canvasPos, ...size); break; case tiles.APPLE: let pxsize = Math.round(size[0]/12); if (!pxsize) { this.game.ctx.fillStyle = "#ff0000"; this.game.ctx.fillRect(...canvasPos, ...size); } else { let width = canvasPos[0]; let height = canvasPos[1]; this.game.ctx.fillStyle = "#00ffff"; this.game.ctx.fillRect(width+pxsize, height+pxsize, 10*pxsize, 10*pxsize); this.game.ctx.fillStyle = "#000000"; this.game.ctx.fillRect(width+4*pxsize, height, pxsize*4, pxsize); this.game.ctx.fillRect(width+4*pxsize, height+11*pxsize, pxsize*4, pxsize); for (const i of [2,5,8]) this.game.ctx.fillRect(width+i*pxsize, height+pxsize, pxsize*2, pxsize); for (const i of [1,4,7,10]) this.game.ctx.fillRect(width+i*pxsize, height+2*pxsize, pxsize, pxsize*2); this.game.ctx.fillRect(width, height+4*pxsize, pxsize, pxsize*4); this.game.ctx.fillRect(width+11*pxsize, height+4*pxsize, pxsize, pxsize*4); for (const i of [1,5,6,10]) this.game.ctx.fillRect(width+i*pxsize, height+8*pxsize, pxsize, pxsize*2); for (const i of [2,5,8]) this.game.ctx.fillRect(width+i*pxsize, height+10*pxsize, pxsize*2, pxsize); for (const i of [3,8,2,9]) this.game.ctx.fillRect(width+i*pxsize, height+4*pxsize, pxsize, pxsize); for (const i of [1,3,8,10]) this.game.ctx.fillRect(width+i*pxsize, height+6*pxsize, pxsize, pxsize); for (const i of [4,7]) this.game.ctx.fillRect(width+i*pxsize, height+7*pxsize, pxsize, pxsize); this.game.ctx.globalCompositeOperation = "destination-out"; this.game.ctx.fillRect(width+1*pxsize, height+1*pxsize, pxsize, pxsize); this.game.ctx.fillRect(width+10*pxsize, height+1*pxsize, pxsize, pxsize); this.game.ctx.fillRect(width+1*pxsize, height+10*pxsize, pxsize, pxsize); this.game.ctx.fillRect(width+10*pxsize, height+10*pxsize, pxsize, pxsize); this.game.ctx.globalCompositeOperation = "source-over"; } break; case tiles.SNAKE: this.game.ctx.fillStyle = "#00ff5f"; this.game.ctx.fillRect(...canvasPos, ...size); break; } this.game.ctx.stroke(); } /** * Get the tile position on the canvas * @returns {[int, int]} */ getCanvasPos() { return [this.getSize()[0]*this.x, this.getSize()[1]*this.y] } /** * Get the tile size on the canvas * @returns {[int, int]} */ getSize() { const s = Math.min(Math.round(this.game.ctx.canvas.width/this.game.size[0]), Math.round(this.game.ctx.canvas.height/this.game.size[1])); return [s, s] } } export class InvalidTileOption extends Error { /** * @param {string} name */ constructor(name) { super(`Invalid Tile option: ${name}`); } } export const tiles = { EMPTY: "empty", APPLE: "apple", SNAKE: "snake" };