在SFML中拖动屏幕

时间:2017-01-22 08:28:30

标签: c++ graphics 2d sfml

我正在使用SFML在C ++中构建一个基本程序,它允许用户放大对象并拖动屏幕。我已经能够使屏幕移动但是移动与鼠标完全不同步并且不平滑。有没有人对如何重写我的代码有任何建议,以便用鼠标正确移动屏幕?

        Time time = milliseconds(5);
        x1 = Mouse::getPosition().x;
        y1 = Mouse::getPosition().y;

        if (Mouse::isButtonPressed(Mouse::Left))
        {
            std::cout << x1 - Mouse::getPosition().x << " " << y1 - Mouse::getPosition().y << std::endl;
            sleep(time);
            view.move((x1 - Mouse::getPosition().x)*2, (y1 - Mouse::getPosition().y)*2);
        }

5 个答案:

答案 0 :(得分:2)

有多种不同的方法可以实现这一目标。最简单的可能是使用sf::Window::setView()更新您的窗口视图。

您可以执行类似以下示例的操作。尝试理解代码,而不仅仅是复制代码。

#include <SFML/Graphics.hpp>

int main()
{
    // Let's setup a window
    sf::RenderWindow window(sf::VideoMode(640, 480), "SFML View Transformation");

    // Create something simple to draw
    sf::Texture texture;
    texture.loadFromFile("background.jpg");
    sf::Sprite background(texture);

    sf::Vector2f oldPos;
    bool moving = false;

    float zoom = 1;

    // Retrieve the window's default view
    sf::View view = window.getDefaultView();

    while (window.isOpen()) {
        sf::Event event;
        while (window.pollEvent(event)) {
            switch (event.type) {
                case sf::Event::Closed:
                    window.close();
                    break;
                case sf::Event::MouseButtonPressed:
                    // Mouse button is pressed, get the position and set moving as active
                    if (event.mouseButton.button == 0) {
                        moving = true;
                        oldPos = window.mapPixelToCoords(sf::Vector2i(event.mouseButton.x, event.mouseButton.y));
                    }
                    break;
                case  sf::Event::MouseButtonReleased:
                    // Mouse button is released, no longer move
                    if (event.mouseButton.button == 0) {
                        moving = false;
                    }
                    break;
                case sf::Event::MouseMoved:
                    {
                        // Ignore mouse movement unless a button is pressed (see above)
                        if (!moving)
                            break;
                        // Determine the new position in world coordinates
                        const sf::Vector2f newPos = window.mapPixelToCoords(sf::Vector2i(event.mouseMove.x, event.mouseMove.y));
                        // Determine how the cursor has moved
                        // Swap these to invert the movement direction
                        const sf::Vector2f deltaPos = oldPos - newPos;

                        // Move our view accordingly and update the window
                        view.setCenter(view.getCenter() + deltaPos);
                        window.setView(view);

                        // Save the new position as the old one
                        // We're recalculating this, since we've changed the view
                        oldPos = window.mapPixelToCoords(sf::Vector2i(event.mouseMove.x, event.mouseMove.y));
                        break;
                    }
                case sf::Event::MouseWheelScrolled:
                    // Ignore the mouse wheel unless we're not moving
                    if (moving)
                        break;

                    // Determine the scroll direction and adjust the zoom level
                    // Again, you can swap these to invert the direction
                    if (event.mouseWheelScroll.delta <= -1)
                        zoom = std::min(2.f, zoom + .1f);
                    else if (event.mouseWheelScroll.delta >= 1)
                        zoom = std::max(.5f, zoom - .1f);

                    // Update our view
                    view.setSize(window.getDefaultView().getSize()); // Reset the size
                    view.zoom(zoom); // Apply the zoom level (this transforms the view)
                    window.setView(view);
                    break;
            }
        }

        // Draw our simple scene
        window.clear(sf::Color::White);
        window.draw(background);
        window.display();
    }
}

另请注意,代码只会放大/缩小,它不会向光标位置缩放,但这应该很容易添加(基本上只是移动视图类似于我已经完成的操作)鼠标运动)。

答案 1 :(得分:0)

(回答而不是评论,因为我没有足够的声誉)

您是否尝试删除sleepcout?我很确定这两个导致它

答案 2 :(得分:0)

  

使用自定义视图或调整窗口大小时,像素   显示在目标上不再匹配2D世界中的单位。对于   例如,单击像素(10,50)可能会点击(26.5,-84)   你的世界。您最终必须使用转换功能来映射您的   像素坐标到世界坐标:mapPixelToCoords。

// get the current mouse position in the window
sf::Vector2i pixelPos = sf::Mouse::getPosition(window);

// convert it to world coordinates
sf::Vector2f worldPos = window.mapPixelToCoords(pixelPos);
  

默认情况下,mapPixelToCoords使用当前视图。如果你想   使用不是活动视图的视图转换坐标,你   可以将它作为函数的附加参数传递。

     

相反,将世界坐标转换为像素坐标,是   也可以使用mapCoordsToPixel函数。

您可以在页面底部看到它:https://www.sfml-dev.org/tutorials/2.0/graphics-view.php

答案 3 :(得分:0)

因为user3881815建议您的sleep(时间)存在问题,因为它不能保证会为time [ms]休眠。相反,可以添加任何OS调度粒度间隔的计数,从而导致波动性。更不用说它会阻止执行...而且你不是通过鼠标改变而是通过某种比例而移动(所以不要惊讶它不同步)。那么如何摆脱它?

您需要记住最后一个鼠标位置并在处理循环中使用每次运行。例如:

double mx=0,my=0,mx0=0,my0=0; // globals with actual and last mouse position

// here your main loop or event or whatever
for (bool exit=false;!exit;)
 {
 // here your other stuff

 // mouse handler
 mx0=mx; mx = Mouse::getPosition().x;
 my0=my; my = Mouse::getPosition().y;
 // here convert mx,my to coordinate system the view.move needs
 if (Mouse::isButtonPressed(Mouse::Left)) view.move(mx-mx0,my-my0);
 }

如果您的视图使用缩放,那么您很可能需要将坐标转换应用于mx,my,但这取决于view.move想要的内容。

我不使用SFML进行编码,因此我对您的观点没有经验,但您可以尝试

view.move((mx-mx0)*view.zoom,(my-my0)*view.zoom);

view.move((mx-mx0)/view.zoom,(my-my0)/view.zoom);

要使移动与鼠标同步,view.zoom是视图的比例。两者中的哪一个取决于view符号。

为了更好地处理鼠标,您还应该具有按钮的最后和实际状态,以便您可以处理mousedown,mouseup和mousemove事件。有关详细信息,请参阅:

答案 4 :(得分:0)

我一直在尝试类似的事情,并且希望改进@Mario's answer

实际上,mapPixelToCoords的使用最终以某种方式昂贵。这有点奇怪,因为mapPixelToCoords仅对坐标应用了一些矩阵运算,但是事情是当我使用mapPixelToCoords时,如果缩放不是原始缩放,我的图像就会发疯。 >

就我而言,我更喜欢保持累积的缩放比例并将deltaPos乘以缩放比例。

@Mario代码的更改

新变量accumZoom
double accumZoom = 1;
按钮按下事件:
case sf::Event::MouseButtonPressed:
    // Mouse button is pressed, get the position and set moving as active
    if (event.mouseButton.button == 0) {
        moving = true;
        oldPos = sf::Vector2f(sf::Mouse::getPosition(window)); // No call to mapPixelToCoords
    }
    break;
鼠标移动事件:
case sf::Event::MouseMoved:
{
    // Ignore mouse movement unless a button is pressed (see above)
    if (!moving)
        break;
    // Determine the new position in world coordinates
    const sf::Vector2f newPos = sf::Vector2f(event.mouseMove.x, event.mouseMove.y);
    // Determine how the cursor has moved
    // Swap these to invert the movement direction
    const sf::Vector2f deltaPos = oldPos - newPos;

    // Applying zoom "reduction" (or "augmentation")
    deltaPos.x *= accumZoom;
    deltaPos.y *= accumZoom;

    // Move our view accordingly and update the window
    view.move(deltaPos); // <-- Here I use move
    window.setView(view);

    // Save the new position as the old one
    // We're recalculating this, since we've changed the view
    oldPos = newPos; // With move, I don't need to recalculate
    break;
}
鼠标滚轮滚动事件:
case sf::Event::MouseWheelScrolled:
    // Ignore the mouse wheel unless we're not moving
    if (moving)
        break;

    // Determine the scroll direction and adjust the zoom level
    // Again, you can swap these to invert the direction
    if (event.mouseWheelScroll.delta <= -1)
        zoom = std::min(2.f, zoom + .1f);
    else if (event.mouseWheelScroll.delta >= 1)
        zoom = std::max(.5f, zoom - .1f);

    accumZoom *= zoom; // <-- accumulate zoom
    // Update our view
    view.setSize(window.getDefaultView().getSize()); // Reset the size
    view.zoom(zoom); // Apply the zoom level (this transforms the view)
    window.setView(view);
    break;