FLASHのお勉強 ーアクションスクリプトの実践的事始めー

(41) BitmapData クラスを使って画像をスライス   2007/1/28
 画像をいくつかの部分に切り分ける(スライスする)には、一般にはFireWorks などの画像処理ソフトを使うが、FRASH のスクリプトで切り分け、そのままスライスをムービークリップとして扱えればいろいろ面白いことが出来そうである。  ということで、今回は、BitmapData クラスを使ったお勉強である。 このクラスを使って、画像をビットマップデータとして読み込むと、ぼかしを効かせたり、フィルターをかけたりして、楽しめるようである。 ここでは、写真をスライスに切り分けそれぞれに独立してアクションをかけられることを確認することにする。 その一例として、スライスそれぞれをランダムな4方向に回転させて登場させ(全体では何の写真か分からない)、それを正規の位置に戻すと一枚の写真になると言う一連の動作である。
SAMPLE
BitmapData を使ったスライスの基本
 左の写真は、4列×3行にスライスされている。 ロールオーバーでアルファ値が変わるようにしてあるので、マウスを載せれば確認できる。
 写真のサイズは200*150であるので、スライスのサイズは50*50である。
 スライスの数は、言うまでもなく12枚。
 この数だけオリジナル写真を切り分け、それぞれをビットマップデータとして取得する。 それを、用意したムービークリップに描き出すことで表示される。
 以下にそのスクリプトを示す。
 (一部分を切り抜くためのzackle さんのscriptを参考にしました)

import flash.display.*; //displayクラスの読み込み
import flash.geom.*; //geomクラスの読み込み
var originalPic:BitmapData = BitmapData.loadBitmap("pict.jpg"); //ライブラリーからBitmapDataとしてロード
for (i=1; i<=12; i++) {
partMc = createEmptyMovieClip("mc"+i, this.getNextHighestDepth());
//空のMC、partMcを作成
tx = partMc._x=(i-1)%4*50; //partMcを4列に配置するときのx座標(txは関数に渡す引数)
ty = partMc._y=Math.floor((i-1)/4)*50; //y座標
var partPic:BitmapData = partition(originalPic, tx, ty, 50, 50); //関数partitionからの戻り値をpartPicとする
partMc.attachBitmap(partPic, this.getNextHighestDepth()); //partMcにpartPicを割当て(表示されるスライス
}
function partition(oPic, x, y, w, h):BitmapData {
var clipRect:Rectangle = new Rectangle(0, 0, w, h);
//切り抜き用の矩形を座標(0,0)に配置
var clipMatrix:Matrix = new Matrix(); //Matrix(移動、変形用クラス)を定義
clipMatrix.translate(-x,-y); //切り抜きデータ部分を矩形位置に移動
var clipPic:BitmapData = new BitmapData(w, h); //切り抜き画像を受けるBitmapDataを定義
clipPic.draw(oPic, clipMatrix, new ColorTransform(), null, clipRect); //切り抜きデータをclipPicに描画
return clipPic; //データを返す
}
ステージの準備
450*350のステージ(背景黒,12fps)を設定
適当な大きさの矩形のシンボルを作成し、rectと名付け、同名でリンケージを設定。アルファ値を0とする。
(これは、回転を施すときに基準点が真ん中のムービークリップを必要とするために作成する。回転を施さない場合は、上の例のようにcreateEmptyMovieClip(基準点が左上)で作成したMCだけでよい)
400*300の写真(pict.jpg)をライブリーに読み込み、同名でリンケージを設定
スクリプト(一枚の画像をスライスしてランダム4方向に回転を施して表示し、正常位置に戻して再表示するまで)
_root、FRAME1に記述
import flash.display.*;
import flash.geom.*;
var x0 = 50;
var y0 = 50;
var divx = 8;
var divy = 6;
var originalPic:BitmapData = BitmapData.loadBitmap("pict.jpg");
var divx_width = originalPic.width/divx;
var divy_height = originalPic.height/divy;
      
for (i=1; i<=divx*divy; i++) {
        rect = attachMovie("rect", "rect"+i, this.getNextHighestDepth());
        partMc = rect.createEmptyMovieClip("partMc"+i, this.getNextHighestDepth());
        rect._x = x0+originalPic.width/2;
        rect._y = y0+originalPic.height/2;
        partMc._x = -divx_width*0.5;
        partMc._y = -divy_height*0.5;
        rect.targetx = x0+(i-1)%divx*divx_width;
        rect.targety = y0+Math.floor((i-1)/divx)*divy_height;
        rect._alpha = 0;
        rect._xscale = rect._yscale=0;
        rect._rotation = Math.floor(Math.random()*4)*90;
        var tx = -(i-1)%divx*divx_width;
        var ty = -Math.floor((i-1)/divx)*divy_height;
        var partPic:BitmapData = partition(originalPic, tx, ty, divx_width, divy_height);
        partMc.attachBitmap(partPic, this.getNextHighestDepth());
        //rect.partPic=partPic;
        rect.rnd = Math.floor(Math.random()*6)+3;
        rap = getTimer();
        rect.onEnterFrame = partIn;
}
originalPic.dispose();

function partIn() {
        rnd = this.rnd;
        this._alpha += (100-this._alpha)/8;
        this._xscale += (100-this._xscale)/8;
        this._yscale += (100-this._yscale)/8;
        this._x += (this.targetx-this._x)/rnd;
        this._y += (this.targety-this._y)/rnd;
        if ((getTimer()-rap)>5000 && (getTimer()-rap)<6000) {
                this._xscale += (50-this._xscale)/8;
                this._yscale += (50-this._yscale)/8;
                this._rotation = 0;
        }
        if ((getTimer()-rap)>10000) {
        delete this.onEnterFrame;
        }
      }
      
function partition(oPic, x, y, w, h):BitmapData {
        var clipRect:Rectangle = new Rectangle(0, 0, w, h);
        var clipMatrix:Matrix = new Matrix();
        clipMatrix.translate(x, y);
        var clipPic:BitmapData = new BitmapData(w, h);
        clipPic.draw(oPic, clipMatrix, new ColorTransform(), null, clipRect);
        return clipPic;
}
スクリプトの説明
●MC(ムービークリップ) rect は、スライス画像の移動、回転などを司るもので、その中に partMC と言う空のMCを置いてそこに画像を取り込む。rectの基準点は真ん中。
●1番目のスライスの配置座標を、x0,y0とおく。
●8×6のスライスに切り分ける
●空のMCを作成すると基準点が左上なので、partMcとrectの中心を一致させるために、partMcの座標を補正する。
    partMc._x = -divx_width*0.5;  partMc._y = -divy_height*0.5;
●MCが最終的に落ち着く先 targetx、targety:
    rect.targetx = x0+(i-1)%divx*divx_width;
    rect.targety = y0+Math.floor((i-1)/divx)*divy_height;

●MCの初期座標を全体画像が表示される部分の中心とし、アルファ値を0、scaleを0に設定する。
●MCの向きがランダム4方向になるように設定
    rect._rotation = Math.floor(Math.random()*4)*90;
●MCの座標のマイナス値(この場合はx0,y0を含まない)、スライスの幅、高さを引数として、関数partitionに渡す。
    var partPic:BitmapData = partition(originalPic, tx, ty, divx_width, divy_height);
●関数partitionからの戻り値(ビットマップ)をpartMcに割り当てる。
    partMc.attachBitmap(partPic, this.getNextHighestDepth());
●後で画像を削除(dispose())するために、partPicに目印を付ける(この例では繰り返し表示がないので不要)
    rect.partPic=partPic;
●スライス画像の登場をバラバラな感じにするための乱数を発生させ、経過時間の初期値を設定して関数partInに。
    rect.rnd = Math.floor(Math.random()*6)+3;  rap = getTimer();  rect.onEnterFrame = partIn;
●スライス画像を取り込んだところで、原画を削除する。
    originalPic.dispose();
●partIn 関数(スライス画像の2ステップ登場)
 ・アルファ、スケールを100に戻しながら、target(本来配置されるべき座標)に移動
 ・移動はバラバラになるように、各スライスについて発生させた乱数を移動速度に反映させる
 ・経過時間が5秒を過ぎて6秒になるまでスライスを縮小させる(6秒を過ぎると元に戻る)
 ・10秒を過ぎたら onEnterFrame を削除して終了

上の例では、繰り返し再生と、2枚の写真の切り替え表示機能を付与している。
簡単にその方法を解説する。
 ・FRAME1に count=0;
 ・FRAME2に 上記スクリプト+下記スクリプト
 ・FRAME130に count++; gotoAndPlay(2);
 
 写真切り替え用スクリプト:
    if (count%2==0) {
    var originalPic:BitmapData = BitmapData.loadBitmap("pict.jpg");
    } else {
    var originalPic:BitmapData = BitmapData.loadBitmap("pict2.jpg"); }

 partIn関数の最後:
    if ((getTimer()-rap)>10000) {
     this._alpha += (0-this._alpha)/2;}
    if ((getTimer()-rap)>=10800) {
     this.partPic.dispose();
     delete this.onEnterFrame;}
 
flashirohaサイト内  Web全体 
HOME   お勉強総リスト