SFML community forums

Help => Graphics => Topic started by: Nical on May 20, 2020, 11:58:38 am

Title: Dragging whole scene
Post by: Nical on May 20, 2020, 11:58:38 am
Hi all,

I'm trying to implement a scene drag functionality. When the middle mouse button is pressed, I want to translate all my scene positions from the exact amount of pixel the mouse traveled.

Here is a POC of what I did. I represented the scene graph by a simple rectangle.

int main(int argc, char* argv[])
{
  sf::RenderWindow window(sf::VideoMode(400, 400), "Drag world");

  sf::Vector2f sceneOrigin(100., 100.);
  sf::RectangleShape scene({50., 50.});

  bool isDragging = false;
  sf::Vector2i lastMousePosition = sf::Mouse::getPosition(window);
  sf::Transform transform;

  while (window.isOpen())
  {
    sf::Event event;

    while (window.pollEvent(event))
    {
      if (event.type == sf::Event::MouseButtonPressed)
      {
        if (event.mouseButton.button == sf::Mouse::Middle)
          isDragging = true;
      }
      else if (event.type == sf::Event::MouseButtonReleased)
      {
        if (event.mouseButton.button == sf::Mouse::Middle)
          isDragging = false;
      }
      else if (event.type == sf::Event::MouseMoved and isDragging)
      {
        auto mouseDelta =
          window.mapPixelToCoords(sf::Vector2i(event.mouseMove.x, event.mouseMove.y))
          - window.mapPixelToCoords(lastMousePosition)
        ;

        transform.translate(mouseDelta);
      }
      else if (event.type == sf::Event::Resized)
      {
        window.setView(sf::View(sf::FloatRect(0., 0., event.size.width, event.size.height)));
      }
    }

    lastMousePosition = sf::Mouse::getPosition(window);

    scene.setPosition(transform.transformPoint(sceneOrigin));

    window.clear(sf::Color::Black);
    window.draw(scene);
    window.display();
  }

  return EXIT_SUCCESS;
}
 

When I test it, the rectangle (scene) is moved, but faster than the mouse cursor. It seems that my mouse delta is too high.
I tried the same thing raw mouse position (without the call to mapPixelToCoords), but the result is the same.

I don't understand what I missed here. Any help ?
Title: Re: Dragging whole scene
Post by: Athenian Hoplite on May 20, 2020, 12:52:39 pm
Never a good idea to mix real time input with event based input just as a caution you should initialize sf::Vector2i lastMousePosition with event.mouseButton.x and event.mouseButton.y when sf::Event::MouseButtonPressed as the starting position.

If I'm not mistaken for calculating a mouse delta for movement no conversion is needed just raw position in this scenario. I've never used transform.translate but I've implemented this kind of behaviour exactly as I have described by using sf::Transformable::move(offset) meaning in this case scene.move(mouseDelta). In a case where you would need this to propagate further down a hierarchy you could implement that by overloading the move method and calling it on children or simply by passing the appropriate states to child draw calls.
Title: Re: Dragging whole scene
Post by: Nical on May 20, 2020, 01:18:48 pm
This worked like a charm, thanks a lot :)