In this part, we will implement the part that deals with the game state. It includes detecting collisions, calculating the new position of the snake, and finding a free place to place food. Let’s jump in!
First, let’s fill the region with constants that we will need throughout the code.
The first two variables we will use to see if the pressed key was space or a, w, d, s or left, top, right, down.
We can see that objects with movement keys, direction, and movement have the same keys. It will help us to escape typing errors.
A default config is an object. We will use it in the function that will generate the initial state for the game.
We are measuring time in the game in milliseconds and will update the state of the game and re-render everything 60 times per second, so that movement will look super-smooth.
We start the core region with a function that will find a free from the snake spot on the field to place food.
The function receives the width and height of the game with the snake. Worth to mention that the game coordinates don’t have any business with coordinates on the screen. In the core region, we don’t care if the game renders on canvas, SVG, or some virtual reality space. We measure distance in-game field cells. On the example below, we can see the game the width equal to 17 and height equal to 15.
First, we ignore the snake and generate all possible positions for food in the center of each cell. Then we filter all the points so that they are not inside some segment of the snake and randomly pick one of them.
When we can place food on the game field, we are ready to write the function that will create an initial state for the game.
In this function, we merge in a received state default state, create a snake, take food, and return an initial state.
Next, the function that will return a new direction given old direction in the form of vector and movement in the form of string.
It checks that movement is defined and direction is not opposed to the old one.
We have different logic for updating the position of the snake head and the rest of the body. To update the tail, we go over each snake segment and make it shorter or remove it at all.
Process of new state generation consists of three parts:
- Receive state after processing movement.
- Receive state after processing possible collisions with food.
- Check if the game is over.
The function for movement processing receives old state, movement in the form of a string, and calculated distance.
Here we need to catch the right moment for changing snake direction according to player movement. We are doing this by calculating a new position if so there was no movement change and then checking if the snake head crossed the center of the cell.
On the second stage, we make the snake tail on one unit longer and generate a new position for the food if segment with snake head intersect food.
Here we are leveraging our geometry functionality to detect intersection and calculate a new position for the tail.
Game is over when the snake goes outside the game field or when there is a self-intersection.
To see if snake crosses boundaries, we take coordinates of the head and see if they are in the range between zero and width, height appropriately. Self-intersection can happen only when the number of points is more or equal to five. To see if the head intersects some segment we project head to the segment line, and if the projected point is inside of the segment and distance between it and the head is less than half of the cell it means that the game is over.
It receives an old state, movement in the form of string and time from the previous update.
To calculate distance, we multiple speed on the timespan. After updating the state, we check if the game is over and if so return the initial state.
Reach the next level of focus and productivity with increaser.org.