繁体   English   中英

在SFML中拖动屏幕

[英]Dragging screen in 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);
        }

实际上有多种不同的方法。 最直接的方法可能是使用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();
    }
}

还要注意,代码只会放大/缩小,不会放大到您的光标位置,但是添加起来应该是微不足道的(基本上只是移动视图,就像我为鼠标移动所做的那样)。

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

你有没有试图消除sleepcout 我很确定这是两个原因造成的

使用自定义视图或调整窗口大小时,目标上显示的像素不再与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

正如user3881815所建议的那样,问题出在您的sleep( time )因为它不能保证睡眠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应用坐标变换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事件。 有关更多信息,请参见:

我一直在尝试类似的事情,我想改善@Mario的答案

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

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

@Mario代码的更改

新变量accumZoom
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::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; 

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM