|
|
<!DOCTYPE html> |
|
|
<html lang="en"> |
|
|
<head> |
|
|
<meta charset="UTF-8"> |
|
|
<meta name="viewport" content="width=device-width, initial-scale=1.0"> |
|
|
<title>Slither Game</title> |
|
|
<link rel="icon" type="image/x-icon" href="/static/favicon.ico"> |
|
|
<style> |
|
|
body { |
|
|
margin: 0; |
|
|
overflow: hidden; |
|
|
background: #000; |
|
|
} |
|
|
canvas { |
|
|
display: block; |
|
|
} |
|
|
</style> |
|
|
</head> |
|
|
<body> |
|
|
<canvas id="gameCanvas"></canvas> |
|
|
|
|
|
<script> |
|
|
const canvas = document.getElementById('gameCanvas'); |
|
|
const ctx = canvas.getContext('2d'); |
|
|
|
|
|
canvas.width = window.innerWidth; |
|
|
canvas.height = window.innerHeight; |
|
|
|
|
|
|
|
|
const player = { |
|
|
x: canvas.width / 2, |
|
|
y: canvas.height / 2, |
|
|
size: 10, |
|
|
speed: 3, |
|
|
trail: [], |
|
|
maxTrail: 100, |
|
|
color: '#00FF00' |
|
|
}; |
|
|
|
|
|
const food = { |
|
|
x: Math.random() * canvas.width, |
|
|
y: Math.random() * canvas.height, |
|
|
size: 5, |
|
|
color: '#FF0000' |
|
|
}; |
|
|
|
|
|
let direction = { x: 0, y: 0 }; |
|
|
|
|
|
|
|
|
window.addEventListener('mousemove', (e) => { |
|
|
const angle = Math.atan2(e.clientY - player.y, e.clientX - player.x); |
|
|
direction.x = Math.cos(angle) * player.speed; |
|
|
direction.y = Math.sin(angle) * player.speed; |
|
|
}); |
|
|
|
|
|
|
|
|
window.addEventListener('touchmove', (e) => { |
|
|
e.preventDefault(); |
|
|
const touch = e.touches[0]; |
|
|
const angle = Math.atan2(touch.clientY - player.y, touch.clientX - player.x); |
|
|
direction.x = Math.cos(angle) * player.speed; |
|
|
direction.y = Math.sin(angle) * player.speed; |
|
|
}); |
|
|
|
|
|
function gameLoop() { |
|
|
|
|
|
ctx.fillStyle = '#000'; |
|
|
ctx.fillRect(0, 0, canvas.width, canvas.height); |
|
|
|
|
|
|
|
|
player.x += direction.x; |
|
|
player.y += direction.y; |
|
|
|
|
|
|
|
|
if (player.x < 0) player.x = canvas.width; |
|
|
if (player.x > canvas.width) player.x = 0; |
|
|
if (player.y < 0) player.y = canvas.height; |
|
|
if (player.y > canvas.height) player.y = 0; |
|
|
|
|
|
|
|
|
player.trail.push({ x: player.x, y: player.y }); |
|
|
if (player.trail.length > player.maxTrail) { |
|
|
player.trail.shift(); |
|
|
} |
|
|
|
|
|
|
|
|
for (let i = 0; i < player.trail.length; i++) { |
|
|
const segment = player.trail[i]; |
|
|
const size = player.size * (i / player.trail.length); |
|
|
ctx.fillStyle = player.color; |
|
|
ctx.beginPath(); |
|
|
ctx.arc(segment.x, segment.y, size, 0, Math.PI * 2); |
|
|
ctx.fill(); |
|
|
} |
|
|
|
|
|
|
|
|
ctx.fillStyle = player.color; |
|
|
ctx.beginPath(); |
|
|
ctx.arc(player.x, player.y, player.size, 0, Math.PI * 2); |
|
|
ctx.fill(); |
|
|
|
|
|
|
|
|
ctx.fillStyle = food.color; |
|
|
ctx.beginPath(); |
|
|
ctx.arc(food.x, food.y, food.size, 0, Math.PI * 2); |
|
|
ctx.fill(); |
|
|
|
|
|
|
|
|
const dist = Math.sqrt( |
|
|
Math.pow(player.x - food.x, 2) + |
|
|
Math.pow(player.y - food.y, 2) |
|
|
); |
|
|
|
|
|
if (dist < player.size + food.size) { |
|
|
|
|
|
player.maxTrail += 50; |
|
|
|
|
|
|
|
|
food.x = Math.random() * canvas.width; |
|
|
food.y = Math.random() * canvas.height; |
|
|
} |
|
|
|
|
|
requestAnimationFrame(gameLoop); |
|
|
} |
|
|
|
|
|
gameLoop(); |
|
|
|
|
|
|
|
|
window.addEventListener('resize', () => { |
|
|
canvas.width = window.innerWidth; |
|
|
canvas.height = window.innerHeight; |
|
|
}); |
|
|
</script> |
|
|
</body> |
|
|
</html> |