線をアニメーションするやつを作ってみたけど色々と課題が…

2008/09/21

こんばんは。台風も去って、いよいよ秋到来という感じですね。

今回、こんなサイトを見てこれをやってみたい!と思いました。ピクルスさん作成です。線の動きが面白いです。なめらか。
Hello! Panasonic
それで、この線の動きを作ってみたかったんです。線をどうやってるのか観察したところ、太さがスムーズにかわっていないところをみるとどうやらlineToで線をひっぱっていってるみたいです。塗りじゃないと思います。形になってからほどける部分はどうやってやるのかさっぱりわかりません。とりあえず、今回は線じゃなくて、塗りで線のアニメーションのみ挑戦してみようと思いました。
なんで、塗りなのかというと線の太さをスムーズに変えて漢字の「はらい」を表現できたらいいなと思ったからです。

とりあえずできたものはこれです。

黒地にフィルターかけてるのはいろいろとごまかすためだったりします、、。
あと動きがぎこちないのは、いろいろと理由があります。

まず、もとの図形データなんですが、これはfla上で書いたものをnutsuさんの作ったjsflで書きだして使用しています。ちなみに、今回のスクリプトはほとんどnutsuさんのパクリです。nutsuさんありがとうございます。ていうかすみません。
jsflのコードはこちらです。

//****************************************************************************
// author nutsu
// きんくま勝手に組み合わせ
//
//****************************************************************************

var edgeArray = fl.getDocumentDOM().selection[0].edges;

var tmp  = [];
var tmp2 = [];
var turn = [];
for ( i=0; i<edgeArray.length; i++ )
  tmp.push( edgeArray[i] );

var e0 = tmp.shift();
tmp2.push( e0 );
turn.push( false );
joinX0 = e0.getControl(0).x;
joinY0 = e0.getControl(0).y;
joinX2 = e0.getControl(2).x;
joinY2 = e0.getControl(2).y;

while( tmp2.length<edgeArray.length )
{
  flg_join = false;
  var min_value = -1;
  var min_pos   = -1;
  var min_index = -1;
  for( i=0; i<tmp.length; i++ )
  {
    var ed = tmp[i];
    var p0 = ed.getControl(0);
    var p2 = ed.getControl(2);
    if( p0.x==joinX2 && p0.y==joinY2 )
    {
      flg_join = true;
      tmp2.push( ed );
      turn.push( false );
      joinX2 = p2.x;
      joinY2 = p2.y;
      tmp.splice( i, 1 );
      i = 0;
    }
    else if( p2.x==joinX0 && p2.y==joinY0 )
    {
      flg_join = true;
      tmp2.unshift( ed );
      turn.push( false );
      joinX0 = p0.x;
      joinY0 = p0.y;
      tmp.splice( i, 1 );
      i = 0;
    }
    else if( p2.x==joinX2 && p2.y==joinY2 )
    {
      flg_join = true;
      tmp2.push( ed );
      turn.push( true );
      joinX2 = p0.x;
      joinY2 = p0.y;
      tmp.splice( i, 1 );
      i = 0;
    }
    else if( p0.x==joinX0 && p0.y==joinY0 )
    {
      flg_join = true;
      tmp2.unshift( ed );
      turn.push( true );
      joinX0 = p2.x;
      joinY0 = p2.y;
      tmp.splice( i, 1 );
      i = 0;
    }
    else
    {
      var min1 = (p0.x-joinX2)*(p0.x-joinX2) + (p0.y-joinY2)*(p0.y-joinY2);
      var min2 = (p2.x-joinX0)*(p2.x-joinX0) + (p2.y-joinY0)*(p2.y-joinY0);
      var min3 = (p2.x-joinX2)*(p2.x-joinX2) + (p2.y-joinY2)*(p2.y-joinY2);
      var min4 = (p0.x-joinX0)*(p0.x-joinX0) + (p0.y-joinY0)*(p0.y-joinY0);
      if( min1<min_value || min_value<0 )
      {
        min_value = min1;
        min_pos   = 1;
        min_index = i;
      }
      if( min2<min_value )
      {
        min_value = min2;
        min_pos   = 2;
        min_index = i;
      }
      if( min3<min_value )
      {
        min_value = min3;
        min_pos   = 3;
        min_index = i;
      }
      if( min4<min_value )
      {
        min_value = min4;
        min_pos   = 4;
        min_index = i;
      }
    }
  }
  //最近傍に連結
  if( flg_join==false )
  {
    fl.trace("debug>>" + "join nearest point." );
    var ed = tmp[min_index];
    var p0 = ed.getControl(0);
    var p2 = ed.getControl(2);
    if( min_pos==1 )
    {
      tmp2.push( ed );
      turn.push( false );
      joinX2 = p2.x;
      joinY2 = p2.y;
    }
    else if( min_pos==2 )
    {
      tmp2.unshift( ed );
      turn.push( false );
      joinX0 = p0.x;
      joinY0 = p0.y;
    }
    else if( min_pos==3 )
    {
      tmp2.push( ed );
      turn.push( true );
      joinX2 = p0.x;
      joinY2 = p0.y;
    }
    else
    {
      tmp2.unshift( ed );
      turn.push( true );
      joinX0 = p2.x;
      joinY0 = p2.y;
    }
    tmp.splice( min_index, 1 );
  }
}

var xmlstr = "<shape>n";
for( i=0; i<tmp2.length; i++ )
{
    var ed = tmp2[i];
    var p0 = ed.getControl(0);
    var p1 = ed.getControl(1);
    var p2 = ed.getControl(2);
  xmlstr += "<edge id="" + i + """ +
      " x0="" + p0.x + "" y0="" +  p0.y +  """ +
      " x1="" + p1.x + "" y1="" +  p1.y +  """ +
      " x2="" + p2.x + "" y2="" +  p2.y + """   +
      " line="" +  ed.isLine + "" />n";

}
xmlstr += "</shape>";
fl.trace( xmlstr );

これの使用方法は、こちらを参考にしてください。
[jsfl]Tweenerの_bezier用パラメータ書き出し(改め)
2次ベジェ曲線 その2

これを使えば、ステージ上に書いた線を今回のスクリプトに反映することができます。ただし、注意点があって、アニメーションさせる線は交差しないように描かないと、アニメーションの順番がおかしくなります。アニメーションの順番を無視してよければ、こんな感じのものができます。

今回の手順
1.flaのステージ上に書いたパス(線)をjsflで変換
2.変換したデータをとりこみ
3.アニメーション

パスをデータに変換するときに2次ベジェに変換されます。これはflaの内部ではパスは2次ベジェで扱われているものだと思われます。CS3から一見3次ベジェを扱っているかのようですが、スクリプトでshapeのedgeをとりだすと2次ベジェに置き換わっています。それでたぶんこの3次→2次への変換の過程で精度を保つためだと思うのですが、例えばfla上のコントロールポイントが2つだったとしても、2次に分割すると節が3つとか4つとかに増えてしまうんです。この辺で少しデータが重くなると思います。

あと、各節を係数tを使って表します。この辺はnutsuさん参照してください。
改めて、2次ベジェ曲線
[as]ベジェ曲線の分割
tを等分しても一本の線を等分割しないってあたりがまたやっかいです。
今回は、ある節をアニメーションさせたらその次の節をアニメーションさせて、、、というのを続けているだけなので、一本の線として統一したアニメーションができていません。
これを実現するためには、以下のことができればよさそうです。
各節の長さの合計から一本の線の長さをもとめる→
一本の線の長さを等分割する→
そのときの点が、どの節のどのtかというのをもとめる→
あとは分割点をプロパティかなんかにしてTweenerで回せばイージングとかかけまくりのアニメーションができる、、ハズ。
でも、自分にできるのか、、、。?

あと、節の間に隙間ができるのも、どうにかしたいですね。この辺の角処理のアルゴリズムとかってどこかに書いてあるんだろうか?

いろいろとやれば、日本語タイポグラフィの基本?「永」のアニメーションができると思うんだけどなあ。

今回のソース一式です。


自作iPhoneアプリ 好評発売中!
フォルメモ - シンプルなフォルダつきメモ帳
ジッピー電卓 - 消費税や割引もサクサク計算!

ページトップへ戻る