From 533853eaa3ffdb3d278ce7730a0012dfbc6b3fd1 Mon Sep 17 00:00:00 2001 From: Rose Hogenson Date: Wed, 23 Oct 2024 18:11:33 -0700 Subject: Use tabs. --- static/pong/pong.js | 500 ++++++++++++++++++++++++++-------------------------- static/styles.css | 43 ++--- 2 files changed, 272 insertions(+), 271 deletions(-) diff --git a/static/pong/pong.js b/static/pong/pong.js index b91cb06..b8bdc2d 100644 --- a/static/pong/pong.js +++ b/static/pong/pong.js @@ -6,281 +6,281 @@ const canvas = document.getElementById("pong"); const ctx = canvas.getContext("2d"); class Vector2 { - constructor(x, y) { - this.x = x; - this.y = y; - } - - add(v) { - return new Vector2(this.x + v.x, this.y + v.y); - } + constructor(x, y) { + this.x = x; + this.y = y; + } + + add(v) { + return new Vector2(this.x + v.x, this.y + v.y); + } } class Rect { - constructor(x, y, w, h) { - this.x = x; - this.y = y; - this.w = w; - this.h = h; - } - - bottom() { - return this.y + this.h; - } - - right() { - return this.x + this.w; - } - - intersects(r) { - return r.x <= this.right() && r.right() >= this.x && r.y <= this.bottom() && r.bottom() >= this.y; - } - - fill() { - ctx.clearRect(this.x, this.y, this.w, this.h); - } + constructor(x, y, w, h) { + this.x = x; + this.y = y; + this.w = w; + this.h = h; + } + + bottom() { + return this.y + this.h; + } + + right() { + return this.x + this.w; + } + + intersects(r) { + return r.x <= this.right() && r.right() >= this.x && r.y <= this.bottom() && r.bottom() >= this.y; + } + + fill() { + ctx.clearRect(this.x, this.y, this.w, this.h); + } } const digitSegments = [0x77, 0x24, 0x5d, 0x6d, 0x2e, 0x6b, 0x7b, 0x25, 0x7f, 0x6f]; function drawNumber(n, x, y) { - const width = 60; - const height = 100; - const thickness = 10; - const padding = 20; - - const digits = n.toString(); - for (let i = 0; i < digits.length; i++) { - const segments = digitSegments[digits[i] - '0']; - for (let j = 0; j < 7; j++) { - if ((segments & 1 << j) === 0) { - continue; - } - switch (j) { - case 0: - new Rect(x, y, width, thickness).fill(); - break; - case 1: - new Rect(x, y, thickness, height / 2).fill(); - break; - case 2: - new Rect(x + width - thickness, y, thickness, height / 2).fill(); - break; - case 3: - new Rect(x, y + height / 2 - thickness / 2, width, thickness).fill(); - break; - case 4: - new Rect(x, y + height / 2, thickness, height / 2).fill(); - break; - case 5: - new Rect(x + width - thickness, y + height / 2, thickness, height / 2).fill(); - break; - case 6: - new Rect(x, y + height - thickness, width, thickness).fill(); - break; - } - } - x += width + padding; - } + const width = 60; + const height = 100; + const thickness = 10; + const padding = 20; + + const digits = n.toString(); + for (let i = 0; i < digits.length; i++) { + const segments = digitSegments[digits[i] - '0']; + for (let j = 0; j < 7; j++) { + if ((segments & 1 << j) === 0) { + continue; + } + switch (j) { + case 0: + new Rect(x, y, width, thickness).fill(); + break; + case 1: + new Rect(x, y, thickness, height / 2).fill(); + break; + case 2: + new Rect(x + width - thickness, y, thickness, height / 2).fill(); + break; + case 3: + new Rect(x, y + height / 2 - thickness / 2, width, thickness).fill(); + break; + case 4: + new Rect(x, y + height / 2, thickness, height / 2).fill(); + break; + case 5: + new Rect(x + width - thickness, y + height / 2, thickness, height / 2).fill(); + break; + case 6: + new Rect(x, y + height - thickness, width, thickness).fill(); + break; + } + } + x += width + padding; + } } class Ball { - constructor() { - this.reset('left'); - } - - bounds() { - const ballSize = 30; - - return new Rect( - this.pos.x - ballSize / 2, - this.pos.y - ballSize / 2, - ballSize, - ballSize, - ); - } - - predictIntersection(targetX) { - if (this.velocity.x <= 0) { - return null; - } - const dist = targetX - this.pos.x; - const prediction = this.pos.y + this.velocity.y * dist / this.velocity.x; - if (prediction < 0) { - const bounces = Math.floor(-prediction / canvas.height); - if (bounces % 2 === 0) { - return -prediction - canvas.height * bounces; - } - return prediction + canvas.height * (bounces + 1); - } - if (prediction > canvas.height) { - const bounces = Math.floor(prediction / canvas.height); - if (bounces % 2 === 0) { - return prediction - canvas.height * bounces; - } - return -prediction + canvas.height * (bounces + 1); - } - return prediction; - } - - reset(side) { - this.pos = new Vector2(canvas.width / 2, canvas.height / 2); - this.velocity = new Vector2(ballSpeed, 0); - if (side === 'left') { - this.velocity.x = -this.velocity.x; - } - } + constructor() { + this.reset('left'); + } + + bounds() { + const ballSize = 30; + + return new Rect( + this.pos.x - ballSize / 2, + this.pos.y - ballSize / 2, + ballSize, + ballSize, + ); + } + + predictIntersection(targetX) { + if (this.velocity.x <= 0) { + return null; + } + const dist = targetX - this.pos.x; + const prediction = this.pos.y + this.velocity.y * dist / this.velocity.x; + if (prediction < 0) { + const bounces = Math.floor(-prediction / canvas.height); + if (bounces % 2 === 0) { + return -prediction - canvas.height * bounces; + } + return prediction + canvas.height * (bounces + 1); + } + if (prediction > canvas.height) { + const bounces = Math.floor(prediction / canvas.height); + if (bounces % 2 === 0) { + return prediction - canvas.height * bounces; + } + return -prediction + canvas.height * (bounces + 1); + } + return prediction; + } + + reset(side) { + this.pos = new Vector2(canvas.width / 2, canvas.height / 2); + this.velocity = new Vector2(ballSpeed, 0); + if (side === 'left') { + this.velocity.x = -this.velocity.x; + } + } } class Paddle { - constructor(side) { - this.pos = canvas.height / 2; - this.side = side; - } - - bounds() { - const paddleHeight = 200; - const thickness = 10; - const padding = 100; - - let r = new Rect( - padding - thickness / 2, - this.pos - paddleHeight / 2, - thickness, - paddleHeight, - ); - if (this.side === 'right') { - r.x = canvas.width - padding - thickness / 2; - } - return r; - } + constructor(side) { + this.pos = canvas.height / 2; + this.side = side; + } + + bounds() { + const paddleHeight = 200; + const thickness = 10; + const padding = 100; + + let r = new Rect( + padding - thickness / 2, + this.pos - paddleHeight / 2, + thickness, + paddleHeight, + ); + if (this.side === 'right') { + r.x = canvas.width - padding - thickness / 2; + } + return r; + } } function updateCanvasSize() { - canvas.width = window.innerWidth; - canvas.height = window.innerHeight; + canvas.width = window.innerWidth; + canvas.height = window.innerHeight; } const pingAudio = new Audio('/static/pong/ping.mp3'); function ping() { - pingAudio.pause(); - pingAudio.currentTime = 0; - pingAudio.play(); + pingAudio.pause(); + pingAudio.currentTime = 0; + pingAudio.play(); } function main() { - updateCanvasSize(); - - let playerScore = 0; - let aiScore = 0; - - const ball = new Ball(); - - const paddle1 = new Paddle('left'); - const paddle2 = new Paddle('right'); - - const keys = {}; - window.addEventListener('keydown', (e) => keys[e.key] = true); - window.addEventListener('keyup', (e) => delete keys[e.key]); - let mousePressed = false; - let mouseY = 0; - window.addEventListener('mousedown', () => mousePressed = true); - window.addEventListener('mouseup', () => mousePressed = false); - window.addEventListener('mousemove', (e) => mouseY = e.y); - let touchPressed = false; - let touchY = 0; - window.addEventListener('touchstart', (e) => { - touchPressed = true; - if (e.changedTouches.length > 0) { - touchY = e.changedTouches[0].clientY; - } - }); - window.addEventListener('touchmove', (e) => { - touchPressed = true; - if (e.changedTouches.length > 0) { - touchY = e.changedTouches[0].clientY; - } - }); - window.addEventListener('touchend', () => touchPressed = false); - window.addEventListener('touchcancel', () => touchPressed = false); - - let lastFrameTime = performance.now(); - let accumulator = 0; - - function gameLoop() { - updateCanvasSize(); - - const now = performance.now(); - const frameTime = now - lastFrameTime; - lastFrameTime = now; - accumulator += frameTime; - - const simulationSpeed = 1000 / ticksPerSecond; - for (; accumulator >= simulationSpeed; accumulator -= simulationSpeed) { - if ((keys["w"] || keys["ArrowUp"] || mousePressed && paddle1.pos >= mouseY + paddleSpeed || touchPressed && paddle1.pos >= touchY + paddleSpeed) && paddle1.bounds().y >= 0) { - paddle1.pos -= paddleSpeed; - } else if ((keys["s"] || keys["ArrowDown"] || mousePressed && paddle1.pos <= mouseY - paddleSpeed || touchPressed && paddle1.pos <= touchY - paddleSpeed) && paddle1.bounds().bottom() <= canvas.height) { - paddle1.pos += paddleSpeed; - } - - const prediction = ball.predictIntersection(paddle2.bounds().x); - if (prediction !== null) { - if (paddle2.pos <= prediction - paddleSpeed && paddle2.bounds().bottom() <= canvas.height) { - paddle2.pos += paddleSpeed; - } else if (paddle2.pos >= prediction + paddleSpeed && paddle2.bounds().y >= 0) { - paddle2.pos -= paddleSpeed; - } - } - - ball.pos = ball.pos.add(ball.velocity); - if (ball.bounds().intersects(paddle1.bounds()) && ball.velocity.x <= 0) { - ping(); - let d = (ball.pos.y - paddle1.pos) / (paddle1.bounds().h / 2 + ball.bounds().h); - if (d < 0) { - d = -d; - } - let angle = d * 75 * 2 * Math.PI / 360; - if (ball.pos.y < paddle1.pos) { - angle = -angle; - } - const speed = ballSpeed * (1 + 4 * d); - ball.velocity = new Vector2(speed * Math.cos(angle), speed * Math.sin(angle)); - } else if (ball.bounds().intersects(paddle2.bounds()) && ball.velocity.x >= 0) { - ping(); - let d = (ball.pos.y - paddle2.pos) / (paddle2.bounds().h / 2 + ball.bounds().h); - if (d < 0) { - d = -d; - } - let angle = d * 75 * 2 * Math.PI / 360; - if (ball.pos.y < paddle2.pos) { - angle = -angle; - } - angle += Math.PI; - const speed = ballSpeed * (1 + 4 * d); - ball.velocity = new Vector2(speed * Math.cos(angle), speed * Math.sin(angle)); - } else if (ball.bounds().right() <= 0) { - aiScore++; - ball.reset('right'); - } else if (ball.bounds().x >= canvas.width) { - playerScore++; - ball.reset('left'); - } else if (ball.bounds().y <= 0 && ball.velocity.y < 0 || ball.bounds().bottom() >= canvas.height && ball.velocity.y > 0) { - ping(); - ball.velocity.y = -ball.velocity.y; - } - } - - ctx.fillRect(0, 0, canvas.width, canvas.height); - paddle1.bounds().fill(); - paddle2.bounds().fill(); - ball.bounds().fill(); - drawNumber(playerScore, 150, 30) - drawNumber(aiScore, canvas.width / 2 + 150, canvas.height - 130); - - requestAnimationFrame(gameLoop); - } - gameLoop(); + updateCanvasSize(); + + let playerScore = 0; + let aiScore = 0; + + const ball = new Ball(); + + const paddle1 = new Paddle('left'); + const paddle2 = new Paddle('right'); + + const keys = {}; + window.addEventListener('keydown', (e) => keys[e.key] = true); + window.addEventListener('keyup', (e) => delete keys[e.key]); + let mousePressed = false; + let mouseY = 0; + window.addEventListener('mousedown', () => mousePressed = true); + window.addEventListener('mouseup', () => mousePressed = false); + window.addEventListener('mousemove', (e) => mouseY = e.y); + let touchPressed = false; + let touchY = 0; + window.addEventListener('touchstart', (e) => { + touchPressed = true; + if (e.changedTouches.length > 0) { + touchY = e.changedTouches[0].clientY; + } + }); + window.addEventListener('touchmove', (e) => { + touchPressed = true; + if (e.changedTouches.length > 0) { + touchY = e.changedTouches[0].clientY; + } + }); + window.addEventListener('touchend', () => touchPressed = false); + window.addEventListener('touchcancel', () => touchPressed = false); + + let lastFrameTime = performance.now(); + let accumulator = 0; + + function gameLoop() { + updateCanvasSize(); + + const now = performance.now(); + const frameTime = now - lastFrameTime; + lastFrameTime = now; + accumulator += frameTime; + + const simulationSpeed = 1000 / ticksPerSecond; + for (; accumulator >= simulationSpeed; accumulator -= simulationSpeed) { + if ((keys["w"] || keys["ArrowUp"] || mousePressed && paddle1.pos >= mouseY + paddleSpeed || touchPressed && paddle1.pos >= touchY + paddleSpeed) && paddle1.bounds().y >= 0) { + paddle1.pos -= paddleSpeed; + } else if ((keys["s"] || keys["ArrowDown"] || mousePressed && paddle1.pos <= mouseY - paddleSpeed || touchPressed && paddle1.pos <= touchY - paddleSpeed) && paddle1.bounds().bottom() <= canvas.height) { + paddle1.pos += paddleSpeed; + } + + const prediction = ball.predictIntersection(paddle2.bounds().x); + if (prediction !== null) { + if (paddle2.pos <= prediction - paddleSpeed && paddle2.bounds().bottom() <= canvas.height) { + paddle2.pos += paddleSpeed; + } else if (paddle2.pos >= prediction + paddleSpeed && paddle2.bounds().y >= 0) { + paddle2.pos -= paddleSpeed; + } + } + + ball.pos = ball.pos.add(ball.velocity); + if (ball.bounds().intersects(paddle1.bounds()) && ball.velocity.x <= 0) { + ping(); + let d = (ball.pos.y - paddle1.pos) / (paddle1.bounds().h / 2 + ball.bounds().h); + if (d < 0) { + d = -d; + } + let angle = d * 75 * 2 * Math.PI / 360; + if (ball.pos.y < paddle1.pos) { + angle = -angle; + } + const speed = ballSpeed * (1 + 4 * d); + ball.velocity = new Vector2(speed * Math.cos(angle), speed * Math.sin(angle)); + } else if (ball.bounds().intersects(paddle2.bounds()) && ball.velocity.x >= 0) { + ping(); + let d = (ball.pos.y - paddle2.pos) / (paddle2.bounds().h / 2 + ball.bounds().h); + if (d < 0) { + d = -d; + } + let angle = d * 75 * 2 * Math.PI / 360; + if (ball.pos.y < paddle2.pos) { + angle = -angle; + } + angle += Math.PI; + const speed = ballSpeed * (1 + 4 * d); + ball.velocity = new Vector2(speed * Math.cos(angle), speed * Math.sin(angle)); + } else if (ball.bounds().right() <= 0) { + aiScore++; + ball.reset('right'); + } else if (ball.bounds().x >= canvas.width) { + playerScore++; + ball.reset('left'); + } else if (ball.bounds().y <= 0 && ball.velocity.y < 0 || ball.bounds().bottom() >= canvas.height && ball.velocity.y > 0) { + ping(); + ball.velocity.y = -ball.velocity.y; + } + } + + ctx.fillRect(0, 0, canvas.width, canvas.height); + paddle1.bounds().fill(); + paddle2.bounds().fill(); + ball.bounds().fill(); + drawNumber(playerScore, 150, 30) + drawNumber(aiScore, canvas.width / 2 + 150, canvas.height - 130); + + requestAnimationFrame(gameLoop); + } + gameLoop(); } main(); diff --git a/static/styles.css b/static/styles.css index 6902bd2..00e6d59 100644 --- a/static/styles.css +++ b/static/styles.css @@ -1,41 +1,42 @@ @font-face { - font-family: 'QuickLove'; - src: url('/static/QuickLove.woff2') format('woff2'), - url('/static/QuickLove.woff') format('woff'); - font-weight: normal; - font-style: normal; + font-family: 'QuickLove'; + src: + url('/static/QuickLove.woff2') format('woff2'), + url('/static/QuickLove.woff') format('woff'); + font-weight: normal; + font-style: normal; } body { - background: #f5f5f5; - font-size: 25px; + background: #f5f5f5; + font-size: 25px; } h1 { - font-size: 70px; - color: #ff69b4; - font-family: 'QuickLove'; + font-size: 70px; + color: #ff69b4; + font-family: 'QuickLove'; } section { - max-width: 800px; - margin: 0 auto 50px; - padding: 40px; - background: #fff0f5; - border: 5px solid #ff69b4; - border-radius: 15px; - box-shadow: 0 0 10px rgba(255, 105, 180, 0.5); + max-width: 800px; + margin: 0 auto 50px; + padding: 40px; + background: #fff0f5; + border: 5px solid #ff69b4; + border-radius: 15px; + box-shadow: 0 0 10px rgba(255, 105, 180, 0.5); } img { - border: 5px solid #ff69b4; - background: white; + border: 5px solid #ff69b4; + background: white; } a:link { - color: #ff69b4; + color: #ff69b4; } a:visited { - color: #a02090; + color: #a02090; } -- cgit v1.3.1