[英]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();
}
}
还要注意,代码只会放大/缩小,不会放大到您的光标位置,但是添加起来应该是微不足道的(基本上只是移动视图,就像我为鼠标移动所做的那样)。
(因为我没有足够的声誉而回答,而不是评论)
你有没有试图消除sleep
和cout
? 我很确定这是两个原因造成的
使用自定义视图或调整窗口大小时,目标上显示的像素不再与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
乘以缩放级别。
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.