Mercurial
view mrjunejune/src/public/dog-game.js @ 212:84826b3c655b
[MrJuneJune] Forgot to add assets.
| author | MrJuneJune <me@mrjunejune.com> |
|---|---|
| date | Sun, 15 Feb 2026 21:38:36 -0800 |
| parents | |
| children |
line wrap: on
line source
// Dog frames const imagesSrc = [ "/public/sprite_shiba0.png", "/public/sprite_shiba1.png", "/public/sprite_shiba2.png", "/public/sprite_shiba3.png", ]; const images =imagesSrc.map((src, index) => { const img = new Image(); img.src = src; img.onload = () => { if (index == imagesSrc.length-1) startAnimation(); }; return img }); // Load treat image const treatImage = new Image(); treatImage.src = "/public/dog-treat.png"; // Load star images for background let starImages = [ { src: "/public/start-large.png", img: new Image() }, { src: "/public/start-small-1.png", img: new Image() }, { src: "/public/start-small-2.png", img: new Image() }, { src: "/public/start-small-3.png", img: new Image() } ]; starImages.forEach(star => star.img.src = star.src); const background = document.getElementById('background'); const bgCtx = background.getContext("2d"); const ctx = game.getContext("2d"); const uiCtx = gameUI.getContext("2d"); // Dog initial position and movement const initialDogVx = 2; let x = Math.random() * (game.width); let y = Math.random() * (game.height); let vx = initialDogVx; let vy = 0; const gravity = 0.5; const jumpForce = -12; let isFlipped = false; // Random jump interval // TODO: let's do it by frame? let nextJump = Math.random() * 2000 + 1000; // Treat system const originalTreatSize = 30; let treatSize = originalTreatSize; const treatMargin = 20; const reachDistance = 50; let treatRainActive = false; let treats = []; let lastTreatSpawn = 0; const treatFallSpeed = 0.25; const treatGravity = 0.13; // Background stars let stars = []; function createStars() { stars = []; const starCount = window.innerWidth * 0.05; for (let i = 0; i < starCount; i++) { const starType = starImages[Math.floor(Math.random() * starImages.length)]; const scale = 0.5 + Math.random() * 0.8; // Random scale stars.push({ x: Math.random() * background.width, y: Math.random() * background.height, vx: (Math.random() - 0.5) * 0.5, vy: (Math.random() - 0.5) * 0.5, rotation: Math.random() * Math.PI * 2, rotationSpeed: (Math.random() - 0.5) * 0.02, image: starType.img, size: starType.img.width, scale: scale, opacity: 0.3 + Math.random() * 0.4 // Random opacity }); } } function animateBackground() { bgCtx.clearRect(0, 0, background.width, background.height); stars.forEach(star => { // Update position star.x += star.vx; star.y += star.vy; star.rotation += star.rotationSpeed; // Wrap around edges if (star.x < -100) star.x = background.width + 100; if (star.x > background.width + 100) star.x = -100; if (star.y < -100) star.y = background.height + 100; if (star.y > background.height + 100) star.y = -100; // Draw star bgCtx.save(); bgCtx.globalAlpha = star.opacity; bgCtx.translate(star.x, star.y); bgCtx.rotate(star.rotation); const size = star.size * star.scale; bgCtx.drawImage(star.image, -size / 2, -size / 2, size, size); bgCtx.restore(); }); requestAnimationFrame(animateBackground); } function getMousePosition(event) { const rect = game.getBoundingClientRect(); const x = event.clientX - rect.left; const y = event.clientY - rect.top; return { x: x, y: y }; } // UI canvas click - toggle treat rain gameUI.addEventListener('click', (e) => { treatRainActive = !treatRainActive; if (treatRainActive) game.classList.add('active'); else game.classList.remove('active'); }); game.addEventListener('click', (e) => { if (treatRainActive) { const mousePos = getMousePosition(e); treats.push({ x: mousePos.x, y: mousePos.y, vy: treatFallSpeed }); } }); function startAnimation() { requestAnimationFrame(animate); } let index = 0; let last = 0; const frameDuration = 120; // ms per frame function animate(ts) { if (ts - last > frameDuration) { index = (index + 1) % images.length; last = ts; } // Get image dimensions const imgWidth = images[0].width; const imgHeight = images[0].height; // Update falling treats treats.forEach(treat => { treat.vy += treatGravity; treat.y += treat.vy; }); treats = treats.filter(treat => treat.y < game.height + treatSize); // Find closest treat for dog to chase let targetTreat = null; let closestDist = Infinity; treats.forEach(treat => { const dx = treat.x + treatSize / 2 - (x + imgWidth / 2); const dy = treat.y + treatSize / 2 - (y + imgHeight / 2); const dist = Math.sqrt(dx * dx + dy * dy); if (dist < closestDist) { closestDist = dist; targetTreat = treat; } }); // Dog behavior if (targetTreat) { const dx = targetTreat.x + treatSize / 2 - (x + imgWidth / 2); const dy = targetTreat.y + treatSize / 2 - (y + imgHeight / 2); const distance = Math.sqrt(dx * dx + dy * dy); // Dog eating if (distance < reachDistance) { treats = treats.filter(t => t !== targetTreat); vx = initialDogVx; } // Looking for it else { const speed = initialDogVx * 1.5; vx = dx > 0 ? speed : -speed; // Update flip direction if ((dx > 0 && isFlipped) || (dx < 0 && !isFlipped)) { isFlipped = !isFlipped; } // Jump if treat is above and dog is on ground const onGround = y + imgHeight >= game.height - 5; if (dy < -50 && onGround && Math.abs(vy) < 1) { vy = jumpForce; } } } // --- Entity updates --- // vy += gravity; x += vx; y += vy; // Bounce off walls if (x <= 0 || x + imgWidth >= game.width) { if (!targetTreat) { vx = -vx; isFlipped = !isFlipped; } x = x <= 0 ? 0 : game.width - imgWidth; } // Bounce off floor if (y + imgHeight >= game.height) { y = game.height - imgHeight; vy = -vy * 0.7; if (Math.abs(vy) < 2) vy = 0; } // Random jumps (only when not chasing treat) if (!targetTreat && Date.now() > nextJump && Math.abs(vy) < 1) { vy = jumpForce; nextJump = Date.now() + 1000 + Math.random() * 3000; } // --- Draw entity --- // ctx.clearRect(0, 0, game.width, game.height); ctx.save(); if (isFlipped) { ctx.translate(x + imgWidth, y); ctx.scale(-1, 1); ctx.drawImage(images[index], 0, 0); } else { ctx.drawImage(images[index], x, y); } ctx.restore(); treats.forEach(treat => { ctx.drawImage(treatImage, treat.x, treat.y, treatSize, treatSize); }); drawUI(); // repeat requestAnimationFrame(animate); } // Draw UI elements (treat toggle button) function drawUI() { uiCtx.drawImage(treatImage, 0, 0, treatSize, treatSize); } // --- Window functions --- // function resizeCanvas() { background.width = window.innerWidth; background.height = window.innerHeight; game.width = window.innerWidth; game.height = window.innerHeight; // resize treats treatSize = window.innerWidth < 700 ? originalTreatSize * 0.6 : originalTreatSize; // Size UI canvas to fit treat button + text gameUI.width = treatSize + 10; gameUI.height = treatSize + 25; createStars(); // Recreate stars on resize drawUI(); // Redraw UI after resize } resizeCanvas(); window.addEventListener('resize', resizeCanvas); window.onload = () => { resizeCanvas(); // ensure canvas has real size createStars(); // stars need correct canvas size animateBackground(); // safe to start background animation };