pong game 2 player
đŽ 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>