omaigot
Gà con

<!DOCTYPE html><html lang="vi"><head> <meta charset="UTF-8"> <title>🍎 Physics Apple - Bouncing Effect</title> <style> * { margin: 0; padding: 0; box-sizing: border-box; } body { text-align: center; background: #050a10; display: flex; flex-direction: column; align-items: center; justify-content: center; min-height: 100vh; font-family: 'Segoe UI', sans-serif; color: white; overflow: hidden; cursor: none; } canvas { background: radial-gradient(circle, #1a2a44 0%, #0a1018 100%); border-radius: 20px; box-shadow: 0 0 60px rgba(0,0,0,1); display: block; touch-action: none; } .hud { position: absolute; top: 20px; left: 20px; text-align: left; pointer-events: none; } h2 { color: #f1c40f; font-size: 24px; text-shadow: 0 2px 4px rgba(0,0,0,0.5); } </style></head><body> <div class="hud"> <h2>🍎 ĐIỂM: <span id="scoreVal">0</span></h2> </div> <canvas id="gameCanvas" width="480" height="720"></canvas> <script> const canvas = document.getElementById("gameCanvas"); const ctx = canvas.getContext("2d"); const scoreVal = document.getElementById("scoreVal"); // --- CẤU HÌNH VẬT LÝ NÂNG CAO --- const GRAVITY = 0.4; const BOUNCE_FORCE = -0.65; // Tăng độ nảy khi chạm đáy giỏ (Sắp rơi ra ngoài) const FRICTION_IN_BASKET = 0.96; const MAX_APPLES = 15; let score = 0; let gameOver = false; let fallingApples = []; let basketApples = []; let particles = []; const basket = { width: 140, height: 70, x: 170, y: 600, targetX: 170, vx: 0, color: "#A0522D", rimY: 610 }; class FallingApple { constructor() { this.reset(); } reset() { this.x = Math.random() * (canvas.width - 80) + 40; this.y = -60; this.radius = 18; this.vy = 2; this.color = "#ff4d4d"; } update() { this.vy += GRAVITY; this.y += this.vy; } draw() { drawApple(this.x, this.y, this.radius, this.color, true); } } class BasketApple { constructor(x, y, vy) { this.x = x; this.y = y; this.radius = 15; this.vx = (Math.random() - 0.5) * 5; this.vy = vy * BOUNCE_FORCE; // Phản lực nảy lên khi rơi vào this.angle = 0; this.va = 0; // Vận tốc góc (xoay khi lắc) } update() { this.vy += GRAVITY; // Lực quán tính từ giỏ tác động lên táo this.vx -= basket.vx * 0.15; this.va += basket.vx * 0.01; // Táo xoay nhẹ khi giỏ di chuyển this.x += this.vx; this.y += this.vy; this.angle += this.va; this.vx *= FRICTION_IN_BASKET; this.va *= 0.9; // --- GIỚI HẠN VẬT LÝ TRONG GIỎ (VÁCH NGĂN VÔ HÌNH) --- const leftWall = basket.x + 15; const rightWall = basket.x + basket.width - 15; const bottomWall = basket.y + basket.height - 15; const topLimit = basket.y - 40; // Cho phép nảy cao hơn mép giỏ 40px // Chạm đáy giỏ (Nảy lên) if (this.y > bottomWall - this.radius) { this.y = bottomWall - this.radius; this.vy *= BOUNCE_FORCE; if (Math.abs(this.vy) < 1) this.vy = 0; } // Chạm tường trái/phải if (this.x < leftWall + this.radius) { this.x = leftWall + this.radius; this.vx *= -0.5; } if (this.x > rightWall - this.radius) { this.x = rightWall - this.radius; this.vx *= -0.5; } // Chặn không cho nảy quá cao rồi bay mất if (this.y < topLimit) { this.y = topLimit; this.vy = 0.5; // Đẩy nhẹ xuống } } draw() { ctx.save(); ctx.translate(this.x, this.y); ctx.rotate(this.angle); drawApple(0, 0, this.radius, "#d63031", false); ctx.restore(); } } function drawApple(x, y, r, color, glow) { if (glow) { ctx.shadowBlur = 20; ctx.shadowColor = "rgba(255,0,0,0.4)"; } ctx.fillStyle = color; ctx.beginPath(); ctx.arc(x, y, r, 0, Math.PI*2); ctx.fill(); // Chi tiết highlight cho táo thật hơn ctx.fillStyle = "rgba(255,255,255,0.3)"; ctx.beginPath(); ctx.arc(x - r/3, y - r/3, r/4, 0, Math.PI*2); ctx.fill(); // Cuống ctx.fillStyle = "#4a2c2a"; ctx.fillRect(x-2, y-r-5, 4, 8); ctx.shadowBlur = 0; } // Điều khiển window.addEventListener("mousemove", (e) => { const rect = canvas.getBoundingClientRect(); basket.targetX = e.clientX - rect.left - basket.width / 2; }); window.addEventListener("mousedown", () => { if (gameOver) restartGame(); }); function update() { // Cập nhật vị trí và vận tốc giỏ let oldX = basket.x; basket.x += (basket.targetX - basket.x) * 0.2; basket.vx = basket.x - oldX; if (gameOver) return; // Quản lý táo rơi if (fallingApples.length < 1 + Math.floor(score/10)) { if (Math.random() < 0.02) fallingApples.push(new FallingApple()); } fallingApples.forEach((a, i) => { a.update(); // Check hứng được táo if (a.y + a.radius > basket.y && a.y < basket.y + 30 && a.x > basket.x && a.x < basket.x + basket.width) { if (basketApples.length < MAX_APPLES) { basketApples.push(new BasketApple(a.x, a.y, a.vy)); } score++; scoreVal.innerText = score; fallingApples.splice(i, 1); } // Check thua if (a.y > canvas.height + 50) gameOver = true; }); basketApples.forEach(ba => ba.update()); } function draw() { ctx.clearRect(0, 0, canvas.width, canvas.height); // Vẽ giỏ - Lớp sau ctx.fillStyle = "#5D4037"; ctx.beginPath(); ctx.roundRect(basket.x, basket.y, basket.width, basket.height, [5, 5, 20, 20]); ctx.fill(); // Vẽ táo trong giỏ (nằm giữa lớp trước và lớp sau của giỏ) basketApples.forEach(ba => ba.draw()); // Vẽ giỏ - Lớp trước (tạo hiệu ứng táo ở bên trong) ctx.fillStyle = "rgba(139, 69, 19, 0.9)"; ctx.beginPath(); ctx.roundRect(basket.x, basket.y + 20, basket.width, basket.height - 20, [0, 0, 20, 20]); ctx.fill(); // Vân rổ ctx.strokeStyle = "rgba(0,0,0,0.2)"; for(let i=20; i<basket.width; i+=25) { ctx.strokeRect(basket.x + i, basket.y + 25, 1, basket.height - 35); } fallingApples.forEach(a => a.draw()); if (gameOver) { ctx.fillStyle = "rgba(0,0,0,0.8)"; ctx.fillRect(0,0,canvas.width, canvas.height); ctx.fillStyle = "white"; ctx.textAlign = "center"; ctx.font = "bold 40px Arial"; ctx.fillText("TÁO RƠI MẤT RỒI!", 240, 340); ctx.font = "20px Arial"; ctx.fillText("Click để chơi lại", 240, 390); } } function restartGame() { score = 0; scoreVal.innerText = "0"; gameOver = false; fallingApples = [new FallingApple()]; basketApples = []; } function loop() { update(); draw(); requestAnimationFrame(loop); } loop(); </script></body></html>
Sửa lần cuối: