diff options
Diffstat (limited to 'frontend')
| -rw-r--r-- | frontend/ts/login.ts | 10 | ||||
| -rw-r--r-- | frontend/ts/startGame.ts | 451 | ||||
| -rw-r--r-- | frontend/ts/timer.ts | 30 |
3 files changed, 405 insertions, 86 deletions
diff --git a/frontend/ts/login.ts b/frontend/ts/login.ts index ec4defa..2e50884 100644 --- a/frontend/ts/login.ts +++ b/frontend/ts/login.ts @@ -5,7 +5,7 @@ class Login { static html = /* html */ ` <div class="container text-center fs-1" style="margin-top: 45vh;"> <label for="username">Vad heter du?</label> - <input type="text" name="username" value="maks" required> + <input type="text" name="username" required> <button type="button" class="btn btn-light btn-lg" onclick="Login.login">Starta spelet</button> </div> `; @@ -13,12 +13,14 @@ class Login { static async start() { let res = await (await fetch("/startPoint")).json(); if (res.status === true) { - new StartGame(JSON.parse(res.data[0].data)); + new StartGame({ data: res.data.data, uid: res.uid }); } else { document.body.innerHTML = Login.html; document.getElementsByTagName("button")[0].onclick = () => Login.login(); // !! + document.getElementsByTagName("input")[0].value = "maks " + Helpers.getRandomInt(1, 100); + document.title = document.getElementsByTagName("input")[0].value; document.getElementsByTagName("button")[0].click(); } } @@ -26,9 +28,9 @@ class Login { static async login(username = "") { if (username === "") username = document.getElementsByTagName("input")[0].value; - + let res = await Helpers.mFetch("/login", { name: username }); - new StartGame(await res.json()); + new StartGame(res); } } Login.start();
\ No newline at end of file diff --git a/frontend/ts/startGame.ts b/frontend/ts/startGame.ts index e97f4ea..71a9abf 100644 --- a/frontend/ts/startGame.ts +++ b/frontend/ts/startGame.ts @@ -1,131 +1,418 @@ -import { Data } from "../../helpers/helpersBack"; +import { Data, Coordinates, tColors, HomesOrBases, Square, HoBSquare, Ghost, mFetch } from "../../helpers/helpersBack"; import Helpers from "../../helpers/helpers.js"; import { Chequer, GameBoard } from "../../helpers/helpersBack.js"; +import Timer from "./timer.js"; export default class StartGame { - colors = ["primary", "danger", "success", "warning"]; + bgColors = ["primary", "danger", "success", "warning"]; + colors = ["blue", "red", "green", "yellow"]; radius = 20; + numberOfSquaresOnGameBoard = 11; + startInterval = () => { this.getData(); this.interval = setInterval(() => this.getData(), 2000); } + + uid!: string; + color!: tColors; + data!: Data; + timeTillTurnEnd!: number; + gameBoard!: GameBoard; + index!: number; + oldIndex!: number; - ctx!: CanvasRenderingContext2D; - canvas!: HTMLCanvasElement; interval!: any; - img!: HTMLImageElement; - - chequers: Array<Chequer> = []; - gameBoard: GameBoard = []; - gmString = "[\n"; + timer!: Timer; + + btnStateToggle!: HTMLInputElement; + gameTable!: HTMLTableElement; + btnRollDice!: HTMLButtonElement; + divDice!: HTMLDivElement; + + mineTurn = false; + gameStarted = false; + toggleStop = false; - constructor(data: Data) { + constructor(data: { data: Data, uid: string }) { this.init(data); } - async init(data: Data) { + async init(data: { data: Data, uid: string }) { document.body.innerHTML = await (await fetch("/map.html")).text(); - document.getElementsByTagName("input")[0].onclick = this.readyStateToggle; - [this.canvas, this.ctx] = this.getCanvasAndCtx(); - this.setOpponents(data); + this.uid = data.uid; + this.data = data.data; + this.index = data.data.filter(el => el.id === this.uid)[0].index; + this.color = data.data.filter(el => el.id === this.uid)[0].color; - this.canvas.onclick = e => this.canvasClickHandler(e); + this.setOpponents(data.data, true); - this.img = await this.loadImage("https://jopek.eu/maks/szkola/apkKli/fiaFiles/fia.png"); - - await this.getData(); - this.ctx.drawImage(this.img, 0, 0, this.img.width, this.img.height, 0, 0, this.canvas.width, this.canvas.height); - this.drawChequer({ x: 4, y: 1, color: 1 }); + this.gameTable = document.getElementsByTagName("table")[1]; + this.btnStateToggle = document.getElementsByTagName("input")[0]; + this.btnRollDice = document.getElementsByTagName("button")[0]; + this.divDice = document.getElementById("dice") as HTMLDivElement; + this.timer = new Timer(); - // this.interval = setInterval(this.getData, 2000); - } + this.btnStateToggle.onclick = this.readyStateToggle; + this.btnRollDice.onclick = this.rollDice; + + this.drawGameTable(); - getCanvasAndCtx(): [HTMLCanvasElement, CanvasRenderingContext2D] { - let canvas = document.getElementsByTagName("canvas")[0], - ctx = canvas.getContext("2d"); - if (ctx === null) { - document.write("stop using IE ..."); - throw new Error("Player is using browser older than ..."); - } else return [canvas, ctx]; + this.startInterval(); } - async setOpponents(data: Data): Promise<void> { + async setOpponents(data: Data, firstTime: boolean): Promise<void> { let tds = (document.getElementsByClassName("player-name") as HTMLCollectionOf<HTMLElement>), i = 0; - + for (let player of data) { - if (player.ready === true) - tds[i].classList.add("bg-" + this.colors[player.color]); + tds[i].className = tds[i].className.replace(/\bbg-.*\b/, ''); + + if (player.ready === true) { + tds[i].classList.add("bg-" + this.bgColors[player.color]); + if (this.uid === player.id) + document.getElementsByTagName("input")[0].checked = true; + } else tds[i].classList.add("bg-secondary"); - tds[i].innerText = player.name; - console.log("player, i", player, i); + (tds[i].children[0] as HTMLElement).innerText = player.name; i++; } - for (; i < 4; i++) { - console.log("i", i); - tds[i].classList.add("bg-secondary"); - tds[i].innerText = "?"; + if (firstTime === true) { + for (; i < 4; i++) { + tds[i].classList.add("bg-secondary"); + (tds[i].children[0] as HTMLElement).innerText = "?"; + } + } + } + + readyStateToggle = async (e: MouseEvent): Promise<void> => { + if (this.toggleStop) { + this.btnStateToggle.checked = true; + return; } + this.toggleStop = true; + let res = await Helpers.mFetch("/readyStateToggle", { + state: this.btnStateToggle.checked + }); + if (res.started === true) + this.toggleStop = true; + else + this.toggleStop = false; + clearInterval(this.interval); + this.getData(); + this.startInterval(); } - isIntersect(point: { x: number, y: number }, circle: Chequer) { - return Math.sqrt((point.x - circle.x) ** 2 + (point.y - circle.y) ** 2) < this.radius; + rollDice = async (e: MouseEvent): Promise<void> => { + let number = Helpers.getRandomInt(1, 7); + this.divDice.classList.add(`dice-${number}`); + this.btnRollDice.style.display = "none"; + this.calcMoves(number); } - canvasClickHandler(e: MouseEvent) { - const mousePos = { - x: e.clientX - this.canvas.offsetLeft, - y: e.clientY - this.canvas.offsetTop - }; + calcMoves(number: number) { + if ([1, 6].includes(number)) + this.moveFromBase(); - if (Math.round((mousePos.x - 30) / 60) == 0 && Math.round((mousePos.y - 28) / 60) == 0) { - console.log(this.gmString + "]"); - this.gmString = "[\n" - } + this.moveInMap(number); + this.moveInHome(number); + + this.drawGameBoard(); + console.log("checking for ghosts"); + if (this.anyGhosts() === false) + this.sendGameBoard(); else - this.gmString += JSON.stringify({ x: Math.round((mousePos.x - 30) / 60), y: Math.round((mousePos.y - 28) / 60) }) + ",\n"; + console.log("ghost were created"); + } + moveFromBase() { + let start: Square, i: number; - this.chequers.forEach(chequer => { - if (this.isIntersect(mousePos, chequer)) { - alert('click on circle: ' + chequer); + this.gameBoard.map.forEach((square, j) => { + if (square.start === this.color) { + start = square; + i = j; } - }); + }) + + this.gameBoard.bases[this.color as keyof HomesOrBases].forEach((chequer, j) => { + if (chequer.chequer > -1) { + chequer.ghost = { + where: { + from: "base", oldIndex: j, + to: "map", newIndex: i + }, + color: this.color, + coords: { x: start.x, y: start.y } + }; + } + }) } + moveInMap(number: number) { + this.gameBoard.map.forEach((square, i) => { + if (square.chequers.length > 0 && square.chequers[0].color === this.color) { + + for (let chequer of square.chequers) { + let x: number | undefined, y: number | undefined, coords: Coordinates | undefined, inMap: boolean, + homeIndex: number | undefined; + + if (i + number < this.gameBoard.map.length) { + x = this.gameBoard.map[i + number].x; + y = this.gameBoard.map[i + number].y; + inMap = true; + } + else { + homeIndex = this.gameBoard.map.length - i - 1 - number - 1; + inMap = true; + + if (homeIndex < this.gameBoard.homes[0].length) { + x = this.gameBoard.homes[this.color as keyof HomesOrBases][homeIndex].x; + y = this.gameBoard.homes[this.color as keyof HomesOrBases][homeIndex].y; + } + else { + x = y = undefined; + } + } + + if (x === undefined || y === undefined) + coords = undefined; + else + coords = { x, y }; + + chequer.ghost = { + where: { + from: "map", oldIndex: i, + to: (inMap === true ? "map" : "home"), newIndex: homeIndex || i + number + }, + color: this.color, + coords, + } + } + } + }) + } + moveInHome(number: number) { + let home = this.gameBoard.homes[this.color as keyof HomesOrBases]; + + home.forEach((chequer, i) => { + if (chequer.chequer > -1) { + let x: number | undefined, y: number | undefined, coords: Coordinates | undefined; + if (home[i + number] !== undefined) { + x = home[i + number].x; + y = home[i + number].y; + } else { + x = y = undefined; + } + + if (x === undefined || y === undefined) + coords = undefined; + else + coords = { x, y }; - readyStateToggle(e: MouseEvent): void { - Helpers.mFetch("/readyStateToggle", { - state: (e.target as HTMLInputElement).checked + chequer.ghost = { + where: { + from: "home", oldIndex: i, + to: "home", newIndex: i + number + }, + color: this.color, + coords, + }; + } }); } - async loadImage(src: string): Promise<HTMLImageElement> { - return new Promise(resolve => { - let img = new Image() - img.src = src - img.onload = () => resolve(img) - }) + showGhost(chequer: Chequer | HoBSquare) { + if (chequer.ghost === undefined || chequer.ghost.coords === undefined) { + console.log("showChequer::chequer.ghost.coords === undefined", chequer.ghost?.coords === undefined); + return; + } + this.showChequer(chequer.ghost.coords, this.color) + } + hideGhost(chequer: Chequer | HoBSquare): void { + if (chequer.ghost === undefined || chequer.ghost.coords === undefined) { + console.log("hideChequer::chequer.ghost.coords === undefined", chequer.ghost?.coords === undefined); + return; + } + this.hideChequer(chequer.ghost.coords); + } + doTurn(chequer: Chequer | HoBSquare): void { + if (chequer.ghost === undefined || chequer.ghost.coords === undefined) { + console.log("hideChequer::chequer.ghost.coords === undefined", chequer.ghost?.coords === undefined); + return; + } + this.mineTurn = false; + let where = chequer.ghost.where; + + if (where.from === "map") { + this.gameBoard.map[where.oldIndex].chequers.pop(); + } else if (where.from === "base") { + this.gameBoard.bases[this.color as keyof HomesOrBases][where.oldIndex].chequer = -1; + } else { + this.gameBoard.homes[this.color as keyof HomesOrBases][where.oldIndex].chequer = -1; + } + + if (where.to === "map") { + this.gameBoard.map[where.newIndex].chequers.push({ color: this.color }); + } else if (where.to === "base") { + this.gameBoard.bases[this.color as keyof HomesOrBases][where.newIndex].chequer = this.color; + } else { + this.gameBoard.homes[this.color as keyof HomesOrBases][where.newIndex].chequer = this.color; + } + + this.sendGameBoard(); + } + removeGhosts(): void { + for (let square of this.gameBoard.map) { + for (let chequer of square.chequers) { + chequer.ghost = undefined; + } + } + for (let chequer of this.gameBoard.bases[this.color as keyof HomesOrBases]) { + chequer.ghost = undefined; + } + for (let chequer of this.gameBoard.homes[this.color as keyof HomesOrBases]) { + chequer.ghost = undefined; + } + } + anyGhosts(): boolean { + for (let square of this.gameBoard.map) { + for (let chequer of square.chequers) { + if (chequer.ghost !== undefined) + return true; + } + } + for (let chequer of this.gameBoard.bases[this.color as keyof HomesOrBases]) { + if (chequer.ghost !== undefined) + return true; + } + for (let chequer of this.gameBoard.homes[this.color as keyof HomesOrBases]) { + if (chequer.ghost !== undefined) + return true; + } + return false; } - drawChequer(chequer: Chequer): void { - let x = chequer.x * 60 + 30, - y = chequer.y * 60 + 28; + drawGameBoard(): void { - this.ctx.beginPath(); - this.ctx.arc(x, y, this.radius, 0, 2 * Math.PI); - this.ctx.fillStyle = this.colors[chequer.color]; - this.ctx.fill(); - this.ctx.lineWidth = 5; - this.ctx.strokeStyle = 'grey'; - this.ctx.closePath(); - this.ctx.stroke(); + for (let square of this.gameBoard.map) { + if (square.chequers.length !== 0) { + for (let chequer of square.chequers) + this.drawChequer({ x: square.x, y: square.y }, chequer.color, chequer); + } + } + for (let baseOfColor in this.gameBoard.bases) { + for (let square of this.gameBoard.bases[baseOfColor as unknown as keyof HomesOrBases]) { + if (square.chequer > -1) + this.drawChequer({ x: square.x, y: square.y }, square.chequer, square); + } + } + for (let baseOfColor in this.gameBoard.homes) { + for (let square of this.gameBoard.homes[baseOfColor as unknown as keyof HomesOrBases]) { + if (square.chequer > -1) + this.drawChequer({ x: square.x, y: square.y }, square.chequer, square); + } + } + } - this.chequers.push(chequer); + drawGameTable(): void { + for (let i = 0; i < this.numberOfSquaresOnGameBoard; i++) { + let tr = document.createElement("tr"); + for (let j = 0; j < this.numberOfSquaresOnGameBoard; j++) { + let td = document.createElement("td"); + td.classList.add("chequer"); + td.dataset.count = '0'; + tr.appendChild(td); + } + this.gameTable.appendChild(tr); + } + } + + async sendGameBoard() { + this.divDice.className.replace(/dice.*/, ''); + this.removeGhosts(); + await Helpers.mFetch("/saveGameBoard", { gameBoard: this.gameBoard }); + } + + getTd(coords: Coordinates): HTMLElement { + return this.gameTable.children[coords.y].children[coords.x] as HTMLElement; + } + showChequer(coords: Coordinates, color: tColors): void { + let td = this.getTd(coords); + if (td.dataset.count === undefined) + throw new Error("td.dataset.count is undefined!!!") + + if (td.dataset.count === '0') { + td.classList.add("chequer-" + this.colors[color]); + td.dataset.count = "1"; + } else { + td.dataset.count = (parseInt(td.dataset.count) + 1).toString(); + td.innerHTML = 'x' + td.dataset.count; + } + } + hideChequer(coords: Coordinates, all = false) { + let td = this.getTd(coords); + if (td.dataset.count === undefined) + throw new Error("td.dataset.count is undefined!!!") + + if (td.dataset.count === '0') + throw new Error("Cannot remove from empty td!!!"); + + if (td.dataset.count === '1' || all === true) { + td.className = td.className.replace(/chequer-.*/, ''); + td.innerHTML = 'x' + td.dataset.count; + } else { + td.dataset.count = (parseInt(td.dataset.count) - 1).toString(); + td.innerHTML = 'x' + td.dataset.count; + } + } + + drawChequer(coords: Coordinates, color: tColors, chequer: Chequer | HoBSquare): void { + let td = this.getTd(coords); + this.showChequer(coords, color); + if (this.mineTurn === true && chequer.ghost !== undefined) { + td.onmouseenter = () => { console.log("mouseenter"); this.showGhost(chequer); } + td.onmouseleave = () => { console.log("mouseleave"); this.hideGhost(chequer); } + td.onclick = () => { console.log("mouseclick"); this.doTurn(chequer); } + } + } + removeChequer(coords: Coordinates) { + let td = this.getTd(coords); + this.hideChequer(coords, true); + td.onmouseenter = () => null; + td.onmouseleave = () => null; + td.onclick = () => null; + } + + async startTimer(currentPlayer: number) { + await this.timer.start(currentPlayer, this.timeTillTurnEnd); + this.sendGameBoard(); } async getData() { - let data = await Helpers.mFetch("/getCurrentGameState", {}); - // this.setOpponents(JSON.parse(data.data)); - // TODO: assign data to this.gameBoard and draw it - // TODO: add D6 dice - // TODO: if currentPLayer === true, call to logic or calc logic here + let data: { gameBoard: GameBoard, currentPlayer: number, started: number, data: Data, timeTillTurnEnd: number } + = await Helpers.mFetch("/getCurrentGameState", {}); + if (data.started === 1) { + if (this.oldIndex !== data.currentPlayer) { + this.oldIndex = data.currentPlayer; + if (data.currentPlayer === this.index && this.mineTurn === false) { + this.mineTurn = true; + this.btnRollDice.style.display = "block"; + }// else if (JSON.stringify(data.gameBoard) !== JSON.stringify(this.gameBoard)) { + this.gameBoard = data.gameBoard; + this.drawGameBoard(); + // } + this.timeTillTurnEnd = data.timeTillTurnEnd; + this.startTimer(data.currentPlayer); + } + } + + if (JSON.stringify(data.data) !== JSON.stringify(this.data)) { + console.log("startGame::getData::data", data.data); + this.data = data.data; + this.setOpponents(this.data, false); + } + + // TODO: Animation: blinking of chequers with ghosts + // TODO: Ending turn + // TODO: Ghost not working + // TODO: Moving not working } -}
\ No newline at end of file +} diff --git a/frontend/ts/timer.ts b/frontend/ts/timer.ts new file mode 100644 index 0000000..f8dab25 --- /dev/null +++ b/frontend/ts/timer.ts @@ -0,0 +1,30 @@ +export default class Timer { + divTimer!: HTMLElement; + + interval!: any; + async start(playerIndex: number, finishTime: number): Promise<void> { + return new Promise(resolve => { + let divTimer = document.getElementById(`${playerIndex}-player-time`); + if (divTimer === null) + throw new Error("divTimer doesn't Exist"); + else + this.divTimer = divTimer; + + this.interval = setInterval(() => { + this.updateDisplay(finishTime - Date.now(), resolve); + }, 1000); + }) + } + + updateDisplay(time: number, resolve: Function): void { + let secondsElapsed = Math.floor(time / 1000); + this.divTimer.innerHTML = secondsElapsed.toString(); + if (secondsElapsed === 0) { + resolve(); + clearInterval(this.interval); + } + } + stop(): void { + clearInterval(this.interval); + } +}
\ No newline at end of file |
