From ed2aa325e5a55d1e71349c3eee7b409d7ca14aa9 Mon Sep 17 00:00:00 2001 From: y-syo Date: Sun, 19 Oct 2025 09:29:33 +0200 Subject: [PATCH] =?UTF-8?q?=E3=80=8C=F0=9F=8F=97=EF=B8=8F=E3=80=8D=20wip(f?= =?UTF-8?q?ront):=20profile=20page?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/front/index.html | 4 +- src/front/static/css/style.css | 9 ++ src/front/static/ts/main.ts | 11 +- src/front/static/ts/oneko.ts | 17 +-- src/front/static/ts/views/Game.ts | 43 +++++-- src/front/static/ts/views/LoginPage.ts | 34 ++++-- src/front/static/ts/views/Profile.ts | 139 ++++++++++++---------- src/front/static/ts/views/ProfileMenu.ts | 86 +++++++++++++ src/front/static/ts/views/RegisterPage.ts | 34 ++++-- src/front/static/ts/views/Settings.ts | 84 +++++++++++++ src/front/static/ts/views/Tetris.ts | 115 ++++++++++++++---- 11 files changed, 448 insertions(+), 128 deletions(-) create mode 100644 src/front/static/ts/views/ProfileMenu.ts create mode 100644 src/front/static/ts/views/Settings.ts diff --git a/src/front/index.html b/src/front/index.html index 233ae24..6471bae 100644 --- a/src/front/index.html +++ b/src/front/index.html @@ -42,8 +42,8 @@
|
- rusty - tetris + rusty + tetris-guideline.pdf
12:37 diff --git a/src/front/static/css/style.css b/src/front/static/css/style.css index 35cd827..56bb708 100644 --- a/src/front/static/css/style.css +++ b/src/front/static/css/style.css @@ -1,4 +1,13 @@ @import "tailwindcss"; +@layer utilities { + .no-scrollbar::-webkit-scrollbar { + display: none; + } + .no-scrollbar { + -ms-overflow-style: none; + scrollbar-width: none; + } +} @font-face { font-family: Kubasta; diff --git a/src/front/static/ts/main.ts b/src/front/static/ts/main.ts index 6533fd8..7473ebc 100644 --- a/src/front/static/ts/main.ts +++ b/src/front/static/ts/main.ts @@ -1,6 +1,6 @@ import { oneko } from "./oneko.ts"; -import Profile from "./views/Profile.ts"; -let profile_view = new Profile; +import ProfileMenu from "./views/ProfileMenu.ts"; +let profile_view = new ProfileMenu; export async function isLogged(): Promise { let uuid_req = await fetch("http://localhost:3001/me", { @@ -40,6 +40,9 @@ const routes = [ { path: "/login", view: () => import("./views/LoginPage.ts") }, { path: "/register", view: () => import("./views/RegisterPage.ts") }, + + { path: "/profile", view: () => import("./views/Profile.ts") }, + { path: "/settings", view: () => import("./views/Settings.ts") }, ]; const router = async () => { @@ -97,8 +100,6 @@ document.addEventListener("DOMContentLoaded", () => { router(); }); -oneko(); - function updateClock() { const days = ['sun', 'mon', 'tue', 'wed', 'thu', 'fri', 'sat']; @@ -116,3 +117,5 @@ function updateClock() setInterval(updateClock, 5000); updateClock(); + +oneko(); diff --git a/src/front/static/ts/oneko.ts b/src/front/static/ts/oneko.ts index 9c579d4..a2a159b 100644 --- a/src/front/static/ts/oneko.ts +++ b/src/front/static/ts/oneko.ts @@ -18,20 +18,23 @@ export function setOnekoState(state: string) { default: oneko_state = 0; } + return; } export function setOnekoOffset() { - if (oneko_state == 1) + if (oneko_state != 0) { offsetX = document.getElementById("window").offsetLeft + 44; offsetY = document.getElementById("window").offsetTop + 44 + 24; - console.log(offsetX, offsetY); } + return; } -export function setBallPos(x: number, y: number) { +export function setBallPos(x: number, y: number) +{ mousePosX = x + offsetX; mousePosY = y + offsetY; + return; } export function oneko() { @@ -39,7 +42,7 @@ export function oneko() { window.matchMedia(`(prefers-reduced-motion: reduce)`) === true || window.matchMedia(`(prefers-reduced-motion: reduce)`).matches === true; - if (isReducedMotion) return; + if (isReducedMotion) return ; const nekoEl = document.createElement("div"); @@ -141,15 +144,15 @@ export function oneko() { { mousePosX = event.clientX; mousePosY = event.clientY; - } + } }); window.requestAnimationFrame(onAnimationFrame); } - let lastFrameTimestamp; + let lastFrameTimestamp: number; - function onAnimationFrame(timestamp) { + function onAnimationFrame(timestamp: number) { // Stops execution if the neko element is removed from DOM if (!nekoEl.isConnected) { return; diff --git a/src/front/static/ts/views/Game.ts b/src/front/static/ts/views/Game.ts index 2b73777..5e29d7b 100644 --- a/src/front/static/ts/views/Game.ts +++ b/src/front/static/ts/views/Game.ts @@ -4,7 +4,7 @@ import { dragElement } from "./drag.js" import { setOnekoState, setBallPos, setOnekoOffset } from "../oneko.ts" export default class extends Aview { - + running: boolean; constructor() @@ -27,7 +27,7 @@ export default class extends Aview {
- +
@@ -46,6 +46,7 @@ export default class extends Aview { async run() { dragElement(document.getElementById("window")); + let uuid: string; let start: number = 0; let elapsed: number; @@ -103,7 +104,7 @@ export default class extends Aview { ballSpeedY = ballSpeed * Math.sin(theta); } - function moveBall() { + async function moveBall() { let length = Math.sqrt(ballSpeedX * ballSpeedX + ballSpeedY * ballSpeedY); let scale = ballSpeed / length; ballX += (ballSpeedX * scale) * elapsed; @@ -142,6 +143,17 @@ export default class extends Aview { if (p1_score === 3 || p2_score === 3) { + console.log(isLogged()); + if (await isLogged()) + { + let uuid = document.cookie.match(new RegExp('(^| )' + "uuid" + '=([^;]+)'))[2]; + fetch(`http://localhost:3002/users/${uuid}/matchHistory`, { + method: "POST", + headers: { "Content-Type": "application/json", }, + credentials: "include", + body: JSON.stringify({ "opponent": p2_name, "myScore": p1_score, "opponentScore": p2_score }) + }); + } // ------------------------------------------------------------------------------------------------------------------------------------------ // // insert the fetch to the ScoreStore api here @@ -225,13 +237,13 @@ export default class extends Aview { } } - const gameLoop = (timestamp: number) => { + const gameLoop = async (timestamp: number) => { elapsed = (timestamp - start) / 1000; start = timestamp; if (game_playing) { movePaddles(); - moveBall(); + await moveBall(); } draw(); if (!game_playing) @@ -257,13 +269,26 @@ export default class extends Aview { p2_input.value = "Player 2"; if (await isLogged()) - p1_input.value = document.cookie.match(new RegExp('(^| )' + "uuid" + '=([^;]+)'))[2]; + { + uuid = document.cookie.match(new RegExp('(^| )' + "uuid" + '=([^;]+)'))[2]; + const userdata_req = await fetch(`http://localhost:3002/users/${uuid}`, { + method: "GET", + credentials: "include", + }); + if (userdata_req.status == 404) + { + console.error("invalid user"); + return ; + } + let userdata = await userdata_req.json(); + p1_input.value = userdata.displayName; + } else p1_input.value = "Player 1"; document.getElementById("game-start")?.addEventListener("click", () => { - p1_name = p1_input.value; - p2_name = p2_input.value; + p1_name = p1_input.value.length > 16 ? p1_input.value.substring(0, 16) + "." : p1_input.value; + p2_name = p2_input.value.length > 16 ? p2_input.value.substring(0, 16) + "." : p2_input.value; document.getElementById("player-inputs").remove(); canvas = document.createElement("canvas"); @@ -272,7 +297,7 @@ export default class extends Aview { document.getElementById("main-div").prepend(canvas); - ctx = canvas.getContext("2d"); + ctx = canvas.getContext("2d", {alpha: false}); ctx.canvas.width = 600; ctx.canvas.height = 600; diff --git a/src/front/static/ts/views/LoginPage.ts b/src/front/static/ts/views/LoginPage.ts index f1b04bd..0311473 100644 --- a/src/front/static/ts/views/LoginPage.ts +++ b/src/front/static/ts/views/LoginPage.ts @@ -24,14 +24,30 @@ export default class extends Aview {
-
-

welcome back ! please login.

- - - -
- -
+
+
+

welcome back ! please login.

+ + + +
+ +
+ +
+ + +
+
`; } @@ -49,7 +65,6 @@ export default class extends Aview { credentials: "include", body: JSON.stringify({ user: username, password: password }), }); - const data = await data_req.json(); if (data_req.status === 200) { @@ -58,6 +73,7 @@ export default class extends Aview { } else if (data_req.status === 400) { + const data = await data_req.json(); document.getElementById("login-error-message").innerHTML = "error: " + data.error; document.getElementById("login-error-message").classList.remove("hidden"); } diff --git a/src/front/static/ts/views/Profile.ts b/src/front/static/ts/views/Profile.ts index 502b15c..e233f52 100644 --- a/src/front/static/ts/views/Profile.ts +++ b/src/front/static/ts/views/Profile.ts @@ -1,29 +1,38 @@ import Aview from "./Aview.ts" +import { dragElement } from "./drag.ts"; +import { setOnekoState } from "../oneko.ts" import { isLogged, navigationManager } from "../main.ts" + export default class extends Aview { constructor() { super(); this.setTitle("profile"); + setOnekoState("default"); } async getHTML() { return ` -
-
-
- -
girls kissing :3
+
+
+ profile.ts +
+ + + ×
- -
-
+
+
+
+
-
@@ -31,43 +40,15 @@ export default class extends Aview { `; } - open: boolean = false; + async run() { + if (!await isLogged()) + navigationManager("/"); - async run() { - let uuid: String; - if (this.open) - { - this.open = false; - document.getElementById("taskbar-menu").innerHTML = ""; - return ; - } - this.open = true; - document.getElementById("taskbar-menu").innerHTML = await this.getHTML(); + dragElement(document.getElementById("window")); + let uuid: String; + uuid = document.cookie.match(new RegExp('(^| )' + "uuid" + '=([^;]+)'))[2]; - async function getMainHTML() { - if (!(await isLogged())) - { - document.getElementById("menu-bottom-div").classList.add("hidden"); - return ` - login - register - `; - } - document.getElementById("menu-bottom-div").classList.remove("hidden"); - - uuid = document.cookie.match(new RegExp('(^| )' + "uuid" + '=([^;]+)'))[2]; - return ` - hi, ${uuid} ! -
- - - `; - } - - - document.getElementById("profile-items").innerHTML = await getMainHTML(); - - /*const userdata_req = await fetch(`http://localhost:3002/users/${uuid}`, { + const userdata_req = await fetch(`http://localhost:3002/users/${uuid}`, { method: "GET", credentials: "include", }); @@ -78,28 +59,56 @@ export default class extends Aview { } let userdata = await userdata_req.json(); - console.log(userdata_req);*/ + const matchCount_req = await fetch(`http://localhost:3002/users/${uuid}/matchHistory/count`, { + method: "GET", + credentials: "include", + }); + const matchCount = await matchCount_req.json(); - /*const main = document.getElementById("profile-profile"); - const nametag = main.appendChild(document.createElement("span")); + const matches_req = await fetch(`http://localhost:3002/users/${uuid}/matchHistory?iStart=0&iEnd=${matchCount.n_matches}`, { + method: "GET", + credentials: "include", + }); + const matches = await matches_req.json(); - nametag.innerHTML = `Hiiiiii ${userdata.displayName} ! :D`; + const main = document.getElementById("profile-scorelist"); + if (!main) + return console.error("what"); + + console.log(matches); + if (matches.matchHistory) + { + for (let match of matches.matchHistory) + { + const newEntry = document.createElement("li"); + newEntry.classList.add("m-2", "default-button", "bg-neutral-200", "dark:bg-neutral-800", "text-neutral-900", "dark:text-white"); + newEntry.innerHTML = match.score.p1Score > match.score.p2Score ? `${match.score.p1} - winner` : `${match.score.p2} - winner`; + main.insertBefore(newEntry, main.firstChild); + console.log(match.tx); + } + } + + const profile = document.getElementById("profile-profile"); + if (!profile) return; + + const picture = profile.appendChild(document.createElement("img")); + picture.src = "https://api.kanel.ovh/pp"; + picture.classList.add("text-neutral-900", "dark:text-white", "center", "h-18", "w-18", "mx-3"); + + const nametag = profile.appendChild(document.createElement("div")); + nametag.innerHTML = ` +
Hi ${userdata.displayName} ! :D
+
${uuid}
+ `; nametag.classList.add("text-neutral-900", "dark:text-white"); - const winrate = main.appendChild(document.createElement("div")); + const winrate = profile.appendChild(document.createElement("div")); - winrate.innerHTML = `wins: ${userdata.wins} | losses: ${userdata.losses} | winrate: ${userdata.wins / (userdata.wins + userdata.losses)}`; - winrate.classList.add("text-neutral-900", "dark:text-white");*/ - //console.log(document.getElementById("menu-logout")); - document.getElementById("menu-logout").addEventListener("click", async () => { - let req = await fetch("http://localhost:3001/logout", { - method: "GET", - credentials: "include", - }); - if (req.status === 200) - this.run(); - else - console.error("logout failed"); - }); - } + winrate.innerHTML = ` +
wins: ${userdata.wins}
+
losses: ${userdata.losses}
+
winrate: ${Math.round(userdata.wins / (userdata.wins + userdata.losses) * 100)} %
+ `; + winrate.classList.add("text-neutral-900", "dark:text-white", "grow", "content-center"); + } } diff --git a/src/front/static/ts/views/ProfileMenu.ts b/src/front/static/ts/views/ProfileMenu.ts new file mode 100644 index 0000000..0113c08 --- /dev/null +++ b/src/front/static/ts/views/ProfileMenu.ts @@ -0,0 +1,86 @@ +import Aview from "./Aview.ts" +import { isLogged, navigationManager } from "../main.ts" + +export default class extends Aview { + + async getHTML() { + return ` +
+
+
+ +
girls kissing :3
+
+ +
+
+
+ +
+
+
+ `; + } + + open: boolean = false; + + async run() { + let uuid: String; + if (this.open) + { + this.open = false; + document.getElementById("taskbar-menu").innerHTML = ""; + return ; + } + this.open = true; + document.getElementById("taskbar-menu").innerHTML = await this.getHTML(); + + async function getMainHTML() { + if (!(await isLogged())) + { + document.getElementById("menu-bottom-div").classList.add("hidden"); + return ` + login + register + `; + } + document.getElementById("menu-bottom-div").classList.remove("hidden"); + + uuid = document.cookie.match(new RegExp('(^| )' + "uuid" + '=([^;]+)'))[2]; + const userdata_req = await fetch(`http://localhost:3002/users/${uuid}`, { + method: "GET", + credentials: "include", + }); + if (userdata_req.status == 404) + { + console.error("invalid user"); + return ; + } + let userdata = await userdata_req.json(); + + return ` + hi, ${ userdata.displayName.length > 8 ? userdata.displayName.substring(0, 8) + "." : userdata.displayName } ! +
+ profile + settings + `; + } + + + document.getElementById("profile-items").innerHTML = await getMainHTML(); + + document.getElementById("menu-logout").addEventListener("click", async () => { + let req = await fetch("http://localhost:3001/logout", { + method: "GET", + credentials: "include", + }); + if (req.status === 200) + this.run(); + else + console.error("logout failed"); + }); + } +} diff --git a/src/front/static/ts/views/RegisterPage.ts b/src/front/static/ts/views/RegisterPage.ts index 67c828f..429cc09 100644 --- a/src/front/static/ts/views/RegisterPage.ts +++ b/src/front/static/ts/views/RegisterPage.ts @@ -1,7 +1,7 @@ import Aview from "./Aview.ts" +import { dragElement } from "./drag.ts"; import { setOnekoState } from "../oneko.ts" import { isLogged, navigationManager } from "../main.ts" -import { dragElement } from "./drag.ts"; export default class extends Aview { @@ -24,14 +24,30 @@ export default class extends Aview {
-
-

welcome ! please register.

- - - -
- -
+
+
+

welcome ! please register.

+ + + +
+ +
+ +
+ + +
+
`; } diff --git a/src/front/static/ts/views/Settings.ts b/src/front/static/ts/views/Settings.ts new file mode 100644 index 0000000..fb5fbc6 --- /dev/null +++ b/src/front/static/ts/views/Settings.ts @@ -0,0 +1,84 @@ +import Aview from "./Aview.ts" +import { dragElement } from "./drag.ts"; +import { setOnekoState } from "../oneko.ts" +import { isLogged, navigationManager } from "../main.ts" + + +export default class extends Aview { + + constructor() + { + super(); + this.setTitle("profile"); + setOnekoState("default"); + } + + async getHTML() { + return ` +
+
+ settings.ts +
+ + + × +
+
+
+ + + +
+
+ `; + } + + async run() { + if (!await isLogged()) + navigationManager("/"); + + dragElement(document.getElementById("window")); + + let uuid: String; + uuid = document.cookie.match(new RegExp('(^| )' + "uuid" + '=([^;]+)'))[2]; + const userdata_req = await fetch(`http://localhost:3002/users/${uuid}`, { + method: "GET", + credentials: "include", + }); + if (userdata_req.status == 404) { + console.error("invalid user"); + return; + } + let userdata = await userdata_req.json(); + + (document.getElementById("displayName-input") as HTMLInputElement).placeholder = userdata.displayName; + (document.getElementById("displayName-input") as HTMLInputElement).value = userdata.displayName; + + document.getElementById("displayName-button")?.addEventListener("click", async () => { + const changeDisplayName_req = await fetch(`http://localhost:3002/users/${uuid}/displayName`, { + method: "PATCH", + headers: { "Content-Type": "application/json", }, + credentials: "include", + body: JSON.stringify({ displayName: (document.getElementById("displayName-input") as HTMLInputElement).value }) + }); + if (changeDisplayName_req.status == 200) { + // idk display success + } + else { + // display error ig, uuuh it's in await changeDisplayName.json().error + } + }); + + document.getElementById("deleteAccount-button")?.addEventListener("click", async () => { + const delete_req = await fetch(`http://localhost:3002/users/${uuid}`, { + method: "DELETE", + credentials: "include", + }); + + if (delete_req.status == 200) + navigationManager("/"); + else + console.error("xd"); // should never happen, wtf + }); + } +} diff --git a/src/front/static/ts/views/Tetris.ts b/src/front/static/ts/views/Tetris.ts index f01eb08..a6d43c9 100644 --- a/src/front/static/ts/views/Tetris.ts +++ b/src/front/static/ts/views/Tetris.ts @@ -1,5 +1,6 @@ import Aview from "./Aview.ts"; import { dragElement } from "./drag.js"; +import { setOnekoState, setBallPos, setOnekoOffset } from "../oneko.ts" export default class extends Aview { running: boolean; @@ -7,6 +8,7 @@ export default class extends Aview { constructor() { super(); this.setTitle("tetris (local match)"); + setOnekoState("tetris"); this.running = true; } @@ -274,33 +276,42 @@ export default class extends Aview { canvas: HTMLCanvasElement | null; holdCanvas: HTMLCanvasElement | null; queueCanvas: HTMLCanvasElement | null; - ctx: CanvasRenderingContext2D; - holdCtx: CanvasRenderingContext2D; - queueCtx: CanvasRenderingContext2D; + ctx: CanvasRenderingContext2D | null; + holdCtx: CanvasRenderingContext2D | null; + queueCtx: CanvasRenderingContext2D | null; piece: Piece | null = null; holdPiece: Piece | null = null; canHold: boolean = true; nextQueue: string[] = []; - score = 0; - level = 1; - lines = 0; - dropInterval = 1000; - lastDrop = 0; - isGameOver = false; - isPaused = false; + score: number = 0; + level: number = 1; + lines: number = 0; + dropInterval: number = 1000; + lastDrop: number = 0; + isLocking: boolean = false; + lockRotationCount: number = 0; + lockLastRotationCount: number = 0; + isGameOver: boolean = false; + isPaused: boolean = false; constructor(canvasId: string) { const el = document.getElementById( canvasId, ) as HTMLCanvasElement | null; this.canvas = el; + if (!this.canvas) + throw console.error("no canvas :c"); this.canvas.width = COLS * BLOCK; this.canvas.height = ROWS * BLOCK; const ctx = this.canvas.getContext("2d"); this.ctx = ctx; + if (!this.ctx) + throw console.error("no ctx D:"); - this.holdCanvas = document.getElementById("hold"); - this.queueCanvas = document.getElementById("queue"); + this.holdCanvas = document.getElementById("hold") as HTMLCanvasElement; + this.queueCanvas = document.getElementById("queue") as HTMLCanvasElement; + if (!this.holdCanvas || !this.queueCanvas) + throw console.error("no canvas :c"); this.holdCtx = this.holdCanvas.getContext("2d"); this.queueCtx = this.queueCanvas.getContext("2d"); @@ -337,6 +348,7 @@ export default class extends Aview { [this.piece, this.holdPiece] = [this.holdPiece, this.piece]; if (!this.piece) this.spawnPiece(); + if (!this.piece) return; this.piece.x = Math.floor((COLS - this.piece.shape[0].length) / 2); this.piece.y = -2; @@ -352,7 +364,6 @@ export default class extends Aview { if (this.nextQueue.length < 7) this.fillBag(); const type = this.nextQueue.shift()!; this.piece = new Piece(type); - // If spawn collides immediately -> game over if (this.collides(this.piece)) { this.isGameOver = true; } @@ -374,12 +385,11 @@ export default class extends Aview { let y: number = 0; while (true) { for (const cell of piece.getCells()) { - console.log(cell.y + y); if ( cell.y + y >= ROWS || (cell.y + y >= 0 && this.board[cell.y + y][cell.x]) ) - return y - 1; + return y - 1; } y++; @@ -388,11 +398,12 @@ export default class extends Aview { lockPiece() { if (!this.piece) return; + this.isLocking = false; let isValid: boolean = false; for (const cell of this.piece.getCells()) { if (cell.y >= 0 && cell.y < ROWS && cell.x >= 0 && cell.x < COLS) this.board[cell.y][cell.x] = cell.val; - if (cell.y < 20) isValid = true; + if (cell.y > 0) isValid = true; } if (!isValid) this.isGameOver = true; @@ -427,6 +438,8 @@ export default class extends Aview { rotatePiece(dir: "cw" | "ccw") { if (!this.piece) return; + if (this.isLocking && this.lockRotationCount < 15) + this.lockRotationCount++; // Try rotation with wall kicks const originalIndex = this.piece.rotationIndex; if (dir === "cw") this.piece.rotateCW(); @@ -446,6 +459,7 @@ export default class extends Aview { if (!this.piece) return; this.piece.x += dx; this.piece.y += dy; + if (this.collides(this.piece)) { this.piece.x -= dx; this.piece.y -= dy; @@ -470,6 +484,26 @@ export default class extends Aview { } keys: Record = {}; + direction: number = 0; + inputDelay = 200; + inputTimestamp = Date.now(); + move: boolean = false; + + inputManager() { + if (this.move || Date.now() > this.inputTimestamp + this.inputDelay) + { + if (this.keys["ArrowLeft"] && !this.keys["ArrowRight"]) + this.movePiece(-1, 0); + else if (!this.keys["ArrowLeft"] && this.keys["ArrowRight"]) + this.movePiece(1, 0); + else if (this.keys["ArrowLeft"] && this.keys["ArrowRight"]) + this.movePiece(this.direction, 0); + this.move = false; + } + + /*if (this.keys["ArrowDown"]) + this.softDrop();*/ + } registerListeners() { window.addEventListener("keydown", (e) => { @@ -482,8 +516,18 @@ export default class extends Aview { if (this.isPaused) return; - if (e.key === "ArrowLeft") this.movePiece(-1, 0); - else if (e.key === "ArrowRight") this.movePiece(1, 0); + if (e.key === "ArrowLeft") + { + this.inputTimestamp = Date.now(); + this.direction = -1;//this.movePiece(-1, 0); + this.move = true; + } + else if (e.key === "ArrowRight") + { + this.inputTimestamp = Date.now(); + this.direction = 1;//this.movePiece(1, 0); + this.move = true; + } else if (e.key === "ArrowDown") this.softDrop(); else if (e.code === "Space") { e.preventDefault(); @@ -504,9 +548,25 @@ export default class extends Aview { loop(timestamp: number) { if (!this.lastDrop) this.lastDrop = timestamp; - if (!this.isPaused && !this.isGameOver) { - if (timestamp - this.lastDrop > this.dropInterval) { - if (!this.movePiece(0, 1)) this.lockPiece(); + if (!this.isPaused && !this.isGameOver) + { + this.inputManager(); + if (this.isLocking ? timestamp - this.lastDrop > 500 : timestamp - this.lastDrop > this.dropInterval) + { + if (this.isLocking && this.lockRotationCount == this.lockLastRotationCount) + this.lockPiece(); + this.lockLastRotationCount = this.lockRotationCount; + if (!this.movePiece(0, 1)) + { + if (!this.isLocking) + { + this.lockRotationCount = 0; + this.lockLastRotationCount = 0; + this.isLocking = true; + } + } + else if (this.isLocking) + this.lockRotationCount = 0; this.lastDrop = timestamp; } } @@ -516,6 +576,8 @@ export default class extends Aview { drawGrid() { const ctx = this.ctx; + if (!ctx || !this.canvas) + return; ctx.clearRect(0, 0, this.canvas.width, this.canvas.height); ctx.strokeStyle = "#222"; for (let r = 0; r <= ROWS; r++) { @@ -556,7 +618,7 @@ export default class extends Aview { } drawHold() { - if (!this.holdPiece) return; + if (!this.holdPiece || !this.holdCtx) return; this.holdCtx.clearRect(0, 0, 200, 200); let y: number = 0; @@ -567,6 +629,7 @@ export default class extends Aview { this.holdCtx.fillStyle = this.canHold ? COLORS[this.holdPiece.findColorIndex()] : "gray"; + console.log(this.holdCtx.fillStyle); this.holdCtx.fillRect( x * BLOCK + 1 + @@ -584,9 +647,9 @@ export default class extends Aview { } drawQueue() { + if (!this.queueCtx) return ; this.queueCtx.clearRect(0, 0, 500, 500); let placement: number = 0; - console.log(this.nextQueue.slice(0, 5)); for (const nextPiece of this.nextQueue.slice(0, 5)) { let y: number = 0; for (const row of TETROMINOES[nextPiece][0]) { @@ -620,22 +683,26 @@ export default class extends Aview { } fillBlock(x: number, y: number, color: string) { + if (!this.ctx) return; const ctx = this.ctx; ctx.fillStyle = color; ctx.fillRect(x * BLOCK + 1, y * BLOCK + 1, BLOCK - 2, BLOCK - 2); } fillGhostBlock(x: number, y: number, color: string) { + if (!this.ctx) return; const ctx = this.ctx; ctx.strokeStyle = color; ctx.strokeRect(x * BLOCK + 1, y * BLOCK + 1, BLOCK - 2, BLOCK - 2); } clearBlock(x: number, y: number) { + if (!this.ctx) return; const ctx = this.ctx; ctx.clearRect(x * BLOCK + 1, y * BLOCK + 1, BLOCK - 2, BLOCK - 2); } drawHUD() { + if (!this.ctx || !this.canvas) return; const ctx = this.ctx; ctx.fillStyle = "rgba(0,0,0,0.6)"; ctx.fillRect(4, 4, 120, 60); @@ -675,6 +742,7 @@ export default class extends Aview { } draw() { + if (!this.ctx || !this.canvas) return; // clear everything this.ctx.clearRect(0, 0, this.canvas.width, this.canvas.height); @@ -698,6 +766,7 @@ export default class extends Aview { this.drawBoard(); this.drawPiece(); this.drawHUD(); + this.drawQueue(); } }