C++ SFML 如何通过鼠标移动调整游戏视图
C++ SFML How to adjust game view via mouse movements
我有一个带 sf::view
的 SFML window,我需要通过鼠标移动来围绕我的游戏地图移动视图。
我想让它看起来好像玩家正在抓取并移动物体。
例如:myCube.setPosition(mousePos);
但是我不想移动游戏世界中的对象,而是希望它移动视图。
我的尝试:
view.setCenter(sf::Mouse::getPosition(window).x, sf::Mouse::getPosition(window).y);
如果您还没有阅读有关视图的信息,请访问此处的一个很好的页面来解释视图:https://www.sfml-dev.org/tutorials/2.5/graphics-view.php
我的做法是使用与拖动相关的三个鼠标事件(sf::Event::MouseButtonPressed、sf::Event::MouseButtonReleased 和 sf::Event::MouseMoved),并在拖动时更新视图根据鼠标移动的距离。
事件解释如下:https://www.sfml-dev.org/tutorials/2.5/window-events.php
我认为你需要存储你是否正在拖动(所以,一个布尔值),以及之前的鼠标位置(sf::Vector2i)。我将使用一个 class 来存储这些,并为我的示例提供一个 handleEvent()
函数。我还将存储渲染目标,或者您可以存储视图或将渲染 target/view 传递到 handleEvent()
函数中。
class ViewDragger {
public:
/// set render target with view and initialize dragging to false
ViewDragger(sf::RenderTarget& target) :
target{target},
dragging{}
{}
/// handle dragging related events
void handleEvent(const sf::Event event) {
// todo...
}
private:
/// the render target with the view we want to change
sf::RenderTarget& target;
/// the last known mouse position
sf::Vector2i previous_mouse_position;
/// whether we are dragging or not
bool dragging;
};
让我们实例化 class 并调用 handleEvent 函数。我将在创建 window 之后实例化 class,并在事件循环底部调用 handleEvent 函数。
ViewDragger view_dragger{ window };
...
while (window.pollEvent(event)) {
...
view_dragger.handleEvent(event);
}
最后我们将编写移动视图的函数。
先看看是不是拖动吧
void handleEvent(const sf::Event event) {
switch (event.type) {
// if mouse button is pressed start dragging
case sf::Event::MouseButtonPressed:
dragging = true;
break;
// if mouse button is released stop draggin
case sf::Event::MouseButtonReleased:
dragging = false;
break;
}
}
现在我们知道我们是否在拖动,让我们在我们刚刚创建的两个拖动视图的下方创建第三个事件。
首先我们将编写更新先前鼠标位置的代码。
// if dragging mouse
case sf::Event::MouseMoved:
// get mouse position
const sf::Vector2i mouse_position{
event.mouseMove.x, event.mouseMove.y
};
// if dragging, move view
if (dragging) {
// todo...
}
// update previous mouse position
previous_mouse_position = mouse_position;
break;
现在我们要计算鼠标在视图中移动了多远。
这与鼠标在 window 中移动的距离不同。
鼠标可能在 window 中从 (0, 0) 移动到 (10, 0),但这并不意味着它在视图中移动了 10 个单位。如果视图已经移动,则 (0, 0) 可以是任何值,如果缩放视图,则水平方向 10 个像素不是向右 10 个单位,如果旋转视图,则很难弄清楚.
幸运的是,我们已经有一个功能可以让我们从 window space 更改为查看 space: sf::RenderTarget::mapPixelToCoords()
.
我们将把它与当前鼠标位置和先前鼠标位置一起使用。
// calculate how far mouse has moved in view
const auto delta =
target.mapPixelToCoords(mouse_position) -
target.mapPixelToCoords(previous_mouse_position);
最后我们需要将它消极地应用到视图中。
因此,如果我们将鼠标向右移动十个单位,我们希望视图向左移动 10 个单位。
// apply negatively to view
auto view = target.getView();
view.move(-delta);
target.setView(view);
应该就是了!
完整代码:
#include <SFML/Graphics.hpp>
class ViewDragger {
public:
/// set render target with view and initialize dragging to false
ViewDragger(sf::RenderTarget& target) :
target{ target },
dragging{}
{}
/// handle dragging related events
void handleEvent(const sf::Event event) {
switch (event.type) {
// if mouse button is pressed start dragging
case sf::Event::MouseButtonPressed:
dragging = true;
break;
// if mouse button is released stop draggin
case sf::Event::MouseButtonReleased:
dragging = false;
break;
// if dragging mouse
case sf::Event::MouseMoved:
// get mouse position
const sf::Vector2i mouse_position{
event.mouseMove.x, event.mouseMove.y
};
// if dragging, move view
if (dragging) {
// calculate how far mouse has moved in view
const auto delta =
target.mapPixelToCoords(mouse_position) -
target.mapPixelToCoords(previous_mouse_position);
// apply negatively to view
auto view = target.getView();
view.move(-delta);
target.setView(view);
}
// update previous mouse position
previous_mouse_position = mouse_position;
break;
}
}
private:
/// the render target with the view we want to change
sf::RenderTarget& target;
/// the last known mouse position
sf::Vector2i previous_mouse_position;
/// whether we are dragging or not
bool dragging;
};
int main() {
sf::RenderWindow window{ sf::VideoMode(200, 200), "View Dragging!" };
ViewDragger view_dragger{ window };
sf::CircleShape shape{ 100.f };
shape.setFillColor(sf::Color::Green);
while (window.isOpen()) {
sf::Event event;
while (window.pollEvent(event)) {
if (event.type == sf::Event::Closed) {
window.close();
}
view_dragger.handleEvent(event);
}
window.clear();
window.draw(shape);
window.display();
}
return EXIT_SUCCESS;
}
太棒了,谢谢。完美的。也许对我来说有点太复杂了,尤其是自动功能和 renderTarget 的使用,但我会深入研究它。我只对人民币加反应。
我的版本:
class ViewDragger
{
private:
sf::RenderTarget& RTwindow;
sf::Vector2i previousMousePosition;
bool dragging;
public:
//get window at construct and initialize variables with initializer list
ViewDragger(sf::RenderTarget& RTwindow)
: RTwindow{RTwindow}, dragging{}
{
}
//use after window.pollEvent(event)) to get event handler
void handleEvent(const sf::Event event)
{
switch (event.type)
{
case sf::Event::MouseButtonPressed:
if (event.mouseButton.button == sf::Mouse::Right)
{
//start dragging
dragging = true;
}
break;
case sf::Event::MouseButtonReleased:
if (event.mouseButton.button == sf::Mouse::Right)
{
//stop dragging
dragging = false;
}
break;
case sf::Event::MouseMoved:
//get new mouse position
const sf::Vector2i mousePosition(event.mouseMove.x, event.mouseMove.y);
if (dragging)
{
//if mouse is dragging, count difference between new mouse position and old mouse position
//example: mouse move down by x100: new(x400,.y300) - (x300,y300) = x100 and for opposite direction make it -x100
const sf::Vector2f delta = RTwindow.mapPixelToCoords(mousePosition) - RTwindow.mapPixelToCoords(previousMousePosition);
sf::View view = RTwindow.getView();
view.move(-delta);
//update view
RTwindow.setView(view);
}
//save current mouse position as old mouse position for next run
previousMousePosition = mousePosition;
break;
}
}
};
`
我有一个带 sf::view
的 SFML window,我需要通过鼠标移动来围绕我的游戏地图移动视图。
我想让它看起来好像玩家正在抓取并移动物体。
例如:myCube.setPosition(mousePos);
但是我不想移动游戏世界中的对象,而是希望它移动视图。
我的尝试:
view.setCenter(sf::Mouse::getPosition(window).x, sf::Mouse::getPosition(window).y);
如果您还没有阅读有关视图的信息,请访问此处的一个很好的页面来解释视图:https://www.sfml-dev.org/tutorials/2.5/graphics-view.php
我的做法是使用与拖动相关的三个鼠标事件(sf::Event::MouseButtonPressed、sf::Event::MouseButtonReleased 和 sf::Event::MouseMoved),并在拖动时更新视图根据鼠标移动的距离。
事件解释如下:https://www.sfml-dev.org/tutorials/2.5/window-events.php
我认为你需要存储你是否正在拖动(所以,一个布尔值),以及之前的鼠标位置(sf::Vector2i)。我将使用一个 class 来存储这些,并为我的示例提供一个 handleEvent()
函数。我还将存储渲染目标,或者您可以存储视图或将渲染 target/view 传递到 handleEvent()
函数中。
class ViewDragger {
public:
/// set render target with view and initialize dragging to false
ViewDragger(sf::RenderTarget& target) :
target{target},
dragging{}
{}
/// handle dragging related events
void handleEvent(const sf::Event event) {
// todo...
}
private:
/// the render target with the view we want to change
sf::RenderTarget& target;
/// the last known mouse position
sf::Vector2i previous_mouse_position;
/// whether we are dragging or not
bool dragging;
};
让我们实例化 class 并调用 handleEvent 函数。我将在创建 window 之后实例化 class,并在事件循环底部调用 handleEvent 函数。
ViewDragger view_dragger{ window };
...
while (window.pollEvent(event)) {
...
view_dragger.handleEvent(event);
}
最后我们将编写移动视图的函数。 先看看是不是拖动吧
void handleEvent(const sf::Event event) {
switch (event.type) {
// if mouse button is pressed start dragging
case sf::Event::MouseButtonPressed:
dragging = true;
break;
// if mouse button is released stop draggin
case sf::Event::MouseButtonReleased:
dragging = false;
break;
}
}
现在我们知道我们是否在拖动,让我们在我们刚刚创建的两个拖动视图的下方创建第三个事件。
首先我们将编写更新先前鼠标位置的代码。
// if dragging mouse
case sf::Event::MouseMoved:
// get mouse position
const sf::Vector2i mouse_position{
event.mouseMove.x, event.mouseMove.y
};
// if dragging, move view
if (dragging) {
// todo...
}
// update previous mouse position
previous_mouse_position = mouse_position;
break;
现在我们要计算鼠标在视图中移动了多远。
这与鼠标在 window 中移动的距离不同。
鼠标可能在 window 中从 (0, 0) 移动到 (10, 0),但这并不意味着它在视图中移动了 10 个单位。如果视图已经移动,则 (0, 0) 可以是任何值,如果缩放视图,则水平方向 10 个像素不是向右 10 个单位,如果旋转视图,则很难弄清楚.
幸运的是,我们已经有一个功能可以让我们从 window space 更改为查看 space: sf::RenderTarget::mapPixelToCoords()
.
我们将把它与当前鼠标位置和先前鼠标位置一起使用。
// calculate how far mouse has moved in view
const auto delta =
target.mapPixelToCoords(mouse_position) -
target.mapPixelToCoords(previous_mouse_position);
最后我们需要将它消极地应用到视图中。
因此,如果我们将鼠标向右移动十个单位,我们希望视图向左移动 10 个单位。
// apply negatively to view
auto view = target.getView();
view.move(-delta);
target.setView(view);
应该就是了!
完整代码:
#include <SFML/Graphics.hpp>
class ViewDragger {
public:
/// set render target with view and initialize dragging to false
ViewDragger(sf::RenderTarget& target) :
target{ target },
dragging{}
{}
/// handle dragging related events
void handleEvent(const sf::Event event) {
switch (event.type) {
// if mouse button is pressed start dragging
case sf::Event::MouseButtonPressed:
dragging = true;
break;
// if mouse button is released stop draggin
case sf::Event::MouseButtonReleased:
dragging = false;
break;
// if dragging mouse
case sf::Event::MouseMoved:
// get mouse position
const sf::Vector2i mouse_position{
event.mouseMove.x, event.mouseMove.y
};
// if dragging, move view
if (dragging) {
// calculate how far mouse has moved in view
const auto delta =
target.mapPixelToCoords(mouse_position) -
target.mapPixelToCoords(previous_mouse_position);
// apply negatively to view
auto view = target.getView();
view.move(-delta);
target.setView(view);
}
// update previous mouse position
previous_mouse_position = mouse_position;
break;
}
}
private:
/// the render target with the view we want to change
sf::RenderTarget& target;
/// the last known mouse position
sf::Vector2i previous_mouse_position;
/// whether we are dragging or not
bool dragging;
};
int main() {
sf::RenderWindow window{ sf::VideoMode(200, 200), "View Dragging!" };
ViewDragger view_dragger{ window };
sf::CircleShape shape{ 100.f };
shape.setFillColor(sf::Color::Green);
while (window.isOpen()) {
sf::Event event;
while (window.pollEvent(event)) {
if (event.type == sf::Event::Closed) {
window.close();
}
view_dragger.handleEvent(event);
}
window.clear();
window.draw(shape);
window.display();
}
return EXIT_SUCCESS;
}
太棒了,谢谢。完美的。也许对我来说有点太复杂了,尤其是自动功能和 renderTarget 的使用,但我会深入研究它。我只对人民币加反应。 我的版本:
class ViewDragger
{
private:
sf::RenderTarget& RTwindow;
sf::Vector2i previousMousePosition;
bool dragging;
public:
//get window at construct and initialize variables with initializer list
ViewDragger(sf::RenderTarget& RTwindow)
: RTwindow{RTwindow}, dragging{}
{
}
//use after window.pollEvent(event)) to get event handler
void handleEvent(const sf::Event event)
{
switch (event.type)
{
case sf::Event::MouseButtonPressed:
if (event.mouseButton.button == sf::Mouse::Right)
{
//start dragging
dragging = true;
}
break;
case sf::Event::MouseButtonReleased:
if (event.mouseButton.button == sf::Mouse::Right)
{
//stop dragging
dragging = false;
}
break;
case sf::Event::MouseMoved:
//get new mouse position
const sf::Vector2i mousePosition(event.mouseMove.x, event.mouseMove.y);
if (dragging)
{
//if mouse is dragging, count difference between new mouse position and old mouse position
//example: mouse move down by x100: new(x400,.y300) - (x300,y300) = x100 and for opposite direction make it -x100
const sf::Vector2f delta = RTwindow.mapPixelToCoords(mousePosition) - RTwindow.mapPixelToCoords(previousMousePosition);
sf::View view = RTwindow.getView();
view.move(-delta);
//update view
RTwindow.setView(view);
}
//save current mouse position as old mouse position for next run
previousMousePosition = mousePosition;
break;
}
}
};
`