C ++ 11のラムダのアニメーション





開発会社は、原則として、新しいC ++に切り替えることを急いでいません。 主にそのコンパイラのサポート、またはむしろその完全または部分的な不在による。 私は最近、GCCコンパイラでC ++ 11をサポートするという点で新しいことを見つけることにしました。 そして、開始する時が来たことに気付きました 。 幸いなことに、私たちIvideonは新しいテクノロジーに忠実であり、新しいことに挑戦する機会を与えてくれます。

もちろん、最もおいしいものから始めました-ラムダ式で! そして、スレッドで。





ラムダがコードをより読みやすく簡潔にするのにどのように役立つかというトピックに関する小さなスケッチを読者に紹介したいと思います。 このようなコードは、関数を定期的に呼び出す必要がある場合はいつでも使用できます。たとえば、アニメーションなど、前の呼び出しから経過した時間を渡します。



タイトル:



#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
      
      







インターフェイスはシンプルです。start()で、呼び出しの間隔、関数、オプションの完了ハンドラーを渡します。



そして実装:



 #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
      
      







ここで興味深いのは、引数と間隔で渡された関数に基づいて、渡された引数がコピーされる新しい関数( closure )が構築されることです([=]は、ラムダで使用されるすべての変数を現在のスコープから値でキャプチャすることを意味します)。 さらに、この新しい関数は別のスレッドで起動され、不運なアクター関数を無限ループで追跡し、trueを返します。 さて、またはアプリケーションが閉じません。 次に、start()が終了し、ストリーム内でアニメーションが回転したままになります。



以下は使用例です。 ピンポンやアルカノイドのようなおもちゃを書いており、ボールを作動させる必要があるとします。 実装方法は次のとおりです。

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







これをすべてコンパイルします。いつものように、スイッチ-std = c ++ 11または-std = c ++ 0xで必要です。 さらに、リンク段階で、-pthreadスイッチを渡す必要があります。 私のようにQMakeを使用する場合は、次の2行を.proファイルに追加するだけです。

 CONFIG += c++11 QMAKE_LFLAGS += -pthread
      
      







改善の可能性No. 1:実際のタスクでは、呼び出し間隔の計算を改善することをお勧めします。 そのためには、アクター関数が機能するまでの時間を考慮する必要があります。 そして今、間隔が少し長くなっていることがわかります。 しかし、私はこれで気にしませんでした:それについてのメモではありません。



可能な改善No. 2:アニメーションを中断できる追加機能を導入できます。 これを行うことは難しくありません(少なくとも、アニメーションを含むすべてのストリームが操作中にチェックするフラグを導入することによって)が、この場合もサンプルコードは大きくなります。



この問題を解決するためのより簡潔な方法を知っている可能性があります-コメントでそれを述べればクールです。 または、ラムダが人生を簡素化するというより興味深いケースを知っていますか?一般的に、あなたは何をすべきかを知っています。



ご清聴ありがとうございました!



All Articles