Jump to content
  • Advertisement
Sign in to follow this  

beginning a snake SFML

This topic is 1735 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

Hello. I'm trying to make a snake in C++ with SFML.

The code is fairly small, what I did atm is that when we press one key (left/right/up/down) the direction change, and while the window is open there are 4 while loops: while(direction = right/left/down/up) (one loop for each direction) and in that loop I put sprite.move(x,y).

I really can't find the error. It's maybe a C++ error but I really can't find it.

Here is the code :

#include <SFML/Window.hpp>
#include <SFML/Graphics.hpp>
#include <SFML/System.hpp>
#include <vector>


sf::Event event;
enum Direction { Up, Down, Left, Right};
int dir = Up;

class SnakeBlock
{
    public:

    SnakeBlock * next;
    sf::Texture texture;
    sf::Sprite snakeblock;
};

int main()
{
    sf::Sprite background;
    sf::Texture backgroundtex;
    backgroundtex.loadFromFile("background.png", sf::IntRect(0, 0, 1987, 1315));
    background.setTexture(backgroundtex);

    SnakeBlock snakeHead;
    snakeHead.texture.loadFromFile("spritesheetsnake.png", sf::IntRect(0,0,52,44));
    snakeHead.snakeblock.setTexture(snakeHead.texture);

    std::vector<SnakeBlock> Snake;
    Snake.push_back(snakeHead);
    Snake[0].snakeblock.setPosition(100,100);

    sf::RenderWindow window(sf::VideoMode(800,600), "SFML Snake");
    window.setFramerateLimit(30);
    while(window.isOpen())
    {
        while(window.pollEvent(event))
        {
            switch(event.type)
            {
                case sf::Event::Closed:

                window.close();
                break;

                default:
                break;
            }

        }

        if(sf::Keyboard::isKeyPressed(sf::Keyboard::Left))
        {
                dir = Left;
        }
        if(sf::Keyboard::isKeyPressed(sf::Keyboard::Right))
        {
                dir = Right;
        }
        if(sf::Keyboard::isKeyPressed(sf::Keyboard::Down))
        {
                dir = Down;
        }
        if(sf::Keyboard::isKeyPressed(sf::Keyboard::Up))
        {
                dir = Up;
        }
        while(dir == Up)
        {
            Snake[0].snakeblock.move(0,-5);
        }
        while(dir == Down)
        {
            Snake[0].snakeblock.move(0,5);
        }
        while(dir == Left)
        {
            Snake[0].snakeblock.move(-5,0);
        }
        while(dir == Right)
        {
            Snake[0].snakeblock.move(5,0);
        }
        window.clear(sf::Color::Green);

        window.draw(background);
        window.draw(Snake[0].snakeblock);

        window.display();
    }
    return 0;

}

By the way, if that code works, after that, I plan to make the snake bigger when he collide with something, delete the thing he went into, and add one snakeblock to the vector of snakeblock called Snake, then I will get (the last element minus one) of Snake and initialize the *next variable pointer to the last element, and in the main isOpen loop, I will make a for loop where I draw the last block of the snake, and then draw each *next of the snakeblock, but I wonder how I could make the snake not look like a line of blocks but such as that :

_______

|.............|___O      

|

where the line is the body of the snake and the "O" is the head of the snake.

 

If you don't understand what I said about making the snake  game just try to find the error in my code, I know what I said is not very clear.

 

Thanks you a lot in advance.

Share this post


Link to post
Share on other sites
Advertisement

From a short look at the code those 4 "while" are likely endless loops which stop your program, just change them to "if". You already have the outer loops to make the game go on.

Also next time please write what the symptoms of the problem are, i.e. the program hangs and stops responding/I got this or that error message/whatever.

Share this post


Link to post
Share on other sites

Better yet, don't even have a "dir" variable; rather, when you capture the direction the user presses from checking the keyboard state, move the snake in that direction.  Also, I'd suggest using else if, otherwise, if the user is pressing 2 directions at once, the snake will both both directions.

 

Like this:

if (sf::Keyboard::isKeyPressed(sf::Keyboard::Left)) {
  Snake.move(-5, 0)
}
else if (sf::Keyboard::isKeyPressed(sf::Keyboard::Right)) {
  Snake.move(5, 0)
}
...

Share this post


Link to post
Share on other sites

Thanks for the tip about the loops, replaced with if and now I can  move snakehead.

 

No you didn't get the point BeerNuts, I'm trying to make a snake, a snake always move in the direction you gave him, even if you stopped pressing the button !

That is why I'm using a direction enum, also I think I could need it for making the rest of the snake follow the head, such as the snake could potentially "bite" itself.

I've been doing lots of upgrades. here is what I got now :

#include <SFML/Window.hpp>
#include <SFML/Graphics.hpp>
#include <SFML/System.hpp>
#include <SFML/Audio.hpp>
#include <deque>

void selfIncrement();

sf::Event event;
sf::Clock clockSnake;
sf::Time elapse;

enum Direction { Up, Down, Left, Right};

int dir = Up;

int n = 1;

class SnakeBlock
{
    public:

    SnakeBlock * next;
    sf::Texture texture;
    sf::Sprite snakeblock;
    int lastX, lastY;
};

std::deque<SnakeBlock> Snake;

int main()
{
    elapse = clockSnake.getElapsedTime();

    sf::Music epicMusic;
    epicMusic.openFromFile("epicmusic.wav");
    epicMusic.play();

    SnakeBlock snakeHead;
    snakeHead.texture.loadFromFile("spritesheetsnake.png", sf::IntRect(0,0,25,22));
    snakeHead.snakeblock.setTexture(snakeHead.texture);
    SnakeBlock snakeBody1;
    snakeBody1.snakeblock.setTexture(*(snakeHead.snakeblock.getTexture()));
    SnakeBlock snakeBody2;
    snakeBody2.snakeblock.setTexture(*(snakeHead.snakeblock.getTexture()));

    Snake.push_front(snakeHead);
    Snake.push_front(snakeBody1);
    Snake.push_front(snakeBody2);
    Snake[2].snakeblock.setPosition(500,350);
    Snake[1].snakeblock.setPosition(475, 338);
    Snake[0].snakeblock.setPosition(450, 316);

    sf::RenderWindow window(sf::VideoMode(1028,768), "SFML Snake");
    window.setFramerateLimit(30);
    while(window.isOpen())
    {
        while(window.pollEvent(event))
        {
            switch(event.type)
            {
                case sf::Event::Closed:
                epicMusic.stop();
                window.close();
                break;

                default:
                break;
            }

        }

        if(sf::Keyboard::isKeyPressed(sf::Keyboard::Left))
        {
                dir = Left;
        }
        if(sf::Keyboard::isKeyPressed(sf::Keyboard::Right))
        {
                dir = Right;
        }
        if(sf::Keyboard::isKeyPressed(sf::Keyboard::Down))
        {
                dir = Down;
        }
        if(sf::Keyboard::isKeyPressed(sf::Keyboard::Up))
        {
                dir = Up;
        }
        if(dir == Up)
        {

            Snake[0].snakeblock.move(0,-5);
            Snake[n].snakeblock.setPosition(Snake[n-1].snakeblock.getPosition().x, Snake[n-1].snakeblock.getPosition().y-22);
        }
        if(dir == Down)
        {
            Snake[0].snakeblock.move(0,5);
            Snake[n].snakeblock.setPosition(Snake[n-1].snakeblock.getPosition().x, Snake[n-1].snakeblock.getPosition().y+22);
        }
        if(dir == Left)
        {
            Snake[0].snakeblock.move(-5,0);
            Snake[n].snakeblock.setPosition(Snake[n-1].snakeblock.getPosition().x+25, Snake[n-1].snakeblock.getPosition().y);
        }
        if(dir == Right)
        {
            Snake[0].snakeblock.move(5,0);
            Snake[n].snakeblock.setPosition(Snake[n-1].snakeblock.getPosition().x-25, Snake[n-1].snakeblock.getPosition().y);
        }
        window.clear(sf::Color::Green);
        selfIncrement();
        for(unsigned int m = 0; m < Snake.size(); m++)
        {
            window.draw(Snake[m].snakeblock);
        }

        window.display();
    }
    return 0;

}

void selfIncrement()
{
    if(elapse.asSeconds() > 3)
    {
        n++;
        clockSnake.restart();
    }
    if(n > Snake.size())
    {
        n = 1;
    }
}


I got one problem:

I don't know how to do what I said, aka "make the snake movement to make it possible to bite himself". What I got now : each snakeblock will take the last snakeblock position, resulting in a perfectly straight snake. :/

Maybe I need to use one variable that auto increments over time, resulting to update the position of each snakeblock one by one, or maybe I need to use the enumeration Direction, or maybe I need to do both of that, but I don't really know how to practically do so.

Some ideas would greatly help me ! Thanks.

Edited by hooby_graphite

Share this post


Link to post
Share on other sites

I also thought it would be complicated to make the snake move like in the original snake game, but i came up with this easy idea:

for (unsigned int i = snake.size()-1; i > 0; i--) // start with the last element(body part)
{
	//snake[i] = snake[i-1]; // works for my code
//you would have to use       snake[i].lastX = snake[i-1].lastX;   and     snake[i].lastY = snake[i-1].lastY;
}

Its important that your "snake-head" is the 0th element of the snake vector. I have just a vector<vec2> snake (vec2 is just x and y). So every time you move your snake-head in any direction the x and y of the next body-block just becomes the old head position(or the position of the block in the vector before it).

Share this post


Link to post
Share on other sites

Here's how I did it:

    void Python::MoveBody()
    {
        // Move the head based on direction.
        switch(m_direction)
        {
        case DIRECTION_UP:
            m_tilePosition.y -= 1;
            break;
        case DIRECTION_RIGHT:
            m_tilePosition.x += 1;
            break;
        case DIRECTION_DOWN:
            m_tilePosition.y += 1;
            break;
        case DIRECTION_LEFT:
            m_tilePosition.x -= 1;
            break;
        }

        // Move the body segments by telling each segment the direction of the segment before it.
        for(std::vector<PythonSegment>::size_type i = 0; i < m_segmentStack.size(); i++)
        {
            // Pass the head's direction if the segment is the first body piece, otherwise pass the previous segment.
            if(i == 0)
            {
                m_segmentStack[i].SetDirection(m_previousMoveDirection);
            }
            else
            {
                m_segmentStack[i].SetDirection(m_segmentStack[i - 1].GetPreviousMoveDirection());
            }

            m_segmentStack[i].Move();
        }

        for(std::vector<PythonSegment>::size_type i = 0; i < m_segmentStack.size(); i++)
        {
            m_segmentStack[i].FinishMove();
        }

        m_previousMoveDirection = m_direction;
    }

Essentially the snake head is the object the player controls, it has a direction that is modified based on player input and after a period of time it will step to the tile it is facing. When it steps it basically loops through and passes the previous facing direction of each segment to the one following it. Essentially if the head goes up then you want the second piece to go left and then up.

 

A little messy, FinishMove() basically sets the previous direction to the current direction after all the pieces move, but it does work. It also works for an arbitrary number of snake pieces.

 

In terms of growing the body this system helps a lot too, all you have to do when you collide with food is add to some "grow count" variable, then whenever the snake takes a step, if the growcount is greater than zero you decrement it by one and push a new snake piece onto the snake where the last piece just was.

Edited by Satharis

Share this post


Link to post
Share on other sites
Sign in to follow this  

  • Advertisement
×

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

Participate in the game development conversation and more when you create an account on GameDev.net!

Sign me up!