Console-Based Snake Game
Back to Projects

Console-Based Snake Game

December 5, 2023
C++Git

The Project

The objective of this project was to develop a dynamic console-based game using C++ and object-oriented design principles. The game is inspired by the classic snake game, where a controllable "snake" character moves around a game board, collecting food and growing with each item consumed. The aim is to collect the maximum amount of food while avoiding self-collision.

My Role

This project was primarily an independent effort. I was responsible for developing various aspects of the game and conducting testing. In the later stages of development, a partner joined to assist with player movement functionalities.

Game Development

Adhering to object-oriented programming principles, the project was divided into distinct modules: object data, player data, food data, and game mechanics. While most classes contain simple getter functions to facilitate development, some are more complex.

Player

The Player class handles player movement, checks interactions between food and the player, and increases the snake's body length. Two key functions in this class are:

  • movePlayer(): Takes input from the game mechanics class and updates the snake's head position accordingly.
cpp
void Player::movePlayer() {
    objPos currHead;
    playerPosList->getHeadElement(currHead);
 
    if (myDir == UP){
        currHead.y--;
        if (currHead.y < 0)
            currHead.y = (mainGameMechsRef->getBoardSizeY())-1;
    }
    if (myDir == LEFT){
        currHead.x--;
        if (currHead.x < 0)
            currHead.x = (mainGameMechsRef->getBoardSizeX())-1;
    }
    if (myDir == RIGHT){
        currHead.x++;
        if (currHead.x > (mainGameMechsRef->getBoardSizeX())-1)
            currHead.x = 0;
    }
    if (myDir == DOWN){
        currHead.y++;
        if (currHead.y > (mainGameMechsRef->getBoardSizeY())-1)
            currHead.y = 0;
    }
    if (myDir != NONE)
        mainGameMechsRef->setStartFlag();
 
    playerPosList->insertHead(currHead);
    playerPosList->removeTail();
 
    if ((checkSelfCollision() == true) &&
        (mainGameMechsRef->getWinFlagStatus() != true))
        mainGameMechsRef->setLoseFlag();
}
  • checkFoodConsumption(): Compares the snake's position with all food items on the board, returning different values based on the type of food encountered.
cpp
int Player::checkFoodConsuption() {
    objPos currHead;
    objPos foodpos;
    objPosArrayList* foodbucketlist = mainFoodRef->getFoodPos();
    playerPosList->getHeadElement(currHead);
 
    for (int i = 0; i < foodbucketlist->getSize(); i++){
        foodbucketlist->getElement(foodpos, i);
        if ((foodpos.x==currHead.x)&&(foodpos.y==currHead.y)){
            if (foodpos.symbol == '$') return 2;
            else return 1;
        }
    }
    return 0;
}

Food

The Food class is the most intricate class in the game. Its generateFood() function places up to five food objects on random game board spaces, excluding those occupied by the player. It also generates two different types of food items.

cpp
void Food::generateFood(objPosArrayList* blockOff) {
    srand(time(NULL));
    int xrand, yrand;
    bool unique;
    objPos tempBody, tempFood, foodComp;
 
    int available = ((mainGameMechsRef->getBoardSizeX()) *
                     (mainGameMechsRef->getBoardSizeY())) -
                    (blockOff->getSize());
 
    if (available < 5){
        tempFood.setObjPos(0, 0, 'o');
        for (int i = 0; i < 5; i++) foodBucket->removeTail();
        for (int i = 0; i < available; i++) foodBucket->insertHead(tempFood);
    }
 
    for (int i = 0; i < foodBucket->getSize(); i++){
        foodBucket->getElement(tempFood, i);
        while (true){
            unique = true;
            xrand = rand() % (mainGameMechsRef->getBoardSizeX());
            yrand = rand() % (mainGameMechsRef->getBoardSizeY());
 
            for (int k = 0; k < blockOff->getSize(); k++){
                blockOff->getElement(tempBody, k);
                if ((tempBody.x == xrand)&&(tempBody.y == yrand)){
                    unique = false; break;
                }
            }
            for (int k = 0; k < i; k++){
                foodBucket->getElement(foodComp, k);
                if ((foodComp.x == xrand)&&(foodComp.y == yrand)){
                    unique = false; break;
                }
            }
            if (unique == true){
                tempFood.x = xrand;
                tempFood.y = yrand;
                if (i == 0 || i == 1) tempFood.symbol = '$';
                break;
            }
        }
        foodBucket->insertHead(tempFood);
        foodBucket->removeTail();
    }
}

Final Product

Here is a recording of the game in action.

Console Snake Game demo