📜 ⬆️ ⬇️

Animations on lambdas in C ++ 11



Development companies, as a rule, are not particularly in a hurry to switch to a new C ++. Mainly due to the support of its compilers, or rather its complete or partial absence. Recently, I decided to find out what's new in terms of supporting C ++ 11 with the GCC compiler, and I realized that it was time to start . Fortunately, we at Ivideon are loyal to new technologies and give to try something new.
He began, of course, with the most delicious - with lambda expressions! And from the streams.


I want to present the reader with a little sketch on how lambdas can help make the code more readable and concise. Such code can be used everywhere, where you have to call some function periodically, while transferring to it the time elapsed from the previous call - for example, in animations.
')
Title:

#ifndef ANIMATION_ENGINE_H #define ANIMATION_ENGINE_H #include <functional> namespace animation { // Actor function has one parameter: time delta since previous frame // It should return true if animation has finished, // or false if it should go on typedef std::function<bool(float)> actor_func; // Handler is called after the animation is complete typedef std::function<void(void)> handler_func; const handler_func doNothing = [] {}; void start(unsigned intervalMs, actor_func, handler_func = doNothing); } // end of namespace animation #endif // ANIMATION_ENGINE_H 


The interface is simple: in start (), we pass a call interval, a function, and an optional completion handler.

And implementation:

 #include "animation_engine.h" #include <thread> namespace animation { void start(unsigned intervalMs, actor_func actor, handler_func handler) { std::thread t([=]() { auto timeStart = std::chrono::system_clock::now(); float lastInterval = 0; while(1) { std::this_thread::sleep_for(std::chrono::milliseconds(intervalMs)); float timeDelta = std::chrono::duration_cast<std::chrono::milliseconds> (std::chrono::system_clock::now() - timeStart).count(); if (actor(timeDelta - lastInterval)) { handler(); break; } lastInterval = timeDelta; } }); t.detach(); } } // end of namespace animation 


Here it is more interesting: on the basis of the functions that are passed by the arguments, and the interval, a new function ( closure ) is built, where the passed arguments are copied ([=] means to capture all the variables from the current scope that are used in the lambda). Then this new function is launched in a separate thread, where it is chasing our unfortunate actor function in an infinite loop until it returns true. Well, or the application will not close. Next, start () is completed, leaving the animation spinning in its thread.

Below is an example of use. Suppose we write a toy like a ping-pong or arkanoid, and we need to activate a ball. Here's how to implement it:
 animation::start (30, [=] (float dt) { this->adjustBallDirection(dt); // bouncing, maybe gravitation this->updateBallPosition(dt); return (this->ballMissed()) // if player missed the ball -> stop }, [this] { resetBall(); } ); 


Compile this all, as usual, it is necessary with the key-std = c ++ 11 or -std = c ++ 0x. In addition, at the linking stage, you need to pass the -pthread key. If you, like me, are working with QMake, just add these two lines to the .pro file:
 CONFIG += c++11 QMAKE_LFLAGS += -pthread 


Possible improvement # 1: for real tasks, it would be nice to improve the calculation of the interval between calls. To do this, consider the time while the function-actor executes. And now it turns out that the interval becomes a little more. But I did not bother with it this time: just a note about this.

Possible improvement number 2: you can introduce additional functionality that would allow to interrupt the animation. This is easy to do (yes, at least by introducing a flag that all streams with animations would check during operation), but, again, the example code would be swollen.

It is likely that you know a more concise way to solve this problem - it will be cool if you state it in the comments. Or do you know a more interesting case where lambdas would simplify life ... well, you know what to do.

Thanks for attention!

Source: https://habr.com/ru/post/230501/


All Articles