Home CV Blog

Coding a Snake Clone

Coding a Snake Clone

Recently I decided to look at coding games in C with raylib, made a few experiments and then I decided to code a snake clone from scratch. I knew that a snake could work as queue of positions. Moving a snake would be simply pushing a new position to the list and removing its tail. In order to make the snake grow all I had to do was not removing its tail if the snake encountered food.

After coding my snake clone in C, I decided to compare different ways of coding games and ended up with three versions of my snake clone:

Snake in C

typedef struct SnakeNode SnakeNode;
struct SnakeNode {
    Vector2 pos;
    SnakeNode *next;
    SnakeNode *prev;
};

typedef struct {
    SnakeNode *head;
    SnakeNode *tail;
    Vector2 dir;
    bool dead;
} Snake;

Snake CreateSnake(Vector2 pos, Vector2 dir);
void PushSnakeNode(Snake *snake, Vector2 pos);
void PopSnakeNode(Snake *snake);
void UpdateSnake(Snake *snake);
void DrawSnake(const Snake *snake);
void ResetFoodPosition();

For the C version, I used two structs, Snake and SnakeNode. SnakeNode is used for the linked list nodes and Snake contains the linked list and other variables related to the Snake (direction if it’s dead or not).

And I wrote these functions:

Snake in C Style C++

struct Snake {
    std::list<Vector2> positions;
    Vector2 dir;
    bool dead;

    Snake(Vector2 pos, Vector2 dir) {
        this->positions.push_front(pos);
        this->dir = dir;
        this->dead = false;
    }
};

void UpdateSnake(Snake *snake);
void DrawSnake(const Snake *snake);
void ResetFoodPosition();

For the C Style C++, I removed the SnakeNode struct and the PushSnakeNode, PopSnakeNode functions as I used an std::list for keeping a linked list of positions and CreateSnake was replaced by the constructor of Snake.

Snake in C++

class Snake {
    std::list<Vector2> positions;
    Vector2 dir;
    bool dead;

public:
    Snake(Vector2 pos, Vector2 dir);
    void Update();
    void Draw();
};

void ResetFoodPosition();

For the last version, I changed the struct to a class, making the member variables private, and moved both the update and draw functions to inside the class.