<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>カラフルなパーティクル掃除機ゲーム</title>
<style>
body {
margin: 0;
overflow: hidden;
background-color: #000;
}
canvas {
display: block;
}
.nozzle {
position: absolute;
width: 50px;
height: 50px;
background-color: #fff;
border-radius: 50%;
}
.fps-counter {
position: absolute;
top: 10px;
left: 10px;
color: #00ff00;
font-size: 20px;
font-family: monospace;
}
</style>
</head>
<body>
<canvas id="gameCanvas"></canvas>
<div id="nozzle" class="nozzle"></div>
<div id="fpsCounter" class="fps-counter"></div>
<script>
const canvas = document.getElementById('gameCanvas');
const ctx = canvas.getContext('2d');
const nozzle = document.getElementById('nozzle');
const fpsCounter = document.getElementById('fpsCounter');
canvas.width = window.innerWidth;
canvas.height = window.innerHeight;
let particles = [];
let isSucking = false;
let lastTime = performance.now();
let fps = 0;
function getRandomColor() {
const letters = '0123456789ABCDEF';
let color = '#';
for (let i = 0; i < 6; i++) {
color += letters[Math.floor(Math.random() * 16)];
}
return color;
}
function createParticles() {
for (let i = 0; i < 100; i++) {
particles.push({
x: Math.random() * canvas.width,
y: Math.random() * canvas.height,
radius: 5,
dx: (Math.random() - 0.5) * 2,
dy: (Math.random() - 0.5) * 2,
color: getRandomColor()
});
}
}
function drawParticles() {
ctx.clearRect(0, 0, canvas.width, canvas.height);
particles.forEach((particle, index) => {
ctx.beginPath();
ctx.arc(particle.x, particle.y, particle.radius, 0, Math.PI * 2);
ctx.fillStyle = particle.color;
ctx.fill();
// パーティクルの移動
particle.x += particle.dx;
particle.y += particle.dy;
// パーティクルが画面外に出たら反転させる
if (particle.x < 0 || particle.x > canvas.width) particle.dx *= -1;
if (particle.y < 0 || particle.y > canvas.height) particle.dy *= -1;
// 吸引機能
if (isSucking) {
let dx = particle.x - (nozzle.offsetLeft + nozzle.offsetWidth / 2);
let dy = particle.y - (nozzle.offsetTop + nozzle.offsetHeight / 2);
let distance = Math.sqrt(dx * dx + dy * dy);
if (distance < 100) {
particle.dx = -dx / distance * 5;
particle.dy = -dy / distance * 5;
// ノズルに近づいたら吸い込む
if (distance < 20) {
particles.splice(index, 1);
}
}
}
});
}
function updateFPS() {
const now = performance.now();
fps = Math.round(1000 / (now - lastTime));
lastTime = now;
fpsCounter.textContent = `FPS: ${fps}`;
}
function animate() {
drawParticles();
updateFPS();
requestAnimationFrame(animate);
}
createParticles();
animate();
// マウスの動きにノズルを追従させる
document.addEventListener('mousemove', (e) => {
nozzle.style.left = `${e.clientX - nozzle.offsetWidth / 2}px`;
nozzle.style.top = `${e.clientY - nozzle.offsetHeight / 2}px`;
});
// スペースキーで吸引開始・停止
document.addEventListener('keydown', (e) => {
if (e.code === 'Space') {
isSucking = true;
nozzle.style.backgroundColor = getRandomColor();
}
});
document.addEventListener('keyup', (e) => {
if (e.code === 'Space') {
isSucking = false;
}
});
</script>
</body>
</html>