For this weeks assignment I decided to create the popular Snake game. In the creative process I tried to optimize it and I am quite happy with the results. I created a simple class for a snake element and then reused it while creating food items.
To make the game even more optimized I decided to draw the snake in a specific fashion. When the snake eats their food, the food is not “added” to it. Rather than that, the last part of the snake is not removed from it a single time, as it would usually be. That makes the transition a lot smoother and also makes the code cleaner.
With regard to the hit boxes I made them simple as the game was designed on a 10px grid. As a result the snake elements are 10px/10px. Due to that, I could simply compare the X and Y dimensions of the Snake’s leading tile against food’s location, rather than comparing whole ranges, which would be much less efficient.
class snakeRect {
constructor(x, y) {
this.x = x;
this.y = y;
}
}
score = 0;
food = new snakeRect(-10,-10);
vx = -10;
vy = 0;
snake = [new snakeRect(200, 200),
new snakeRect(210, 200),
new snakeRect(220, 200),
new snakeRect(230, 200),
];
function setup() {
createCanvas(400, 400);
textSize(50);
food.x = round(random(0, (width-10)/10))*10;
food.y = round(random(0, (height-10)/10))*10;
}
function draw() {
background(220);
fill(255);
textAlign(LEFT);
text(score, 20, 50);
if (isGameOver()){
textAlign(CENTER);
translate(width/2, height/2);
fill(255);
text('Game Over', 0, 0);
return;
}
drawSnake();
drawFood();
if (frameCount%5==0) {
moveSnake();
}
}
function getFood() {
randX = round(random(0, (width-10)/10))*10;
randY = round(random(0, (height-10)/10))*10;
for(i=0; i<snake.length; i++) {
if (snake[i].x==randX && snake[i].y==randY) {
getFood();
}
}
food.x = randX;
food.y = randY;
}
function drawFood() {
fill(255, 255, 0);
rect(food.x, food.y, 10, 10);
}
function drawSnake() {
fill(200,200,0);
for (i=0; i<snake.length; i++) {
rect(snake[i].x, snake[i].y, 10, 10);
}
}
function moveSnake() {
newElem = new snakeRect(snake[0].x+vx, snake[0].y+vy);
snake.unshift(newElem);
if (snake[0].x === food.x && snake[0].y === food.y) {
score+=10;
getFood();
}
else {
snake.pop();
}
}
function keyPressed() {
if (keyCode===LEFT_ARROW && vx!=10) {
vx=-10;
vy=0;
}
else if (keyCode === RIGHT_ARROW && vx!=-10) {
vx=10;
vy=0;
}
else if (keyCode === UP_ARROW && vy!=10) {
vx=0;
vy=-10;
}
else if (keyCode === DOWN_ARROW && vy!=-10) {
vx=0;
vy=10;
}
}
function isGameOver() {
for (i=4; i<snake.length; i++)
{
if (snake[i].x === snake[0].x && snake[i].y === snake[0].y) {
return true;
}
}
return snake[0].x<0 || snake[0].x>width-10 || snake[0].y<0 || snake[0].y>height-10;
}