scratch_flash.jpg

スクラッチのテスト

flaファイル側で、親のMovieClipとマスク対象のMovieClipを指定してScratchクラスのクラスインスタンスを作成、createメソッドでattachするブラシのシンボルリンケージとブラシの最小サイズを指定してマスクを開始します。

scratch.fla

var scratch = new Scratch( _root, target_mc );
scratch.create("BRUSH",30);
scratch_lib.jpg

ブラシはこんな感じで不整形にしておくといいと思う。

クラス内部では主にattachしたマスクをポインタ(マウス)の動きに合わせて変形する処理をしています。現在のポインタ位置と1フレーム前のポインタ位置から距離と角度を計算して、

  • マスクの幅=ポインタの移動距離
  • マスクの角度=ポインタの移動角度

としています。また、より「らしさ」を演出するために

  • 速度が20px以下の時はマスク描画しない
  • 一定速度以上のときはマスクの幅を広げる

処理をしています。

最後のdrawSightはおまけでブラシの大きさを矩形で表示します。

Scratch.as

import flash.geom.Point
class Scratch extends MovieClip
{
  private var mc:MovieClip;//_root
  private var tar_mc:MovieClip;//マスクの対象
  private var mask_mc:MovieClip;//マスク自身
  private var linkage:String;//ブラシのリンケージシンボル
  private var size:Number;//ブラシの最小サイズ
  //
  function Scratch(_mc:MovieClip,_tar:MovieClip)
  {
    mc=_mc;
    tar_mc=_tar;
  }
  public function create(_linkage:String,_size:Number):Void
  {
    linkage=_linkage;
    size=_size;
    mask_mc = mc.createEmptyMovieClip("mask_mc",mc.getNextHighestDepth());
    tar_mc.setMask( mask_mc );
    beginDraw(drawMask,this);
  }
  public function resetMask():Void
  {
    mask_mc.removeMovieClip();
    mask_mc = mc.createEmptyMovieClip("mask_mc",mc.getNextHighestDepth());
    tar_mc.setMask( mask_mc );
    beginDraw(drawMask,this);
  }
  private function beginDraw(callback:Function,scope:Scratch):Void
  {
    var id:Number;//一意の番号
    var cur = new Point( mc._xmouse, mc._ymouse );//現在のポインタ位置
    var old = new Point( mc._xmouse, mc._ymouse );//1フレーム前のポインタ位置
    mc.onEnterFrame = function()
    {
      id = getTimer();
      cur = new Point( this._xmouse, this._ymouse );
      var sx:Number = cur.x-old.x;//X軸速度
      var sy:Number = cur.y-old.y;//Y軸速度
      if( Math.abs(sx)>20||Math.abs(sy)>20 )
      {
        callback.call(scope,old,cur,sx,sy,id);
      }
      old = new Point( this._xmouse, this._ymouse );
    }
    drawSight(mc);
  }
  private function drawMask(cur:Point,old:Point,sx:Number,sy:Number,id:Number):Void
  {
    var piece_mc:MovieClip = mask_mc.attachMovie(linkage,
                           "piece_"+id+"_mc",
                           mask_mc.getNextHighestDepth()
                           );
    var r:Number = Math.atan2(sy, sx);//ポインタの移動角度(ラジアン)
    var a:Number = r*180/Math.PI;//ポインタの移動角度(°)
    var d:Number = Math.sqrt(sx*sx+sy*sy);//ポインタの移動距離
    piece_mc._x = cur.x;
    piece_mc._y = cur.y;
    piece_mc._width = (d>size)?d:size;
    piece_mc._height = (d/5>size)?d/5:size;
    piece_mc._rotation = a;
  }
  private function drawSight(scope:MovieClip)
  {
    var sight_mc:MovieClip = mc.createEmptyMovieClip("sight_mc",mc.getNextHighestDepth());
    sight_mc.lineStyle(1,0x99FFFF,50,true,"normal","none","miter",1);
    sight_mc.moveTo(-size/2,-size/2);
    sight_mc.lineTo(-size/2,size/2);
    sight_mc.lineTo(size/2,size/2);
    sight_mc.lineTo(size/2,-size/2);
    sight_mc.lineTo(-size/2,-size/2);
    //
    sight_mc.onEnterFrame = function()
    {
      this._x = scope._xmouse;
      this._y = scope._ymouse;
    }
  }
}