◆PROCESSING 逆引きリファレンス
カテゴリー:スマホ(AndroidMode)
アニメーションを行うには(AndroidMode:SDK編)
【概要】
PROCESSINGにAndroidMode を導入する事で、PROCESSINGで開発したプログラムをAndroid端末上で動かす事ができるようになります。
AndroidModeの導入については「PROCESSINGをAndroid端末で動かすには(4.0版)」記事を参照してください。
アニメーションには、大きく2種類のものがあります。
1つは、画像そのものに対して行うアニメーション(画像を移動する、回転する、透明にするなど)で、Tweenアニメーションと呼ばれています。
もう1つは、異なる画像を高速に切り替えながら表示するアニメーション(いわゆるパラパラ漫画風アニメ)で、Frameアニメーションと呼ばれています。
(画像URL:illust-AC 様:nomoさん、愛楽ゆに の 創作研究所 様)
Android にはアニメーションを行う命令が沢山あります。
しかしその多くは、アニメーションする対象に View を想定しているため、PROCESSINGでは利用することができません(正確に言うと利用はできるのですが、いろいろと困難を伴います)。
ですが、あきらめるのは早いです。
数ある命令の中でProperty Animation は、View以外のオブジェクトに対してパラメータを線形変更できるため、PROCESSINGでも利用する事ができるのです。
Property Animationを使うと、PImageに対してTweenアニメーションを行わせることが可能となります。また、がんばれば Frameアニメーションも実現できます。
Property Animationには、Animatorクラスをベースとしたサブクラスが沢山ありますが、本記事ではAnimatorSetクラスとObjectAnimatorクラスを取り上げます。
これらのクラスをざっくりと説明すると
Animatorクラス
Property Animationの基本的なメソッドが定義されているスーパークラスです。実際には、このクラスを元に派生した下位のクラスを使います。
ValueAnimatorクラス
ある数値からある数値まで、指定した時間で変化する値を計算するクラスです。
ObjectAnimatorクラス
オブジェクト(Viewなど)がもつプロパティを、指定した時間で変化させるクラスです。
TimeAnimatorクラス
アニメーションフレームの更新通知を受け取って処理をすることができるクラスです。最小16ms単位でアニメーションフレームの更新通知を受け取ります。
AnimatorSetクラス
複数のアニメーションをまとめるクラスです。ValueAnimatorやObjectAnimatorクラスで定義した値の変化を、1つのアニメーションとしてまとめて再生する事が可能です。
詳しくは下記公式リファレンスを参照して下さい。
また、以下のページが大変参考となりました。ありがとうございます。
なおProperty AnimationはAndroidの命令ですので、JavaModeのPROCESSINGやJavaからは利用できません。
JavaModeのPROCESSINGやJavaでアニメーションを行いたい場合には、「java-universal-tween-engine 」や「Sprites for Processing」を利用すると良いでしょう。
そして嬉しいことに、java-universal-tween-engine と Sprites for ProcessingはPROCESSINGのAndroidModeでも動作します。
それぞれについては後日説明記事を起こす予定ですので、そちらを参照して下さい。
【詳細】
ObjectAnimatorの仕組み
ObjectAnimatorは対象となるオブジェクトのプロパティを、指定した時間内かつ指定した範囲内で線形変更する命令です。
通常はViewなどが持つプロパティを、指定した時間内で順次変更する事で、Viewがアニメーションする手助けをします。
例えばImageViewがもつAlphaプロパティを、3秒かけて1(不透明:100%)から0(透明:0%)に変化させると、ImageViewにセットされた画像が徐々に透明になるわけです。
またImageViewがもつtranslationXとtranslationYプロパティを変化させれば、ImegeViewの表示位置が変化するので、画像の移動が実現します。
ObjectAnimatorはView以外にも様々なオブジェクトのプロパティを変化させる事が可能ですが、対象となるオブジェクトには、操作したいプロパティを変更するためのセッターメソッドがある事が条件となります。
セッターメソッドとは、プロパティに値をセットするための専用関数の事です。例えばtranslationXというX座標を管理するプロパティがあったとして、これに値をセットするメソッド(setTranslationX())をセッターメソッドと呼びます。
ObjectAnimatorが扱うセッターメソッドの名前は、何でも良いというわけではなく、Javaの命名規則に従ってsetXxxxx(Xxxxxはプロパティ名)という名前である必要があります。
(画像URL:illust-AC 様:nomoさん、R-DESIGNさん)
ImageViewには、Alphaプロパティをセットする setAlpha() や、translationXプロパティをセットする setTranslationX() メソッドが備わっているため、ObjectAnimatorから直接 ImageViewオブジェクトを操作する事が可能となっているのです。
同じように、ObjectAnimatorでPROCESSINGのPImageを操作するなら、PImageに座標や透明度をセットするためのセッターメソッドが必要となります。しかし残念な事に、PImageにはそのようなプロパティやメソッドはありません。
ObjectAnimatorをPROCESSINGのオブジェクト(PImageなど)に適用したいなら、PImageを制御するための座標や透明度プロパティを持つクラス(プロパティ制御クラス)を用意して、そこに必要なプロパティとセッターメソッドを実装する工夫が必要となります。
(画像URL:illust-AC 様:nomoさん、K-factoryさん)
ObjectAnimatorで、プロパティ制御クラスにあるプロパティを変化させ、それをDraw関数などで読み取ってPImageに反映する事で、アニメーションを実現します。
プロパティ制御クラスの準備
まずは操作対象となるプロパティとセッターメソッドを持ったプロパティ制御クラスを用意します。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 |
/** * Property Animation プロパティ制御クラス * @author MSLABO * @version 1.0 2018/03 */ public class PropertyControl { private float translationX; //縦座標 private float translationY; //横座標 private float rotation; //回転角度 private float transparency; //透明度 private float scaling; //拡大縮小率 private float framer; //フレーム番号 /** * コンストラクタ * @param _x translationX 初期値 * @param _y translationY 初期値 */ public PropertyControl(float _x, float _y ){ this(_x, _y, 255.0f, 1.0f); } public PropertyControl(float _x, float _y , float _tran, float _scale){ translationX = _x; translationY = _y; transparency = _tran; scaling = _scale; rotation = 0; framer = 0; } //----------------------------- //セッターメソッド群 //----------------------------- public void setTranslationX(float arg){ translationX = arg; } public void setTranslationY(float arg){ translationY = arg; } public void setRotation(float arg){ rotation = arg; } public void setTransparency(float arg){ transparency = arg; } public void setScaling(float arg){ scaling = arg; } public void setFramer(float arg){ framer = arg; } //----------------------------- //ゲッターメソッド群 //----------------------------- public float getTranslationX(){ return translationX; } public float getTranslationY(){ return translationY; } public float getRotation(){ return rotation; } public float getTransparency(){ return transparency; } public float getScaling(){ return scaling; } public float getFramer(){ return framer; } } |
例えばこんな感じです。
ゲッターメソッドはSketchの中からプロパティ制御クラス内の各プロパティを読み取るのに利用します。
今回は縦横座標、透明度、拡大縮小率、回転角度、フレーム数といったプロパティを持つクラスを用意しましたが、どのようなプロパティを持つかは、どのようなアニメーションを行いたいかに応じてみなさんで工夫してください。
プロパティ変更:移動の例
float値を変化させるObjectAnimator oba = ObjectAnimator . ofFloat (Object target, String propertyName, float… values);
target : 対象となるオブジェクト
propertyName : プロパティ名
values : 変化させる範囲
oba : ObjectAnimator
ObjectAnimator.ofFloat() で、値の変化が設定された ObjectAnimator を生成します。例えば上下移動するなら
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
@Override public void setup() { //…いろいろな処理 //画面中央に表示する int sx = (width - girlWidth)/2; int sy = (height - girlHeight)/2; //プロパティ制御OBJを生成する PropertyControl target = new PropertyControl(sx, sy); //sy からsy+100 までtransparencyを変化させる ObjectAnimator move = ObjectAnimator.ofFloat( target, "translationY", sy, sy + 100); //…いろいろな処理 } |
といった感じになります。target には先程用意した PropertyControl クラスのインスタンスを与えます。
ポイントは ObjectAnimator . ofFloat() で、プロパティ名(この場合は translationY )と変化量( sy から sy + 100 まで )を指定している箇所です。
時間を指定するObjectAnimator oba = ObjectAnimator . setDuration (long duration);
duration: アニメーション時間(ms)
oba : ObjectAnimator
ObjectAnimator . setDurationでプロパティが変化する時間をミリセカンド単位で指定します。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
@Override public void setup() { //…いろいろな処理 //画面中央に表示する int sx = (width - girlWidth)/2; int sy = (height - girlHeight)/2; //プロパティ制御OBJを生成する PropertyControl target = new PropertyControl(sx, sy); //sy からsy+100 までtransparencyを変化させる ObjectAnimator move = ObjectAnimator.ofFloat( target, "translationY", sy, sy + 100); //動作時間セット(100ms) objectAnimator.setDuration(100); //…いろいろな処理 } |
こんな感じですね。
これで ObjectAnimator.ofFloat()で指定した動作が、100msかけて実行する準備が整いました。
プロパティの変更を開始するvoid ObjectAnimator .start ();
実際のプロパティの変更は、start() メソッドで開始します。
下記例では、画面にタッチされた時にプロパティの変更処理を開始しています。
1 2 3 4 5 6 7 8 9 10 11 |
public void touchStarted(TouchEvent touchEvent) { super.touchStarted(touchEvent); //プロパティの変更をUIスレッドで開始する getActivity().runOnUiThread(new Runnable() { @Override public void run() { objectAnimator.start(); } }); } |
ここでのポイントは、Property Animationによるプロパティの変更は必ず「UIスレッドで動作させる」という事です。
PROCESSINGは、(一部の特殊なメソッドを除き)UIスレッドではなく別スレッドで動作しています。プロパティの変更は必ずUIスレッドで動作させる必要があるため、このような記述を行っています。
UIスレッド以外でstart() メソッドを発行すると、例外エラーとなるので注意してください。
これで PropertyControl クラスのY方向のプロパティ(translationY)が、sy からsy + 100 まで100msで変化します。
実際にアニメーションを行う(イメージを動かす)ためには、draw() 関数の中から translationY プロパティを読み取って、指定された位置に画像を表示する必要があります。
全体のコーディングは下記のようになります。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 |
import android.animation.ObjectAnimator; import processing.core.PApplet; import processing.core.PImage; import processing.event.TouchEvent; /** * PROCESSING AndroidMode Animation Sample * @author MSLABO * @version 1.0 2018/03 */ public class Sketch extends PApplet { PImage dragon; PropertyControl target; ObjectAnimator objectAnimator; @Override public void settings() { fullScreen(); } @Override public void setup() { //画像を読み込む dragon = loadImage("dragon.png"); //画面中央に表示する int sx = (width - dragon.width)/2; int sy = (height - dragon.height)/2; //プロパティ制御OBJを生成する target = new PropertyControl(sx, sy); //動作指定OBJ作成 //sy から 下方向に100 pixl 移動する objectAnimator = ObjectAnimator.ofFloat( target, "translationY", sy, sy + 100); //動作時間セット(100ms) objectAnimator.setDuration(100); } @Override public void draw() { background(255); //座標取得 float x = target.getTranslationX(); float y = target.getTranslationY(); image( dragon, x, y); } @Override public void touchStarted(TouchEvent touchEvent) { super.touchStarted(touchEvent); //プロパティの変更をUIスレッドで開始する getActivity().runOnUiThread(new Runnable() { @Override public void run() { objectAnimator.start(); } }); } } |
プロパティ変更:透明度の例
透明度は transparency を変化させる処理を記述します。
1 2 3 4 |
// 透明度を変化させる // transparency を start から value まで変化させる ObjectAnimator tran = ObjectAnimator.ofFloat( target, "transparency", 0.0f, 255.0f); |
こんな感じですね。
これでtarget に指定した PropertyControl クラスの transparency プロパティが 0 から 255 まで変化します。
あとは transparencyプロパティを元に画像の透明度を変化させる処理を draw() 関数の中に記述し、objectAnimator.start()でプロパティの変更を開始すればOKです。
たとえば、画像の透明度を変化させる draw()関数は下記のようになります。
1 2 3 4 5 6 7 8 9 10 11 12 |
@Override public void draw() { background(255); //透明度を変化させる tint(255, target.getTransparency()); //画像を描画する float x = target.getTranslationX(); float y = target.getTranslationY(); image( dragon, x, y); } |
プロパティ変更:並列に組み合わせる例
ここまでは単発のアニメーション例でしたが、これらを組み合わせるにはどうしたら良いでしょうか?。
例えば「横に移動しながら、徐々に大きくなる」などです。
これにはAnimatorSetクラスを利用する方法と、PropertyValuesHolderクラスを利用する方法があります。
AnimatorSetクラスについては後ほど紹介しますので、ここではPropertyValuesHolderクラスを利用する方法について記述します。
float… values)
propertyName : プロパティ名
values : 変化させる範囲
pvf : PropertyValuesHolder
使い方は ObjectAnimator.ofFloat() 命令とほとんど一緒ですね(笑)。第一引数にターゲットを指定していないだけです。
例えば拡大縮小と横移動を行う操作は、以下のように記述できます。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
@Override public void setup() { //…いろいろな処理 //画面中央に表示する int sx = (width - girlWidth)/2; int sy = (height - girlHeight)/2; //プロパティ制御OBJを生成する target = new PropertyControl(sx, sy); //動作指定 //1.0倍から1.5倍に拡大する PropertyValuesHolder scale = PropertyValuesHolder.ofFloat( "scaling", 1.0f, 1.5f); //sx から sx - 100 まで移動する PropertyValuesHolder move = PropertyValuesHolder.ofFloat( "translationX", sx, sx - 100 ); //…いろいろな処理 } |
拡大縮小率プロパティ(scaling)と、横座標プロパティ(translationX)を変化させています。
作成したPropertyValuesHolderは、ObjectAnimatorを使って並列化できます。
並列化するObjectAnimator oba = ObjectAnimator . ofPropertyValuesHolder (Object target,PropertyValuesHolder… values);
target : 対象となるオブジェクト
values : PropertyValuesHolder
oba : ObjectAnimator
ObjectAnimator.ofFloat() 命令と同じ要領で、作成したPropertyValuesHolderオブジェクトを並べて記述します。
ここで記述したPropertyValuesHolderオブジェクトは、アニメーションする際に並列実行(同時にアニメーション)されます。
左に100ピクセル移動しながら1.25倍に拡大する動作は
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 |
@Override public void setup() { //…いろいろな処理 //画面中央に表示する int sx = (width - girlWidth)/2; int sy = (height - girlHeight)/2; //プロパティ制御OBJを生成する target = new PropertyControl(sx, sy); //動作指定 //1.0倍から1.5倍に拡大する PropertyValuesHolder scale = PropertyValuesHolder.ofFloat( "scaling", 1.0f, 1.5f); //sx から sx - 100 まで移動する PropertyValuesHolder move = PropertyValuesHolder.ofFloat( "translationX", sx, sx - 100 ); //拡大縮小とX座標の変化は同時に行わせる ObjectAnimator objectAnimator = ObjectAnimator.ofPropertyValuesHolder( target, scale, move); //…いろいろな処理 } |
のようになります。
アニメーション:直列に組み合わせる例
それでは直列に組み合わせるには、どうしたら良いでしょうか?。
例えば「左に移動した後で、拡大する」などです。
これを実現するには、AnimatorSetクラスを利用します。
コンストラクタAnimatorSet animatorSet = new AnimatorSet();
直列化するvoid animatorSet.playSequentially ( Animator… items);
items : Animatorクラスを継承したオブジェクト
AnimatorSetは複数のアニメーションをまとめて、再生順番を指定するクラスです。
playSequentially命令は、引数で指定したアニメーションをシーケンシャル(記述した順番)で再生するように準備します。
この他にも、引数で指定したアニメーションを単発で再生するための play 命令、引数で指定したアニメーションを並列で再生するためのplayTogether命令などがあります。
再生時間を指定するAnimatorSet animatorSet = animatorSet.setDuration (long duration);
duration : アニメーション時間(ms)
animatorSet : AnimatorSet
AnimatorSetにも再生時間を指定する命令があります。使い方はObjectAnimator.setDuration() と一緒ですね。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 |
public void setup() { //画像を読み込む dragon = loadImage("dragon.png"); //画面中央に表示する int sx = (width - dragon.width)/2; int sy = (height - dragon.height)/2; //プロパティOBJに初期値をセットする target = new PropertyControl(sx, sy); //sx から sx - 100 まで移動する ObjectAnimator move = ObjectAnimator.ofFloat(target, "translationX", sx, sx-100); //1.0倍から1.5倍に拡大する ObjectAnimator scale = ObjectAnimator.ofFloat(target, "scaling", 1.0f, 1.5f); //再生順番を指定する animatorSet = new AnimatorSet(); //左に移動してから拡大する animatorSet.playSequentially(move, scale); //アニメーション時間を指定する(100ms) animatorSet.setDuration(100); } |
再生するvoid animatorSet.start ();
start() 命令で再生を開始します。
以下の例では、画面にタッチした時に再生を開始しています。
1 2 3 4 5 6 7 8 9 10 11 12 |
@Override public void touchStarted(TouchEvent touchEvent) { super.touchStarted(touchEvent); //アニメーションをUIスレッドで開始する getActivity().runOnUiThread(new Runnable() { @Override public void run() { animatorSet.start(); } }); } |
アニメーションは必ず「UIスレッドで動作させる」という注意点も、ObjectAnimatorの場合と一緒です。
アニメーション:繰り返す例
アニメーションを繰り返すには注意が必要です。というのもAnimatorSetクラスには、繰り返しを指定する命令がないからです。
いろいろなサイト様を検索すると、クラスにAnimatorListenerやAnimatorListenerAdapterを実装し、onAnimationEndイベントで再度アニメーションを開始するように書かれています。
参考になるサイト様:
- Androidプログラマへの道 ~ Moonlight 明日香 ~ 様
- Stackoverflow 様:Repeat AnimatorSet
- Qiita 様 :@mattak さん:AndroidでAnimatorSetをRepeatするときの注意点
が・・・どうしたわけか、この方法ではPROCESSINGでアニメーションを繰り返す事ができませんでした。
結論から言うと、PROCESSINGでアニメーションを繰り返したい場合は、ObjectAnimatorに繰り返し回数と繰り返し動作を指定します。
繰り返し動作指定void oba . setRepeatMode (int repeatMode)
repeatMode : 繰り返し動作。ObjectAnimator.RESTART/REVERSE
oba : ObjectAnimator
RESTARTを指定すると最初から繰り返し、REVERSEを指定すると反転繰り返し(逆再生)になります。
繰り返し回数指定void oba . setRepeatCount (int repeatCount)
repeatCount : 繰り返し回数。0なら繰り返しなし。ObjectAnimator.INFINITEなら無限繰り返し
oba : ObjectAnimator
例えば下記のようになります。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
//アニメーションOBJ作成 //1.5倍に拡大する PropertyValuesHolder valueScale = PropertyValuesHolder.ofFloat( "scaling", 1.0f, 1.5f); //フレーム番号を 0 から MAX まで変化させる PropertyValuesHolder valueFrame = PropertyValuesHolder.ofFloat( "framer", 0, imageList.size()-1); //拡大とフレーム番号の変化は同時に行わせる ObjectAnimator objectAnimator = ObjectAnimator.ofPropertyValuesHolder(target, valueFrame,valueScale); //繰り返しと時間指定(最初から無限に繰り返す) objectAnimator.setRepeatMode(ObjectAnimator.RESTART); objectAnimator.setRepeatCount(ObjectAnimator.INFINITE); //時間指定 objectAnimator.setDuration(1000); |
この例では1.5倍に拡大する処理と、フレーム数(framerプロパティ)を0からMAXフレーム数まで変化させる処理を繰り返し行わせています。
【関連記事】
- PROCESSINGをAndroid端末で動かすには(4.0版)
- アニメーションを行うには(tween-engine編)
- アニメーションを行うには(Sprite編)
サンプルプログラム
繰り返しアニメーションする例:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 |
import android.animation.ObjectAnimator; import android.animation.PropertyValuesHolder; import java.util.ArrayList; import processing.core.PApplet; import processing.core.PImage; import processing.event.TouchEvent; /** * PROCESSING AndroidMode Animation Sample * @author MSLABO * @version 1.0 2018/03 */ public class Sketch extends PApplet { PropertyControl target; ArrayList<PImage> imageList; ObjectAnimator objectAnimator; int girlWidth, girlHeight; @Override public void settings() { fullScreen(); } @Override public void setup() { //画像を読み込む //Assetsに 000.png から 009.png がある想定です imageList = new ArrayList<PImage>(); for(int i = 0; i < 10; i++){ PImage img = loadImage(nf(i,3) + ".png"); girlWidth = img.width; girlHeight = img.height; imageList.add(img); } //画面中央に表示する int sx = (width - girlWidth)/2; int sy = (height - girlHeight)/2; //プロパティ制御OBJを生成する target = new PropertyControl(sx, sy); //アニメーション指定 //1.0倍から1.5倍に拡大する PropertyValuesHolder valueScale = PropertyValuesHolder.ofFloat( "scaling", 1.0f, 1.5f); //フレーム番号を 0 から MAX まで変化させる PropertyValuesHolder valueFrame = PropertyValuesHolder.ofFloat( "framer", 0, imageList.size()-1); //拡大とフレーム番号の変化は同時に行わせる objectAnimator = ObjectAnimator.ofPropertyValuesHolder( target, valueFrame,valueScale); //繰り返し指定(再スタート・無限)と時間指定(2000ms) objectAnimator.setRepeatMode(ObjectAnimator.RESTART); objectAnimator.setRepeatCount(ObjectAnimator.INFINITE); objectAnimator.setDuration(2000); } @Override public void draw() { background(255); //アニメーション画像の座標取得 float x = target.getTranslationX(); float y = target.getTranslationY(); //原点保存 pushMatrix(); //原点移動:原点を画像中央にする translate(x + girlWidth/2, y + girlHeight/2); //サイズを変化させる scale(target.getScaling()); //描画する imageMode(CENTER); image( imageList.get((int)target.getFramer()), 0,0); imageMode(CORNER); //原点を元に戻す popMatrix(); } @Override public void touchStarted(TouchEvent touchEvent) { super.touchStarted(touchEvent); if( objectAnimator.isRunning() == false){ //アニメーション非再生なら、アニメーションをUIスレッドで開始する getActivity().runOnUiThread(new Runnable() { @Override public void run() { objectAnimator.start(); } }); } else { if( objectAnimator.isPaused()) { //一時停止中なら再開する objectAnimator.resume(); } else { //再生中なら一時停止する objectAnimator.pause(); } } } } |
詳細で説明したPropertyControlクラスがある前提です。
Assetsフォルダに、000.pngから009.png までの連番になった10枚の画像を用意しておきます。
画面にタッチすると拡大とフレームアニメーションを繰り返します。再度タッチすると一時停止します。
<出力サンプル>
(画像URL:らくがき。 様)※2018/06 Link先が見つかりません
下記はサンプルプログラムと同じ動きになるように、 P5.js で書き直したものです。動作イメージを確認できます。
P5.jsではマウスクリックでアニメーションを開始し、再クリックで一時停止するように変更しています。
なお一部のスマホ搭載ブラウザからは正しく表示されない場合があります。その場合はPCから閲覧してください。
(画像URL:らくがき。 様)※2018/06 Link先が見つかりません
本ページで利用している「初音ミク」は、クリプトン・フューチャー・メディア株式会社 様に版権があります。「初音ミク」は、ピアプロ・キャラクター・ライセンスに基づいて掲載されています。
本ページで利用しているアイコン画像は、下記サイト様より拝借しております。各画像の著作権は、それぞれのサイト様および作者にあります。