-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathmain.js
252 lines (238 loc) · 7.96 KB
/
main.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
//Defines initial Snake Variables - Speed, colors, and position
const GAME_SPEED = 100;
const CANVAS_BORDER_COLOUR = 'black';
const CANVAS_BACKGROUND_COLOUR = "white";
const SNAKE_COLOUR = 'lightgreen';
const SNAKE_BORDER_COLOUR = 'darkgreen';
const FOOD_COLOUR = 'red';
const FOOD_BORDER_COLOUR = 'darkred';
const test = "This is a test";
let snake = [
{x: 150, y: 150},
{x: 140, y: 150},
{x: 130, y: 150},
{x: 120, y: 150},
{x: 110, y: 150}
]
// The user's score
let score = 0;
// When set to true the snake is changing direction
let changingDirection = false;
// Food x-coordinate
let foodX;
// Food y-coordinate
let foodY;
// Horizontal velocity
let dx = 10;
// Vertical velocity
let dy = 0;
// Get the canvas element
const gameCanvas = document.getElementById("gameCanvas");
// Return a two dimensional drawing context
const ctx = gameCanvas.getContext("2d");
// Start game
main();
// Create the first food location
createFood();
// Call changeDirection whenever a key is pressed
document.addEventListener("keydown", changeDirection);
/**
* Main function of the game
* called repeatedly to advance the game
*/
function main() {
// If the game ended return early to stop game
if (didGameEnd()) return;
setTimeout(function onTick() {
changingDirection = false;
clearCanvas();
drawFood();
advanceSnake();
drawSnake();
// Call game again
main();
}, GAME_SPEED)
}
/**
* Change the background colour of the canvas to CANVAS_BACKGROUND_COLOUR and
* draw a border around it
*/
function clearCanvas() {
// Select the colour to fill the drawing
ctx.fillStyle = CANVAS_BACKGROUND_COLOUR;
// Select the colour for the border of the canvas
ctx.strokestyle = CANVAS_BORDER_COLOUR;
// Draw a "filled" rectangle to cover the entire canvas
ctx.fillRect(0, 0, gameCanvas.width, gameCanvas.height);
// Draw a "border" around the entire canvas
ctx.strokeRect(0, 0, gameCanvas.width, gameCanvas.height);
}
/**
* Draw the food on the canvas
*/
function drawFood() {
ctx.fillStyle = FOOD_COLOUR;
ctx.strokestyle = FOOD_BORDER_COLOUR;
ctx.fillRect(foodX, foodY, 10, 10);
ctx.strokeRect(foodX, foodY, 10, 10);
}
/**
* Advances the snake by changing the x-coordinates of its parts
* according to the horizontal velocity and the y-coordinates of its parts
* according to the vertical veolocity
*/
function advanceSnake() {
// Create the new Snake's head
const head = {x: snake[0].x + dx, y: snake[0].y + dy};
// Add the new head to the beginning of snake body
snake.unshift(head);
const didEatFood = snake[0].x === foodX && snake[0].y === foodY;
if (didEatFood) {
// Increase score
score += 10;
// Display score on screen
document.getElementById('score').innerHTML = score;
createFood();
} else {
// Remove the last part of snake body
snake.pop();
}
}
/**
* Returns true if the head of the snake touched another part of the game
* or any of the walls
*/
function didGameEnd() {
for (let i = 4; i < snake.length; i++) {
if (snake[i].x === snake[0].x && snake[i].y === snake[0].y) return true
}
const hitLeftWall = snake[0].x < 0;
const hitRightWall = snake[0].x > gameCanvas.width - 10;
const hitToptWall = snake[0].y < 0;
const hitBottomWall = snake[0].y > gameCanvas.height - 10;
return hitLeftWall || hitRightWall || hitToptWall || hitBottomWall
}
/**
* Generates a random number that is a multiple of 10 given a minumum
* and a maximum number
* @param { number } min - The minimum number the random number can be
* @param { number } max - The maximum number the random number can be
*/
function randomTen(min, max) {
return Math.round((Math.random() * (max-min) + min) / 10) * 10;
}
/**
* Creates random set of coordinates for the snake food.
*/
function createFood() {
// Generate a random number the food x-coordinate
foodX = randomTen(0, gameCanvas.width - 10);
// Generate a random number for the food y-coordinate
foodY = randomTen(0, gameCanvas.height - 10);
// if the new food location is where the snake currently is, generate a new food location
snake.forEach(function isFoodOnSnake(part) {
const foodIsoNsnake = part.x == foodX && part.y == foodY;
if (foodIsoNsnake) createFood();
});
}
/**
* Draws the snake on the canvas
*/
function drawSnake() {
// loop through the snake parts drawing each part on the canvas
snake.forEach(drawSnakePart)
}
/**
* Draws a part of the snake on the canvas
* @param { object } snakePart - The coordinates where the part should be drawn
*/
function drawSnakePart(snakePart) {
// Set the colour of the snake part
ctx.fillStyle = SNAKE_COLOUR;
// Set the border colour of the snake part
ctx.strokestyle = SNAKE_BORDER_COLOUR;
// Draw a "filled" rectangle to represent the snake part at the coordinates
// the part is located
ctx.fillRect(snakePart.x, snakePart.y, 10, 10);
// Draw a border around the snake part
ctx.strokeRect(snakePart.x, snakePart.y, 10, 10);
}
/**
* Changes the vertical and horizontal velocity of the snake according to the
* key that was pressed.
* The direction cannot be switched to the opposite direction, to prevent the snake
* from reversing
* For example if the the direction is 'right' it cannot become 'left'
* @param { object } event - The keydown event
*/
function changeDirection(event) {
//Left
const LEFT_KEY = 37;
const A_KEY = 65;
//Right
const RIGHT_KEY = 39;
const D_KEY = 68;
//Up
const UP_KEY = 38;
const W_KEY = 87;
//Down
const DOWN_KEY = 40;
const S_KEY = 83;
/**
* Prevent the snake from reversing
* Example scenario:
* Snake is moving to the right. User presses down and immediately left
* and the snake immediately changes direction without taking a step down first
*/
if (changingDirection) return;
changingDirection = true;
const keyPressed = event.keyCode;
const goingUp = dy === -10;
const goingDown = dy === 10;
const goingRight = dx === 10;
const goingLeft = dx === -10;
if (keyPressed === A_KEY && !goingRight || keyPressed === LEFT_KEY && !goingRight) {
dx = -10;
dy = 0;
}
if (keyPressed === W_KEY && !goingDown || keyPressed === UP_KEY && !goingDown) {
dx = 0;
dy = -10;
}
if (keyPressed === D_KEY && !goingLeft ||keyPressed === RIGHT_KEY && !goingLeft) {
dx = 10;
dy = 0;
}
if (keyPressed === S_KEY && !goingUp || keyPressed === DOWN_KEY && !goingUp) {
dx = 0;
dy = 10;
}
}
// Sets snake to original position
function resetSnake() {
snake = [
{x: 150, y: 150},
{x: 140, y: 150},
{x: 130, y: 150},
{x: 120, y: 150},
{x: 110, y: 150}
]
}
//Starts a new game
function restart() {
if (didGameEnd()) {
clearCanvas();
// Initialize score
score = 0;
// Display score on screen
document.getElementById('score').innerHTML = score;
advanceSnake();
drawFood();
resetSnake();
// Horizontal velocity
dx = 10;
// Vertical velocity
dy = 0;
};
main();
}