Advertisement

Bugs in code?

Started by July 08, 2015 08:10 AM
10 comments, last by sn0k3 9 years, 5 months ago

Hello guys,

I've tried making simple snake game with SDL 2, but..The code doesn't work in Visual Studio, I mean when I compile it, there is only black screen, but when I compile it in Code::Blocks, there is other result..Any ideas?


#include <iostream>

#include <SDL.h>

#include <deque>



using namespace std;



static const int WINDOW_WIDTH = 800;

static const int WINDOW_HEIGHT = 600;



static const int GO_UP = 1;

static const int GO_LEFT = 2;

static const int GO_RIGHT = 3;

static const int GO_DOWN = 4;



static const int CELL_SIZE = 20;

static const int CELL_WIDTH = WINDOW_WIDTH / CELL_SIZE;

static const int CELL_HEIGHT = WINDOW_HEIGHT / CELL_SIZE;



static const int START_X = CELL_WIDTH / 2;

static const int START_Y = CELL_HEIGHT / 2;

static const int START_LENGTH = 3;



bool b[4] = { 0, 0, 0, 0 };



class SnakeParts {

public:

    int x, y;



    SnakeParts(int x, int y)

    {

        this->x = x;

        this->y = y;

    }

};





class Food {

public:

    int x, y;



    Food()

    {

        newFood();

    }



    void newFood()

    {

        x = 1 + rand() % (CELL_WIDTH - 2);

        y = 1 + rand() % (CELL_HEIGHT - 2);

    }

};



class Snake {

public:

    Snake(int headColor, int bodyColor, int appleColor)

    {

        this->headColor = headColor;

        this->bodyColor = bodyColor;

        this->appleColor = appleColor;

        restart();

    }

    

    ~Snake()

    {

        snakeParts.clear();

    }



    void restart()

    {

        snakeParts.clear();

        for(int i = 0; i < START_LENGTH; i++)

        {

            addPart(START_X - i, START_Y);

            direction = GO_RIGHT;

            time = 0;

            timeOut = 6;

            eaten = false;

        }

    }



    void update()

    {

        if(eaten) { return; };

        updateInputControls();

        time++;



        if(time < timeOut)

        {

            return;

        }

        time = 0;



        if(isCollidingWithWall() == true || isCollidingWithSelf() == true) {

            eaten = true;

        }



        if(isCollidingWithApple() == true) {

            apple.newFood();

        }

        else

        {

            snakeParts.pop_back();

        }



        moveSnake();

    }

    void render(SDL_Surface* screen)

    {

        if(eaten) { return; }



        renderRectangle.x = CELL_SIZE;

        renderRectangle.y = CELL_SIZE;



        renderApple(screen);

        renderSnake(screen);

    }

    inline bool isEaten() { return eaten; }



private:

    deque<SnakeParts> snakeParts;

    Food apple;

    bool eaten;

    int direction;

    int time, timeOut;

    int headColor, bodyColor, appleColor;

    SDL_Rect renderRectangle;





    void updateInputControls()

    {

        if(b[0] == true && direction != GO_DOWN)

        {

            direction = GO_UP;

        }

        else

        {

            if(b[1] == true && direction != GO_DOWN)

            {

                direction = GO_DOWN;

            }

        }



        if(b[2] == true && direction != GO_LEFT)

        {

            direction = GO_LEFT;

        }

        else

        {

            if(b[3] == true && direction != GO_RIGHT)

            {

                direction = GO_RIGHT;

            }

        }

    }



    void renderSnake(SDL_Surface* screen)

    {

        renderRectangle.x = snakeParts[0].x * CELL_SIZE;

        renderRectangle.y = snakeParts[0].y * CELL_SIZE;

        SDL_FillRect(screen, &renderRectangle, SDL_MapRGB(screen->format, 33, 246, 39));



        for(int i = 0; i < snakeParts.size(); i++)

        {

            renderRectangle.x = snakeParts[i].x * CELL_SIZE;

            renderRectangle.y = snakeParts[i].y * CELL_SIZE;



            SDL_FillRect(screen, &renderRectangle, SDL_MapRGB(screen->format, 93, 246, 39));

        }

    }

    void renderApple(SDL_Surface* screen)

    {

        renderRectangle.x = apple.x * CELL_SIZE;

        renderRectangle.y = apple.y * CELL_SIZE;



        SDL_FillRect(screen, &renderRectangle, SDL_MapRGB(screen->format, 215, 37, 49));

    }

    

    void addPart(int x, int y)

    {

        SnakeParts body(x, y);

        snakeParts.push_back(body);

    }



    void moveSnake()

    {

        static const int moveX[] = { 0, 0, -1, 1 };

        static const int moveY[] = { -1, 1, 0, 0 };

        

        int x = snakeParts[0].x + moveX[direction];

        int y = snakeParts[0].y + moveY[direction];



        SnakeParts nextPart(x, y);



        snakeParts.push_front(nextPart);

    }

    bool isCollidingWithWall()

    {

        int snakeHeadPositionX = snakeParts[0].x;

        int snakeHeadPositionY = snakeParts[0].y;



        return ((snakeHeadPositionX == 0) || (snakeHeadPositionY == 0) || (snakeHeadPositionX == CELL_WIDTH) || (snakeHeadPositionY == CELL_HEIGHT));



    }

    bool isCollidingWithSelf()

    {

        int headPositionX = snakeParts[0].x;

        int headPositionY = snakeParts[0].y;



        for(int i = 0; i < snakeParts.size(); i++)

        {

            if(snakeParts[i].x == headPositionX && snakeParts[i].y == headPositionY)

            {

                return true;

            }

        }

        return false;

    }

    bool isCollidingWithApple()

    {

        return (snakeParts[0].x == apple.x && snakeParts[0].y == apple.y);

    }

};



int main(int argc, char* argv[])

{

    SDL_Window* window = NULL;

    SDL_Surface* screen = NULL;

    

    bool appQuit = false;

    SDL_Event event;

//    bool b[4] = { 0, 0, 0, 0 };



    Snake snake(1, 2, 3);



    if(SDL_Init(SDL_INIT_EVERYTHING) < 0)

    {

        cout << "Error, while initializing SDL - " << SDL_GetError() << endl;

    }



    window = SDL_CreateWindow("Snake Game", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, WINDOW_WIDTH, WINDOW_HEIGHT, SDL_WINDOW_SHOWN);

    if(window == NULL)

    {

        cout << "Error, while oppening the window! " << SDL_GetError() << endl;

    }

    



    while(appQuit != true)

    {

        if(SDL_PollEvent(&event))

        {

            if(event.type == SDL_QUIT)

            {

                appQuit = true;

            }



            if(event.type == SDL_KEYUP)

            {

                if(event.type == SDL_KEYDOWN)

                {

                    switch(event.key.keysym.sym)

                    {

                    case SDLK_UP:

                        b[0] = 0;

                        break;



                    case SDLK_LEFT:

                        b[1] = 0;

                        break;



                    case SDLK_RIGHT:

                        b[2] = 0;

                        break;



                    case SDLK_DOWN:

                        b[3] = 0;

                        break;

                    }

                }

            }

            if(event.type == SDL_KEYDOWN)

            {

                switch(event.key.keysym.sym)

                {

                case SDLK_UP:

                    b[0] = 1;

                    break;



                case SDLK_LEFT:

                    b[1] = 1;

                    break;



                case SDLK_RIGHT:

                    b[2] = 1;

                    break;



                case SDLK_DOWN:

                    b[3] = 1;

                    break;

                }

            }

        }







        screen = SDL_GetWindowSurface(window);





//        SDL_FillRect(screen, NULL, SDL_MapRGB(screen->format, 0x00, 0x00, 0x00));

//        SDL_FillRect(screen, &boxRectangle, SDL_MapRGB(screen->format, 0x33, 0x99, 0xFF));



        snake.render(screen);

        snake.update();





        SDL_UpdateWindowSurface(window);

    }



    SDL_Quit();

    return 0;

}

Also if you are using SDL2 you are still using old SDL functions...

SDL_Surface*, SDL_FillRect()... why don't you create a SDL renderer? Will be much easier.

Try to use:

SDL_CreateRenderer()

SDL_SetRenderDrawColor()

SDL_RenderClear()

SDL_RenderFillRect()

SDL_RenderPresent()

Advertisement

If you get different behavior with different compilers (or when running on different machines), one thing to look for is uninitialized variables.

I'd put breakpoints on the calls to SDL_FillRect and check if the values of renderRectangle are what you expect them to be...

Also if you are using SDL2 you are still using old SDL functions...

SDL_Surface*, SDL_FillRect()... why don't you create a SDL renderer? Will be much easier.

Try to use:

SDL_CreateRenderer()

SDL_SetRenderDrawColor()

SDL_RenderClear()

SDL_RenderFillRect()

SDL_RenderPresent()

I second this. Check out this SDL2 Migration Guide for more info regarding the changes between SDL1.2 and SDL2. SDL_CreateTextureFromSurface() can be used to create a texture from a surface. In SDL2, it's recommended that you use textures and a renderer.

Also, SDL_ShowSimpleMessageBox() is very useful for reporting runtime errors. I once attempted to load a character spritesheet when the image was missing from my Graphics folder (forgot to put it there). Because I included an if-statement to check if the variable was NULL and a message box to display exactly why the app wasn't working, I was able to swiftly fix the error.

Thank you for the info! smile.png

I rewrite the code like this, but it's not working again..

#include <iostream>
#include <SDL.h>
#include <deque>


using namespace std;


static const int WINDOW_WIDTH = 800;
static const int WINDOW_HEIGHT = 600;


static const int GO_UP = 1;
static const int GO_LEFT = 2;
static const int GO_RIGHT = 3;
static const int GO_DOWN = 4;


static const int CELL_SIZE = 20;
static const int CELL_WIDTH = WINDOW_WIDTH / CELL_SIZE;
static const int CELL_HEIGHT = WINDOW_HEIGHT / CELL_SIZE;


static const int START_X = CELL_WIDTH / 2;
static const int START_Y = CELL_HEIGHT / 2;
static const int START_LENGTH = 3;



bool b[4] = { 0, 0, 0, 0 };



class SnakeParts {

public:

    int x, y;

    SnakeParts(int x, int y)
    {
        this->x = x;
        this->y = y;
    }

};





class Food {

public:

    int x, y;

    Food()
    {
        newFood();
    }


    void newFood()
    {
        x = 1 + rand() % (CELL_WIDTH - 2);
        y = 1 + rand() % (CELL_HEIGHT - 2);
    }

};



class Snake {

public:

    Snake(int headColor, int bodyColor, int appleColor)
    {
        this->headColor = headColor;

        this->bodyColor = bodyColor;

        this->appleColor = appleColor;

        restart();
    }


    ~Snake()
    {
        snakeParts.clear();
    }


    void restart()
    {
        snakeParts.clear();

        for(int i = 0; i < START_LENGTH; i++)
        {
            addPart(START_X - i, START_Y);
            direction = GO_RIGHT;
            time = 0;
            timeOut = 6;
            eaten = false;
        }

    }



    void update()
    {
        if(eaten) { return; };

        updateInputControls();

        time++;



        if(time < timeOut)
        {
            return;
        }
        time = 0;



        if(isCollidingWithWall() == true || isCollidingWithSelf() == true) {
            eaten = true;
        }



        if(isCollidingWithApple() == true) {
            apple.newFood();
        }
        else
        {
            snakeParts.pop_back();
        }

        moveSnake();

    }

    void render(SDL_Renderer* renderer)
    {

        if(eaten) { return; }



        renderRectangle.x = CELL_SIZE;

        renderRectangle.y = CELL_SIZE;



        renderApple(renderer);

        renderSnake(renderer);

    }

    inline bool isEaten() { return eaten; }



private:

    deque<SnakeParts> snakeParts;

    Food apple;

    bool eaten;

    int direction;

    int time, timeOut;

    int headColor, bodyColor, appleColor;

    SDL_Rect renderRectangle;





void updateInputControls()
{
    if(b[0] == true && direction != GO_DOWN)
    {
        direction = GO_UP;
    }
    else
    {
        if(b[1] == true && direction != GO_DOWN)
        {
            direction = GO_DOWN;
        }

    }



    if(b[2] == true && direction != GO_LEFT)
    {
        direction = GO_LEFT;
    }
    else
    {
        if(b[3] == true && direction != GO_RIGHT)
        {
            direction = GO_RIGHT;
        }

    }

}



void renderSnake(SDL_Renderer* renderer)
{
    renderRectangle.x = snakeParts[0].x * CELL_SIZE;

    renderRectangle.y = snakeParts[0].y * CELL_SIZE;

    SDL_SetRenderDrawColor(renderer, 33, 246, 39, 255);
    SDL_RenderDrawRect(renderer, &renderRectangle);

//    SDL_FillRect(screen, &renderRectangle, SDL_MapRGB(screen->format, 33, 246, 39));



    for(int i = 0; i < snakeParts.size(); i++)
    {

        renderRectangle.x = snakeParts[i].x * CELL_SIZE;

        renderRectangle.y = snakeParts[i].y * CELL_SIZE;



//        SDL_FillRect(screen, &renderRectangle, SDL_MapRGB(screen->format, 93, 246, 39));

        SDL_SetRenderDrawColor(renderer, 93, 246, 39, 255);
        SDL_RenderDrawRect(renderer, &renderRectangle);

    }
}

void renderApple(SDL_Renderer* renderer)
{

    renderRectangle.x = apple.x * CELL_SIZE;
    renderRectangle.y = apple.y * CELL_SIZE;

    SDL_SetRenderDrawColor(renderer, 128, 255, 15, 255);
    SDL_RenderDrawRect(renderer, &renderRectangle);

//    SDL_FillRect(screen, &renderRectangle, SDL_MapRGB(screen->format, 215, 37, 49));
}



void addPart(int x, int y)
{
    SnakeParts body(x, y);

    snakeParts.push_back(body);
}

void moveSnake()
{

    static const int moveX[] = { 0, 0, -1, 1 };

    static const int moveY[] = { -1, 1, 0, 0 };



    int x = snakeParts[0].x + moveX[direction];

    int y = snakeParts[0].y + moveY[direction];



    SnakeParts nextPart(x, y);



    snakeParts.push_front(nextPart);

}

bool isCollidingWithWall()

{

    int snakeHeadPositionX = snakeParts[0].x;

    int snakeHeadPositionY = snakeParts[0].y;



    return ((snakeHeadPositionX == 0) || (snakeHeadPositionY == 0) || (snakeHeadPositionX == CELL_WIDTH) || (snakeHeadPositionY == CELL_HEIGHT));



}

bool isCollidingWithSelf()
{

    int headPositionX = snakeParts[0].x;

    int headPositionY = snakeParts[0].y;



    for(int i = 0; i < snakeParts.size(); i++)

    {

        if(snakeParts[i].x == headPositionX && snakeParts[i].y == headPositionY)

        {

            return true;

        }

    }

    return false;

}

bool isCollidingWithApple()
{

    return (snakeParts[0].x == apple.x && snakeParts[0].y == apple.y);

}

};



int main(int argc, char* argv[])

{

    SDL_Window* window = NULL;

    SDL_Surface* screen = NULL;
    SDL_Renderer* renderer = NULL;

    bool appQuit = false;
    SDL_Event event;

    //    bool b[4] = { 0, 0, 0, 0 };

    Snake snake(1, 2, 3);

    if(SDL_Init(SDL_INIT_EVERYTHING) < 0)
    {
        cout << "Error, while initializing SDL - " << SDL_GetError() << endl;
    }

    window = SDL_CreateWindow("Snake Game", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, WINDOW_WIDTH, WINDOW_HEIGHT, SDL_WINDOW_SHOWN);
    if(window == NULL)
    {
        cout << "Error, while oppening the window! " << SDL_GetError() << endl;
    }

    renderer = SDL_CreateRenderer(window, -1, NULL);

    while(appQuit != true)
    {
        if(SDL_PollEvent(&event))
        {
            if(event.type == SDL_QUIT)
            {
                appQuit = true;

            }

            if(event.type == SDL_KEYUP)
            {
                if(event.type == SDL_KEYDOWN)
                {
                    switch(event.key.keysym.sym)
                    {

                    case SDLK_UP:
                        b[0] = 0;
                        break;

                    case SDLK_LEFT:
                        b[1] = 0;
                        break;


                    case SDLK_RIGHT:
                        b[2] = 0;
                        break;


                    case SDLK_DOWN:
                        b[3] = 0;
                        break;
                    }

                }

            }

            if(event.type == SDL_KEYDOWN)
            {
                switch(event.key.keysym.sym)
                {
                case SDLK_UP:
                    b[0] = 1;
                    break;

                case SDLK_LEFT:
                    b[1] = 1;
                    break;

                case SDLK_RIGHT:
                    b[2] = 1;
                    break;

                case SDLK_DOWN:
                    b[3] = 1;
                    break;
                }
            }
        }


//        SDL_SetRenderDrawColor(renderer, 21, 0, 0, 255);

        snake.render(renderer);

        snake.update();

        SDL_RenderClear(renderer);

        SDL_RenderPresent(renderer);

        SDL_UpdateWindowSurface(window);

    }



    SDL_Quit();

    return 0;

}

but it's not working again..

Define "not working".

Helping someone is a lot harder when you don't know what the problem is.

EDIT:

That said, you're currently clearing the screen right before presenting it, which will essentially discard all rendering you've done before the clear.

You should also separate updating and rendering better than you do. Currently, you render the snake, then update it, then render other stuff -- I'd suggest updating everything that needs to be updated first, and then rendering everything that needs to be rendered after.

Additionally, your snake seems to have a lot of responsibilities -- updating time and input, spawning food, etc. For future projects, I would suggest splitting these responsibilities up further into additional classes. (See also: Single Responsibility Principle).

Hello to all my stalkers.

Advertisement

Okay, there is only window, without the snake..The window is painted, but there isn't snake..

Okay, there is only window, without the snake..The window is painted, but there isn't snake..

This sounds like what I spotted in my edited post above. Have a look and see if that solves your problem.

Hello to all my stalkers.

Posting the PM I got here since it might help other people. In general, posting is probably a much better idea than sending PMs. More people have a chance at responding and spotting the bugs, and other people might find it helpful in the future.

I think there is wrong something here:


SDL_SetRenderDrawColor(renderer, 0, 0, 0, 255);



        SDL_RenderPresent(renderer);







        snake.render(renderer);







        SDL_RenderClear(renderer);







        snake.update();



        SDL_UpdateWindowSurface(window);

but I'm not sure what..Have you used SDL?

Let's look at this, 1 line at a time.


SDL_SetRenderDrawColor(renderer, 0, 0, 0, 255); //Sets the clear color. This is the color used for SDL_RenderClear
SDL_RenderPresent(renderer); //Show what we've rendered so far.
snake.render(renderer); //Render the snake.
SDL_RenderClear(renderer); //Clear everything to our clear color.
snake.update(); //Update the snake.
SDL_UpdateWindowSurface(window); //??? This doesn't seem like it should be here, based on some googling. Just use SDL_RenderPresent.

So, as we can see, we do render the snake, but then we do a clear after, which essentially discards everything we've rendered so far.

You need to re-order the code so that it:

1. Updates the snake.

2. Sets the clear color.

3. Clears the screen.

4. Renders what needs to render.

5. Presents what has been rendered.

Hello to all my stalkers.

I didn't saw your post, well after searching on google and tryed something I got snake part's draw on the screen! They aren't moving, but

The last part of the code, that I rewrite:


        SDL_SetRenderDrawColor(renderer, 0, 0, 0, 255);
        SDL_RenderClear(renderer);

        snake.render(renderer);

        SDL_RenderPresent(renderer);
 

EDIT: I read your post now, and yea SDL_UpdateWindow shouldnt be there!

This topic is closed to new replies.

Advertisement