flaファイル側で、親のMovieClipとマスク対象のMovieClipを指定してScratchクラスのクラスインスタンスを作成、createメソッドでattachするブラシのシンボルリンケージとブラシの最小サイズを指定してマスクを開始します。
scratch.fla
var scratch = new Scratch( _root, target_mc );
scratch.create("BRUSH",30);
ブラシはこんな感じで不整形にしておくといいと思う。
クラス内部では主に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;
}
}
}