0

So, I wrote this snake game in C++ using SFML 2.0 RC and everything was working perfectly until I tried to implement frame independent movement. I understand how to do it, but I can't seem to make it work with my snake game. If the SCALE define is set to 10, then I want the snake to move 10 pixels. I never want it to move less or more than that, but I want the snake to move at the same speed on all computers, which is why I needed to implement frame independent movement. Here is my code, in the updateSnake method is where the movement occurs.

If someone could help me fix this problem it would be much appreciated :)

#include <SFML/Graphics.hpp>
#include <iostream>
#include <cmath>
#include <ctime>
#include <sstream>

#define WIDTH 40
#define HEIGHT 40
#define SCALE 20

const int MAX_PARTS = HEIGHT * WIDTH;

enum {
    UP,
    DOWN,
    LEFT,
    RIGHT
};

struct Apple {
    Apple() {
        x = (int) ((rand() % (WIDTH - 1)) + 1) * SCALE;
        y = (int) ((rand() % (HEIGHT - 1)) + 1) * SCALE;
        texture.loadFromFile("Apple.png");
    }
    float x, y;
    sf::Texture texture;
};

struct SnakePart {
    SnakePart(float x, float y) {
        this->x = x;
        this->y = y;
    }
    float x, y;
};

struct Snake {
    Snake(float x, float y, int dir) {
        this->x = x;
        this->y = y;
        this->dir = dir;
        numParts = 0;
        headTexture.loadFromFile("HeadSnake.png");
        bodyTexture.loadFromFile("BodySnake.png");
        for (int i = 0; i < MAX_PARTS; i++) {
            parts[i] = NULL;
        }
        parts[0] = new SnakePart((((WIDTH - 1) * SCALE) / 2), 
            ((HEIGHT * SCALE) / 2));
        numParts++;
    }
    ~Snake() {
        for (int i = 0; i < MAX_PARTS; i++) {
            delete parts[i];
        }
    }
    int dir, numParts;
    float x, y;
    SnakePart* parts[MAX_PARTS];
    sf::Texture headTexture;
    sf::Texture bodyTexture;
};

bool gameRunning;

void updateSnake(Snake&, Apple&, const long);
void drawSnake(const Snake&, sf::RenderWindow&);
void drawApple(const Apple&, sf::RenderWindow&);

int main(int argc, char* argv[]) {
    srand(static_cast<unsigned int>(time(0)));
    sf::RenderWindow window(sf::VideoMode(WIDTH * SCALE, HEIGHT * SCALE), 
        "SFML Snake");
    //window.setFramerateLimit(60);

    Snake* snake = new Snake((WIDTH * SCALE) / 2, 
        (HEIGHT * SCALE) / 2, RIGHT);
    Apple* apple = new Apple();
    sf::Clock clock;
    gameRunning = true;
    sf::Text text;
    sf::Font font;
    font.loadFromFile("digital-7.ttf");
    text.setFont(font);
    text.setPosition(30, 30);
    text.setString("Score: 0");
    text.setCharacterSize(15);

    while (window.isOpen() && gameRunning) {
        sf::Time time = clock.restart();
        long delta = time.asMilliseconds();
        sf::Event event;
        while (window.pollEvent(event)) {
            if (event.type == sf::Event::Closed) {
                window.close();
            }
        }
        if (sf::Keyboard::isKeyPressed(sf::Keyboard::A) && 
            snake->dir != RIGHT)  {
            snake->dir = LEFT;
        } else if (sf::Keyboard::isKeyPressed(sf::Keyboard::D) && 
            snake->dir != LEFT) {
            snake->dir = RIGHT;
        } else if (sf::Keyboard::isKeyPressed(sf::Keyboard::W) && 
            snake->dir != DOWN) {
            snake->dir = UP;
        } else if (sf::Keyboard::isKeyPressed(sf::Keyboard::S) && 
            snake->dir != UP) {
            snake->dir = DOWN;
        }
        std::stringstream ss;
        ss << (snake->numParts - 1);
        text.setString("Score: " + ss.str());
        updateSnake(*snake, *apple, delta);
        window.clear();
        drawSnake(*snake, window);
        drawApple(*apple, window);
        window.draw(text);
        window.display();
    }
    delete snake;
    delete apple;
    //std::cin.get();
    return 0;
}

void updateSnake(Snake& snake, Apple& apple, const long delta) {
    int x = 0, y = 0;
    switch (snake.dir) {
    case UP:
        y = -1;
        break;
    case DOWN:
        y = 1;
        break;
    case LEFT:
        x = -1;
        break;
    case RIGHT:
        x = 1;
        break;
    }
    snake.x += (x * SCALE) * (delta / 1000.f);
    snake.y += (y * SCALE) * (delta / 1000.f);
    if (snake.x >= (WIDTH * SCALE) || 
        snake.y >= (HEIGHT * SCALE) ||
        snake.x < 0 ||
        snake.y < 0) {
            gameRunning = false;
            return;
    }
    if ((snake.x == apple.x) && (snake.y == apple.y)) {
        snake.parts[snake.numParts] = new SnakePart(snake.parts[snake.numParts - 1]->x - 1, 
            snake.parts[snake.numParts - 1]->y);
        snake.numParts++;
        apple.x = (int) ((rand() % (WIDTH - 1)) + 1) * SCALE;
        apple.y = (int) ((rand() % (HEIGHT - 1)) + 1) * SCALE;
    }
    for (int i = 0; i < snake.numParts; i++) {
        if ((snake.x == snake.parts[i]->x) && 
            (snake.y == snake.parts[i]->y)) {
            gameRunning = false;
            return;
        }
    }
    float lastPartX = snake.x - (x * SCALE), 
        lastPartY = snake.y - (y * SCALE);
    for (int i = 0; i < snake.numParts; i++) {
        SnakePart* part = snake.parts[i];
        float oldX = part->x, oldY = part->y;
        part->x = lastPartX;
        part->y = lastPartY;
        lastPartX = oldX;
        lastPartY = oldY;
    }
}

void drawSnake(const Snake& snake, sf::RenderWindow& window) {
    sf::Sprite sprite;
    sprite.setTexture(snake.headTexture);
    sprite.setPosition(snake.x, snake.y);
    float scaleFactor = SCALE / 10;
    sprite.setScale(scaleFactor, scaleFactor);
    window.draw(sprite);
    for (int i = 0; i < snake.numParts; i++) {
        sprite.setTexture(snake.bodyTexture);
        sprite.setPosition(snake.parts[i]->x, snake.parts[i]->y);
        window.draw(sprite);
    }
}

void drawApple(const Apple& apple, sf::RenderWindow& window) {
    sf::Sprite sprite;
    sprite.setTexture(apple.texture);
    sprite.setPosition(apple.x, apple.y);
    float scaleFactor = SCALE / 10;
    sprite.setScale(scaleFactor, scaleFactor);
    window.draw(sprite);
}

Thank you in advance for any help :)

1
Contributor
1
Reply
3
Views
5 Years
Discussion Span
Last Post by Haxifix
This question has already been answered. Start a new discussion instead.
Have something to contribute to this discussion? Please be thoughtful, detailed and courteous, and be sure to adhere to our posting rules.