Welcome, Guest. Please login or register. Did you miss your activation email?

Author Topic: Thor 2.0 released!  (Read 381488 times)

0 Members and 5 Guests are viewing this topic.

Nexus

  • SFML Team
  • Hero Member
  • *****
  • Posts: 6287
  • Thor Developer
    • View Profile
    • Bromeon
Re: Thor 2.0
« Reply #255 on: December 14, 2013, 07:35:38 pm »
The signature must be
void onClick(thor::ActionContext<Button_Actions> context)
however at you it is
void Button::onClick(thor::ActionContext<Button_Actions> context)
You are passing a member function pointer instead of a function pointer.

An easy fix is to make onClick() static. If it needs access to other members, you can bind the member function to the object:
std::bind(&Button::onClick, this, _1)
Zloxx II: action platformer
Thor Library: particle systems, animations, dot products, ...
SFML Game Development:

The Terminator

  • Full Member
  • ***
  • Posts: 224
  • Windows and Mac C++ Developer
    • View Profile
Re: Thor 2.0
« Reply #256 on: December 14, 2013, 08:48:16 pm »
The signature must be
void onClick(thor::ActionContext<Button_Actions> context)
however at you it is
void Button::onClick(thor::ActionContext<Button_Actions> context)
You are passing a member function pointer instead of a function pointer.

An easy fix is to make onClick() static. If it needs access to other members, you can bind the member function to the object:
std::bind(&Button::onClick, this, _1)

Thanks! It works now.
Current Projects:
Technoport

didii

  • Full Member
  • ***
  • Posts: 122
    • View Profile
Re: Thor 2.0
« Reply #257 on: December 15, 2013, 12:32:07 pm »
Hi,

Is it possible to use the thor::ActionMap::isActive function as
sf::RenderWindow window(...);
thor::ActionMap<std::string> action_map;

// gameloop
while (window.isOpen()) {
    action_map.update(window);
    if (action_map.isActive(thor::Action(...)) // <- this
        // do stuff
}

If I want for example to pass the thor::ActionMap to an object to access all occurred events, it seems a bit of a detour to add it to the list of actions, assign a random key value for it, and then check for the random key.
I also saw the object thor::detail::EventBuffer on the ActionMap. I suppose that is the container holding all events? It doesn't seem possible to pass that one as an argument either.

Nexus

  • SFML Team
  • Hero Member
  • *****
  • Posts: 6287
  • Thor Developer
    • View Profile
    • Bromeon
Re: Thor 2.0
« Reply #258 on: December 15, 2013, 01:05:42 pm »
If I want for example to pass the thor::ActionMap to an object to access all occurred events, it seems a bit of a detour to add it to the list of actions, assign a random key value for it, and then check for the random key.
The idea of the action map and the actions is to abstract from underlying SFML events and realtime input. With thor::ActionMap, you don't test anymore if the Space key is pressed, instead you test whether the Shoot action is active. This allows you to re-map keys easily, and you can even add combinatoric expressions of multiple actions ("Space or Shift and X").

When you need to find a random ID to register your action, you are bypassing this abstraction mechanism and could (more or less) as well poll SFML events directly. Since the action you want to pass is associated with specific game logic (such as "shoot" or "jump" or "quit application"), it should be possible to find a meaningful ID.

I also saw the object thor::detail::EventBuffer on the ActionMap. I suppose that is the container holding all events? It doesn't seem possible to pass that one as an argument either.
As the namespace detail suggests, this is an implementation detail and not part of the public API.
Zloxx II: action platformer
Thor Library: particle systems, animations, dot products, ...
SFML Game Development:

didii

  • Full Member
  • ***
  • Posts: 122
    • View Profile
Re: Thor 2.0
« Reply #259 on: December 15, 2013, 10:16:44 pm »
The idea of the action map and the actions is to abstract from underlying SFML events and realtime input. With thor::ActionMap, you don't test anymore if the Space key is pressed, instead you test whether the Shoot action is active. This allows you to re-map keys easily, and you can even add combinatoric expressions of multiple actions ("Space or Shift and X").
Yes, I think I do understand that part of the thor::ActionMap.
But let me rephrase my question, since I'm bad with words... How would I use a thor::ActionMap if I want event handling in different places, such as inside the main loop (pauze menu, command window, ...) and one or more objects (such as the player (shoot, move, ...) or even multiple players).

I could give them all a thor::ActionMap and use thor::ActionMap::pushEvent, but then I would have multiple identical event containers. I could also handle all events inside the main loop, but then I could be checking for inputs that aren't used. I like having an object where I only need to call his update-function and it can manage itself.

I also might have an inefficient design and could have overlooked many things. But I don't (yet) see a better way of handling events efficiently.

Nexus

  • SFML Team
  • Hero Member
  • *****
  • Posts: 6287
  • Thor Developer
    • View Profile
    • Bromeon
Re: Thor 2.0
« Reply #260 on: December 15, 2013, 11:35:28 pm »
In general, you should try to keep responsibilities separate and modular. Game entities should not know about SFML events like "space key pressed", but they can know about high-level actions such as "shoot" or "jump". One possibility is to feed them with actions:
void Entity::HandleAction(const std::string& highlevelAction);
They can also get passed actions in their update step:
void Entity::Update(const std::vector<std::string>& actions);
Instead of strings, it's of course possible to use Action structures with more associated information.

You can make the separation more strict, in this case entities are not aware of input at all. They just provide corresponding member functions that are invoked by another class (the world containing them, for example).
void World::Update()
{
    if (mActionMap.isActive("Shoot"))
        mPlayer.Shoot();
}

Furthermore, a quite important feature that thor::ActionMap provides are callbacks. They allow to dispatch messages indirectly and reduce dependencies between modules. For example, in the World constructor you can register the callbacks.
typedef thor::ActionMap<std::string> ActionMap;

class World
{
    ActionMap::CallbackSystem   mCallbacks;
    Player                      mPlayer;
public:
    World()
    {
        auto shootFn = [this] (thor::ActionContext<MyAction> /*unused*/)
        {
            mPlayer.Shoot();
        };

        mCallbacks.connect("shoot", shootFn);
    }

    void HandleInput(const ActionMap& map, sf::RenderWindow& window)
    {
        map.invokeCallbacks(mCallbacks, &window);
    }
};

To get back to your initial question: When you have multiple places like menus and the game, it can be worthwhile to have one central ActionMap and multiple CallbackSystems (one per menu/game). With this approach, you can react to the same events differently in different application states. In the code above, a central class Application could then invoke World::HandleInput() with its action map and window.

As you see, there are many different approaches, with advantages and disadvantages. It depends on how you structure and design your game, and also a bit on personal preferences.
Zloxx II: action platformer
Thor Library: particle systems, animations, dot products, ...
SFML Game Development:

Lolilolight

  • Hero Member
  • *****
  • Posts: 1232
    • View Profile
Re: Thor 2.0
« Reply #261 on: December 20, 2013, 12:53:38 pm »
I have a question : can we only load resources from file with thor ?

I saw that we can use the fonction fromFile for the key of the resource but how does it work if I need to load a resource from the memory by example ?

How does it work if we need to use different kinds of functions to load resources ?

PS : I have another question, std::bind can return every kind of function ?

I think I'll use it. *-*

« Last Edit: December 20, 2013, 01:17:48 pm by Lolilolight »

eXpl0it3r

  • SFML Team
  • Hero Member
  • *****
  • Posts: 11034
    • View Profile
    • development blog
    • Email
Re: Thor 2.0
« Reply #262 on: December 20, 2013, 02:21:42 pm »
You should read the tutorial for resources, it's nicely explained there.
You can use different resource key factories, see here.
Official FAQ: https://www.sfml-dev.org/faq.php
Official Discord Server: https://discord.gg/nr4X7Fh
——————————————————————
Dev Blog: https://duerrenberger.dev/blog/

Nexus

  • SFML Team
  • Hero Member
  • *****
  • Posts: 6287
  • Thor Developer
    • View Profile
    • Bromeon
[Thor] Custom actions, simpler callback registration
« Reply #263 on: December 23, 2013, 10:26:26 pm »
I worked again on the Input module. Besides large internal simplifications and refactorings of the action resolution system, the following parts have changed:


1. Custom actions

It is now possible to bind user-defined actions to thor::Action. That is, you can not only combine existing action types with the boolean operators, but define yourself when an action is considered active. For this purpose, two factory functions thor::eventAction() and thor::realtimeAction() have been added. These take functors that return a bool whenever an action is supposed to be active.

For example, you can react specifically to every event, or once per frame to a realtime condition:
bool enteredLowerH(const sf::Event& event)
{
    return event.type == sf::Event::TextEntered && event.text.unicode == 'h';
}

bool joystickConnected()
{
    return sf::Joystick::isConnected(1);
}

thor::Action a = thor::eventAction(&enteredLowerH);
thor::Action b = thor::realtimeAction(&joystickConnected);

As you see, the realtime action is not directly linked to SFML, so you can also use it to check other states in your application.


2. Simpler callback registration


The two classes thor::EventSystem and thor::CallbackTimer allow you to register callbacks through the connect() function:
void listener(thor::CallbackTimer& trigger)
{
    std::cout << "expired" << std::endl;
    trigger.restart(sf::seconds(1.f));
}

thor::CallbackTimer timer;
timer.connect(&listener);

These callbacks take the instance that triggered them as a parameter. While this is useful in the above example, there are many cases where you just want to perform an action and don't care about the source. That is why I added the additional member functions connect0(), where 0 stands for "nullary" (meaning the function takes no arguments). Unfortunately I can't overload connect() because of ambiguities, at least not without a lot of black TMP magic.

An implication of this change is that the functions registered at thor::ActionMap::CallbackSystem do not need to carry a unused thor::ActionContext parameter. Instead of
void listener(thor::ActionContext<MyAction> context);

thor::ActionMap<MyAction>::CallbackSystem system;
system.connect(ActionXY, &listener);
you can now omit the parameter:
void listener();

thor::ActionMap<MyAction>::CallbackSystem system;
system.connect0(ActionXY, &listener);


3. API changes


The named-parameter-idiom function thor::joy() has been renamed to thor::joystick() for clarity.

The member typedefs Listener of thor::CallbackTimer and thor::EventSystem have been removed, and the connect() and connect0() parameters are written directly as std::function<...> instead of Listener. I hope that, by omitting this abstraction, it is clearer how the signature of the callbacks has to look.
Zloxx II: action platformer
Thor Library: particle systems, animations, dot products, ...
SFML Game Development:

zsbzsb

  • Hero Member
  • *****
  • Posts: 1409
  • Active Maintainer of CSFML/SFML.NET
    • View Profile
    • My little corner...
    • Email
Re: Thor 2.0
« Reply #264 on: December 23, 2013, 10:45:44 pm »
Looks good, but now I need to go update NetEXT  :P
Motion / MotionNET - Complete video / audio playback for SFML / SFML.NET

NetEXT - An SFML.NET Extension Library based on Thor

Nexus

  • SFML Team
  • Hero Member
  • *****
  • Posts: 6287
  • Thor Developer
    • View Profile
    • Bromeon
Re: Thor 2.0
« Reply #265 on: December 23, 2013, 11:41:41 pm »
True, however the implementation is simpler than before ;)

And it's still possible to reduce the amount of code in the current implementation by using thor::eventAction() and thor::realtimeAction() even for built-in actions, so there would only be a few node classes. But at the moment, these functions incur additional overhead because of the std::function indirection. One way to mitigate this is are template parameters for the functors.

Bottom line: Concerning internal refactorings, don't be too eager to adapt them always immediately.
Zloxx II: action platformer
Thor Library: particle systems, animations, dot products, ...
SFML Game Development:

Carlitox

  • Jr. Member
  • **
  • Posts: 53
    • View Profile
Re: Thor 2.0
« Reply #266 on: December 25, 2013, 03:06:54 am »
Hello I'm new with this library and in the forum. I cannot see the option to insert code.


I'm dealing with the particle system and learning all about it. I read that you can create your own distributions and apply it to the particles properties like the lifetime, rotation, position, etc.

For example:


thor::UniversalEmitter emitter;
emitter.setParticleLifetime(thor::Distributions::uniform(sf::seconds(1.f), sf::seconds(3.f)));


I tried to make the same but with my own distribution following the documentation.


unsigned int seed = std::chrono::system_clock::now().time_since_epoch().count();
std::mt19937 engine(seed);
std::uniform_real_distribution<float> distr(1.f, 3.f);
auto randomizer = std::bind(distr, engine);
thor::Distribution<float> thorDistr(randomizer);

thor::UniversalEmitter emitter;
emitter.setParticleLifetime(sf::seconds(thorDistr()));

 

This solution gives the same lifetime to all the particles, therefore it fails.

I think that I must use something like this but the library doesn't allow to do it or maibe I don't know how to implement it correctly:



unsigned int seed = std::chrono::system_clock::now().time_since_epoch().count();
std::mt19937 engine(seed);
std::uniform_real_distribution<float> distr(1.f, 3.f);
auto randomizer = std::bind(distr, engine);
thor::Distribution<sf::Time> thorDistr(randomizer);

thor::UniversalEmitter emitter;
emitter.setParticleLifetime(thorDistr().asSeconds());

 

Do you how I can implement it?
« Last Edit: December 25, 2013, 02:21:45 pm by Carlitox »

Nexus

  • SFML Team
  • Hero Member
  • *****
  • Posts: 6287
  • Thor Developer
    • View Profile
    • Bromeon
Re: Thor 2.0
« Reply #267 on: December 25, 2013, 12:49:45 pm »
Your mistake is that you pass a constant; the following expression does not yield a functor. So the result will always be the same.
sf::seconds(thorDistr())

The function sf::seconds() takes a float and it returns a sf::Time object, so you can't simply convert a uniform float distribution to a sf::Time distribution. You need to write your own functor:
struct Randomizer
{
    Randomizer()
    : distr(1.f, 3.f)
    , engine(mySeed)
    {
    }

    sf::Time operator() () const
    {
        return sf::seconds(distr(engine));
    }

    std::uniform_real_distribution<float> distr;
    std::mt19937 engine;
};

You can then pass such a function object to the emitter:
emitter.setParticleLifetime(Randomizer());

It would also be possible to achieve the same using a lambda expression. By the way, the C++ code can be inserted using the rightmost dropdown field with "Code".
« Last Edit: December 25, 2013, 12:51:39 pm by Nexus »
Zloxx II: action platformer
Thor Library: particle systems, animations, dot products, ...
SFML Game Development:

Carlitox

  • Jr. Member
  • **
  • Posts: 53
    • View Profile
Re: Thor 2.0
« Reply #268 on: December 25, 2013, 03:38:30 pm »
Thank you, it works. I tried to do the same with lambda and works as well.

auto randomizer_lambda =
[]()
{
        std::uniform_real_distribution<float> distr(1.f, 3.f);
        std::mt19937 mt(std::chrono::system_clock::now().time_since_epoch().count());
        return sf::seconds(distr(mt));
};

emitter.setParticleLifetime(randomizer_lambda);

Nexus

  • SFML Team
  • Hero Member
  • *****
  • Posts: 6287
  • Thor Developer
    • View Profile
    • Bromeon
Re: Thor 2.0
« Reply #269 on: December 25, 2013, 03:51:11 pm »
That's not how you should do it. You create a new engine and distribution every time the functor is invoked. Thus, the random number generator is useless.

Pass both distribution and engine as reference in the lambda's capture clause (or simply use the functor class I showed you).
Zloxx II: action platformer
Thor Library: particle systems, animations, dot products, ...
SFML Game Development:

 

anything