<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Clean Escape</title>
<style>
body {
margin: 0;
background: #1b1b1b;
color: white;
font-family: sans-serif;
overflow: hidden;
}
#ui {
position: absolute;
top: 10px;
left: 10px;
z-index: 10;
background: rgba(0,0,0,0.5);
padding: 10px;
border-radius: 10px;
}
canvas {
display: block;
margin: auto;
background: #7a9b52;
}
</style>
</head>
<body>
<div id="ui">
<div>スコア: <span id="score">0</span></div>
<div>臭いゲージ: <span id="smell">0</span></div>
<div>警戒度: <span id="alert">0</span></div>
<div>操作: WASD / 矢印キー</div>
<div>Space: 💩する</div>
</div>
<canvas id="game" width="960" height="600"></canvas>
<script>
const canvas = document.getElementById('game');
const ctx = canvas.getContext('2d');
const scoreEl = document.getElementById('score');
const smellEl = document.getElementById('smell');
const alertEl = document.getElementById('alert');
const keys = {};
document.addEventListener('keydown', e => {
keys[e.key.toLowerCase()] = true;
if (e.code === 'Space') {
dropPoop();
}
});
document.addEventListener('keyup', e => {
keys[e.key.toLowerCase()] = false;
});
const player = {
x: 120,
y: 120,
size: 18,
speed: 3,
color: 'white'
};
const owner = {
x: 700,
y: 400,
size: 22,
speed: 1.5,
dirX: 1,
dirY: 0,
vision: 140,
timer: 0
};
const poops = [];
let score = 0;
let smell = 0;
let alertLevel = 0;
let gameOver = false;
function dropPoop() {
if (gameOver) return;
poops.push({
x: player.x,
y: player.y,
size: 10,
age: 0
});
smell += 5;
score += 10;
updateUI();
}
function updateUI() {
scoreEl.textContent = score;
smellEl.textContent = Math.floor(smell);
alertEl.textContent = Math.floor(alertLevel);
}
function movePlayer() {
if (keys['w'] || keys['arrowup']) player.y -= player.speed;
if (keys['s'] || keys['arrowdown']) player.y += player.speed;
if (keys['a'] || keys['arrowleft']) player.x -= player.speed;
if (keys['d'] || keys['arrowright']) player.x += player.speed;
player.x = Math.max(20, Math.min(canvas.width - 20, player.x));
player.y = Math.max(20, Math.min(canvas.height - 20, player.y));
}
function moveOwner() {
owner.timer--;
if (owner.timer <= 0) {
owner.timer = 120;
const angle = Math.random() * Math.PI * 2;
owner.dirX = Math.cos(angle);
owner.dirY = Math.sin(angle);
}
owner.x += owner.dirX * owner.speed;
owner.y += owner.dirY * owner.speed;
if (owner.x < 20 || owner.x > canvas.width - 20) {
owner.dirX *= -1;
}
if (owner.y < 20 || owner.y > canvas.height - 20) {
owner.dirY *= -1;
}
}
function updatePoops() {
for (const poop of poops) {
poop.age++;
}
smell = poops.length * 4;
if (smell > 30) {
alertLevel += 0.05;
}
if (smell > 60) {
alertLevel += 0.1;
}
}
function checkDetection() {
const dx = player.x - owner.x;
const dy = player.y - owner.y;
const dist = Math.sqrt(dx * dx + dy * dy);
if (dist < owner.vision + alertLevel) {
gameOver = true;
}
}
function drawBarn() {
ctx.fillStyle = '#8fbc5a';
ctx.fillRect(0, 0, canvas.width, canvas.height);
ctx.strokeStyle = '#5f7c3c';
for (let x = 0; x < canvas.width; x += 64) {
ctx.beginPath();
ctx.moveTo(x, 0);
ctx.lineTo(x, canvas.height);
ctx.stroke();
}
for (let y = 0; y < canvas.height; y += 64) {
ctx.beginPath();
ctx.moveTo(0, y);
ctx.lineTo(canvas.width, y);
ctx.stroke();
}
}
function drawPlayer() {
ctx.beginPath();
ctx.fillStyle = player.color;
ctx.arc(player.x, player.y, player.size, 0, Math.PI * 2);
ctx.fill();
ctx.fillStyle = 'pink';
ctx.fillRect(player.x - 10, player.y - 20, 6, 12);
ctx.fillRect(player.x + 4, player.y - 20, 6, 12);
}
function drawOwner() {
ctx.beginPath();
ctx.fillStyle = '#2040ff';
ctx.arc(owner.x, owner.y, owner.size, 0, Math.PI * 2);
ctx.fill();
ctx.strokeStyle = 'rgba(255,255,0,0.2)';
ctx.beginPath();
ctx.arc(owner.x, owner.y, owner.vision + alertLevel, 0, Math.PI * 2);
ctx.stroke();
}
function drawPoops() {
for (const poop of poops) {
ctx.beginPath();
ctx.fillStyle = '#5b3510';
ctx.arc(poop.x, poop.y, poop.size, 0, Math.PI * 2);
ctx.fill();
}
}
function drawGameOver() {
ctx.fillStyle = 'rgba(0,0,0,0.7)';
ctx.fillRect(0, 0, canvas.width, canvas.height);
ctx.fillStyle = 'white';
ctx.font = '48px sans-serif';
ctx.fillText('見つかった!', 330, 260);
ctx.font = '28px sans-serif';
ctx.fillText('最終スコア: ' + score, 360, 320);
ctx.font = '20px sans-serif';
ctx.fillText('F5でリスタート', 390, 370);
}
function gameLoop() {
ctx.clearRect(0, 0, canvas.width, canvas.height);
drawBarn();
if (!gameOver) {
movePlayer();
moveOwner();
updatePoops();
checkDetection();
}
drawPoops();
drawPlayer();
drawOwner();
if (gameOver) {
drawGameOver();
}
updateUI();
requestAnimationFrame(gameLoop);
}
gameLoop();
</script>
</body>
</html>