토론

AI 상대와의 퐁 게임

Wikiprompt, 무료 프롬프트 백과사전에서

Alex Prompter

2025년 8월 15일

AI 상대와의 퐁 게임 클래식 퐁 게임을 생성하는 프롬프트로, HTML, CSS, JavaScript를 사용하여 사용자 및 AI 제어 패들을 구현합니다.

프롬프트 내용저장

🌐
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Pong · user vs AI</title> <style> * { box-sizing: border-box; user-select: none; } body { margin: 0; min-height: 100vh; background: linear-gradient(145deg, #0b0e1a 0%, #1a1f2f 100%); display: flex; justify-content: center; align-items: center; font-family: 'Segoe UI', Roboto, system-ui, sans-serif; } .game-wrapper { background: #0f1322; padding: 1.5rem 2rem 2rem; border-radius: 3rem; box-shadow: 0 20px 30px rgba(0,0,0,0.6), inset 0 0 0 1px rgba(255,255,255,0.06); } canvas { display: block; margin: 0 auto; background: #0a0d18; border-radius: 2rem; box-shadow: 0 0 0 2px #2e3a5e, 0 15px 25px rgba(0,0,0,0.7); width: 800px; height: 500px; } .controls { display: flex; justify-content: space-between; align-items: center; margin-top: 1.2rem; color: #b7c6e8; font-weight: 500; letter-spacing: 0.5px; padding: 0 0.5rem; } .keys { background: #1d253a; padding: 0.4rem 1rem; border-radius: 3rem; font-size: 0.9rem; border: 1px solid #3f4d73; box-shadow: inset 0 2px 3px rgba(0,0,0,0.4); } .keys span { background: #0f1422; padding: 0.2rem 0.8rem; border-radius: 2rem; margin: 0 0.2rem; border: 1px solid #4c5b82; color: #dbe5ff; } .score-badge { background: #1d253a; padding: 0.4rem 1.6rem; border-radius: 3rem; font-size: 1.3rem; font-weight: 700; color: #eaf0ff; border: 1px solid #3f4d73; box-shadow: inset 0 2px 5px rgba(0,0,0,0.5); letter-spacing: 2px; } .ai-note { font-size: 0.8rem; opacity: 0.7; background: #1a2133; padding: 0.3rem 1rem; border-radius: 2rem; } </style> </head> <body> <div class="game-wrapper"> <canvas id="pongCanvas" width="800" height="500"></canvas> <div class="controls"> <div class="keys"> <span>▲</span> <span>▼</span> move </div> <div class="score-badge" id="scoreDisplay">0 : 0</div> <div class="ai-note">AI · right</div> </div> </div> <script> (function() { const canvas = document.getElementById('pongCanvas'); const ctx = canvas.getContext('2d'); const scoreDisplay = document.getElementById('scoreDisplay'); // ---------- GAME CONSTANTS ---------- const W = 800, H = 500; const PADDLE_WIDTH = 14; const PADDLE_HEIGHT = 90; const BALL_SIZE = 14; // square ball (classic feel) const PADDLE_SPEED = 6.2; // user paddle speed const AI_SPEED = 4.6; // AI paddle speed (slightly slower, human-like) const INITIAL_BALL_SPEED = 4.2; const MAX_BALL_SPEED = 9.5; const SPEED_INCREASE = 0.15; // per paddle hit // ---------- GAME STATE ---------- let leftPaddleY = H / 2 - PADDLE_HEIGHT / 2; let rightPaddleY = H / 2 - PADDLE_HEIGHT / 2; let ballX = W / 2 - BALL_SIZE / 2; let ballY = H / 2 - BALL_SIZE / 2; let ballSpeedX = INITIAL_BALL_SPEED * (Math.random() > 0.5 ? 1 : -1); let ballSpeedY = (Math.random() * 2 - 1) * 2.5; let leftScore = 0; let rightScore = 0; // ---------- INPUT ---------- let upPressed = false; let downPressed = false; // ---------- HELPER: RESET BALL ---------- function resetBall(direction = 1) { ballX = W / 2 - BALL_SIZE / 2; ballY = H / 2 - BALL_SIZE / 2; // random vertical component, but not too steep ballSpeedY = (Math.random() * 2 - 1) * 3.0; // direction: 1 -> to the right (AI), -1 -> to the left (user) ballSpeedX = INITIAL_BALL_SPEED * direction; // ensure not perfectly horizontal if (Math.abs(ballSpeedY) < 0.8) ballSpeedY = 1.2 * (Math.random() > 0.5 ? 1 : -1); } // ---------- AI: follow ball ---------- function updateAI() { // ball center const ballCenterY = ballY + BALL_SIZE / 2; const paddleCenterY = rightPaddleY + PADDLE_HEIGHT / 2; // only move if ball is moving towards AI (right) or if ball is on right side // classic: always follow, but with max speed const diff = ballCenterY - paddleCenterY; // dead zone to avoid jitter if (Math.abs(diff) > 4) { if (diff > 0) { rightPaddleY = Math.min(H - PADDLE_HEIGHT, rightPaddleY + AI_SPEED); } else if (diff < 0) { rightPaddleY = Math.max(0, rightPaddleY - AI_SPEED); } } // extra: if ball is moving away, still track slowly (but we already do) // clamp just in case rightPaddleY = Math.max(0, Math.min(H - PADDLE_HEIGHT, rightPaddleY)); } // ---------- COLLISION & PHYSICS ---------- function updateBall() { // move ball ballX += ballSpeedX; ballY += ballSpeedY; // top / bottom walls if (ballY <= 0) { ballY = 0; ballSpeedY = -ballSpeedY; } else if (ballY + BALL_SIZE >= H) { ballY = H - BALL_SIZE; ballSpeedY = -ballSpeedY; } // paddle collision (left paddle) // left paddle rect const leftRect = { x: 0, y: leftPaddleY, w: PADDLE_WIDTH, h: PADDLE_HEIGHT }; // right paddle rect const rightRect = { x: W - PADDLE_WIDTH, y: rightPaddleY, w: PADDLE_WIDTH, h: PADDLE_HEIGHT }; // ball rect const ballRect = { x: ballX, y: ballY, w: BALL_SIZE, h: BALL_SIZE }; // helper: AABB collision function rectsOverlap(r1, r2) { return !(r2.x > r1.x + r1.w || r2.x + r2.w < r1.x || r2.y > r1.y + r1.h || r2.y + r2.h < r1.y); } // LEFT paddle collision (only if ball moving left) if (ballSpeedX < 0 && rectsOverlap(ballRect, leftRect)) { // adjust position to avoid sticking ballX = leftRect.x + leftRect.w; // reflect horizontal ballSpeedX = -ballSpeedX; // add slight speed up ballSpeedX = Math.sign(ballSpeedX) * Math.min(Math.abs(ballSpeedX) + SPEED_INCREASE, MAX_BALL_SPEED); // add spin based on hit position const hitOffset = (ballY + BALL_SIZE/2) - (leftPaddleY + PADDLE_HEIGHT/2); ballSpeedY = hitOffset * 0.18; // clamp vertical speed ballSpeedY = Math.max(-7, Math.min(7, ballSpeedY)); } // RIGHT paddle collision (only if ball moving right) if (ballSpeedX > 0 && rectsOverlap(ballRect, rightRect)) { // adjust position ballX = rightRect.x - BALL_SIZE; ballSpeedX = -ballSpeedX; ballSpeedX = Math.sign(ballSpeedX) * Math.min(Math.abs(ballSpeedX) + SPEED_INCREASE, MAX_BALL_SPEED); const hitOffset = (ballY + BALL_SIZE/2) - (rightPaddleY + PADDLE_HEIGHT/2); ballSpeedY = hitOffset * 0.18; ballSpeedY = Math.max(-7, Math.min(7, ballSpeedY)); } // scoring (left/right out) if (ballX + BALL_SIZE < 0) { // right scores rightScore++; updateScore(); resetBall(-1); // ball goes to left (towards user) } else if (ballX > W) { // left scores leftScore++; updateScore(); resetBall(1); // ball goes to right (towards AI) } // extra safety: keep ball within vertical bounds (already done) } // ---------- UPDATE SCORE UI ---------- function updateScore() { scoreDisplay.textContent = `${leftScore} : ${rightScore}`; } // ---------- USER PADDLE MOVEMENT ---------- function updateUserPaddle() { if (upPressed) { leftPaddleY = Math.max(0, leftPaddleY - PADDLE_SPEED); } if (downPressed) { leftPaddleY = Math.min(H - PADDLE_HEIGHT, leftPaddleY + PADDLE_SPEED); } } // ---------- DRAW EVERYTHING ---------- function draw() { ctx.clearRect(0, 0, W, H); // background grid (subtle) ctx.fillStyle = '#0a0d18'; ctx.fillRect(0, 0, W, H); // center dashed line ctx.strokeStyle = '#2f3c5f'; ctx.lineWidth = 3; ctx.setLineDash([12, 18]); ctx.beginPath(); ctx.moveTo(W/2, 0); ctx.lineTo(W/2, H); ctx.stroke(); ctx.setLineDash([]); // reset // center circle ctx.beginPath(); ctx.arc(W/2, H/2, 40, 0, Math.PI * 2); ctx.strokeStyle = '#2f3c5f'; ctx.lineWidth = 3; ctx.stroke(); // left paddle (user) - cyan glow ctx.shadowColor = '#4cc9f0'; ctx.shadowBlur = 18; ctx.fillStyle = '#8ecae6'; ctx.fillRect(0, leftPaddleY, PADDLE_WIDTH, PADDLE_HEIGHT); ctx.shadowBlur = 0; // right paddle (AI) - red/orange glow ctx.shadowColor = '#ff9e5e'; ctx.shadowBlur = 18; ctx.fillStyle = '#f4a261'; ctx.fillRect(W - PADDLE_WIDTH, rightPaddleY, PADDLE_WIDTH, PADDLE_HEIGHT); ctx.shadowBlur = 0; // ball (white with glow) ctx.shadowColor = '#ffffff'; ctx.shadowBlur = 20; ctx.fillStyle = '#f8f9fa'; ctx.fillRect(ballX, ballY, BALL_SIZE, BALL_SIZE); ctx.shadowBlur = 0; // small reflection (optional) ctx.fillStyle = 'rgba(255,255,255,0.1)'; ctx.fillRect(ballX + 2, ballY + 2, BALL_SIZE - 4, BALL_SIZE - 4); } // ---------- GAME LOOP ---------- function gameLoop() { // update user paddle updateUserPaddle(); // update AI updateAI(); // update ball physics + collisions updateBall(); // draw draw(); requestAnimationFrame(gameLoop); } // ---------- EVENT LISTENERS ---------- window.addEventListener('keydown', (e) => { // prevent arrow scrolling if (e.key === 'ArrowUp' || e.key === 'ArrowDown' || e.key === ' ') { e.preventDefault(); } if (e.key === 'ArrowUp') upPressed = true; if (e.key === 'ArrowDown') downPressed = true; }); window.addEventListener('keyup', (e) => { if (e.key === 'ArrowUp') upPressed = false; if (e.key === 'ArrowDown') downPressed = false; }); // prevent page move on touch / space (extra) window.addEventListener('keydown', (e) => { if (e.key === ' ' || e.key === 'ArrowUp' || e.key === 'ArrowDown') { e.preventDefault(); } }, { passive: false }); // initial score display updateScore(); // start the loop gameLoop(); })(); </script> </body> </html>

전체 프롬프트를 보려면 로그인하세요

Continue with:

By logging in, you agree to our Terms of Use and Privacy Policy

사용법

이 프롬프트는 coding와 함께 사용하도록 설계되었습니다. 위의 프롬프트 내용을 복사하여 원하는 AI 도구에 붙여넣으세요.

최상의 결과를 얻으려면 자리 표시자(대괄호 또는 대문자로 표시)를 특정 요구 사항으로 사용자 지정할 수 있습니다.

참고 자료

분류:coding| twitter| pong-game| html-css-js

토론