├── screenshots
└── Snake.png
├── README.md
├── index.html
├── style.css
└── app.js
/screenshots/Snake.png:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | ## 🐍 Enhanced Snake Game!
2 |
3 | ## 🎮 About The Game
4 |
5 | Snake Game is a simple, fun and easy to learn JavaScript game. The goal is to grow the snake with food and score as many points as possible without touching the walls or its own body.
6 |
7 | The game is perfect for both beginners and those who want to develop game projects with JS.
8 |
9 | ## 🕹️ How To Play
10 |
11 | Open the index.html file in your browser.
12 |
13 | Use the Arrow Keys to move the snake:
14 |
15 | - Arrow Up – up
16 |
17 | - Arrow Down – down
18 |
19 | - Arrow Left – left
20 |
21 | - Arrow Right – right
22 |
23 | Try to eat the red food and score points.
24 |
25 | If the snake touches the wall or its own body, the game will end.
26 |
27 | ## ⚡ Features
28 |
29 | - Simple and user-friendly UI
30 |
31 | - Fun with a scoring system
32 |
33 | - Responsive gameplay that works on all devices
34 |
35 | ## 📈 Technologies Used
36 |
37 | - HTML5
38 |
39 | - CSS3
40 |
41 | - JavaScript (Vanilla)
42 |
43 | ## 💡 Future Improvements
44 |
45 | - Add sound effects
46 |
47 | - Colorful and animated snake
48 |
49 | - Speed levels and game difficulty
50 |
51 | - Mobile-friendly controls
52 |
53 | ## 👤 Author
54 |
55 | - Murad – Full-Stack Developer & JavaScript Enthusiast
56 | GitHub Profile
57 |
58 | - TheM1ddleM1n - for adding improvements!
59 |
--------------------------------------------------------------------------------
/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | Enhanced Snake Game
7 |
8 |
9 |
10 |
11 |
🐍 Snake Game
12 |
13 |
14 |
18 |
19 |
High Score
20 |
0
21 |
22 |
26 |
27 |
28 |
29 |
30 |
31 | Easy
32 |
33 |
34 |
35 | Medium
36 |
37 |
38 |
39 | Hard
40 |
41 |
42 |
43 |
44 |
45 |
46 | Start Game
47 | Pause
48 | Reset
49 |
50 |
51 |
52 | Use Arrow Keys or WASD to control the snake. Eat food to grow and score points!
53 |
54 |
55 |
56 |
57 |
58 |
Game Over!
59 |
Final Score: 0
60 |
High Score: 0
61 |
Play Again
62 |
63 |
64 |
65 |
66 |
67 |
68 |
--------------------------------------------------------------------------------
/style.css:
--------------------------------------------------------------------------------
1 | * {
2 | margin: 0;
3 | padding: 0;
4 | box-sizing: border-box;
5 | }
6 |
7 | body {
8 | display: flex;
9 | flex-direction: column;
10 | align-items: center;
11 | justify-content: center;
12 | font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
13 | background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
14 | color: #fff;
15 | min-height: 100vh;
16 | padding: 20px;
17 | }
18 |
19 | .game-container {
20 | background: rgba(255, 255, 255, 0.1);
21 | backdrop-filter: blur(10px);
22 | border-radius: 20px;
23 | padding: 30px;
24 | box-shadow: 0 8px 32px rgba(0, 0, 0, 0.3);
25 | text-align: center;
26 | }
27 |
28 | h1 {
29 | font-size: 2.5em;
30 | margin-bottom: 10px;
31 | text-shadow: 2px 2px 4px rgba(0, 0, 0, 0.3);
32 | background: linear-gradient(45deg, #fff, #a8edea);
33 | -webkit-background-clip: text;
34 | -webkit-text-fill-color: transparent;
35 | background-clip: text;
36 | }
37 |
38 | .stats-container {
39 | display: flex;
40 | gap: 30px;
41 | justify-content: center;
42 | margin: 20px 0;
43 | flex-wrap: wrap;
44 | }
45 |
46 | .stat-box {
47 | background: rgba(255, 255, 255, 0.15);
48 | padding: 15px 25px;
49 | border-radius: 12px;
50 | min-width: 120px;
51 | }
52 |
53 | .stat-label {
54 | font-size: 0.9em;
55 | opacity: 0.9;
56 | margin-bottom: 5px;
57 | }
58 |
59 | .stat-value {
60 | font-size: 2em;
61 | font-weight: bold;
62 | text-shadow: 2px 2px 4px rgba(0, 0, 0, 0.3);
63 | }
64 |
65 | canvas {
66 | background: linear-gradient(135deg, #1a1a2e 0%, #16213e 100%);
67 | margin: 20px 0;
68 | border: 3px solid rgba(255, 255, 255, 0.3);
69 | border-radius: 10px;
70 | box-shadow: 0 4px 20px rgba(0, 0, 0, 0.4);
71 | max-width: 100%;
72 | height: auto;
73 | }
74 |
75 | .controls {
76 | display: flex;
77 | gap: 15px;
78 | flex-wrap: wrap;
79 | justify-content: center;
80 | margin-top: 20px;
81 | }
82 |
83 | button {
84 | background: rgba(255, 255, 255, 0.2);
85 | color: white;
86 | border: 2px solid rgba(255, 255, 255, 0.3);
87 | padding: 12px 25px;
88 | border-radius: 10px;
89 | font-size: 1em;
90 | font-weight: bold;
91 | cursor: pointer;
92 | transition: all 0.3s ease;
93 | text-transform: uppercase;
94 | letter-spacing: 1px;
95 | }
96 |
97 | button:hover {
98 | background: rgba(255, 255, 255, 0.3);
99 | transform: translateY(-2px);
100 | box-shadow: 0 4px 12px rgba(0, 0, 0, 0.3);
101 | }
102 |
103 | button:active {
104 | transform: translateY(0);
105 | }
106 |
107 | .difficulty-selector {
108 | margin: 15px 0;
109 | }
110 |
111 | .difficulty-selector label {
112 | margin: 0 10px;
113 | cursor: pointer;
114 | padding: 8px 15px;
115 | background: rgba(255, 255, 255, 0.1);
116 | border-radius: 8px;
117 | display: inline-block;
118 | transition: all 0.3s ease;
119 | }
120 |
121 | .difficulty-selector input[type="radio"] {
122 | margin-right: 5px;
123 | }
124 |
125 | .difficulty-selector label:hover {
126 | background: rgba(255, 255, 255, 0.2);
127 | }
128 |
129 | .game-over-overlay {
130 | display: none;
131 | position: fixed;
132 | top: 0;
133 | left: 0;
134 | width: 100%;
135 | height: 100%;
136 | background: rgba(0, 0, 0, 0.8);
137 | justify-content: center;
138 | align-items: center;
139 | z-index: 1000;
140 | }
141 |
142 | .game-over-content {
143 | background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
144 | padding: 40px;
145 | border-radius: 20px;
146 | text-align: center;
147 | animation: slideIn 0.5s ease;
148 | }
149 |
150 | @keyframes slideIn {
151 | from {
152 | transform: scale(0.5);
153 | opacity: 0;
154 | }
155 | to {
156 | transform: scale(1);
157 | opacity: 1;
158 | }
159 | }
160 |
161 | .instructions {
162 | margin-top: 20px;
163 | font-size: 0.9em;
164 | opacity: 0.8;
165 | max-width: 400px;
166 | }
167 |
168 | @media (max-width: 600px) {
169 | h1 {
170 | font-size: 1.8em;
171 | }
172 |
173 | .game-container {
174 | padding: 20px;
175 | }
176 | }
177 |
--------------------------------------------------------------------------------
/app.js:
--------------------------------------------------------------------------------
1 | const canvas = document.getElementById('gameCanvas');
2 | const ctx = canvas.getContext('2d');
3 | const box = 20;
4 |
5 | let snake = [];
6 | let food = {};
7 | let direction = "";
8 | let score = 0;
9 | let highScore = 0;
10 | let level = 1;
11 | let game = null;
12 | let isPaused = false;
13 | let gameStarted = false;
14 | let speed = 150;
15 |
16 | const difficulties = {
17 | easy: 150,
18 | medium: 100,
19 | hard: 60
20 | };
21 |
22 | function initGame() {
23 | snake = [{ x: 9 * box, y: 10 * box }];
24 | direction = "";
25 | score = 0;
26 | level = 1;
27 | isPaused = false;
28 | gameStarted = false;
29 | updateScore();
30 | generateFood();
31 | draw();
32 | }
33 |
34 | function generateFood() {
35 | food = {
36 | x: Math.floor(Math.random() * (canvas.width / box)) * box,
37 | y: Math.floor(Math.random() * (canvas.height / box)) * box
38 | };
39 |
40 | for(let segment of snake) {
41 | if(food.x === segment.x && food.y === segment.y) {
42 | generateFood();
43 | return;
44 | }
45 | }
46 | }
47 |
48 | function drawSnake() {
49 | for(let i = 0; i < snake.length; i++) {
50 | const gradient = ctx.createLinearGradient(
51 | snake[i].x, snake[i].y,
52 | snake[i].x + box, snake[i].y + box
53 | );
54 |
55 | if(i === 0) {
56 | gradient.addColorStop(0, '#00ff88');
57 | gradient.addColorStop(1, '#00cc66');
58 | } else {
59 | gradient.addColorStop(0, '#44ff99');
60 | gradient.addColorStop(1, '#22dd77');
61 | }
62 |
63 | ctx.fillStyle = gradient;
64 | ctx.fillRect(snake[i].x, snake[i].y, box - 2, box - 2);
65 |
66 | if(i === 0) {
67 | ctx.fillStyle = '#fff';
68 | ctx.beginPath();
69 | ctx.arc(snake[i].x + 6, snake[i].y + 8, 2, 0, Math.PI * 2);
70 | ctx.arc(snake[i].x + 14, snake[i].y + 8, 2, 0, Math.PI * 2);
71 | ctx.fill();
72 | }
73 | }
74 | }
75 |
76 | function drawFood() {
77 | const gradient = ctx.createRadialGradient(
78 | food.x + box/2, food.y + box/2, 2,
79 | food.x + box/2, food.y + box/2, box/2
80 | );
81 | gradient.addColorStop(0, '#ff4444');
82 | gradient.addColorStop(1, '#cc0000');
83 |
84 | ctx.fillStyle = gradient;
85 | ctx.beginPath();
86 | ctx.arc(food.x + box/2, food.y + box/2, box/2 - 2, 0, Math.PI * 2);
87 | ctx.fill();
88 |
89 | ctx.fillStyle = '#00ff00';
90 | ctx.fillRect(food.x + box/2 - 2, food.y + 2, 2, 4);
91 | }
92 |
93 | function draw() {
94 | ctx.fillStyle = "#1a1a2e";
95 | ctx.fillRect(0, 0, canvas.width, canvas.height);
96 |
97 | drawSnake();
98 | drawFood();
99 |
100 | if(!gameStarted) {
101 | ctx.fillStyle = "rgba(255, 255, 255, 0.8)";
102 | ctx.font = "24px Arial";
103 | ctx.textAlign = "center";
104 | ctx.fillText("Press START to begin", canvas.width/2, canvas.height/2);
105 | return;
106 | }
107 |
108 | if(isPaused) {
109 | ctx.fillStyle = "rgba(0, 0, 0, 0.7)";
110 | ctx.fillRect(0, 0, canvas.width, canvas.height);
111 | ctx.fillStyle = "white";
112 | ctx.font = "30px Arial";
113 | ctx.textAlign = "center";
114 | ctx.fillText("PAUSED", canvas.width/2, canvas.height/2);
115 | return;
116 | }
117 |
118 | let snakeX = snake[0].x;
119 | let snakeY = snake[0].y;
120 |
121 | if(direction === "LEFT") snakeX -= box;
122 | if(direction === "UP") snakeY -= box;
123 | if(direction === "RIGHT") snakeX += box;
124 | if(direction === "DOWN") snakeY += box;
125 |
126 | if(snakeX === food.x && snakeY === food.y) {
127 | score++;
128 | level = Math.floor(score / 5) + 1;
129 | updateScore();
130 | generateFood();
131 | } else {
132 | snake.pop();
133 | }
134 |
135 | let newHead = { x: snakeX, y: snakeY };
136 |
137 | if(snakeX < 0 || snakeX >= canvas.width || snakeY < 0 || snakeY >= canvas.height || collision(newHead, snake)) {
138 | gameOver();
139 | return;
140 | }
141 |
142 | snake.unshift(newHead);
143 | }
144 |
145 | function collision(head, array) {
146 | for(let i = 0; i < array.length; i++) {
147 | if(head.x === array[i].x && head.y === array[i].y) return true;
148 | }
149 | return false;
150 | }
151 |
152 | function updateScore() {
153 | document.getElementById('score').textContent = score;
154 | document.getElementById('level').textContent = level;
155 |
156 | if(score > highScore) {
157 | highScore = score;
158 | document.getElementById('highScore').textContent = highScore;
159 | }
160 | }
161 |
162 | function gameOver() {
163 | clearInterval(game);
164 | gameStarted = false;
165 | document.getElementById('finalScore').textContent = score;
166 | document.getElementById('finalHighScore').textContent = highScore;
167 | document.getElementById('gameOverOverlay').style.display = 'flex';
168 | }
169 |
170 | function restartGame() {
171 | document.getElementById('gameOverOverlay').style.display = 'none';
172 | initGame();
173 | startGame();
174 | }
175 |
176 | function startGame() {
177 | if(gameStarted) return;
178 |
179 | const selectedDifficulty = document.querySelector('input[name="difficulty"]:checked').value;
180 | speed = difficulties[selectedDifficulty];
181 |
182 | gameStarted = true;
183 | isPaused = false;
184 |
185 | if(direction === "") {
186 | direction = "RIGHT";
187 | }
188 |
189 | if(game) clearInterval(game);
190 | game = setInterval(draw, speed);
191 | }
192 |
193 | function pauseGame() {
194 | if(!gameStarted) return;
195 | isPaused = !isPaused;
196 | document.getElementById('pauseBtn').textContent = isPaused ? 'Resume' : 'Pause';
197 | }
198 |
199 | function resetGame() {
200 | if(game) clearInterval(game);
201 | initGame();
202 | document.getElementById('pauseBtn').textContent = 'Pause';
203 | }
204 |
205 | document.addEventListener("keydown", (event) => {
206 | if(!gameStarted && (event.key.startsWith("Arrow") || "wasd".includes(event.key.toLowerCase()))) {
207 | startGame();
208 | }
209 |
210 | if(event.key === " ") {
211 | event.preventDefault();
212 | pauseGame();
213 | return;
214 | }
215 |
216 | if((event.key === "ArrowLeft" || event.key === "a") && direction !== "RIGHT") direction = "LEFT";
217 | if((event.key === "ArrowUp" || event.key === "w") && direction !== "DOWN") direction = "UP";
218 | if((event.key === "ArrowRight" || event.key === "d") && direction !== "LEFT") direction = "RIGHT";
219 | if((event.key === "ArrowDown" || event.key === "s") && direction !== "UP") direction = "DOWN";
220 | });
221 |
222 | document.getElementById('startBtn').addEventListener('click', startGame);
223 | document.getElementById('pauseBtn').addEventListener('click', pauseGame);
224 | document.getElementById('resetBtn').addEventListener('click', resetGame);
225 |
226 | document.querySelectorAll('input[name="difficulty"]').forEach(radio => {
227 | radio.addEventListener('change', () => {
228 | if(gameStarted) {
229 | resetGame();
230 | }
231 | });
232 | });
233 |
234 | initGame();
235 |
--------------------------------------------------------------------------------