Discover amazing projects created by our talented students. Like, love, and star your favorites!
William Tedjosaputro
3 months ago
Wah, mantap! 😄 Jadi konsep gamenya: 🕹️ Judul: Flapy Jump 🎯 Tujuan: Jangan kena pipa, kalau kenaimport pygame, sys, random pygame.init() lebar, tinggi = 400, 600 layar = pygame.display.set_mode((lebar, tinggi)) clock = pygame.time.Clock() font = pygame.font.SysFont(None, 48) # Warna biru = (135, 206, 235) hijau = (0, 200, 0) kuning = (255, 255, 0) # Karakter burung = pygame.Rect(100, tinggi//2, 34, 24) gravitasi = 0 pipa_list = [] score = 0 def buat_pipa(): tinggi_pipa = random.randint(150, 450) bawah = pygame.Rect(lebar, tinggi_pipa, 52, tinggi - tinggi_pipa) atas = pygame.Rect(lebar, tinggi_pipa - 150 - 320, 52, 320) return atas, bawah def gerak_pipa(pipa_list): for pipa in pipa_list: pipa.centerx -= 3 return [p for p in pipa_list if p.right > 0] def tampil_score(): teks = font.render(str(score), True, (0, 0, 0)) layar.blit(teks, (lebar//2 - teks.get_width()//2, 50)) pipa_timer = pygame.USEREVENT + 1 pygame.time.set_timer(pipa_timer, 1400) # Loop utama jalan = True while jalan: for event in pygame.event.get(): if event.type == pygame.QUIT: pygame.quit() sys.exit() if event.type == pygame.KEYDOWN: if event.key == pygame.K_SPACE: gravitasi = -7 if event.type == pipa_timer: pipa_list.extend(buat_pipa()) # Fisika burung gravitasi += 0.4 burung.y += gravitasi # Gerak pipa pipa_list = gerak_pipa(pipa_list) # Deteksi tabrakan for p in pipa_list: if burung.colliderect(p): pygame.quit() sys.exit() if burung.top <= 0 or burung.bottom >= tinggi: pygame.quit() sys.exit() # Skor for p in pipa_list: if p.centerx == burung.centerx: score += 1 # Gambar layar.fill(biru) pygame.draw.rect(layar, kuning, burung) for p in pipa_list: pygame.draw.rect(layar, hijau, p) tampil_score() pygame.display.update() clock.tick(60) kalahpygame.init() lebar, tinggi = 400, 600 layar = pygame.display.set_mode((lebar, tinggi)) clock = pygame.time.Clock() font = pygame.font.SysFont(None, 48) biru = (135, 206, 235) hijau = (0, 200, 0) kuning = (255, 255, 0) burung = pygame.Rect(100, tinggi//2, 34, 24) gravitasi = 0 pipa_list = [] score = 0 # ====== HIGH SCORE SYSTEM ====== HIGH_SCORE_FILE = "highscore.txt" def load_high_score(): if os.path.exists(HIGH_SCORE_FILE): with open(HIGH_SCORE_FILE, "r") as f: try: return int(f.read()) except: return 0 return 0 def save_high_score(skor): with open(HIGH_SCORE_FILE, "w") as f: f.write(str(skor)) high_score = load_high_score() # ====== GAME FUNCTIONS ====== def buat_pipa(): tinggi_pipa = random.randint(150, 450) bawah = pygame.Rect(lebar, tinggi_pipa, 52, tinggi - tinggi_pipa) atas = pygame.Rect(lebar, tinggi_pipa - 150 - 320, 52, 320) return atas, bawah def gerak_pipa(pipa_list): for pipa in pipa_list: pipa.centerx -= 3 return [p for p in pipa_list if p.right > 0] def tampil_score(): teks = font.render(f"{score}", True, (0, 0, 0)) layar.blit(teks, (lebar//2 - teks.get_width()//2, 50)) hs_teks = pygame.font.SysFont(None, 28).render(f"High Score: {high_score}", True, (0, 0, 0)) layar.blit(hs_teks, (10, 10)) # ====== GAME LOOP ====== pipa_timer = pygame.USEREVENT + 1 pygame.time.set_timer(pipa_timer, 1400) while True: for event in pygame.event.get(): if event.type == pygame.QUIT: pygame.quit() sys.exit() if event.type == pygame.KEYDOWN: if event.key == pygame.K_SPACE: gravitasi = -7 if event.type == pipa_timer: pipa_list.extend(buat_pipa()) gravitasi += 0.4 burung.y += gravitasi pipa_list = gerak_pipa(pipa_list) for p in pipa_list: if burung.colliderect(p): if score > high_score: save_high_score(score) pygame.quit() sys.exit() if burung.top <= 0 or burung.bottom >= tinggi: if score > high_score: save_high_score(score) pygame.quit() sys.exit() # Tambah skor for p in pipa_list: if p.centerx == burung.centerx: score += 1 layar.fill(biru) pygame.draw.rect(layar, kuning, burung) for p in pipa_list: pygame.draw.rect(layar, hijau, p) tampil_score() pygame.display.update() clock.tick(60) 📝 Catatan: Skor tertinggi disimpan di file highscore.txt, jadi tidak hilang meskipun kamu keluar dari game. 🌐 Versi HTML + JavaScript — dengan High Score Simpan sebagai flapy_jump.html <!DOCTYPE html> <html lang="id"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Flapy Jump</title> <style> body { margin: 0; overflow: hidden; background: skyblue; } canvas { display: block; margin: auto; background: #87ceeb; } </style> </head> <body> <canvas id="game" width="400" height="600"></canvas> <script> const canvas = document.getElementById('game'); const ctx = canvas.getContext('2d'); let birdY = 300, velocity = 0, gravity = 0.4; let pipes = []; let score = 0, highScore = localStorage.getItem('highScore') || 0; let frame = 0; function jump() { velocity = -7; } document.addEventListener('keydown', e => { if (e.code === 'Space') jump(); }); function reset() { if (score > highScore) { highScore = score; localStorage.setItem('highScore', highScore); } birdY = 300; velocity = 0; pipes = []; score = 0; frame = 0; } function draw() { ctx.fillStyle = '#87ceeb'; ctx.fillRect(0, 0, 400, 600); // Burung ctx.fillStyle = 'yellow'; ctx.fillRect(100, birdY, 30, 24); // Pipa if (frame % 90 === 0) { const topHeight = Math.random() * 200 + 100; pipes.push({x: 400, top: topHeight, bottom: topHeight + 150}); } for (let p of pipes) { p.x -= 3; ctx.fillStyle = 'green'; ctx.fillRect(p.x, 0, 50, p.top); ctx.fillRect(p.x, p.bottom, 50, 600 - p.bottom); if (100 + 30 > p.x && 100 < p.x + 50 && (birdY < p.top || birdY + 24 > p.bottom)) { alert('💥 Kena pipa!\nSkor kamu: ' + score + '\nHigh Score: ' + highScore); reset(); return; } } pipes = pipes.filter(p => p.x + 50 > 0); velocity += gravity; birdY += velocity; if (birdY < 0 || birdY > 600) { alert('💥 Kamu jatuh!\nSkor kamu: ' + score + '\nHigh Score: ' + highScore); reset(); return; } if (frame % 90 === 0) score++; ctx.fillStyle = 'black'; ctx.font = '36px Arial'; ctx.fillText(score, 190, 50); ctx.font = '20px Arial'; ctx.fillText("High Score: " + highScore, 10, 30); frame++; requestAnimationFrame(draw); } draw(); </script> </body> </html> 🏆 Misi: Kalahkan high score kalian! 🔘 Kontrol: Tekan spasi buat lompat
Danadyaksa Reynald Adhyastha
3 months ago
press space to jump and you have to get 20 lives to win
Hillary Alexandra Sutanto
3 months ago
Try to get out of my super hard puzzle only 0.0001 can solve it!! Good Luck!!
William Tedjosaputro
4 months ago
🎮 Aturan Main: Ada dua pemain: 🟥 Pemain Merah (kanan) — gerak pakai panah atas ⬆️ dan bawah ⬇️ 🟦 Pemain Biru (kiri) — gerak pakai W (naik) dan S (turun) Tujuan: kenakan bola ke sisi lawan. Setiap kali lawan gagal menahan bola, kamu dapat 1 poin. Pertama yang mencapai 10 poin menang! 🏆 Kalau Player 2 (biru) yang duluan dapat 10 poin, maka kamu kalah 😢!DOCTYPE html> <html lang="id"> <head> <meta charset="UTF-8" /> <meta name="viewport"<!DOCTYPE html> <html lang="id"> <head> <meta charset="UTF-8" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <title>Pong 2 Player + Suara 🔊</title> <style> * { box-sizing: border-box; } body { background: #000; display: flex; justify-content: center; align-items: center; height: 100vh; color: white; font-family: sans-serif; overflow: hidden; } canvas { background: #111; border: 3px solid #fff; } </style> </head> <body> <canvas id="gameCanvas" width="800" height="500"></canvas> <script> // ==== SETUP DASAR ==== const canvas = document.getElementById("gameCanvas"); const ctx = canvas.getContext("2d"); const paddleHeight = 100, paddleWidth = 15; let player1Y = canvas.height / 2 - paddleHeight / 2; let player2Y = canvas.height / 2 - paddleHeight / 2; let player1Score = 0, player2Score = 0; let ballX = canvas.width / 2, ballY = canvas.height / 2; let ballSpeedX = 5, ballSpeedY = 3; // ==== SUARA ==== const soundBounce = new Audio("https://actions.google.com/sounds/v1/cartoon/wood_plank_flicks.ogg"); const soundScore = new Audio("https://actions.google.com/sounds/v1/cartoon/clang_and_wobble.ogg"); const soundWin = new Audio("https://actions.google.com/sounds/v1/cartoon/slide_whistle_to_drum_hit.ogg"); function drawRect(x, y, w, h, color) { ctx.fillStyle = color; ctx.fillRect(x, y, w, h); } function drawCircle(x, y, r, color) { ctx.fillStyle = color; ctx.beginPath(); ctx.arc(x, y, r, 0, Math.PI * 2, false); ctx.fill(); } function drawText(text, x, y, color) { ctx.fillStyle = color; ctx.font = "32px Arial"; ctx.fillText(text, x, y); } function resetBall() { ballX = canvas.width / 2; ballY = canvas.height / 2; ballSpeedX = -ballSpeedX; ballSpeedY = (Math.random() > 0.5 ? 1 : -1) * (3 + Math.random() * 2); } function draw() { drawRect(0, 0, canvas.width, canvas.height, "#111"); drawRect(0, player1Y, paddleWidth, paddleHeight, "blue"); drawRect(canvas.width - paddleWidth, player2Y, paddleWidth, paddleHeight, "red"); drawCircle(ballX, ballY, 10, "white"); drawText(player1Score, canvas.width / 4, 50, "cyan"); drawText(player2Score, (canvas.width * 3) / 4, 50, "red"); } function move() { ballX += ballSpeedX; ballY += ballSpeedY; // pantulan atas/bawah if (ballY < 0 || ballY > canvas.height) { ballSpeedY = -ballSpeedY; soundBounce.currentTime = 0; soundBounce.play(); } // pantulan pemain biru if ( ballX < paddleWidth && ballY > player1Y && ballY < player1Y + paddleHeight ) { ballSpeedX = -ballSpeedX; soundBounce.currentTime = 0; soundBounce.play(); } // pantulan pemain merah if ( ballX > canvas.width - paddleWidth && ballY > player2Y && ballY < player2Y + paddleHeight ) { ballSpeedX = -ballSpeedX; soundBounce.currentTime = 0; soundBounce.play(); } // goal kiri/kanan if (ballX < 0) { player2Score++; soundScore.currentTime = 0; soundScore.play(); resetBall(); } if (ballX > canvas.width) { player1Score++; soundScore.currentTime = 0; soundScore.play(); resetBall(); } // cek menang if (player1Score >= 10 || player2Score >= 10) { soundWin.play(); setTimeout(() => { let winner = player1Score >= 10 ? "🟦 Player Biru MENANG! 🏆" : "🟥 Player Merah MENANG! 🏆"; alert(winner); document.location.reload(); }, 200); } } function gameLoop() { move(); draw(); requestAnimationFrame(gameLoop); } // kontrol pemain document.addEventListener("keydown", function (e) { switch (e.key) { case "w": case "W": player1Y -= 30; break; case "s": case "S": player1Y += 30; break; case "ArrowUp": player2Y -= 30; break; case "ArrowDown": player2Y += 30; break; } // batasi paddle agar tidak keluar layar player1Y = Math.max(0, Math.min(canvas.height - paddleHeight, player1Y)); player2Y = Math.max(0, Math.min(canvas.height - paddleHeight, player2Y)); }); gameLoop(); </script> </body><!DOCTYPE html> <html lang="id"> <head> <meta charset="UTF-8" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <title>Pong 2 Player + Suara + Ledakan 💥</title> <style> * { box-sizing: border-box; } body { background: #000; display: flex; justify-content: center; align-items: center; height: 100vh; color: white; font-family: sans-serif; overflow: hidden; } canvas { background: #111; border: 3px solid #fff; } </style> </head> <body> <canvas id="gameCanvas" width="800" height="500"></canvas> <script> // === Setup dasar === const canvas = document.getElementById("gameCanvas"); const ctx = canvas.getContext("2d"); const paddleHeight = 100, paddleWidth = 15; let player1Y = canvas.height / 2 - paddleHeight / 2; let player2Y = canvas.height / 2 - paddleHeight / 2; let player1Score = 0, player2Score = 0; let ballX = canvas.width / 2, ballY = canvas.height / 2; let ballSpeedX = 5, ballSpeedY = 3; // === Suara === const soundBounce = new Audio("https://actions.google.com/sounds/v1/cartoon/wood_plank_flicks.ogg"); const soundScore = new Audio("https://actions.google.com/sounds/v1/cartoon/clang_and_wobble.ogg"); const soundWin = new Audio("https://actions.google.com/sounds/v1/cartoon/slide_whistle_to_drum_hit.ogg"); // === Efek Ledakan === let explosions = []; function createExplosion(x, y, color) { for (let i = 0; i < 15; i++) { explosions.push({ x, y, radius: 3 + Math.random() * 3, color, alpha: 1, dx: (Math.random() - 0.5) * 8, dy: (Math.random() - 0.5) * 8 }); } } function drawExplosion() { for (let i = explosions.length - 1; i >= 0; i--) { const p = explosions[i]; ctx.beginPath(); ctx.fillStyle = `rgba(${p.color}, ${p.alpha})`; ctx.arc(p.x, p.y, p.radius, 0, Math.PI * 2); ctx.fill(); p.x += p.dx; p.y += p.dy; p.alpha -= 0.03; if (p.alpha <= 0) explosions.splice(i, 1); } } function drawRect(x, y, w, h, color) { ctx.fillStyle = color; ctx.fillRect(x, y, w, h); } function drawCircle(x, y, r, color) { ctx.fillStyle = color; ctx.beginPath(); ctx.arc(x, y, r, 0, Math.PI * 2, false); ctx.fill(); } function drawText(text, x, y, color) { ctx.fillStyle = color; ctx.font = "32px Arial"; ctx.fillText(text, x, y); } function resetBall() { ballX = canvas.width / 2; ballY = canvas.height / 2; ballSpeedX = -ballSpeedX; ballSpeedY = (Math.random() > 0.5 ? 1 : -1) * (3 + Math.random() * 2); } function draw() { drawRect(0, 0, canvas.width, canvas.height, "#111"); drawRect(0, player1Y, paddleWidth, paddleHeight, "blue"); drawRect(canvas.width - paddleWidth, player2Y, paddleWidth, paddleHeight, "red"); drawCircle(ballX, ballY, 10, "white"); drawText(player1Score, canvas.width / 4, 50, "cyan"); drawText(player2Score, (canvas.width * 3) / 4, 50, "red"); drawExplosion(); } function move() { ballX += ballSpeedX; ballY += ballSpeedY; // Pantulan atas/bawah if (ballY < 0 || ballY > canvas.height) { ballSpeedY = -ballSpeedY; soundBounce.currentTime = 0; soundBounce.play(); } // Pantulan pemain biru if (ballX < paddleWidth && ballY > player1Y && ballY < player1Y + paddleHeight) { ballSpeedX = -ballSpeedX; soundBounce.currentTime = 0; soundBounce.play(); } // Pantulan pemain merah if (ballX > canvas.width - paddleWidth && ballY > player2Y && ballY < player2Y + paddleHeight) { ballSpeedX = -ballSpeedX; soundBounce.currentTime = 0; soundBounce.play(); } // Gol kiri (merah dapat poin) if (ballX < 0) { player2Score++; createExplosion(ballX + 30, ballY, "255, 0, 0"); soundScore.currentTime = 0; soundScore.play(); resetBall(); } // Gol kanan (biru dapat poin) if (ballX > canvas.width) { player1Score++; createExplosion(ballX - 30, ballY, "0, 150, 255"); soundScore.currentTime = 0; soundScore.play(); resetBall(); } // Cek kemenangan if (player1Score >= 10 || player2Score >= 10) { soundWin.play(); setTimeout(() => { let winner = player1Score >= 10 ? "🟦 Player Biru MENANG! 🏆" : "🟥 Player Merah MENANG! 🏆"; alert(winner); document.location.reload(); }, 300); } } function gameLoop() { move(); draw(); requestAnimationFrame(gameLoop); } // Kontrol pemain document.addEventListener("keydown", function (e) { switch (e.key) { case "w": case "W": player1Y -= 30; break; case "s": case "S": player1Y += 30; break; case "ArrowUp": player2Y -= 30; break; case "ArrowDown": player2Y += 30; break; } // Batasi paddle supaya tetap di layar player1Y = Math.max(0, Math.min(canvas.height - paddleHeight, player1Y)); player2Y = Math.max(0, Math.min(canvas.height - paddleHeight, player2Y)); }); gameLoop(); </script> </body> </html> </html> content="width=device-width, initial-scale=1.0" /> <title>Pong 2 Player</title> <style> * { box-sizing: border-box; } body { background: #000; display: flex; justify-content: center; align-items: center; height: 100vh; color: white; font-family: sans-serif; overflow: hidden; } canvas { background: #111; border: 3px solid #fff; } </style> </head> <body> <canvas id="gameCanvas" width="800" height="500"></canvas> <script> const canvas = document.getElementById("gameCanvas"); const ctx = canvas.getContext("2d"); const paddleHeight = 100, paddleWidth = 15; let player1Y = canvas.height / 2 - paddleHeight / 2; let player2Y = canvas.height / 2 - paddleHeight / 2; let player1Score = 0, player2Score = 0; let ballX = canvas.width / 2, ballY = canvas.height / 2; let ballSpeedX = 5, ballSpeedY = 3; function drawRect(x, y, w, h, color) { ctx.fillStyle = color; ctx.fillRect(x, y, w, h); } function drawCircle(x, y, r, color) { ctx.fillStyle = color; ctx.beginPath(); ctx.arc(x, y, r, 0, Math.PI * 2, false); ctx.fill(); } function drawText(text, x, y, color) { ctx.fillStyle = color; ctx.font = "32px Arial"; ctx.fillText(text, x, y); } function resetBall() { ballX = canvas.width / 2; ballY = canvas.height / 2; ballSpeedX = -ballSpeedX; ballSpeedY = (Math.random() > 0.5 ? 1 : -1) * (3 + Math.random() * 2); } function draw() { // background drawRect(0, 0, canvas.width, canvas.height, "#111"); // paddles drawRect(0, player1Y, paddleWidth, paddleHeight, "blue"); drawRect(canvas.width - paddleWidth, player2Y, paddleWidth, paddleHeight, "red"); // ball drawCircle(ballX, ballY, 10, "white"); // score drawText(player1Score, canvas.width / 4, 50, "cyan"); drawText(player2Score, (canvas.width * 3) / 4, 50, "red"); } function move() { ballX += ballSpeedX; ballY += ballSpeedY; // bounce top & bottom if (ballY < 0 || ballY > canvas.height) { ballSpeedY = -ballSpeedY; } // collision with player 1 (blue) if ( ballX < paddleWidth && ballY > player1Y && ballY < player1Y + paddleHeight ) { ballSpeedX = -ballSpeedX; } // collision with player 2 (red) if ( ballX > canvas.width - paddleWidth && ballY > player2Y && ballY < player2Y + paddleHeight ) { ballSpeedX = -ballSpeedX; } // left & right goals if (ballX < 0) { player2Score++; resetBall(); } if (ballX > canvas.width) { player1Score++; resetBall(); } // check win if (player1Score >= 10 || player2Score >= 10) { let winner = player1Score >= 10 ? "🟦 Player Biru MENANG! 🏆" : "🟥 Player Merah MENANG! 🏆"; alert(winner); document.location.reload(); } } function gameLoop() { move(); draw(); requestAnimationFrame(gameLoop); } // kontrol pemain document.addEventListener("keydown", function (e) { switch (e.key) { case "w": case "W": player1Y -= 30; break; case "s": case "S": player1Y += 30; break; case "ArrowUp": player2Y -= 30; break; case "ArrowDown": player2Y += 30; break; } // batasi paddle agar tidak keluar layar player1Y = Math.max(0, Math.min(canvas.height - paddleHeight, player1Y)); player2Y = Math.max(0, Math.min(canvas.height - paddleHeight, player2Y)); }); gameLoop(); </script> </body> </html> <!DOCTYPE html> <html lang="id"> <head> <meta charset="UTF-8" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <title>Pong Neon 2 Player ⚡</title> <style> * { box-sizing: border-box; } body { margin: 0; background: radial-gradient(circle at center, #000010, #000); display: flex; justify-content: center; align-items: center; height: 100vh; overflow: hidden; } canvas { border: 3px solid #0ff; box-shadow: 0 0 20px #0ff; background: transparent; } </style> </head> <body> <canvas id="gameCanvas" width="800" height="500"></canvas> <script> // === Setup dasar === const canvas = document.getElementById("gameCanvas"); const ctx = canvas.getContext("2d"); const paddleHeight = 100, paddleWidth = 15; let player1Y = canvas.height / 2 - paddleHeight / 2; let player2Y = canvas.height / 2 - paddleHeight / 2; let player1Score = 0, player2Score = 0; let ballX = canvas.width / 2, ballY = canvas.height / 2; let ballSpeedX = 5, ballSpeedY = 3; // === Suara === const sBounce = new Audio("https://actions.google.com/sounds/v1/cartoon/wood_plank_flicks.ogg"); const sScore = new Audio("https://actions.google.com/sounds/v1/cartoon/clang_and_wobble.ogg"); const sWin = new Audio("https://actions.google.com/sounds/v1/cartoon/slide_whistle_to_drum_hit.ogg"); // === Bintang latar belakang === let stars = Array.from({length: 80}, () => ({ x: Math.random() * canvas.width, y: Math.random() * canvas.height, r: Math.random() * 2, s: 0.5 + Math.random() * 1.5 })); function drawStars() { ctx.fillStyle = "rgba(0,0,0,0.3)"; ctx.fillRect(0,0,canvas.width,canvas.height); ctx.fillStyle = "#0ff"; stars.forEach(star => { ctx.beginPath(); ctx.arc(star.x, star.y, star.r, 0, Math.PI * 2); ctx.fill(); star.y += star.s; if (star.y > canvas.height) { star.y = 0; star.x = Math.random() * canvas.width; } }); } // === Ledakan === let explosions = []; function createExplosion(x, y, color) { for (let i = 0; i < 15; i++) { explosions.push({ x, y, r: 3 + Math.random() * 3, color, alpha: 1, dx: (Math.random() - 0.5) * 8, dy: (Math.random() - 0.5) * 8 }); } } function drawExplosion() { for (let i = explosions.length - 1; i >= 0; i--) { const p = explosions[i]; ctx.beginPath(); ctx.fillStyle = `rgba(${p.color}, ${p.alpha})`; ctx.arc(p.x, p.y, p.r, 0, Math.PI * 2); ctx.fill(); p.x += p.dx; p.y += p.dy; p.alpha -= 0.03; if (p.alpha <= 0) explosions.splice(i, 1); } } // === Fungsi gambar dasar === function drawRect(x, y, w, h, color, glow) { ctx.shadowColor = glow; ctx.shadowBlur = 20; ctx.fillStyle = color; ctx.fillRect(x, y, w, h); ctx.shadowBlur = 0; } function drawCircle(x, y, r, color) { ctx.fillStyle = color; ctx.beginPath(); ctx.arc(x, y, r, 0, Math.PI * 2); ctx.fill(); } function drawText(text, x, y, color) { ctx.fillStyle = color; ctx.font = "32px Orbitron, Arial"; ctx.fillText(text, x, y); } // === Reset bola === function resetBall() { ballX = canvas.width / 2; ballY = canvas.height / 2; ballSpeedX = -ballSpeedX; ballSpeedY = (Math.random() > 0.5 ? 1 : -1) * (3 + Math.random() * 2); } // === Gambar === function draw() { drawStars(); drawRect(0, player1Y, paddleWidth, paddleHeight, "#0ff", "#0ff"); drawRect(canvas.width - paddleWidth, player2Y, paddleWidth, paddleHeight, "#f00", "#f00"); drawCircle(ballX, ballY, 10, "white"); drawText(player1Score, canvas.width / 4, 50, "#0ff"); drawText(player2Score, (canvas.width * 3) / 4, 50, "#f00"); drawExplosion(); } // === Logika gerak === function move() { ballX += ballSpeedX; ballY += ballSpeedY; if (ballY < 0 || ballY > canvas.height) { ballSpeedY = -ballSpeedY; sBounce.currentTime = 0; sBounce.play(); } if (ballX < paddleWidth && ballY > player1Y && ballY < player1Y + paddleHeight) { ballSpeedX = -ballSpeedX; sBounce.currentTime = 0; sBounce.play(); } if (ballX > canvas.width - paddleWidth && ballY > player2Y && ballY < player2Y + paddleHeight) { ballSpeedX = -ballSpeedX; sBounce.currentTime = 0; sBounce.play(); } // Gol kiri/kanan if (ballX < 0) { player2Score++; createExplosion(ballX + 30, ballY, "255,0,0"); sScore.play(); resetBall(); } if (ballX > canvas.width) { player1Score++; createExplosion(ballX - 30, ballY, "0,255,255"); sScore.play(); resetBall(); } // Menang if (player1Score >= 10 || player2Score >= 10) { sWin.play(); setTimeout(() => { alert(player1Score >= 10 ? "🟦 Player Biru MENANG! 🏆" : "🟥 Player Merah MENANG! 🏆"); document.location.reload(); }, 300); } } function loop() { move(); draw(); requestAnimationFrame(loop); } // === Kontrol === document.addEventListener("keydown", e => { switch (e.key) { case "w": case "W": player1Y -= 30; break; case "s": case "S": player1Y += 30; break; case "ArrowUp": player2Y -= 30; break; case "ArrowDown": player2Y += 30; break; } player1Y = Math.max(0, Math.min(canvas.height - paddleHeight, player1Y)); player2Y = Math.max(0, Math.min(canvas.height - paddleHeight, player2Y)); });<!DOCTYPE html> <html lang="id"> <head> <meta charset="UTF-8" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <title>Pong Neon vs AI ⚡</title> <style> body { margin: 0; background: radial-gradient(circle at center, #000010, #000); display: flex; justify-content: center; align-items: center; height: 100vh; overflow: hidden; } canvas { border: 3px solid #0ff; box-shadow: 0 0 20px #0ff; background: transparent; } </style> </head> <body> <canvas id="gameCanvas" width="800" height="500"></canvas> <script> const canvas = document.getElementById("gameCanvas"); const ctx = canvas.getContext("2d"); const paddleHeight = 100, paddleWidth = 15; let playerY = canvas.height / 2 - paddleHeight / 2; let aiY = canvas.height / 2 - paddleHeight / 2; let playerScore = 0, aiScore = 0; let ballX = canvas.width / 2, ballY = canvas.height / 2; let ballSpeedX = 5, ballSpeedY = 3; // Suara const sBounce = new Audio("https://actions.google.com/sounds/v1/cartoon/wood_plank_flicks.ogg"); const sScore = new Audio("https://actions.google.com/sounds/v1/cartoon/clang_and_wobble.ogg"); const sWin = new Audio("https://actions.google.com/sounds/v1/cartoon/slide_whistle_to_drum_hit.ogg"); // Bintang let stars = Array.from({length: 80}, () => ({ x: Math.random() * canvas.width, y: Math.random() * canvas.height, r: Math.random() * 2, s: 0.5 + Math.random() * 1.5 })); function drawStars() { ctx.fillStyle = "rgba(0,0,0,0.3)"; ctx.fillRect(0,0,canvas.width,canvas.height); ctx.fillStyle = "#0ff"; stars.forEach(star => { ctx.beginPath(); ctx.arc(star.x, star.y, star.r, 0, Math.PI * 2); ctx.fill(); star.y += star.s; if (star.y > canvas.height) { star.y = 0; star.x = Math.random() * canvas.width; } }); } // Ledakan let explosions = []; function createExplosion(x, y, color) { for (let i = 0; i < 15; i++) { explosions.push({ x, y, r: 3 + Math.random() * 3, color, alpha: 1, dx: (Math.random() - 0.5) * 8, dy: (Math.random() - 0.5) * 8 }); } } function drawExplosion() { for (let i = explosions.length - 1; i >= 0; i--) { const p = explosions[i]; ctx.beginPath(); ctx.fillStyle = `rgba(${p.color},${p.alpha})`; ctx.arc(p.x, p.y, p.r, 0, Math.PI * 2); ctx.fill(); p.x += p.dx; p.y += p.dy; p.alpha -= 0.03; if (p.alpha <= 0) explosions.splice(i, 1); } } // Gambar function drawRect(x, y, w, h, color, glow) { ctx.shadowColor = glow; ctx.shadowBlur = 20; ctx.fillStyle = color; ctx.fillRect(x, y, w, h); ctx.shadowBlur = 0; } function drawCircle(x, y, r, color) { ctx.fillStyle = color; ctx.beginPath(); ctx.arc(x, y, r, 0, Math.PI * 2); ctx.fill(); } function drawText(text, x, y, color) { ctx.fillStyle = color; ctx.font = "32px Arial"; ctx.fillText(text, x, y); } function resetBall() { ballX = canvas.width / 2; ballY = canvas.height / 2; ballSpeedX = -ballSpeedX; ballSpeedY = (Math.random() > 0.5 ? 1 : -1) * (3 + Math.random() * 2); } // Gerak dan logika function move() { ballX += ballSpeedX; ballY += ballSpeedY; // AI gerak let aiCenter = aiY + paddleHeight / 2; if (aiCenter < ballY - 30) aiY += 5; else if (aiCenter > ballY + 30) aiY -= 5; // Pantulan if (ballY < 0 || ballY > canvas.height) { ballSpeedY = -ballSpeedY; sBounce.play(); } if (ballX < paddleWidth && ballY > playerY && ballY < playerY + paddleHeight) { ballSpeedX = -ballSpeedX; sBounce.play(); } if (ballX > canvas.width - paddleWidth && ballY > aiY && ballY < aiY + paddleHeight) { ballSpeedX = -ballSpeedX; sBounce.play(); } // Gol if (ballX < 0) { aiScore++; createExplosion(ballX + 30, ballY, "255,0,0"); sScore.play(); resetBall(); } if (ballX > canvas.width) { playerScore++; createExplosion(ballX - 30, ballY, "0,255,255"); sScore.play(); resetBall(); } // Menang if (playerScore >= 10 || aiScore >= 10) { sWin.play(); setTimeout(() => { alert(playerScore >= 10 ? "🏆 Kamu MENANG!" : "😢 AI MENANG!"); document.location.reload(); }, 300); } } // Gambar frame function draw() { drawStars(); drawRect(0, playerY, paddleWidth, paddleHeight, "#0ff", "#0ff"); drawRect(canvas.width - paddleWidth, aiY, paddleWidth, paddleHeight, "#f00", "#f00"); drawCircle(ballX, ballY, 10, "white"); drawText(playerScore, canvas.width / 4, 50, "#0ff"); drawText(aiScore, (canvas.width * 3) / 4, 50, "#f00"); drawExplosion(); } function loop() { move(); draw(); requestAnimationFrame(loop); } // Kontrol document.addEventListener("keydown", e => { if (e.key === "w" || e.key === "W") playerY -= 30; if (e.key === "s" || e.key === "S") playerY += 30; playerY = Math.max(0, Math.min(canvas.height - paddleHeight, playerY)); }); loop(); </script> </body> loop(); </script> </body> </html>