modern_Snake / index.html
ahmadreza13's picture
Update index.html
f77d11f verified
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Snake Game - Mobile Friendly</title>
<style>
body {
margin: 0;
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
min-height: 100vh;
background: #1a1a1a;
font-family: 'Arial', sans-serif;
touch-action: none;
}
.game-container {
position: relative;
padding: 20px;
border-radius: 15px;
background: #2a2a2a;
box-shadow: 0 0 20px rgba(0, 0, 0, 0.3);
margin-bottom: 20px;
}
#gameCanvas {
border-radius: 10px;
background: #333;
}
.score {
position: absolute;
top: -40px;
left: 0;
color: #fff;
font-size: 20px;
font-weight: bold;
}
.controls {
display: none;
margin-top: 20px;
gap: 10px;
}
.mobile-controls {
display: grid;
grid-template-columns: repeat(3, 1fr);
gap: 10px;
margin-top: 20px;
}
.control-btn {
width: 60px;
height: 60px;
border: none;
border-radius: 50%;
background: #4CAF50;
color: white;
font-size: 24px;
cursor: pointer;
transition: all 0.2s ease;
touch-action: manipulation;
}
.control-btn:active {
transform: scale(0.9);
background: #45a049;
}
#up {
grid-column: 2;
}
#down {
grid-column: 2;
grid-row: 2;
}
#left {
grid-column: 1;
grid-row: 2;
}
#right {
grid-column: 3;
grid-row: 2;
}
#startBtn {
padding: 12px 30px;
font-size: 16px;
background: linear-gradient(135deg, #4CAF50, #45a049);
color: white;
border: none;
border-radius: 25px;
cursor: pointer;
transition: transform 0.3s ease;
box-shadow: 0 4px 15px rgba(76, 175, 80, 0.3);
}
.game-over {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
background: rgba(0, 0, 0, 0.9);
color: white;
padding: 20px 40px;
border-radius: 10px;
text-align: center;
display: none;
backdrop-filter: blur(5px);
}
@media (max-width: 600px) {
.mobile-controls {
display: grid;
}
}
.programmer-name {
position: fixed;
bottom: 20px;
left: 50%;
transform: translateX(-50%);
color: rgba(255, 255, 255, 0.8);
font-size: 18px;
font-family: 'Courier New', monospace;
text-transform: uppercase;
letter-spacing: 5px;
cursor: pointer;
transition: all 0.5s ease;
animation: float 3s ease-in-out infinite;
}
.programmer-name:hover {
color: #4CAF50;
letter-spacing: 8px;
text-shadow: 0 0 10px rgba(76, 175, 80, 0.8);
}
@keyframes float {
0%, 100% {
transform: translateX(-50%) translateY(0);
}
50% {
transform: translateX(-50%) translateY(-10px);
}
}
.name-effect {
position: fixed;
width: 20px;
height: 20px;
background: rgba(76, 175, 80, 0.5);
border-radius: 50%;
pointer-events: none;
animation: ripple 1s ease-out;
}
@keyframes ripple {
0% {
transform: scale(0);
opacity: 1;
}
100% {
transform: scale(2);
opacity: 0;
}
}
</style>
</head>
<body>
<div class="game-container">
<div class="score">Score: <span id="score">0</span></div>
<canvas id="gameCanvas" width="400" height="400"></canvas>
<div class="game-over" id="gameOver">
<h2>Game Over!</h2>
<p>Final Score: <span id="finalScore">0</span></p>
<button id="startBtn">Play Again</button>
</div>
</div>
<div class="mobile-controls">
<button class="control-btn" id="up"></button>
<button class="control-btn" id="left"></button>
<button class="control-btn" id="right"></button>
<button class="control-btn" id="down"></button>
</div>
<div class="programmer-name" id="programmerName">Ahmad Reza Anami</div>
<script>
const canvas = document.getElementById('gameCanvas');
const ctx = canvas.getContext('2d');
const scoreElement = document.getElementById('score');
const finalScoreElement = document.getElementById('finalScore');
const gameOverElement = document.getElementById('gameOver');
const startBtn = document.getElementById('startBtn');
const controlButtons = {
up: document.getElementById('up'),
down: document.getElementById('down'),
left: document.getElementById('left'),
right: document.getElementById('right')
};
const gridSize = 20;
const tileCount = canvas.width / gridSize;
let snake = [];
let food = {};
let goldenFood = null;
let dx = gridSize;
let dy = 0;
let score = 0;
let gameLoop;
let goldenFoodInterval;
let growth = 0;
let gameSpeed = 100;
function initGame() {
snake = [
{ x: 5 * gridSize, y: 5 * gridSize },
{ x: 4 * gridSize, y: 5 * gridSize }
];
spawnFood();
score = 0;
growth = 0;
goldenFood = null;
scoreElement.textContent = score;
dx = gridSize;
dy = 0;
gameSpeed = 100;
gameOverElement.style.display = 'none';
clearInterval(gameLoop);
clearInterval(goldenFoodInterval);
gameLoop = setInterval(update, gameSpeed);
goldenFoodInterval = setInterval(spawnGoldenFood, 5000);
}
function spawnFood() {
food = {
x: Math.floor(Math.random() * tileCount) * gridSize,
y: Math.floor(Math.random() * tileCount) * gridSize
};
if (snake.some(segment => segment.x === food.x && segment.y === food.y)) {
spawnFood();
}
}
function spawnGoldenFood() {
if (!goldenFood && Math.random() < 0.2) {
let newFood;
do {
newFood = {
x: Math.floor(Math.random() * tileCount) * gridSize,
y: Math.floor(Math.random() * tileCount) * gridSize
};
} while (snake.some(s => s.x === newFood.x && s.y === newFood.y) ||
(newFood.x === food.x && newFood.y === food.y));
goldenFood = newFood;
setTimeout(() => {
goldenFood = null;
}, 1000);
}
}
function update() {
let head = {
x: (snake[0].x + dx + canvas.width) % canvas.width,
y: (snake[0].y + dy + canvas.height) % canvas.height
};
if (snake.some(segment => segment.x === head.x && segment.y === head.y)) {
gameOver();
return;
}
snake.unshift(head);
if (head.x === food.x && head.y === food.y) {
score += 10;
growth += 1;
scoreElement.textContent = score;
spawnFood();
gameSpeed = Math.max(50, gameSpeed - 2);
clearInterval(gameLoop);
gameLoop = setInterval(update, gameSpeed);
} else if (goldenFood && head.x === goldenFood.x && head.y === goldenFood.y) {
score += 20;
growth += 2;
scoreElement.textContent = score;
goldenFood = null;
}
if (growth > 0) {
growth--;
} else {
snake.pop();
}
draw();
}
function draw() {
ctx.fillStyle = '#333';
ctx.fillRect(0, 0, canvas.width, canvas.height);
snake.forEach((segment, index) => {
const gradient = ctx.createLinearGradient(
segment.x, segment.y,
segment.x + gridSize, segment.y + gridSize
);
gradient.addColorStop(0, index === 0 ? '#4CAF50' : '#45a049');
gradient.addColorStop(1, index === 0 ? '#45a049' : '#3d8b40');
ctx.fillStyle = gradient;
ctx.fillRect(segment.x + 1, segment.y + 1, gridSize - 2, gridSize - 2);
});
ctx.fillStyle = '#ff4444';
ctx.shadowColor = 'rgba(255, 68, 68, 0.5)';
ctx.shadowBlur = 10;
ctx.beginPath();
ctx.arc(food.x + gridSize/2, food.y + gridSize/2, gridSize/2 - 2, 0, Math.PI * 2);
ctx.fill();
if (goldenFood) {
ctx.fillStyle = '#FFD700';
ctx.shadowColor = 'rgba(255, 215, 0, 0.5)';
ctx.beginPath();
ctx.arc(goldenFood.x + gridSize/2, goldenFood.y + gridSize/2, gridSize/2 - 1, 0, Math.PI * 2);
ctx.fill();
}
ctx.shadowBlur = 0;
}
function gameOver() {
clearInterval(gameLoop);
clearInterval(goldenFoodInterval);
gameOverElement.style.display = 'block';
finalScoreElement.textContent = score;
}
// Control handlers
function handleDirectionChange(newDx, newDy) {
if ((dx === 0 && newDx !== 0) || (dy === 0 && newDy !== 0)) {
dx = newDx;
dy = newDy;
}
}
// Keyboard controls
document.addEventListener('keydown', (e) => {
switch(e.key) {
case 'ArrowUp': handleDirectionChange(0, -gridSize); break;
case 'ArrowDown': handleDirectionChange(0, gridSize); break;
case 'ArrowLeft': handleDirectionChange(-gridSize, 0); break;
case 'ArrowRight': handleDirectionChange(gridSize, 0); break;
}
});
// Mobile controls
Object.entries(controlButtons).forEach(([direction, button]) => {
const handlePress = (e) => {
e.preventDefault();
switch(direction) {
case 'up': handleDirectionChange(0, -gridSize); break;
case 'down': handleDirectionChange(0, gridSize); break;
case 'left': handleDirectionChange(-gridSize, 0); break;
case 'right': handleDirectionChange(gridSize, 0); break;
}
};
button.addEventListener('touchstart', handlePress);
button.addEventListener('mousedown', handlePress);
});
startBtn.addEventListener('click', initGame);
initGame();
// Add interactive name effect
const programmerName = document.getElementById('programmerName');
programmerName.addEventListener('click', (e) => {
// Create ripple effect
const ripple = document.createElement('div');
ripple.classList.add('name-effect');
ripple.style.left = `${e.clientX - 10}px`;
ripple.style.top = `${e.clientY - 10}px`;
document.body.appendChild(ripple);
// Remove ripple after animation
setTimeout(() => {
ripple.remove();
}, 1000);
// Change text temporarily
const originalText = programmerName.textContent;
programmerName.textContent = "❤️ Snake Master ❤️";
programmerName.style.color = '#ff4444';
programmerName.style.textShadow = '0 0 15px rgba(255, 68, 68, 0.8)';
setTimeout(() => {
programmerName.textContent = originalText;
programmerName.style.color = 'rgba(255, 255, 255, 0.8)';
programmerName.style.textShadow = 'none';
}, 2000);
});
// Add mouse move effect
document.addEventListener('mousemove', (e) => {
const x = e.clientX;
const y = e.clientY;
const rect = programmerName.getBoundingClientRect();
const dist = Math.sqrt(
Math.pow(x - (rect.left + rect.width / 2), 2) +
Math.pow(y - (rect.top + rect.height / 2), 2)
);
const maxDist = 200;
const scale = 1 + (1 - Math.min(dist / maxDist, 1)) * 0.2;
programmerName.style.transform = `translateX(-50%) scale(${scale})`;
});
</script>
</body>
</html>