C++ SFML Как настроить вид игры с помощью движений мыши

У меня есть окно SFML с sf::view, и мне нужно перемещать вид по моей игровой карте с помощью движения мыши.
Я хочу, чтобы выглядело так, как будто игрок берет и перемещает объект.
Например: myCube.setPosition(mousePos); Но я не хочу перемещать объекты в моем игровом мире, вместо этого я хочу, чтобы он перемещал вид.

Моя попытка:

view.setCenter(sf::Mouse::getPosition(window).x, sf::Mouse::getPosition(window).y);
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
0
0
569
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Ответ принят как подходящий

Если вы не читали о представлениях, хорошая страница с их объяснением находится здесь: 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). Я буду использовать класс, который хранит их и имеет функцию handleEvent() для моего примера. Я также буду хранить цель рендеринга, в качестве альтернативы вы можете сохранить представление или передать цель/представление рендеринга в функцию 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;
};

Давайте создадим экземпляр класса и вызовем функцию handleEvent. Я создам экземпляр класса после создания окна и вызову функцию 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;

Теперь мы собираемся вычислить, как далеко мышь переместилась в представлении.

Это отличается от того, как далеко мышь переместилась в окне.
Мышь может двигаться от (0, 0) до (10, 0) в окне, но это не означает, что она переместилась на 10 единиц в представлении. Если вид уже перемещен, то (0, 0) может быть любым, а если вид масштабируется, то 10 пикселей по горизонтали не на 10 единиц вправо, и если вид повернут, очень сложно понять .

К счастью, для нас уже существует функция перехода от пространства окна к пространству просмотра: 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, но я займусь этим. Я добавляю реакцию только на RMB. Моя версия:

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;
        }
    
    }
};

`

Другие вопросы по теме