Snake Game
Snake Game
Source Code Examples
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Serpentine - Premium Snake Game</title>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
</head>
<body>
<div class="game-container">
<div class="header">
<h1 class="logo">SERPENTINE</h1>
<p class="tagline">Premium Snake Experience with Immersive UX</p>
</div>
<div class="main-content">
<div class="game-section">
<div class="game-wrapper">
<div class="game-board">
<canvas id="gameCanvas"></canvas>
<div id="gameOver" class="game-over">
<h2>GAME OVER</h2>
<p>Your score: <span id="finalScore">0</span></p>
<p>High score: <span id="highScoreDisplay">0</span></p>
<button id="restartBtn" class="control-btn pulse">
<i class="fas fa-redo"></i> PLAY AGAIN
</button>
</div>
</div>
<div class="controls-panel">
<button id="startBtn" class="control-btn">
<i class="fas fa-play"></i> START GAME
</button>
<button id="pauseBtn" class="control-btn secondary">
<i class="fas fa-pause"></i> PAUSE
</button>
<button id="resetBtn" class="control-btn secondary">
<i class="fas fa-undo"></i> RESET
</button>
</div>
<div class="mobile-controls">
<div class="mobile-btn up" data-direction="up"><i class="fas fa-arrow-up"></i></div>
<div class="mobile-btn left" data-direction="left"><i class="fas fa-arrow-left"></i></div>
<div class="mobile-btn right" data-direction="right"><i class="fas fa-arrow-right"></i></div>
<div class="mobile-btn down" data-direction="down"><i class="fas fa-arrow-down"></i></div>
</div>
</div>
</div>
<div class="sidebar">
<div class="stats-card">
<h3 class="card-title"><i class="fas fa-chart-line"></i> GAME STATS</h3>
<div class="stats-grid">
<div class="stat-item">
<div class="stat-value" id="currentScore">0</div>
<div class="stat-label">SCORE</div>
</div>
<div class="stat-item">
<div class="stat-value" id="highScore">0</div>
<div class="stat-label">HIGH SCORE</div>
</div>
<div class="stat-item">
<div class="stat-value" id="snakeLength">3</div>
<div class="stat-label">LENGTH</div>
</div>
<div class="stat-item">
<div class="stat-value" id="gameSpeed">5</div>
<div class="stat-label">SPEED</div>
</div>
</div>
</div>
<div class="settings-card">
<h3 class="card-title"><i class="fas fa-cog"></i> SETTINGS</h3>
<div class="settings-group">
<label class="setting-label">Game Speed</label>
<div class="slider-container">
<input type="range" min="1" max="20" value="5" class="slider" id="speedSlider">
<span class="slider-value" id="speedValue">5</span>
</div>
</div>
<div class="settings-group">
<label class="setting-label">Grid Size</label>
<div class="slider-container">
<input type="range" min="15" max="30" value="20" class="slider" id="gridSlider">
<span class="slider-value" id="gridValue">20</span>
</div>
</div>
<div class="settings-group">
<label class="setting-label" style="display: flex; justify-content: space-between;">
<span>Zen Mode</span>
<div class="toggle-switch">
<input type="checkbox" id="zenToggle">
<span class="toggle-slider"></span>
</div>
</label>
<p style="font-size: 0.85rem; color: #94a3b8; margin-top: 5px;">Calm colors, no time pressure</p>
</div>
</div>
<div class="themes-card">
<h3 class="card-title"><i class="fas fa-palette"></i> VISUAL THEMES</h3>
<div class="theme-grid">
<div class="theme-option theme-nebula active" data-theme="nebula">
<div class="theme-color"></div>
<div class="theme-name">Nebula</div>
</div>
<div class="theme-option theme-biolume" data-theme="biolume">
<div class="theme-color"></div>
<div class="theme-name">Biolume</div>
</div>
<div class="theme-option theme-neoclassic" data-theme="neoclassic">
<div class="theme-color"></div>
<div class="theme-name">Neo-Classic</div>
</div>
<div class="theme-option theme-sunset" data-theme="sunset">
<div class="theme-color"></div>
<div class="theme-name">Sunset</div>
</div>
<div class="theme-option theme-ocean" data-theme="ocean">
<div class="theme-color"></div>
<div class="theme-name">Ocean</div>
</div>
<div class="theme-option theme-matrix" data-theme="matrix">
<div class="theme-color"></div>
<div class="theme-name">Matrix</div>
</div>
</div>
</div>
</div>
</div>
</div>
<script src="game.js"></script>
</body>
</html>
* {
margin: 0;
padding: 0;
box-sizing: border-box;
user-select: none;
}
body {
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, sans-serif;
background: linear-gradient(135deg, #0f172a 0%, #1e293b 100%);
color: #f8fafc;
min-height: 100vh;
display: flex;
justify-content: center;
align-items: center;
padding: 20px;
overflow-x: hidden;
}
.game-container {
display: flex;
flex-direction: column;
align-items: center;
gap: 25px;
max-width: 1200px;
width: 100%;
}
.header {
text-align: center;
padding: 20px;
width: 100%;
}
.logo {
font-size: 3.5rem;
font-weight: 800;
background: linear-gradient(45deg, #6366f1, #8b5cf6);
-webkit-background-clip: text;
background-clip: text;
color: transparent;
margin-bottom: 10px;
letter-spacing: -1px;
}
.tagline {
color: #94a3b8;
font-size: 1.1rem;
font-weight: 300;
}
.main-content {
display: flex;
flex-wrap: wrap;
gap: 30px;
justify-content: center;
width: 100%;
}
.game-section {
flex: 1;
min-width: 320px;
max-width: 600px;
}
.game-wrapper {
background: rgba(30, 41, 59, 0.7);
backdrop-filter: blur(10px);
border-radius: 24px;
padding: 20px;
box-shadow: 0 20px 60px rgba(0, 0, 0, 0.3);
border: 1px solid rgba(255, 255, 255, 0.1);
position: relative;
overflow: hidden;
}
.game-board {
width: 100%;
aspect-ratio: 1;
background: rgba(15, 23, 42, 0.6);
border-radius: 16px;
position: relative;
overflow: hidden;
}
#gameCanvas {
width: 100%;
height: 100%;
display: block;
}
.controls-panel {
display: flex;
flex-wrap: wrap;
gap: 15px;
margin-top: 20px;
justify-content: center;
}
.control-btn {
padding: 14px 28px;
border: none;
border-radius: 50px;
font-size: 1rem;
font-weight: 600;
cursor: pointer;
transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
display: flex;
align-items: center;
gap: 8px;
background: linear-gradient(135deg, #3b82f6 0%, #1d4ed8 100%);
color: white;
box-shadow: 0 4px 20px rgba(59, 130, 246, 0.3);
}
.control-btn:hover {
transform: translateY(-2px);
box-shadow: 0 8px 30px rgba(59, 130, 246, 0.4);
}
.control-btn:active {
transform: translateY(0);
}
.control-btn.secondary {
background: linear-gradient(135deg, #475569 0%, #334155 100%);
box-shadow: 0 4px 20px rgba(71, 85, 105, 0.3);
}
.control-btn.secondary:hover {
box-shadow: 0 8px 30px rgba(71, 85, 105, 0.4);
}
.sidebar {
flex: 1;
min-width: 300px;
max-width: 400px;
display: flex;
flex-direction: column;
gap: 25px;
}
.stats-card, .settings-card, .themes-card {
background: rgba(30, 41, 59, 0.7);
backdrop-filter: blur(10px);
border-radius: 20px;
padding: 25px;
box-shadow: 0 15px 40px rgba(0, 0, 0, 0.2);
border: 1px solid rgba(255, 255, 255, 0.1);
}
.card-title {
font-size: 1.3rem;
font-weight: 700;
margin-bottom: 20px;
color: #e2e8f0;
display: flex;
align-items: center;
gap: 10px;
}
.card-title i {
color: #6366f1;
}
.stats-grid {
display: grid;
grid-template-columns: repeat(2, 1fr);
gap: 20px;
}
.stat-item {
text-align: center;
padding: 15px;
background: rgba(15, 23, 42, 0.5);
border-radius: 12px;
transition: transform 0.2s;
}
.stat-item:hover {
transform: translateY(-2px);
}
.stat-value {
font-size: 2.2rem;
font-weight: 800;
color: #60a5fa;
line-height: 1;
}
.stat-label {
font-size: 0.9rem;
color: #94a3b8;
margin-top: 5px;
text-transform: uppercase;
letter-spacing: 1px;
}
.settings-group {
margin-bottom: 20px;
}
.setting-label {
display: block;
margin-bottom: 8px;
color: #cbd5e1;
font-weight: 500;
}
.slider-container {
display: flex;
align-items: center;
gap: 15px;
}
.slider {
flex: 1;
-webkit-appearance: none;
height: 6px;
background: linear-gradient(to right, #6366f1, #8b5cf6);
border-radius: 3px;
outline: none;
}
.slider::-webkit-slider-thumb {
-webkit-appearance: none;
width: 22px;
height: 22px;
background: white;
border-radius: 50%;
cursor: pointer;
box-shadow: 0 2px 10px rgba(0, 0, 0, 0.2);
}
.slider-value {
min-width: 30px;
text-align: center;
font-weight: 600;
color: #60a5fa;
}
.toggle-switch {
position: relative;
display: inline-block;
width: 60px;
height: 30px;
}
.toggle-switch input {
opacity: 0;
width: 0;
height: 0;
}
.toggle-slider {
position: absolute;
cursor: pointer;
top: 0;
left: 0;
right: 0;
bottom: 0;
background-color: #475569;
transition: .4s;
border-radius: 34px;
}
.toggle-slider:before {
position: absolute;
content: "";
height: 22px;
width: 22px;
left: 4px;
bottom: 4px;
background-color: white;
transition: .4s;
border-radius: 50%;
}
input:checked + .toggle-slider {
background: linear-gradient(135deg, #10b981 0%, #059669 100%);
}
input:checked + .toggle-slider:before {
transform: translateX(30px);
}
.theme-grid {
display: grid;
grid-template-columns: repeat(3, 1fr);
gap: 15px;
}
.theme-option {
aspect-ratio: 1;
border-radius: 12px;
cursor: pointer;
transition: all 0.3s;
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
gap: 8px;
padding: 10px;
border: 2px solid transparent;
}
.theme-option:hover {
transform: scale(1.05);
}
.theme-option.active {
border-color: #60a5fa;
box-shadow: 0 0 0 3px rgba(96, 165, 250, 0.2);
}
.theme-color {
width: 100%;
height: 70%;
border-radius: 8px;
}
.theme-name {
font-size: 0.8rem;
color: #94a3b8;
text-align: center;
}
/* Themes */
.theme-nebula .theme-color { background: linear-gradient(135deg, #0f172a, #1e1b4b); }
.theme-biolume .theme-color { background: linear-gradient(135deg, #064e3b, #0d9488); }
.theme-neoclassic .theme-color { background: linear-gradient(135deg, #1c1917, #44403c); }
.theme-sunset .theme-color { background: linear-gradient(135deg, #7c2d12, #c2410c); }
.theme-ocean .theme-color { background: linear-gradient(135deg, #1e3a8a, #0ea5e9); }
.theme-matrix .theme-color { background: linear-gradient(135deg, #14532d, #22c55e); }
/* Game states */
.game-over {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
background: rgba(15, 23, 42, 0.95);
padding: 40px;
border-radius: 20px;
text-align: center;
z-index: 10;
display: none;
backdrop-filter: blur(10px);
border: 1px solid rgba(255, 255, 255, 0.1);
box-shadow: 0 25px 50px rgba(0, 0, 0, 0.5);
min-width: 300px;
}
.game-over h2 {
font-size: 2.5rem;
color: #f87171;
margin-bottom: 15px;
}
.game-over p {
font-size: 1.2rem;
margin-bottom: 25px;
color: #cbd5e1;
}
.pulse {
animation: pulse 2s infinite;
}
@keyframes pulse {
0% { transform: scale(1); }
50% { transform: scale(1.05); }
100% { transform: scale(1); }
}
.snake-segment {
position: absolute;
border-radius: 4px;
transition: all 0.1s ease-out;
}
.food {
position: absolute;
border-radius: 50%;
animation: float 3s ease-in-out infinite;
}
@keyframes float {
0%, 100% { transform: translateY(0px); }
50% { transform: translateY(-5px); }
}
/* Mobile controls */
.mobile-controls {
display: none;
grid-template-columns: repeat(3, 1fr);
grid-template-rows: repeat(3, 1fr);
gap: 10px;
margin-top: 20px;
max-width: 300px;
aspect-ratio: 1;
}
.mobile-btn {
background: rgba(255, 255, 255, 0.1);
border: 1px solid rgba(255, 255, 255, 0.2);
border-radius: 12px;
display: flex;
justify-content: center;
align-items: center;
font-size: 1.5rem;
color: white;
cursor: pointer;
transition: all 0.2s;
}
.mobile-btn:active {
background: rgba(255, 255, 255, 0.2);
transform: scale(0.95);
}
.mobile-btn.up { grid-column: 2; grid-row: 1; }
.mobile-btn.left { grid-column: 1; grid-row: 2; }
.mobile-btn.right { grid-column: 3; grid-row: 2; }
.mobile-btn.down { grid-column: 2; grid-row: 3; }
/* Responsive */
@media (max-width: 768px) {
.main-content {
flex-direction: column;
}
.mobile-controls {
display: grid;
}
.game-wrapper {
padding: 15px;
}
.logo {
font-size: 2.5rem;
}
}
/* Particle effects */
.particle {
position: absolute;
pointer-events: none;
border-radius: 50%;
opacity: 0;
}
/* Score animation */
@keyframes scorePop {
0% { transform: scale(0); opacity: 0; }
50% { transform: scale(1.2); opacity: 1; }
100% { transform: scale(1); opacity: 1; }
}
.score-pop {
animation: scorePop 0.5s ease-out;
}
// Game Configuration
const config = {
gridSize: 20,
initialSpeed: 5,
themes: {
nebula: { snake: '#6366f1', food: '#f59e0b', bg: '#0f172a', grid: '#1e293b' },
biolume: { snake: '#10b981', food: '#8b5cf6', bg: '#064e3b', grid: '#0d9488' },
neoclassic: { snake: '#fbbf24', food: '#ef4444', bg: '#1c1917', grid: '#44403c' },
sunset: { snake: '#f97316', food: '#eab308', bg: '#7c2d12', grid: '#c2410c' },
ocean: { snake: '#0ea5e9', food: '#f0abfc', bg: '#1e3a8a', grid: '#0ea5e9' },
matrix: { snake: '#22c55e', food: '#84cc16', bg: '#14532d', grid: '#22c55e' }
},
currentTheme: 'nebula'
};
// Game State
let game = {
canvas: null,
ctx: null,
gridSize: config.gridSize,
cellSize: 0,
snake: [],
food: { x: 0, y: 0 },
direction: 'right',
nextDirection: 'right',
score: 0,
highScore: localStorage.getItem('snakeHighScore') || 0,
speed: config.initialSpeed,
gameLoop: null,
isRunning: false,
isPaused: false,
zenMode: false,
particles: []
};
// Initialize Game
function initGame() {
game.canvas = document.getElementById('gameCanvas');
game.ctx = game.canvas.getContext('2d');
// Set canvas size
resizeCanvas();
window.addEventListener('resize', resizeCanvas);
// Initialize UI elements
updateUI();
// Set up event listeners
setupEventListeners();
// Initialize snake
resetGame();
// Apply saved theme
const savedTheme = localStorage.getItem('snakeTheme') || 'nebula';
applyTheme(savedTheme);
document.querySelector(`[data-theme="${savedTheme}"]`).classList.add('active');
// Draw initial state
draw();
}
// Resize canvas to fit container
function resizeCanvas() {
const container = document.querySelector('.game-board');
const size = Math.min(container.clientWidth, container.clientHeight);
game.canvas.width = size;
game.canvas.height = size;
game.cellSize = size / game.gridSize;
draw();
}
// Set up event listeners
function setupEventListeners() {
// Keyboard controls
document.addEventListener('keydown', handleKeyPress);
// Button controls
document.getElementById('startBtn').addEventListener('click', startGame);
document.getElementById('pauseBtn').addEventListener('click', togglePause);
document.getElementById('resetBtn').addEventListener('click', resetGame);
document.getElementById('restartBtn').addEventListener('click', () => {
document.getElementById('gameOver').style.display = 'none';
resetGame();
startGame();
});
// Mobile controls
document.querySelectorAll('.mobile-btn').forEach(btn => {
btn.addEventListener('click', () => {
const direction = btn.dataset.direction;
changeDirection(direction);
// Visual feedback
btn.style.transform = 'scale(0.9)';
setTimeout(() => btn.style.transform = '', 100);
});
});
// Settings controls
const speedSlider = document.getElementById('speedSlider');
const gridSlider = document.getElementById('gridSlider');
const zenToggle = document.getElementById('zenToggle');
speedSlider.addEventListener('input', (e) => {
game.speed = parseInt(e.target.value);
document.getElementById('speedValue').textContent = game.speed;
document.getElementById('gameSpeed').textContent = game.speed;
if (game.isRunning && !game.isPaused) {
clearInterval(game.gameLoop);
game.gameLoop = setInterval(gameUpdate, 1000 / game.speed);
}
});
gridSlider.addEventListener('input', (e) => {
game.gridSize = parseInt(e.target.value);
document.getElementById('gridValue').textContent = game.gridSize;
resizeCanvas();
resetGame();
});
zenToggle.addEventListener('change', (e) => {
game.zenMode = e.target.checked;
applyTheme(config.currentTheme);
});
// Theme selection
document.querySelectorAll('.theme-option').forEach(option => {
option.addEventListener('click', () => {
const theme = option.dataset.theme;
applyTheme(theme);
// Update active theme
document.querySelectorAll('.theme-option').forEach(opt => {
opt.classList.remove('active');
});
option.classList.add('active');
// Save to localStorage
localStorage.setItem('snakeTheme', theme);
});
});
}
// Handle keyboard input
function handleKeyPress(e) {
if (game.isPaused || !game.isRunning) return;
switch(e.key) {
case 'ArrowUp':
case 'w':
case 'W':
if (game.direction !== 'down') game.nextDirection = 'up';
break;
case 'ArrowDown':
case 's':
case 'S':
if (game.direction !== 'up') game.nextDirection = 'down';
break;
case 'ArrowLeft':
case 'a':
case 'A':
if (game.direction !== 'right') game.nextDirection = 'left';
break;
case 'ArrowRight':
case 'd':
case 'D':
if (game.direction !== 'left') game.nextDirection = 'right';
break;
case ' ':
togglePause();
break;
}
e.preventDefault();
}
// Change direction with validation
function changeDirection(newDirection) {
if (!game.isRunning || game.isPaused) return;
const oppositeDirections = {
'up': 'down',
'down': 'up',
'left': 'right',
'right': 'left'
};
if (newDirection !== oppositeDirections[game.direction]) {
game.nextDirection = newDirection;
}
}
// Start the game
function startGame() {
if (game.isRunning) return;
game.isRunning = true;
game.isPaused = false;
document.getElementById('startBtn').innerHTML = '<i class="fas fa-play"></i> RESTART';
game.gameLoop = setInterval(gameUpdate, 1000 / game.speed);
}
// Toggle pause state
function togglePause() {
if (!game.isRunning) return;
game.isPaused = !game.isPaused;
const pauseBtn = document.getElementById('pauseBtn');
if (game.isPaused) {
clearInterval(game.gameLoop);
pauseBtn.innerHTML = '<i class="fas fa-play"></i> RESUME';
} else {
game.gameLoop = setInterval(gameUpdate, 1000 / game.speed);
pauseBtn.innerHTML = '<i class="fas fa-pause"></i> PAUSE';
}
}
// Reset game to initial state
function resetGame() {
// Clear existing game loop
if (game.gameLoop) {
clearInterval(game.gameLoop);
game.gameLoop = null;
}
// Reset game state
game.snake = [
{ x: Math.floor(game.gridSize / 2), y: Math.floor(game.gridSize / 2) },
{ x: Math.floor(game.gridSize / 2) - 1, y: Math.floor(game.gridSize / 2) },
{ x: Math.floor(game.gridSize / 2) - 2, y: Math.floor(game.gridSize / 2) }
];
game.direction = 'right';
game.nextDirection = 'right';
game.score = 0;
game.isRunning = false;
game.isPaused = false;
game.particles = [];
// Generate initial food
generateFood();
// Reset UI
document.getElementById('startBtn').innerHTML = '<i class="fas fa-play"></i> START GAME';
document.getElementById('pauseBtn').innerHTML = '<i class="fas fa-pause"></i> PAUSE';
document.getElementById('gameOver').style.display = 'none';
updateUI();
draw();
}
// Main game update loop
function gameUpdate() {
// Update direction
game.direction = game.nextDirection;
// Calculate new head position
const head = { ...game.snake[0] };
switch(game.direction) {
case 'up': head.y--; break;
case 'down': head.y++; break;
case 'left': head.x--; break;
case 'right': head.x++; break;
}
// Check wall collision
if (head.x < 0 || head.x >= game.gridSize || head.y < 0 || head.y >= game.gridSize) {
gameOver();
return;
}
// Check self collision
for (let segment of game.snake) {
if (head.x === segment.x && head.y === segment.y) {
gameOver();
return;
}
}
// Add new head to snake
game.snake.unshift(head);
// Check food collision
if (head.x === game.food.x && head.y === game.food.y) {
// Increase score
game.score += 10;
// Create particles
createFoodParticles(game.food.x, game.food.y);
// Generate new food
generateFood();
// Update UI with animation
document.getElementById('currentScore').classList.remove('score-pop');
void document.getElementById('currentScore').offsetWidth;
document.getElementById('currentScore').classList.add('score-pop');
// Increase speed slightly
if (game.score % 50 === 0 && game.speed < 20) {
game.speed++;
document.getElementById('speedSlider').value = game.speed;
document.getElementById('speedValue').textContent = game.speed;
document.getElementById('gameSpeed').textContent = game.speed;
clearInterval(game.gameLoop);
game.gameLoop = setInterval(gameUpdate, 1000 / game.speed);
}
} else {
// Remove tail if no food eaten
game.snake.pop();
}
// Update particles
updateParticles();
// Update UI
updateUI();
// Draw everything
draw();
}
// Generate food at random position
function generateFood() {
let foodPosition;
let attempts = 0;
const maxAttempts = 100;
do {
foodPosition = {
x: Math.floor(Math.random() * game.gridSize),
y: Math.floor(Math.random() * game.gridSize)
};
attempts++;
} while (isPositionOnSnake(foodPosition) && attempts < maxAttempts);
game.food = foodPosition;
}
// Check if position is on snake
function isPositionOnSnake(pos) {
return game.snake.some(segment => segment.x === pos.x && segment.y === pos.y);
}
// Game over logic
function gameOver() {
game.isRunning = false;
clearInterval(game.gameLoop);
// Update high score
if (game.score > game.highScore) {
game.highScore = game.score;
localStorage.setItem('snakeHighScore', game.highScore);
// Celebration effect
createConfetti();
}
// Show game over screen
document.getElementById('finalScore').textContent = game.score;
document.getElementById('highScoreDisplay').textContent = game.highScore;
document.getElementById('gameOver').style.display = 'block';
}
// Update UI elements
function updateUI() {
document.getElementById('currentScore').textContent = game.score;
document.getElementById('highScore').textContent = game.highScore;
document.getElementById('snakeLength').textContent = game.snake.length;
document.getElementById('gameSpeed').textContent = game.speed;
}
// Draw everything on canvas
function draw() {
const ctx = game.ctx;
const theme = config.themes[config.currentTheme];
// Clear canvas
ctx.fillStyle = theme.bg;
ctx.fillRect(0, 0, game.canvas.width, game.canvas.height);
// Draw grid (subtle in zen mode)
if (!game.zenMode) {
ctx.strokeStyle = `${theme.grid}20`;
ctx.lineWidth = 0.5;
for (let x = 0; x < game.gridSize; x++) {
for (let y = 0; y < game.gridSize; y++) {
ctx.strokeRect(
x * game.cellSize,
y * game.cellSize,
game.cellSize,
game.cellSize
);
}
}
}
// Draw snake with gradient effect
for (let i = 0; i < game.snake.length; i++) {
const segment = game.snake[i];
// Calculate gradient from head to tail
const alpha = 1 - (i / game.snake.length) * 0.7;
let color = theme.snake;
// Convert hex to rgba for alpha
if (color.startsWith('#')) {
const r = parseInt(color.slice(1, 3), 16);
const g = parseInt(color.slice(3, 5), 16);
const b = parseInt(color.slice(5, 7), 16);
color = `rgba(${r}, ${g}, ${b}, ${alpha})`;
}
// Draw segment with rounded corners
ctx.fillStyle = color;
drawRoundedRect(
ctx,
segment.x * game.cellSize + 1,
segment.y * game.cellSize + 1,
game.cellSize - 2,
game.cellSize - 2,
game.cellSize * 0.2
);
// Draw eyes on head
if (i === 0) {
ctx.fillStyle = '#ffffff';
const eyeSize = game.cellSize * 0.2;
const offset = game.cellSize * 0.25;
// Position eyes based on direction
let leftEye = { x: offset, y: offset };
let rightEye = { x: game.cellSize - offset - eyeSize, y: offset };
if (game.direction === 'up' || game.direction === 'down') {
leftEye = { x: offset, y: offset };
rightEye = { x: game.cellSize - offset - eyeSize, y: offset };
} else if (game.direction === 'left') {
leftEye = { x: offset, y: offset };
rightEye = { x: offset, y: game.cellSize - offset - eyeSize };
} else if (game.direction === 'right') {
leftEye = { x: game.cellSize - offset - eyeSize, y: offset };
rightEye = { x: game.cellSize - offset - eyeSize, y: game.cellSize - offset - eyeSize };
}
ctx.beginPath();
ctx.arc(
segment.x * game.cellSize + leftEye.x + eyeSize/2,
segment.y * game.cellSize + leftEye.y + eyeSize/2,
eyeSize/2,
0,
Math.PI * 2
);
ctx.fill();
ctx.beginPath();
ctx.arc(
segment.x * game.cellSize + rightEye.x + eyeSize/2,
segment.y * game.cellSize + rightEye.y + eyeSize/2,
eyeSize/2,
0,
Math.PI * 2
);
ctx.fill();
}
}
// Draw food with shine effect
const foodX = game.food.x * game.cellSize;
const foodY = game.food.y * game.cellSize;
// Food gradient
const foodGradient = ctx.createRadialGradient(
foodX + game.cellSize/2,
foodY + game.cellSize/2,
0,
foodX + game.cellSize/2,
foodY + game.cellSize/2,
game.cellSize/2
);
foodGradient.addColorStop(0, '#ffffff');
foodGradient.addColorStop(0.5, theme.food);
foodGradient.addColorStop(1, `${theme.food}80`);
ctx.fillStyle = foodGradient;
ctx.beginPath();
ctx.arc(
foodX + game.cellSize/2,
foodY + game.cellSize/2,
game.cellSize/2 - 1,
0,
Math.PI * 2
);
ctx.fill();
// Food shine
ctx.fillStyle = '#ffffff60';
ctx.beginPath();
ctx.arc(
foodX + game.cellSize/3,
foodY + game.cellSize/3,
game.cellSize/6,
0,
Math.PI * 2
);
ctx.fill();
// Draw particles
drawParticles();
}
// Draw rounded rectangle
function drawRoundedRect(ctx, x, y, width, height, radius) {
ctx.beginPath();
ctx.moveTo(x + radius, y);
ctx.lineTo(x + width - radius, y);
ctx.quadraticCurveTo(x + width, y, x + width, y + radius);
ctx.lineTo(x + width, y + height - radius);
ctx.quadraticCurveTo(x + width, y + height, x + width - radius, y + height);
ctx.lineTo(x + radius, y + height);
ctx.quadraticCurveTo(x, y + height, x, y + height - radius);
ctx.lineTo(x, y + radius);
ctx.quadraticCurveTo(x, y, x + radius, y);
ctx.closePath();
ctx.fill();
}
// Create particles when food is eaten
function createFoodParticles(x, y) {
const theme = config.themes[config.currentTheme];
const centerX = (x + 0.5) * game.cellSize;
const centerY = (y + 0.5) * game.cellSize;
for (let i = 0; i < 15; i++) {
game.particles.push({
x: centerX,
y: centerY,
vx: (Math.random() - 0.5) * 8,
vy: (Math.random() - 0.5) * 8,
size: Math.random() * 3 + 1,
color: theme.food,
life: 1.0,
decay: 0.02 + Math.random() * 0.03
});
}
}
// Create confetti for high score
function createConfetti() {
const colors = ['#6366f1', '#8b5cf6', '#f59e0b', '#10b981', '#0ea5e9'];
for (let i = 0; i < 50; i++) {
game.particles.push({
x: Math.random() * game.canvas.width,
y: -10,
vx: (Math.random() - 0.5) * 6,
vy: Math.random() * 3 + 2,
size: Math.random() * 8 + 4,
color: colors[Math.floor(Math.random() * colors.length)],
life: 1.0,
decay: 0.005
});
}
}
// Update particles
function updateParticles() {
for (let i = game.particles.length - 1; i >= 0; i--) {
const p = game.particles[i];
p.x += p.vx;
p.y += p.vy;
p.vy += 0.1; // Gravity
p.life -= p.decay;
if (p.life <= 0 || p.y > game.canvas.height) {
game.particles.splice(i, 1);
}
}
}
// Draw particles
function drawParticles() {
const ctx = game.ctx;
for (const p of game.particles) {
ctx.globalAlpha = p.life;
ctx.fillStyle = p.color;
ctx.beginPath();
ctx.arc(p.x, p.y, p.size, 0, Math.PI * 2);
ctx.fill();
}
ctx.globalAlpha = 1.0;
}
// Apply visual theme
function applyTheme(themeName) {
config.currentTheme = themeName;
// Update CSS variables for theme
const theme = config.themes[themeName];
const root = document.documentElement;
root.style.setProperty('--snake-color', theme.snake);
root.style.setProperty('--food-color', theme.food);
root.style.setProperty('--bg-color', theme.bg);
// Apply zen mode adjustments
if (game.zenMode) {
document.body.style.background = `linear-gradient(135deg, ${theme.bg} 0%, ${theme.grid} 100%)`;
} else {
document.body.style.background = `linear-gradient(135deg, #0f172a 0%, #1e293b 100%)`;
}
// Redraw with new theme
if (game.ctx) draw();
}
// Initialize game when page loads
window.addEventListener('DOMContentLoaded', initGame);
// Export for debugging
window.game = game;
window.config = config;
Project Description
Iyi ni game yinzoka, aho inzoka igenda irya igi , ikagenda ikura muburebure, uko inzoka iriye igi ninako ikura, nawe ugenda ubona amanota menshi, ikozwe muri HTML, CSS na JavaScript. Wowe icyo ukora nukureba aho igi riri ugapimiranya neza, ukayobora inzoka yawe igana kwigi, iyo iriye iryo gi ihita ikura muburebure, namanota yawe agahita yiyongera.
Iyo inzoka ikomeje kugenda ikagonga urukuta rwaho igomaba kugendera, uba utsinzwe, urongera ugatangira bundi bushya. Ifite amabuto atatu ariyo: START GAME ho ukanda kugira ngo utangire gukina game, ibuto ya PAUSE ukandaho, mugihe ushaka kuba uhagaritse gukina kugira ngo uze gukomerezaho nyuma, nindi buto yitwa RESET ukandaho, mugihe ushaka gutangira game bundi bushya.
Ushobora kongera cyangwa kugabanya umuvuduko inzoka igendaho, guhindura ingano yinzoka cyangwa igi. Ifite color themes mubabara atandatu ariyo: Nebula, Biolume, Neo-Classic, Sunset, Ocean na Matrix. Ifite aho urebera umuvuduko, inzoka iri kugenderaho, aho urebera amanota ugejeje, namagi inzoka imaze kurya, arinayo agaragaza uburebure bw'inzoka.
Ikwereka amanota ugenda ugira uko inzoka igenda irya, ibika amanota menshi washoboye kugira. Ugifungura game, inzoka igendera kumuvuduko wa 5 ariko ushobora kuwugabanya, ugashyira kumuvuduko wo munsi ya 5 cyangwa hejuru yaho.
Icyo amakode akoze iyi game, yagufasha kumenya nimba uri umuporogarama
- Kwiga kumuvinga cyangwa se kugendesha elements za html ukoresheje JavaScript
- Kwiga events listener muri JavaScript.
- Guhindura color themes muri JavaScript.
Project Resources
Download source code, images, and documentation