Open In App

Snake Game in C

Last Updated : 10 Jan, 2025
Comments
Improve
Suggest changes
Like Article
Like
Report

The Snake game is a simple arcade game where the player controls a snake that moves around to eat food. The goal is to keep eating food without crashing into the walls. The game ends when the snake crashes, with the player's score based on how much food was collected.

In this article, we will learn how to create snake game using C programming language.

Prerequisite

We can create a console-based snake game using basic knowledge of C along with the following prerequisites:

  • Working C compiler and IDE.
  • For windows, we need <windows.h>. For linux, we need <unistd.h>. These libraries are generally installed by default.
  • We might need to install <console.h> library as it does not comes bundled with the standard C compiler.

Gameplay

The gameplay of the snake game is simple. There are three game objects:

  1. Snake: The snake automatically moves into given direction till we change it. It has a mouth and tail.
  2. Fruit: The object that snake has to eat to grow.
  3. Walls: They are the boundary of the game area.

These objects work according to the game rules which are as follows:

  • The snake moves at a constant speed in one direction, and we can change its direction using the movement keys. However, the snake can only turn 90° at a time.
  • The objective is to eat as many fruits as possible, which will make the snake to grow in length.
  • The game ends if the snake collides with the boundary or its own body.

Implementation of Snake Game in C

Our objective is to create an interactive console-based snake game using C. The whole console screen can be visualized as the grid where each point has two coordinates, x-axis and y-axis coordinates. The position of each object the game will be described by these coordinates. All the game will be based on the continuous updating of these coordinates. The below is the intuition for the implementation of different game mechanics:

Snake Implementation Logic

The snake can be represented by the coordinates of its body stored in two arrays:

  • One Array for x-axis coordinates.
  • One Array for y-axis coordinates.

The head of the snake moves according to the user input:

  • W for up
  • S for down
  • A for left
  • D for right

while the rest of the body follows. When the snake eats some fruit, its length increases, and the coordinate array is updated. Collision detection is implemented to checking if the snake coordinates overlap (self-collision) or goes over the boundary limit (boundary collision).

Fruit Implementation Logic

The fruit is represented as a single coordinate within the game area. It is randomly placed inside the boundary, ensuring it doesn't spawn outside the playable area. The fruit have the following functions:

  • Random Positioning: The fruit's position is generated using random coordinates within the height and width of the game area, excluding the boundary.
  • Snake Eating: If the snake's head reaches the fruit's position, the fruit is "eaten", the snake grows in length, and the score increases.

Boundary Implementation Logic

The boundary defines the playing area of the game. It is created by drawing a box or rectangle that surrounds the playing field using some characters (usually # or | for the sides and - for the top and bottom), and it acts as a collision zone. We can define macros for setting the boundary limits.

Game Motion Implementation Logic

The motion in game is generated by an infinite loop that continuously updates the position of the snake and checks for game events such as collisions, fruit consumption or user input. In each iteration of the loop, the snake moves one step in the current direction, and the screen is redrawn in place or previous one to reflect the new position. It is similar to creating static images as frames and move them fast enough to create a motion.

Real Time Response Logic

Generally, we need to press the Enter key for the input buffer to supply data to the program. But this does not provide real time response. For real time interactive response, we use the kbhit() function provided by <conio.h>. This function returns the pressed character immediately as soon as the key is pressed on the keyboard.

Snake Game Code in C

C
// C program to implement an interactive
// snake game
#include <conio.h>
#include <ctype.h>
#include <stdio.h>
#include <stdlib.h>
#include <windows.h>

// Macros variable (HEIGHT, WIDTH)
#define HEIGHT 20
#define WIDTH 40

// Array to store the coordinates of snake
// tail (x-axis, y-axis)
int snakeTailX[100], snakeTailY[100];

// Variable to store the length of the
// snake's tail
int snakeTailLen;

// Score and signal flags
int gameover, key, score;

// Coordinates of snake's head and fruit
int x, y, fruitx, fruity;

// Function to generate the fruit
// within the boundary
void setup() {
    
    // Flag to signal the gameover
    gameover = 0;

    // Initial coordinates of the snake
    x = WIDTH / 2;
    y = HEIGHT / 2;
    
    // Initial coordinates of the fruit
    fruitx = rand() % WIDTH;
    fruity = rand() % HEIGHT;
    while (fruitx == 0)
        fruitx = rand() % WIDTH;

    while (fruity == 0)
        fruity = rand() % HEIGHT;

    // Score initialzed
    score = 0;
}

// Function to draw the game field, snake
// and fruit
void draw() {
    system("cls");
    
    // Creating top wall
    for (int i = 0; i < WIDTH + 2; i++)
        printf("-");
    printf("\n");
    
    for (int i = 0; i < HEIGHT; i++) {
        for (int j = 0; j <= WIDTH; j++) {

            // Creating side walls with '#'
            if (j == 0 || j == WIDTH)
                printf("#");
            
            // Creating snake's head with 'O'
            if (i == y && j == x)
                printf("O");
            
            // Creating the sanke's food with '*'
            else if (i == fruity && j == fruitx)
                printf("*");
            
            // Creating snake's body with 'o'
            else {
                int prTail = 0;
                for (int k = 0; k < snakeTailLen; k++) {
                    if (snakeTailX[k] == j
                        && snakeTailY[k] == i) {
                        printf("o");
                        prTail = 1;
                    }
                }
                if (!prTail)
                    printf(" ");
            }
        }
      printf("\n");
            
    }
    
    // Creating bottom walls with '-'
    for (int i = 0; i < WIDTH + 2; i++)
        printf("-");
     printf("\n");

    // Print the score and instructions
    printf("score = %d", score);
    printf("\n");
    printf("Press W, A, S, D for movement.\n");
    printf("Press X to quit the game.");
}

// Function to take the real time input and
// set the 'flag' variable accordingly
void input() {
    if (kbhit()) {
        switch (tolower(getch())) {
        case 'a':
            if(key!=2)
            key = 1;
            break;
        case 'd':
            if(key!=1)
            key = 2;
            break;
        case 'w':
            if(key!=4)
            key = 3;
            break;
        case 's':
            if(key!=3)
            key = 4;
            break;
        case 'x':
            gameover = 1;
            break;
        }
    }
}

// Function for the movement logic that
// checks eat, move, collisions
void logic() {
    
    // Updating the coordinates for continous
    // movement of snake
    int prevX = snakeTailX[0];
    int prevY = snakeTailY[0];
    int prev2X, prev2Y;
    snakeTailX[0] = x;
    snakeTailY[0] = y;
    for (int i = 1; i < snakeTailLen; i++) {
        prev2X = snakeTailX[i];
        prev2Y = snakeTailY[i];
        snakeTailX[i] = prevX;
        snakeTailY[i] = prevY;
        prevX = prev2X;
        prevY = prev2Y;
    }
    
    // Changing the direction of movement of snake
    switch (key) {
    case 1:
        x--;
        break;
    case 2:
        x++;
        break;
    case 3:
        y--;
        break;
    case 4:
        y++;
        break;
    default:
        break;
    }

    // If the game is over
    if (x < 0 || x >= WIDTH || y < 0 || y >= HEIGHT)
        gameover = 1;
        
    // Checks for collision with the tail (o)
    for (int i = 0; i < snakeTailLen; i++) {
        if (snakeTailX[i] == x && snakeTailY[i] == y)
            gameover = 1;
    }

    // If snake reaches the fruit
    // then update the score
    if (x == fruitx && y == fruity) {
        fruitx = rand() % WIDTH;
        fruity = rand() % HEIGHT;
        while (fruitx == 0)
            fruitx = rand() % WIDTH;

        // Generation of new fruit
        while (fruity == 0)
            fruity = rand() % HEIGHT;
        score += 10;
         snakeTailLen++;
    }
}

void main() {
  
    // Initial set up that initialize the
    // required variables
    setup();

    // Game loop starts here
    while (!gameover) {

        // Functions that will be called
        // repeatedly after the given interval
        draw();
        input();
        logic();
        Sleep(33);
    }
}


Output:



Next Article

Similar Reads