チュートリアルジオメトリのアニメーション
JUCE アプリケーションで簡単なアニメーションを作成できます。静的なジオメトリ形状に生命を吹き込むにはAnimatedAppComponentクラスである。
レベル初心者
プラットフォーム:Windows, macOS, Linux, iOS, Android
クラス: AnimatedAppComponent,Path,Point
スタート
このチュートリアルのデモ・プロジェクトのダウンロードはこちらから:PIP|ZIP.プロジェクトを解凍し、最初のヘッダーファイルをProjucerで開く。
このステップでヘルプが必要な場合は、以下を参照してください。Tutorial: Projucer Part 1: Getting started with the Projucer.
デモ・プロジェクト
このデモ・プロジェクトが完成すると、画面上に複数の魚の連続的で滑らかなアニメーションが表示される。PathそしてPointオブジェクトがある。
ここで紹介するコードは、大まかに以下のものと似ている。アニメーションの例JUCE Examplesより。
AnimatedAppComponentクラス
単純なアニメーションJUCEアプリケーションを作成する場合、継承すると便利なクラスがあります。AnimatedAppComponentクラスである。ちょうどAudioAppComponentまたはOpenGLAppComponentクラスは、それぞれオーディオ・アプリケーションとOpenGLアプリケーションに役立ちます。AnimatedAppComponentとい うアニメーション制作に有益な機能を提供している:
- setFramesPerSecond():この関数を使うと、アニメーションをできるだけスムーズに実行するために、アプリケーションの開始時にFPSを設定することができます。また、この関数が呼び出されると、指定された頻度で再描画処理が開始されます。
- update():この関数は、setFramesPerSecond() 関数で設定された割合で呼び出され、アニメーションのパラメータを段階的に進めていきます。
- getFrameCounter():定義された FPS レートでアニメーションを開始して以来、update() 関数が呼び出された回数の合計を返します。これは、アニメーションを計算するための周期的な数学関数で有用です。
- getMillisecondsSinceLastUpdate():フレームレートに関係なく正確なタイミングでアニメーションを作成するために、最後のupdate()関数呼び出しからの所要時間をミリ秒で返すもう1つの便利な関数です。
これらの関数と親のpaint()関数を併用することで、以下のようになる。Componentクラスを使えば、簡単なアニメーションを作ることができる。
円のアニメーション
を見ればわかるようにMainContentComponent
クラスを継承しています。AnimatedAppComponent.
アニメーションを作成する最初のステップは、アニメーションのフレームレートを設定することです。これをMainContentComponentコンストラクタで次のように行います。[1]setFramesPerSecond() 関数を呼び出す:
MainContentComponent()
{
setSize (800, 600);
setFramesPerSecond (60); // [1]
}
ここではFPSを60に設定し、アニメーションを1秒間に60回更新するために、内部的に60Hzの周波数でタイマーを呼び出します。これはほとんどのスクリーンのリフレッシュ・レートにほぼ等しく、スムーズなアニメーションになります。
まず、単純な円を円運動でアニメーションさせることから始めよう。paint()関数で、まず円を描く色を設定します。Graphicsクラス[2].次に、形状がたどる円形の経路の半径を定義します。[3]この通りである:
void paint (juce::Graphics& g) override
{
//...
g.setColour (getLookAndFeel().findColour (Slider::thumbColourId)); // [2]
int radius = 150; // [3]
juce::Point p (getWidth() / 2.0f + 1.0f * radius,
getHeight() / 2.0f + 1.0f * radius); // [4]
g.fillEllipse (p.x, p.y, 30.0f, 30.0f); // [5]
}
Slider::thumbColourId@ thumbColourIdThe colour to draw the thumb with.Definition juce_Slider.h:888
そして、次のようにする。Point与えられた時間枠における形状の中心の位置を表す[4].ここでは、円形の動きを作るために、まず画面の幅と高さを2で割って画面の中心を見つける。次に、半径の値を足して、図形のx座標とy座標をオフセットする。
最後に、fillEllipse() 関数を使って実際の円を描きます。Point座標と直径30を引数に取る。
今、アプリケーションを実行すると、円がどうなるかわかりますか?座標系が左上から始まっているため、円は半径の値だけ反対方向に押されるのだ:
の宣言を修正しよう。Point実際のモーションを作成する。
void paint (juce::Graphics& g) override
{
// (Our component is opaque, so we must completely fill the background with a solid colour)
g.fillAll (getLookAndFeel().findColour (juce::ResizableWindow::backgroundColourId));
g.setColour (getLookAndFeel().findColour (juce::Slider::thumbColourId));
int radius = 150;
juce::Point p ((float) getWidth() / 2.0f + 1.0f * (float) radius * std::sin ((float) getFrameCounter() * 0.04f),
(float) getHeight() / 2.0f + 1.0f * (float) radius * std::cos ((float) getFrameCounter() * 0.04f));
g.fillEllipse (p.x, p.y, 30.0f, 30.0f);
}
ここでは、getFrameCounter()関数を使用して、アニメーションの開始からのフレーム数のカウンターを取得し、その値を使用して、次の間の値を計算します。-1 ..1幅と高さにはそれぞれサイン関数とコサイン関数を使用する。フレームカウンターの0.04のスカラー倍は、周期関数が交互に円運動を作り出す速度を制御する。
アプリケーションを実行すると、円運動が現れるはずだ。
この修正版のソースコードはAnimationTutorial_02.h
ファイルにある。
パスのアニメーション
円の代わりに、次は円形のパスに沿って線をアニメートしてみよう。
前のセクションと同じコードベースを使って、複数のPointに沿ったオブジェクトである。Pathが作成されます。Point.paint()関数を以下のように修正する:
void paint (juce::Graphics& g) override
{
// (Our component is opaque, so we must completely fill the background with a solid colour)
g.fillAll (getLookAndFeel().findColour (juce::ResizableWindow::backgroundColourId));
g.setColour (getLookAndFeel().findColour (juce::Slider::thumbColourId));
auto numberOfDots = 15; // [1]
juce::Path spinePath; // [2]
for (auto i = 0; i < numberOfDots; ++i) // [3]
{
int radius = 150;
juce::Point p ((float) getWidth() / 2.0f + 1.0f * (float) radius * std::sin ((float) getFrameCounter() * 0.04f + (float) i * 0.12f),
(float) getHeight() / 2.0f + 1.0f * (float) radius * std::cos ((float) getFrameCounter() * 0.04f + (float) i * 0.12f));
if (i == 0)
spinePath.startNewSubPath (p); // if this is the first point, start a new path..
else
spinePath.lineTo (p); // ...otherwise add the next point
}
// draw an outline around the path that we have created
g.strokePath (spinePath, juce::PathStrokeType (4.0f)); // [4]
}
- [1]最初に、パスに沿って作成するドットの数を定義します。
- [2]次にPathオブジェクトを使って点を結ぶ線を引く。
- [3]今度は、すべてのドットに同じPointしかし今回は、ループの反復ごとにアニメーションをオフセットする。円形の動きの各ドットの間に0.12のオフセットが追加されていることに注目してください。反復が最初のものである場合、startNewSubPath()関数を呼び出して新しいサブパスを作成します。Pathそうでない場合は、現在のドットを以前に定義されたPath.
- [4]最後に、作成したPathに沿っている。Pointオブジェクトがある。
アプリケーションを実行すると、円形に引かれた線を見ることができる。
アプリケーションのFPSを変えてみて、アニメーションの滑らかさがどのように変化するかに注目してください。映画アニメーションの標準的な24FPSではどうなるでしょうか?
この修正版のソースコードはAnimationTutorial_03.h
ファイルにある。
魚のアニメーション
の魚をアニメーション化して、もう少し面白いことをやってみよう。PathそしてPointオブジェクトを作成した。
円形パスに沿って描かれた実際の点を表示し、魚の胴体を作成するために、fillEllipse()関数を使用して円を描き、線に沿って各点の幅と高さを増加させるように指定する行をforループに追加してみましょう。[1]このように:
void paint (juce::Graphics& g) override
{
//...
g.setColour (getLookAndFeel().findColour (juce::Slider::thumbColourId));
auto fishLength = 15;
juce::Path spinePath;
for (auto i = 0; i < fishLength; ++i)
{
int radius = 150;
juce::Point p (getWidth() / 2.0f + 1.0f * radius * std::sin (getFrameCounter() * 0.04f + i * 0.12f),
getHeight() / 2.0f + 1.0f * radius * std::cos (getFrameCounter() * 0.04f + i * 0.12f));
// draw the circles along the fish
g.fillEllipse (p.x - i, p.y - i, 2.0f + 2.0f * i, 2.0f + 2.0f * i); // [1]
if (i == 0)
spinePath.startNewSubPath (p); // if this is the first point, start a new path..
else
spinePath.lineTo (p); // ...otherwise add the next point
}
// draw an outline around the path that we have created
g.strokePath (spinePath, juce::PathStrokeType (4.0f));
}
さて、アプリケーションを実行すると、魚のように見え始めるが、まだ魚のようには動かないものが見えるはずだ。
そこで、魚の動きを模倣するためにアニメーションを少し変えてみよう。
void paint (juce::Graphics& g) override
{
//...
for (auto i = 0; i < fishLength; ++i)
{
auto radius = 100 + 10 * std::sin (getFrameCounter() * 0.1f + i * 0.5f); // [2]
juce::Point p (getWidth() / 2.0f + 1.0f * radius * std::sin (getFrameCounter() * 0.04f + i * 0.12f),
getHeight() / 2.0f + 1.0f * radius * std::cos (getFrameCounter() * 0.04f + i * 0.12f));
//...
}
//...
}
ここでは、正弦関数を使用して円の半径に変調を加え、同じgetFrameCounter()関数とスカラーを使用してフレーム・カウンターに変調を加えている。[2].これでアプリケーションを実行すると、蛇のような動きが得られるはずだ。
その動きは説得力があるように見えるが、驚きがなく、最初の円軌道のまま、かなり速く繰り返されるた め、少し単調な印象を受ける。
void paint (juce::Graphics& g) override
{
//...
for (auto i = 0; i < fishLength; ++i)
{
auto radius = 100 + 10 * std::sin (getFrameCounter() * 0.1f + i * 0.5f);
juce::Point p (getWidth() / 2.0f + 1.5f * radius * std::sin (getFrameCounter() * 0.02f + i * 0.12f),
getHeight() / 2.0f + 1.0f * radius * std::cos (getFrameCounter() * 0.04f + i * 0.12f)); // [3]
//...
}
//...
}
の正弦関数と余弦関数のレートをオフセットすると、次のようになる。Pointを作成し、半径の幅と高さに異なる比率を与える。[3]より説得力のある結果を得ることができる。
最後にもう一度アプリケーションを実行し、動きのランダム性が改善されていることに気づく。
同様の方法で、魚の長さを変更したり、独自のアニメーション形状を作成することができます。
この修正版のソースコードはAnimationTutorial_04.h
ファイルにある。
概要
このチュートリアルでは、JUCE アプリケーションでジオメトリ形状をアニメートする方法を学びました。特に
- のメカニズムを探った。AnimatedAppComponentクラスである。
- を使用して描かれた図形。Graphicsクラスである。
- フレームごとに図形をアニメーションさせる。