我正在使用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);
}
答案 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)
(回答而不是评论,因为我没有足够的声誉)
您是否尝试删除sleep
和cout
?我很确定这两个导致它
答案 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
乘以缩放比例。
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;