Improve your programming skills creating a Snake game in C#

 Do you want to improve your programming logic without relying on frameworks? I have noticed that many of my colleagues struggle to carry out their developments if there is no library (NuGet, Plugin, Component, Package, etc.) that does exactly what is expected as the final result, and this can sometimes be frustrating. Don’t get me wrong, libraries are valuable tools, but many times, a development that could be simple becomes complicated due to the eagerness to save work and effort.

I will demonstrate that with just basic concepts, you can build something amazing. Using a matrix (or a two-dimensional array), we will create a Snake game, from the game engine to the rendering of the image displayed on the screen, and we will also add sounds.

How to achieve this?

This example will be done in C# with .NET, and we will only use libraries from .NET itself.

We will use a matrix as the main component to bring our Snake to life. Each element of the matrix has a number associated with it, called an "index," which allows us to access it.

We can easily compare the graphical representation of a matrix to a chessboard; suppose we have a pawn at position [2, 2] and want to move it one square to our left. We can observe that to simulate this left movement, the new position of our pawn would be [2, 1]. Therefore, we can assume that leftward movements subtract, and rightward movements add, just like on the number line, and the same applies to movements up and down. Although the comparison with the chessboard is a good example, we must be more technical to fully understand the general idea.

A more accurate comparison of our matrix or chessboard would be with the fourth quadrant of the Cartesian plane:

Once on the Cartesian plane, we know that to locate a point, we must use the variables x and y, which, in turn, will be the index of our matrix.

The major difference between the Cartesian plane and a matrix is that in the matrix, we can store different values in each of the indices or positions. For example, we have the following values stored at the given indices:

[4, 3] = 2
[0, 2] = 1
[0, 3] = 1
[2, 1] = 0

These can be represented in the Cartesian plane/matrix as follows:

Now, returning to the initial example, if we want the number "2" to move to the left, we could use the following formula:

matrix[x - 1, y] = 2

In our specific case, it would look like this:

matrix[3 - 1, 4] = 2
matrix[2, 4] = 2

We see that the new index or position for the number 2 is [2, 4], which represents a leftward movement compared to the original position [3, 4]. The same applies to all four directions, as described in the initial example:

  • Left movement: matrix[x - 1, y]

  • Right movement: matrix[x + 1, y]

  • Upward movement: matrix[x, y - 1]

  • Downward movement: matrix[x, y + 1]

Gameplay

This will initially be the base concept of our Snake game. Now it's time to move on to the gameplay. We all know the mechanics of the Snake game: the movement direction of a snake is controlled as it advances automatically. When the game starts, the length of the snake is minimal, and to increase this length, the snake’s head must pass over a point generated at a random position on the game map. Once the snake's length increases, the difficulty also rises because we must avoid the snake’s head colliding with its own body or the map’s edges. If either of these two situations occurs, the game ends.

In addition to gameplay, we must also think about how we will render the graphics of our game. At first glance, this may seem somewhat complicated, but we must remember that an image is a collection of pixels organized in a matrix, and the foundation of our game is a matrix! Keeping this in mind, the only thing we need to do to "render" our game is to copy the matrix into an image. In C#, we can use the System.Drawing.Bitmap library, which allows us to specify the color of a pixel at a given index.

It is important to consider that one index of our matrix corresponds to one pixel of the image, meaning we would not be able to distinguish the snake on the screen. We must use a scale when rendering the image. For example, if we use a scale of 10, each index of our matrix would correspond to 10 pixels of the image displayed on the screen.

Another important aspect to consider is time. We must determine how many frames per second our game will have, or rather, how often we will execute validations and actions for the Snake. The interval between one frame and another will be known as delta time, and we will define it in milliseconds. In each of these intervals, we will move the snake forward one step at a time, but not before verifying that in this next step, it does not collide with the map’s edges or its own body. Similarly, we will check if it has “eaten” a point to increase its length.

Code

To see the example code, check the repository on GitHub Here

Comentarios