3
\$\begingroup\$

Here is my little snake game which I made in c++ using the SFML library. The game is very simple. I have also included a screenshot of how the GUI looks. The files which I am loading are 30x30 colored squares. Yellow is the background. Red represents the snake. White is the cherry/fruit/prize to increase the size of the snake


#include<SFML/graphics.hpp>
#include<windows.h>


using namespace sf;
struct position{
    int x;
    int y;
}snake[200];

char direction = 'r';
int length = 2;

void update(){
    for(int i = length-1;i > 0;i--){
        snake[i].x = snake[i-1].x;
        snake[i].y = snake[i-1].y;
    }
    if (direction == 'u') snake[0].y-=1;
    else if (direction == 'd') snake[0].y+=1;
    else if (direction == 'r') snake[0].x+=1;
    else if (direction == 'l') snake[0].x-=1;
}
int fruitx = 5;
int fruity = 5;

void genrand(){
    int rx = rand() % 20;
    int ry = rand() % 20;
    fruitx = rx;
    fruity = ry;
}
int main(){
    snake[0].x = 5;
    snake[0].y = 5;
    RenderWindow window(VideoMode(620,620),"Snake c++");
    Texture t;
    Texture t2;
    Texture t3;
    t3.loadFromFile("images/green.png");
    t2.loadFromFile("images/red.png");
    t.loadFromFile("images/yellow.png");
    Sprite bg(t);
    Sprite sn(t2);
    Sprite fruit(t3);
    const int size = 31;
    while(window.isOpen()){
        Event e;
        while(window.pollEvent(e)){
            if(e.type == Event::Closed)
                window.close();

            if(e.type == Event::KeyPressed){
                if(e.key.code == Keyboard::Key::Up && direction != 'd') direction = 'u';
                else if(e.key.code == Keyboard::Key::Down && direction != 'u') direction = 'd';
                else if(e.key.code == Keyboard::Key::Left && direction != 'r') direction = 'l';
                else if(e.key.code == Keyboard::Key::Right && direction != 'l') direction = 'r';
            }
        }
        Sleep(60);
        update();
        window.clear();
        for(int i = 0;i < 20;i++){
            for(int j = 0;j < 20;j++){
                bg.setPosition(i*size,j*size);
                window.draw(bg);
            }
        }

        for(int i = 0;i < length;i++) {
            if (snake[i].x < 0) snake[i].x+=20;
            if (snake[i].x > 19) snake[i].x-=20;
            if (snake[i].y < 0) snake[i].y+=20;
            if (snake[i].y > 19) snake[i].y-=20;

            sn.setPosition(snake[i].x*size,snake[i].y*size);
            if (i != 0){
                if(snake[i].x == snake[0].x && snake[i].y == snake[0].y)
                    length = 2;
            }
            if (snake[i].x == fruitx && snake[i].y == fruity){
                length+=1;
                genrand();
                fruit.setPosition(fruitx*size,fruity*size);
            }
            window.draw(sn);
        }
        window.draw(fruit);
        window.display();
    }

    return 0;
}


The snake is represented by an array of position objects. When I detect any collision I just reset the length of the snake. enter image description here

\$\endgroup\$

1 Answer 1

4
\$\begingroup\$

Use correct capitalization of file names

Be careful with upper case and lower case in filenames. While Windows might not treat filenames case sensitively, other operating systems might. The correct #include is:

#include <SFML/Graphics.hpp>

Avoid operating specific functions

You use Sleep(), which is not a standard C function, but rather Windows specific. Since you are using SFML, you can use sf::sleep() instead, like so:

sf::sleep(sf::milliseconds(60));

You can then also remove #include <windows.h>, and then your code compiles and runs on other platforms without errors.

Add error checking

Your code ignores errors trying to open the texture files. Make sure you report an error and exit if any of the required files cannot be found.

Split off more functionality into their own functions

You already created a function update() to handle moving the snake one frame. However, it would be nice to move more functionality out of main() into their own functions, so that the game loop in main() becomes something simple like:

while (window.isOpen()) {
    handle_input();
    update();
    draw();
    sleep(milliseconds(60));
}

Avoid moving the whole body each frame

Instead of moving the position of every element of snake[], use a std::deque to hold the positions, and inside update(), just pop the tail and add a new head:

#include <deque>

struct position {
    int x;
    int y;
};

std::deque<position> snake;

void update() {
    // Calculate the new head position
    position new_head = snake.front();
    if (direction == 'u') new_head.y--;
    else if ...;

    // Handle wraparounds here
    if (new_head.x < 0) new_head.x += ...;
    if (...) ...;

    // Remove the tail and add a new head
    snake.pop_back();
    snake.push_front(new_head);
}

Using std::deque, the container knows its own length, and this makes it easy to use range-for loops. For example, to draw the snake:

for (auto position: snake) {
    sn.setPosition(position.x * size, position.y * size);
    window.draw(sn);
}

Use struct position for all positions

You can also use struct position to store the coordinates of the fruit:

position fruit;

This makes the code more consistent, and if position would have added comparison operators, it would save you from manually comparing the x and y coordinates separately. Which brings me to:

Use sf::Vector2<int> for the positions

SFML has a handy class to store coordinates for you, so you can write:

std::deque<sf::Vector2<int>> snake;
sf::Vector2<int> fruit;

This type also has x and y member variables. But, it also overloads things like operator=(), so instead of comparing x and y coordinates manually, you can write:

if (snake.front() == fruit) {
    // Handle the snake eating the fruit
}

Code formatting

Your code has inconsistent formatting, sometimes there are spaces between operators and around braces, sometimes not. It doesn't really matter that much which code style you use, as long as you are consistent. Instead of manually fixing style issues, consider using a code formatting tool (either an external one like Artistic Style, or your editor's built-in code formatting functions) to keep your code looking tidy.

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.