1
0
Fork 0
This repository has been archived on 2024-02-17. You can view files and clone it, but cannot push or open issues or pull requests.
Snake/sources/js/Tile.js
2021-03-30 09:20:03 +02:00

274 lines
11 KiB
JavaScript

import {Game} from "./Game.js";
import {directions} from "./Snake.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";
const pxsize = Math.round(size[0]/12);
const width = canvasPos[0];
const height = canvasPos[1];
switch (this.type) {
case tiles.EMPTY:
this.game.ctx.strokeStyle = "#999999";
this.game.ctx.rect(...canvasPos, ...size);
break;
case tiles.APPLE:
if (!pxsize) {
this.game.ctx.fillStyle = "#ff0000";
this.game.ctx.fillRect(...canvasPos, ...size);
} else {
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";
for (const [i,j] of [[1,1],[10,1],[1,10],[10,10]])
this.game.ctx.fillRect(width+i*pxsize, height+j*pxsize, pxsize, pxsize);
this.game.ctx.globalCompositeOperation = "source-over";
}
break;
case tiles.HEAD:
if (!pxsize) {
this.game.ctx.fillStyle = "#00ff5f";
this.game.ctx.fillRect(...canvasPos, ...size);
} else {
this.rotate(canvasPos, size);
this.game.ctx.fillStyle = "#FF4294";
this.game.ctx.fillRect(width + 6 * pxsize, height + pxsize, 6 * pxsize, 10 * pxsize);
this.game.ctx.fillRect(width + 4 * pxsize, height + 2 * pxsize, 6 * pxsize, 8 * pxsize);
this.game.ctx.fillRect(width + 2 * pxsize, height + 3 * pxsize, 6 * pxsize, 6 * pxsize);
this.game.ctx.fillRect(width + pxsize, height + 5 * pxsize, pxsize, 2 * pxsize);
this.game.ctx.fillStyle = "#000000";
this.game.ctx.fillRect(width + 6 * pxsize, height, pxsize * 6, pxsize);
this.game.ctx.fillRect(width + 6 * pxsize, height + 11 * pxsize, pxsize * 6, pxsize);
this.game.ctx.fillRect(width + 4 * pxsize, height + pxsize, pxsize * 2, pxsize);
this.game.ctx.fillRect(width + 4 * pxsize, height + 10 * pxsize, pxsize * 2, pxsize);
this.game.ctx.fillRect(width + 2 * pxsize, height + 2 * pxsize, pxsize * 2, pxsize);
this.game.ctx.fillRect(width + 2 * pxsize, height + 9 * pxsize, pxsize * 2, pxsize);
this.game.ctx.fillRect(width + pxsize, height + 7 * pxsize, pxsize, pxsize * 2);
this.game.ctx.fillRect(width + pxsize, height + 3 * pxsize, pxsize, pxsize * 2);
this.game.ctx.fillRect(width, height + 5 * pxsize, pxsize, pxsize * 2);
this.game.ctx.fillRect(width + 6 * pxsize, height + 4 * pxsize, pxsize * 4, pxsize);
this.game.ctx.fillRect(width + 6 * pxsize, height + 7 * pxsize, pxsize * 4, pxsize);
this.game.ctx.setTransform(1, 0, 0, 1, 0, 0);
}
break;
case tiles.BODY:
if (!pxsize) {
this.game.ctx.fillStyle = "#0d5317";
this.game.ctx.fillRect(...canvasPos, ...size);
} else {
this.rotate(canvasPos, size);
this.game.ctx.fillStyle = "#FF4294";
this.game.ctx.fillRect(width, height, 12*pxsize, 12*pxsize);
this.game.ctx.fillStyle = "#000000";
this.game.ctx.fillRect(width, height, pxsize*12, pxsize);
this.game.ctx.fillRect(width, height+11*pxsize, pxsize*12, pxsize);
for (const [i,j] of [[1,1],[1,9],[2,3],[2,7],[3,5],[5,1],[5,9],[6,3],[6,7],[7,5],[9,1],[9,9],[10,3],[10,7],[11,5]])
this.game.ctx.fillRect(width+i*pxsize, height+j*pxsize, pxsize, pxsize*2);
this.game.ctx.setTransform(1, 0, 0, 1, 0, 0);
}
break;
case tiles.TAIL:
if (!pxsize) {
this.game.ctx.fillStyle = "#efff00";
this.game.ctx.fillRect(...canvasPos, ...size);
} else {
this.rotate(canvasPos, size);
this.game.ctx.fillStyle = "#FF4294";
this.game.ctx.fillRect(width, height+pxsize, pxsize, 10*pxsize);
this.game.ctx.fillRect(width+pxsize, height+2*pxsize, pxsize, 8*pxsize);
this.game.ctx.fillRect(width+2*pxsize, height+3*pxsize, 2*pxsize, 6*pxsize);
this.game.ctx.fillRect(width+4*pxsize, height+4*pxsize, 3*pxsize, 4*pxsize);
this.game.ctx.fillRect(width+7*pxsize, height+5*pxsize, 4*pxsize, 2*pxsize);
this.game.ctx.fillStyle = "#000000";
this.game.ctx.fillRect(width, height, pxsize, pxsize);
this.game.ctx.fillRect(width, height+11*pxsize, pxsize, pxsize);
this.game.ctx.fillRect(width+pxsize, height+pxsize, pxsize, pxsize);
this.game.ctx.fillRect(width+pxsize, height+10*pxsize, pxsize, pxsize);
this.game.ctx.fillRect(width+2*pxsize, height+2*pxsize, 2*pxsize, pxsize);
this.game.ctx.fillRect(width+2*pxsize, height+9*pxsize, 2*pxsize, pxsize);
this.game.ctx.fillRect(width+4*pxsize, height+3*pxsize, 3*pxsize, pxsize);
this.game.ctx.fillRect(width+4*pxsize, height+8*pxsize, 3*pxsize, pxsize);
this.game.ctx.fillRect(width+7*pxsize, height+4*pxsize, 4*pxsize, pxsize);
this.game.ctx.fillRect(width+7*pxsize, height+7*pxsize, 4*pxsize, pxsize);
this.game.ctx.fillRect(width+11*pxsize, height+5*pxsize, pxsize, 2*pxsize);
this.game.ctx.fillRect(width+5*pxsize, height+5*pxsize, pxsize, 2*pxsize);
this.game.ctx.fillRect(width, height+4*pxsize, pxsize, 4*pxsize);
this.game.ctx.fillRect(width+pxsize, height+3*pxsize, pxsize, pxsize);
this.game.ctx.fillRect(width+pxsize, height+8*pxsize, pxsize, pxsize);
this.game.ctx.fillRect(width+4*pxsize, height+4*pxsize, pxsize, pxsize);
this.game.ctx.fillRect(width+4*pxsize, height+7*pxsize, pxsize, pxsize);
this.game.ctx.setTransform(1, 0, 0, 1, 0, 0);
}
break;
case tiles.LIFE:
this.game.ctx.fillStyle = "#e400ff";
this.game.ctx.fillRect(...canvasPos, ...size);
break;
case tiles.ORANGE:
this.game.ctx.fillStyle = "#ff7500";
this.game.ctx.fillRect(...canvasPos, ...size);
break;
}
this.game.ctx.stroke();
}
/**
* Get the direction of a sprite depending of the next sprite
* @returns {directions}
*/
getDirection() {
const np = this.game.snake.body[this.game.snake.body.findIndex(([x,y]) => x === this.x && y === this.y)-1];
const d = [this.x, this.y].map((n, i) => -(n - np[i]));
return Object.values(directions).find(([x, y]) => d[0] === x && d[1] === y);
}
/**
* Rotate a sprite depending of the input direction or the next sprite
* @param {[int, int]} canvasPos
* @param {[int, int]} size
*/
rotate(canvasPos, size) {
const cx = canvasPos[0] + 0.5 * size[0];
const cy = canvasPos[1] + 0.5 * size[1];
this.game.ctx.translate(cx, cy);
switch (this.type === tiles.HEAD? this.game.lastDirection : this.getDirection()) {
case directions.UP:
this.game.ctx.rotate(Math.PI / 2);
break;
case directions.DOWN:
this.game.ctx.rotate(-Math.PI / 2);
break;
case directions.RIGHT:
this.game.ctx.rotate(-Math.PI);
break;
case directions.LEFT:
break;
}
this.game.ctx.translate(-cx, -cy);
}
/**
* 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",
HEAD: "head",
BODY: "body",
TAIL: "tail",
LIFE: "life",
ORANGE: "orange"
};