import Aview from "./Aview.ts" import { isLogged } from "../main.js" import { dragElement } from "./drag.js" import { setOnekoState, setBallPos, setOnekoOffset } from "../oneko.ts" export default class extends Aview { running: boolean; constructor() { super(); this.setTitle("pong (local match)"); this.running = true; setOnekoState("default"); } async getHTML() { return `
pong_game.ts
×
`; } async run() { dragElement(document.getElementById("window")); let uuid: string; let start: number = 0; let elapsed: number; let game_playing: boolean = false; let match_over: boolean = false; let p1_score: number = 0; let p2_score: number = 0; let p1_name: string; let p2_name: string; let countdown: number = 3; let countdownTimer: number = 0; let canvas; let ctx; const paddleOffset: number = 15; const paddleHeight: number = 100; const paddleWidth: number = 10; const ballSize: number = 10; const paddleSpeed: number = 727 * 0.69; let leftPaddleY: number; let rightPaddleY: number; let ballX: number; let ballY: number; let ballSpeed: number = 200; let ballSpeedX: number = 300; let ballSpeedY: number = 10; const keys: Record = {}; document.addEventListener("keydown", e => { keys[e.key] = true; }); document.addEventListener("keyup", e => { keys[e.key] = false; }); function movePaddles() { if ((keys["w"] || keys["W"]) && leftPaddleY > 0) leftPaddleY -= paddleSpeed * elapsed; if ((keys["s"] || keys["S"]) && leftPaddleY < canvas.height - paddleHeight) leftPaddleY += paddleSpeed * elapsed; if (keys["ArrowUp"] && rightPaddleY > 0) rightPaddleY -= paddleSpeed * elapsed; if (keys["ArrowDown"] && rightPaddleY < canvas.height - paddleHeight) rightPaddleY += paddleSpeed * elapsed; } function getBounceVelocity(paddleY) { const speed = ballSpeed; const paddleCenterY = paddleY + paddleHeight / 2; let n = (ballY - paddleCenterY) / (paddleHeight / 2); n = Math.max(-1, Math.min(1, n)); let theta = n * ((75 * Math.PI) / 180); ballSpeedY = ballSpeed * Math.sin(theta); } async function moveBall() { let length = Math.sqrt(ballSpeedX * ballSpeedX + ballSpeedY * ballSpeedY); let scale = ballSpeed / length; ballX += (ballSpeedX * scale) * elapsed; ballY += (ballSpeedY * scale) * elapsed; if (ballY <= 0 || ballY >= canvas.height - ballSize) ballSpeedY *= -1; if (ballX <= paddleWidth + paddleOffset && ballX >= paddleOffset && ballY > leftPaddleY && ballY < leftPaddleY + paddleHeight) { ballSpeedX *= -1; ballX = paddleWidth + paddleOffset; getBounceVelocity(leftPaddleY); ballSpeed += 10; } if (ballX >= canvas.width - paddleWidth - ballSize - paddleOffset && ballX <= canvas.width - ballSize - paddleOffset && ballY > rightPaddleY && ballY < rightPaddleY + paddleHeight) { ballSpeedX *= -1; ballX = canvas.width - paddleWidth - ballSize - paddleOffset; getBounceVelocity(rightPaddleY); ballSpeed += 10; } // scoring if (ballX < 0 || ballX > canvas.width - ballSize) { setOnekoState("default"); game_playing = false; if (ballX < 0) p2_score++; else p1_score++; 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?game=pong`, { method: "POST", headers: { "Content-Type": "application/json", }, credentials: "include", body: JSON.stringify({ "game": "pong", "opponent": p2_name, "myScore": p1_score, "opponentScore": p2_score, "date": Date.now(), }), }); } match_over = true; } else { countdown = 3; countdownTimer = performance.now(); } ballX = canvas.width / 2; ballY = canvas.height / 2; ballSpeed = 200; ballSpeedX = 300 * ((ballSpeedX > 0) ? 1 : -1); ballSpeedY = 10; ballSpeedX = -ballSpeedX; leftPaddleY = canvas.height / 2 - paddleHeight / 2; rightPaddleY = canvas.height / 2 - paddleHeight / 2; } setBallPos(ballX, ballY); } function draw() { ctx.fillStyle = "black"; ctx.fillRect(0, 0, canvas.width, canvas.height); ctx.strokeStyle = "white"; ctx.beginPath(); ctx.setLineDash([5, 10]); ctx.moveTo(canvas.width / 2, 0); ctx.lineTo(canvas.width / 2, canvas.height); ctx.stroke(); ctx.fillStyle = "white"; ctx.fillRect(paddleOffset, leftPaddleY, paddleWidth, paddleHeight); ctx.fillRect(canvas.width - paddleWidth - paddleOffset, rightPaddleY, paddleWidth, paddleHeight); ctx.fillStyle = "white"; if (game_playing) ctx.fillRect(ballX, ballY, ballSize, ballSize); ctx.font = "24px Kubasta"; let text_score = `${p1_score} - ${p2_score}`; ctx.fillText(text_score, canvas.width / 2 - (ctx.measureText(text_score).width / 2), 25); ctx.fillText(p1_name, canvas.width / 4 - (ctx.measureText(p1_name).width / 2), 45); ctx.fillText(p2_name, (canvas.width / 4 * 3) - (ctx.measureText(p2_name).width / 2), 45); if (match_over) { ctx.font = "32px Kubasta"; const winner = `${p1_score > p2_score ? p1_name : p2_name} won :D`; ctx.fillText(winner, canvas.width / 2 - (ctx.measureText(winner).width / 2), canvas.height / 2 + 16); document.getElementById("game-buttons").classList.remove("hidden"); } } function startCountdown() { const now = performance.now(); if (countdown > 0) { if (now - countdownTimer >= 500) { countdown--; countdownTimer = now; } ctx.font = "48px Kubasta"; ctx.fillText(countdown.toString(), canvas.width / 2 - 10, canvas.height / 2 + 24); } else if (countdown === 0) { ctx.font = "48px Kubasta"; ctx.fillText("Go!", canvas.width / 2 - 30, canvas.height / 2 + 24); setTimeout(() => { game_playing = true; countdown = -1; }, 500); } } const gameLoop = async (timestamp: number) => { elapsed = (timestamp - start) / 1000; start = timestamp; if (game_playing) { movePaddles(); await moveBall(); } draw(); if (!game_playing) startCountdown(); if (this.running) requestAnimationFrame(gameLoop); }; document.getElementById("game-retry")?.addEventListener("click", () => { setOnekoState("pong"); document.getElementById("game-buttons").classList.add("hidden"); game_playing = false; match_over = false; p1_score = 0; p2_score = 0; countdown = 3; countdownTimer = performance.now(); }); let p1_input = document.getElementById("player1"); let p2_input = document.getElementById("player2"); p2_input.value = "Player 2"; if (await isLogged()) { 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.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"); canvas.id = "gameCanvas"; canvas.classList.add("reverse-border"); document.getElementById("main-div").prepend(canvas); ctx = canvas.getContext("2d", {alpha: false}); ctx.canvas.width = 600; ctx.canvas.height = 600; leftPaddleY = canvas.height / 2 - paddleHeight / 2; rightPaddleY = canvas.height / 2 - paddleHeight / 2; ballX = canvas.width / 2; ballY = canvas.height / 2; setOnekoState("pong"); setOnekoOffset(); requestAnimationFrame(gameLoop); }); } }