Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Exploration of sf::Event::visit use cases #3014

Closed
3 tasks done
vittorioromeo opened this issue May 15, 2024 · 0 comments · Fixed by #3139
Closed
3 tasks done

Exploration of sf::Event::visit use cases #3014

vittorioromeo opened this issue May 15, 2024 · 0 comments · Fixed by #3139

Comments

@vittorioromeo
Copy link
Member

Prerequisite Checklist

Describe your feature request here

In #2990 and event-related PRs, there was some discussion about providing a sf::Event::visit function. Would it actually be worth it?

Here are two examples of what could be achieved with such a function. Note that both examples are based on #2992, which I believe it's the right way forward for events anyway.

First of all, the user defines this convenience function:

void pollEvents(sf::Window& window, auto... lambdas)
{   
    auto visitor = overload(lambdas...);
    while (const std::optional event = window.pollEvent())
        event.visit(visitor);
}

Now, example 1:

//
//
// CURRENT API 
while (window.isOpen())
{
    while (const std::optional event = window.pollEvent())
    {
        if (event->is<sf::Event::Closed>())
        {
            window.close();
            break;
        }

        if (const auto* keyPressed = event->getIf<sf::Event::KeyPressed>();
            keyPressed && keyPressed->code == sf::Keyboard::Key::Escape)
        {
            window.close();
            break;
        }
    }
}

//
//
// WITH VISITATION
while (window.isOpen())
{
    pollEvents(window, 
        [&](sf::Event::Closed)
        { 
            window.close(); 
        },
        [&](sf::Event::KeyPressed e)
        { 
            if (e.code == sf::Keyboard::Key::Escape)
                window.close();
        }
    );
}

Example 2 (from Tennis):

//
//
// CURRENT API
while (const auto event = window.pollEvent())
{
    // Window closed or escape key pressed: exit
    if (event.is<sf::Event::Closed>() || (event.is<sf::Event::KeyPressed>() &&
                                            event.getIf<sf::Event::KeyPressed>()->code == sf::Keyboard::Key::Escape))
    {
        window.close();
        break;
    }

    // Space key pressed: play
    if ((event.is<sf::Event::KeyPressed>() && event.getIf<sf::Event::KeyPressed>()->code == sf::Keyboard::Key::Space) ||
        event.is<sf::Event::TouchBegan>())
    {
        if (!isPlaying)
        {
            // (re)start the game
            isPlaying = true;
            clock.restart();

            // Reset the position of the paddles and ball
            leftPaddle.setPosition({10.f + paddleSize.x / 2.f, gameHeight / 2.f});
            rightPaddle.setPosition({gameWidth - 10.f - paddleSize.x / 2.f, gameHeight / 2.f});
            ball.setPosition({gameWidth / 2.f, gameHeight / 2.f});

            // Reset the ball angle
            do
            {
                // Make sure the ball initial angle is not too much vertical
                ballAngle = sf::degrees(std::uniform_real_distribution<float>(0, 360)(rng));
            } while (std::abs(std::cos(ballAngle.asRadians())) < 0.7f);
        }
    }

    // Window size changed, adjust view appropriately
    if (event.is<sf::Event::Resized>())
    {
        sf::View view;
        view.setSize({gameWidth, gameHeight});
        view.setCenter({gameWidth / 2.f, gameHeight / 2.f});
        window.setView(view);
    }
}

//
//
// WITH VISITATION
auto playAction = [&]
{
    if (!isPlaying)
    {
        // (re)start the game
        isPlaying = true;
        clock.restart();

        // Reset the position of the paddles and ball
        leftPaddle.setPosition({10.f + paddleSize.x / 2.f, gameHeight / 2.f});
        rightPaddle.setPosition({gameWidth - 10.f - paddleSize.x / 2.f, gameHeight / 2.f});
        ball.setPosition({gameWidth / 2.f, gameHeight / 2.f});

        // Reset the ball angle
        do
        {
            // Make sure the ball initial angle is not too much vertical
            ballAngle = sf::degrees(std::uniform_real_distribution<float>(0, 360)(rng));
        } while (std::abs(std::cos(ballAngle.asRadians())) < 0.7f);
    }
}; 

pollEvents(window, 
    [&](sf::Event::Closed)
    { 
        window.close(); 
    },
    [&](sf::Event::KeyPressed e)
    {
        if (e.code == sf::Keyboard::Key::Escape)
            window.close();
        else if (e.code == sf::Keyboard::Key::Space)
            playAction();
    },
    [&](sf::Event::TouchBegan)
    {
        playAction();
    }
    [&](sf::Event::Resized)
    {
        sf::View view;
        view.setSize({gameWidth, gameHeight});
        view.setCenter({gameWidth / 2.f, gameHeight / 2.f});
        window.setView(view);
    }
);

I kinda like it. Thoughts?

Observations:

  • pollEvents makes a sf::Event::visit much more compelling.
  • Yes, every lambda needs to capture, but [&] is safe in this context.
  • Repeated actions need to be extracted such as for playAction. Not a big deal, might actually promote good coding practices.
  • All the "empty state" or "optional has_value" BS disappears.

Use Cases

N/A

API Example

No response

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
Status: Done
Development

Successfully merging a pull request may close this issue.

2 participants