Welcome, Guest. Please login or register. Did you miss your activation email?

Author Topic: Keeping the sf::View inside of the map  (Read 856 times)

0 Members and 1 Guest are viewing this topic.

BreadMonika

  • Newbie
  • *
  • Posts: 5
    • View Profile
Keeping the sf::View inside of the map
« on: March 09, 2023, 01:39:53 am »
Hi, I've just started to learn SFML, and as I was experimenting with the views, I came up with a problem that I do not know how to solve, (I did this in SDL2 but things here are different), anyway, what I'm trying to do is keep the view inside of the map limits while scrolling. Like it would scroll in a super mario game, the view is not completely centered in the player but rather it moves when the player is at half of the window.

How can I keep the view inside of the map limits?

Here is what I have so far, it works well for the top and left corners but the right and bottom ones dont.

please see the gif to see my current behavior.

Here is my code:
#include <SFML/Graphics.hpp>

int main()
{
    sf::RenderWindow app(sf::VideoMode(480, 320), "view demo");

    // create player, at the screen center
    sf::RectangleShape player(sf::Vector2f(20, 20));
    player.setFillColor(sf::Color::Red);
    player.setOrigin(10, 10);
    player.setPosition(240, 160);
    const float player_speed = 100;

    sf::Texture backgroundImg;
    backgroundImg.loadFromFile("./resources/true.jpg");


    sf::Sprite background(backgroundImg);

   

    // we create our custom view
    sf::View player_view(sf::FloatRect(0, 0, app.getSize().x, app.getSize().y));
    player_view.setViewport(sf::FloatRect(0, 0, 1, 1));
    sf::Clock clock;
    bool running = true;
    sf::Event event;
    app.setView(player_view);

    while (running)
    {
        while (app.pollEvent(event))
        {
            if (event.type == sf::Event::Closed)
                running = false;
        }

        // moving player
        float frametime = clock.getElapsedTime().asSeconds();
        if (sf::Keyboard::isKeyPressed(sf::Keyboard::Up))
            player.move(0, -player_speed * frametime);
        if (sf::Keyboard::isKeyPressed(sf::Keyboard::Down))
            player.move(0, player_speed * frametime);
        if (sf::Keyboard::isKeyPressed(sf::Keyboard::Left))
            player.move(-player_speed * frametime, 0);
        if (sf::Keyboard::isKeyPressed(sf::Keyboard::Right))
            player.move(player_speed * frametime, 0);

        clock.restart();

        // we keep our view centered on the player

        sf::Vector2f position;
        auto sizeX(app.getSize().x);
        auto sizeY(app.getSize().y);
        player.getPosition().x >= sizeX / 2 ? position.x = player.getPosition().x : position.x = sizeX / 2;
        player.getPosition().y >= sizeY / 2 ? position.y = player.getPosition().y : position.y = sizeY / 2;


        player_view.setCenter(position);
        app.setView(player_view);

        // rendering entities
        app.draw(background);
        app.draw(player);

        app.display();
        app.clear();
    }
    app.close();
    return 0;
}
 

Stauricus

  • Sr. Member
  • ****
  • Posts: 369
    • View Profile
    • A Mafia Graphic Novel
    • Email
Re: Keeping the sf::View inside of the map
« Reply #1 on: March 09, 2023, 11:43:55 am »
If I understand correctly what you want, you just need to check if the view corners are outside your map coordinates. we don't have a function to get view corners, so you can use the view center minus (or plus) half of its size, both in the X and in the Y coordinates.

//after this line:
player_view.setCenter(position);
//add:
sf::Vector2f map_start(0, 0); //here im setting the map to start at the (0,0) coord
sf::Vector2f map_end(100, 100); //and to end at the (100, 100) coord

//first, in the X axis:

//you check if the view center minus half of the view size is a number smaller than the map default coordinates. if it is, set it to said coordinate.
if (player_view.getCenter().x - player_view.getSize().x/2 < map_start.x) {
  player_view.setCenter(map_start.x +player_view.getSize().x/2 , player_view.getCenter().y);
}
//if its not below the minimum, it could be above the maximum:
else if (player_view.getCenter().x + player_view.getSize().x/2 > map_end.x) {
  player_view.setCenter(map_end.x - player_view.getSize().x/2, player_view.getCenter().y);
}

//then you do the same for the Y axis.
 


EDIT: there are other ways to do it. you could check if the player is in the correct bounds for the view to follow him, and only then use player_view.setCenter(position);
but the way above should work well.
« Last Edit: March 09, 2023, 11:52:14 am by Stauricus »
Visit my game site (and hopefully help funding it? )
Website | IndieDB

BreadMonika

  • Newbie
  • *
  • Posts: 5
    • View Profile
Re: Keeping the sf::View inside of the map
« Reply #2 on: March 13, 2023, 03:45:29 am »
That did it, thank you so much ^-^/