Search code examples
c++sfml

Logic error in SFML game, How to fix the render mechanism?


I am starting with SFML, and wanted to do a Snake game. I am on linux(Kali 2018), using the prebuild gnu g++ compiler. Using commands:

g++ -c snake.cpp

g++ snake.o -o snake -lsfml-graphics -lsfml-window -lsfml-system

It compiles just fine, runs without An error. Heres the snake.cpp:

#include <SFML/Graphics.hpp>
#include <vector>
#include <cstdio>
#include <iostream>
#define SIZE 12
#define WIDTH 600/SIZE
#define HEIGHT 600/SIZE
#define LEFT 0
#define UP 1
#define RIGHT 2
#define DOWN 3

class Tail
{
  public:
    int x;
    int y;
    int dir;
    Tail()
    {

    }
    Tail(int x,int y,int dir)
    {
      this->x = x;
      this->y = y;
      this->dir = dir;
    }
};
//container for the snake
class Snake
{
  public:
    int length = 1;
    std::vector<Tail> v;//vector of the tailes
    Tail head;
    int dir;
    void extend()
    {
      this->v.resize(++this->length);
      this->v.at(this->length - 1) = Tail(this->v.at(this->length - 2).x,this->v.at(this->length - 2).y,this->v.at(this->length - 2).dir);
      std::cout << this->length << std::endl;//For  testing purposes
    }

} snake;
class Apple : Tail
{
  public:
    Apple generate()
    {
      Apple a;
      a.x = rand()%(WIDTH+1);
      a.y = rand()%(WIDTH+1);
      for(int i = 0;i < snake.length;i++)
      {
        if(snake.v.at(i).x == a.x && snake.v.at(i).y == a.y)
        {
          return generate();
        }
      }
      return a;
    }
    bool check()
    {
      if(snake.v.at(0).x == this->x && snake.v.at(0).y == this->y)
      {
        return true;
      }
      return false;
    }
} apple;

int main()
{
    sf::Clock c;//For speed adjusment
    int i = 3;//3 block per second
    sf::RenderWindow window(sf::VideoMode(600, 600), "Snake",sf::Style::Close);
    //initialize the head tail
    snake.v.resize(1);
    snake.v.at(0).x = 30;
    snake.v.at(0).y = 30;
    snake.v.at(0).dir = RIGHT;
    while (window.isOpen())
    {
        sf::Event event;
        while (window.pollEvent(event))
        {
            if (event.type == sf::Event::Closed)
                window.close();
            if (event.type == sf::Event::KeyPressed)
            {
              switch(event.key.code)
              {
                case sf::Keyboard::Up:   snake.dir = UP;
                                         break;
                case sf::Keyboard::Down: snake.dir = DOWN;
                                         break;
                case sf::Keyboard::Left: snake.dir = LEFT;
                                         break;
                case sf::Keyboard::Right:snake.dir = RIGHT;
                                         break;
              }
            }
        }
        if(c.getElapsedTime().asSeconds() >= 10)
        {
          std::cout << c.restart().asSeconds() << std::endl;
          i++;
        } //changes speed after 10 seconds
        window.setFramerateLimit(i);//same
        //RENDERING
        window.clear();
        snake.v.resize(snake.length);//will be significant when the snake is being extended
        //Increment the Coordinates acording to the direction
        switch(snake.dir)
        {
          case UP:    snake.v.at(0).y--;
                      snake.v.at(0).dir = UP;
                      break;
          case DOWN:  snake.v.at(0).y++;
                      snake.v.at(0).dir = DOWN;
                      break;
          case LEFT:  snake.v.at(0).x--;
                      snake.v.at(0).dir = LEFT;
                      break;
          case RIGHT: snake.v.at(0).x++;
                      snake.v.at(0).dir = RIGHT;
                      break;
        }
        snake.extend();//Userd for Testing THIS IS THE Part which doesnt work
        //give the position and directions  of the tail before it to the current tail in the loop
        for(int i = 1; i < snake.length;i++)
        {
          snake.v.at(i).x = snake.v.at(i-1).x;
          snake.v.at(i).y = snake.v.at(i-1).y;
          snake.v.at(i).dir  = snake.v.at(i-1).dir;
        }
        sf::RectangleShape r[snake.v.size()];//Array of shapes for rendering
        //NOTE: Using a single shape which is changing doesnt work either
        for(int i = 0; i < snake.v.size();i++)//render loop
        {
          r[i].setSize(sf::Vector2f(SIZE,SIZE));
          r[i].setPosition(snake.v.at(i).x*SIZE,snake.v.at(i).y*SIZE);
          r[i].setFillColor(sf::Color::White);
          window.draw(r[i]);
        }
        //used for checking sizes, all values including the one in the Snake::extend() function, all are the same
        std::cout << snake.v.size() << std::endl;
        std::cout << snake.length   << std::endl;
        window.display();
    }

    return 0;
}

Note that the Apple class isnt used, yet, but is planed to be used when the extend() function from the Snake class will work. All the cout's relating to the size of the Tails vector are the same, But it render only the head Tail. Looks like this: Snake game picture

The controls and speed is working too. It's probably something stupid but I could't get up with something. The window clears only at the begining so that shouldn't be a problem. Thanks to all your help!

EDIT I want the extend() function to extend the tails vector, so taht the Tail is rendered there where the tail before it was and then behave normally like in a snake game


Solution

  • It was a dumb mistake, thanks for @texus for showing me. replacing the loop responsible for giving over the coordinates with this:

    for(int i = snake.length-1; i > 0; i--)
    

    worked

    EDIT:

    I rewrote the code with a deque as sugested by @texus