Search code examples
c++sfml

SFML sf::View::move inconstancy


UPDATE: I couldn't figure out the exact problem, however I made a fix that's good enough for me: Whenever the player's X value is less then half the screen's width, I just snap the view back to the center (up left corner) using sf::View::setCenter().

So I'm working on a recreating of Zelda II to help learn SFML good enough so I can make my own game based off of Zelda II. The issue is the screen scrolling, for some reason, if link walks away from the wall and initiated the camera to follow him, and then move back toward the wall, the camera won't go all the way back to the end of the wall, which occurs on the other wall at the end of the scene/room. This can be done multiple times to keep making the said camera block get further away from the wall. This happens on both sides of the scene, and I have reason to believe it has something to do with me trying to make the game frame independent, here's an included GIF of my issue to help understand: enter image description here

My camera function:

void Game::camera() {
    if (this->player.getVar('x') >= this->WIDTH / 2 and this->player.getVar('x') < this->sceneWidth - this->WIDTH / 2) {
        this->view.move(int(this->player.getVar('v') * this->player.dt * this->player.dtM), 0);
    }
}

player.getVar() is a temporary function I'm using to get the players x position and x velocity, using the argument 'x' returns the players x position, and 'v' returns the x velocity. WIDTH is equal to 256, and sceneWidth equals 767, which is the image I'm using for the background's width. dt and dtM are variables for the frame independence I mentioned earlier, this is the deceleration:

    sf::Clock sclock;
    float dt = 0;
    float dtM = 60;
    int frame = 0;
    void updateTime() {
        dt = sclock.restart().asSeconds();
        frame += 1 * dt * dtM;
    }

updateTime() is called every frame, so dt is updated every frame as well. frame is just a frame counter for Link's animations, and isn't relevant to the question. Everything that moves and is rendered on the screen is multiplied by dt and dtM respectively.


Solution

  • There's a clear mismatch between the movement of the player and the one of the camera... You don't show the code to move the player, but if I guess you don't cast to int the movement there, as you are doing on the view.move call. That wouldn't be a problem if you were setting the absolute position of the camera, but as you are constantly moving it, the little offset accumulates each frame, causing your problem.

    • One possible solution on is to skip the cast, which is unnecessary because sf::View::move accepts float as arguments.

      void Game::camera() {
        if (this->player.getVar('x') >= this->WIDTH / 2 and this->player.getVar('x') < this->sceneWidth - this->WIDTH / 2) {
            this->view.move(this->player.getVar('v') * this->player.dt * this->player.dtM, 0);
        }
      }
      
    • Or even better, not to use view.move but to directly set the position of the camera each frame. Something like:

      void Game::camera() {
        if (this->player.getVar('x') >= this->WIDTH / 2 and this->player.getVar('x') < this->sceneWidth - this->WIDTH / 2) {
            this->view.setCenter(this->player.getVar('x'), this->view.getCenter().y);
        }
      }