<!DOCTYPE html> <html> <head> <title>野菜に水をあげるゲーム</title> <style> body { margin: 0; overflow: hidden; background-color: #222; } #container { position: relative; width: 640px; height: 480px; margin: 20px auto; border: 4px solid #fff; } #video { transform: scaleX(1); position: absolute; top: 0; left: 0; } #canvas { transform: scaleX(-1); position: absolute; top: 0; left: 0; } #targetImage { position: absolute; top: 20px; left: 50%; transform: translateX(-50%); width: 120px; z-index: 10; filter: drop-shadow(0 0 10px rgba(255,255,255,0.8)); } #status { position: absolute; top: 160px; left: 50%; transform: translateX(-50%); color: white; font-size: 24px; text-shadow: 2px 2px 4px black; } #zoneA, #zoneB { position: absolute; top: 0; width: 320px; height: 480px; pointer-events: none; opacity: 0.3; } #zoneA { left: 0; background-color: rgba(0, 255, 0, 0.5); /* 畑(緑) */ } #zoneB { right: 0; background-color: rgba(0, 150, 255, 0.5); /* 水(青) */ } </style> </head> <body> <div id="container"> <video id="video" width="640" height="480" autoplay playsinline></video> <canvas id="canvas" width="640" height="480"></canvas> <img id="targetImage" src="circle.png" alt="状態表示"> <div id="status">検出中...</div> <div id="zoneA"></div> <div id="zoneB"></div> </div> <script src="https://cdn.jsdelivr.net/npm/@tensorflow/tfjs"></script> <script src="https://cdn.jsdelivr.net/npm/@tensorflow-models/posenet"></script> <script> (async function main() { const video = document.getElementById('video'); const canvas = document.getElementById('canvas'); const ctx = canvas.getContext('2d'); const targetImage = document.getElementById('targetImage'); const status = document.getElementById('status'); const zoneA = document.getElementById('zoneA'); const zoneB = document.getElementById('zoneB'); const waterImg = new Image(); waterImg.src = "water.png"; const vegetableImg = new Image(); vegetableImg.src = "vegetable.png"; let stream; try { stream = await navigator.mediaDevices.getUserMedia({ video: { width: { ideal: 640 }, height: { ideal: 480 }, facingMode: 'user' } }); video.srcObject = stream; } catch (error) { alert('カメラの使用を許可してください'); return; } const net = await posenet.load({ architecture: 'MobileNetV1', outputStride: 16, inputResolution: 256, multiplier: 0.75, quantBytes: 2 }); let handInZoneA = false; let handInZoneB = false; let waterCount = 0; const waterGoal = 5; function isHandInZone(handX, zone, canvasWidth) { const flippedX = canvasWidth - handX; const rect = zone.getBoundingClientRect(); const canvasRect = canvas.getBoundingClientRect(); const zoneLeft = rect.left - canvasRect.left; const zoneRight = rect.right - canvasRect.left; return flippedX >= zoneLeft && flippedX <= zoneRight; } function drawWrist(x, y, ctx) { ctx.beginPath(); ctx.arc(x, y, 10, 0, Math.PI * 2); ctx.fillStyle = 'rgba(255,0,0,0.7)'; ctx.fill(); } function processFrame() { net.estimateSinglePose(video, { flipHorizontal: false, decodingMethod: 'single-person', scoreThreshold: 0.4 }).then(pose => { ctx.drawImage(video, 0, 0, canvas.width, canvas.height); const rightWrist = pose.keypoints.find(k => k.part === 'rightWrist'); if (rightWrist && rightWrist.score > 0.3) { drawWrist(rightWrist.position.x, rightWrist.position.y, ctx); const inZoneA = isHandInZone(rightWrist.position.x, zoneA, canvas.width); const inZoneB = isHandInZone(rightWrist.position.x, zoneB, canvas.width); if (inZoneB && !handInZoneB) { handInZoneB = true; handInZoneA = false; status.textContent = 'ジョウロを取ったよ!'; } if (inZoneA && handInZoneB) { handInZoneB = false; handInZoneA = true; waterCount++; targetImage.src = waterImg.src; status.textContent = `水やり ${waterCount}回目`; if (waterCount >= waterGoal) { targetImage.src = vegetableImg.src; status.textContent = '野菜が育ったよ!🎉'; } setTimeout(() => { if (waterCount < waterGoal) { status.textContent = '検出中...'; targetImage.src = "circle.png"; } }, 1500); } } else { status.textContent = '右手首を映してください'; handInZoneA = false; handInZoneB = false; } requestAnimationFrame(processFrame); }); } video.onloadeddata = () => { canvas.width = video.videoWidth; canvas.height = video.videoHeight; processFrame(); }; })(); </script> </body> </html>