ささきち流 Suzuka & ParaDraw 講座
Suzuka & ParaDraw
TOP
PROFILE
ActionScript Editor
LINK
BBS


フリーのFlash作成ソフト SuzukaParaDraw でFlashな生活を楽しもうというサイトです。
ランダム ジグソーパズル サンプル&作成方法解説


ランダムに外部JPEGを読み込むジグソーパズルです。

外部JPEGを読み込んで自動でパズルを作成するものなので,
JPEGを替えるだけでパズルの写真は入れ替えることができます。

 


サンプルダウンロード
PDR・CSF・JPEGファイル在中(結構重いです)
「jigsaw.zip」 190 KB (195,034 バイト)



ランダム ジグソーパズル 作成方法解説

サンプル作成に使用した ParaDraw のバージョンは Ver.0.3a4, Suzuka のバージョンは Ver. 0.8.0.0[RichEdit版] です。
ロードされる JPEG は,何かの付録として付いてきた Photoshop Elements 2.0 で適当に作成したもので,ParaDraw とも Suzuka とも Flash とも関係ありません。

ParaDrawでのピースの作成段階から意図して作り込んだ仕組みで動作するので,これの作成方法を全て説明するのはちょっと不可能ですので,原理と概略のみ説明します。
作り方の詳細は,ダウンロードファイルを開いて解析してもらわないとわからないと思います。

大筋は,5枚ある外部JPEG(400×300px)の中から1枚をランダムにロードして,ピースに切りきざんでバラバラに配置するという流れです。

JPEGのロードは1回きりです。これには MovieClipLoaderクラス の loadClipメソッド を使用しています。

そして,ロードした JPEG から,BitmapDataクラスの drawメソッドを使って ビットマップデータを写し取って,その写し取ったデータを attachBitmapメソッド で,ムービークリップ(スプライト)に塗りたくって,そのビットマップ塗りのムービークリップ(スプライト)にピースのマスクをかけてジグソーパズルを完成させています。

この BitmapDataクラス の使用によって,JPEGのロードは1回きりで済みます。
Adobe Flash 8 (SWF8) から使用できるようになったこの BitmapDataクラス は本当に面白いことに色々使えますが,これはそのうちの1つの例です。

ActionScriptプログラムの流れをイメージで表すと次のようになっています。

MovieClipLoader & BitmapData

 

スクリプトはメインの フレーム1 のみに記述してます。

// 外部JPEGをランダムに選択する 1〜5 の乱数 r_img を取得
r_img = Math.floor(Math.random()*5)+1;
// 吸着したピース(img?)を持っていく深度の初期値
var dep = 0;
// マスク用ピース(msk?)の初期座標記録用配列を作成
p = new Array();
//
for (var i = 0; i<=47; i++) {
	// マスク用ピース(msk?)を透明にする
	_root.puzzle["msk"+i]._alpha = 0;
	// マスク用ピース(msk?)の初期座標記録(二次元配列)
	p[i] = new Array();
	p[i][0] = _root.puzzle["msk"+i]._x;
	p[i][1] = _root.puzzle["msk"+i]._y;
}
//
// ロードしたイメージで塗りつぶすピースの作成
for (i=0; i<=47; i++) {
	// 空のスプライト(MC) img0〜47 を作成
	var p_m = _root.puzzle.createEmptyMovieClip("img"+i, 1000+i);
	// ムービークリップの固有値変数 n を設定
	p_m.n = i;
	// ピース(img?)をマウスで押したときの動作を定義
	p_m.onPress = function() {
		// _root の n にピース(img?)の固有変数 n を代入
		_root.n = this.n;
		// マウスの相対座標を _root の nmx,nmy に保存
		_root.nmx = _root.puzzle["msk"+this.n]._xmouse;
		_root.nmy = _root.puzzle["msk"+this.n]._ymouse;
		// ピース(img?) の深度を最高深度に移動
		this.swapDepths(this._parent.getNextHighestDepth());
	};
	// ピース(img?)からマウスを放したときの動作を定義
	p_m.onRelease = function() {
		_root.nmx = _root.nmy=_root.n=null;
		// 座標が±10以下であれば
		if (this._x<10 && this._x>=-10 && this._y<=10 && this._y>=-10) {
			// ピース と マスク を定位置に吸着
			this._x = this._y=0;
			_root.puzzle["msk"+this.n]._x = p[this.n][0];
			_root.puzzle["msk"+this.n]._y = p[this.n][1];
			// 吸着する深度の値を1加算
			dep++;
			// その深度に下げる(埋もれの防止)
			this.swapDepths(dep);
			// 動かないようにする
			delete this.onPress;
		}
	};
	p_m.onReleaseOutside = p_m.onRelease;
}
//
// 外部JPEGイメージロード用スプライト(MC)の作成
var l_m = this.createEmptyMovieClip("load_mc", 0);
// とりあえず見えないところに置いておく
l_m._x = Stage.width*2;
//
// ---外部JPEGロードとピースの塗りつぶし---------
// MovieClipLoaderクラスのインスタンスを作成
var myMCL = new MovieClipLoader();
// 外部JPEGロード完了時の動作を定義(リスナーオブジェクト は _root)
_root.onLoadInit = function() {
	// ★BitmapDataクラスのインスタンスを作成
	var myBMD = new flash.display.BitmapData(l_m._width, l_m._height);
	// ★イメージをロードしたMCを myBMDイメージ 上に写し取る
	myBMD.draw(l_m);
	// 外部JPEGイメージはもう不要なのでスプライトごと削除
	l_m.removeMovieClip();
	//
	for (i=0; i<=47; i++) {
		// ランダム配置
		var rx = Math.random()*(Stage.width-80)-p[i][0]-15;
		_root.puzzle["img"+i]._x = rx;
		_root.puzzle["msk"+i]._x = rx+p[i][0];
		var ry = Math.random()*(Stage.height-100)-p[i][1]-20;
		_root.puzzle["img"+i]._y = ry;
		_root.puzzle["msk"+i]._y = ry+p[i][1];
		//
		// ★img? に myBMD を割り当てる(img? を myBMD で塗りつぶす)
		_root.puzzle["img"+i].attachBitmap(myBMD, 1);
		// 塗りつぶされた img? に msk? のマスクをかける
		_root.puzzle["img"+i].setMask(_root.puzzle["msk"+i]);
	}
};
// 外部JPEG jigsawフォルダの「img?.jpg」 のロード
myMCL.loadClip("jigsaw/img"+r_img+".jpg", l_m);
//
// _root を myMCL のリスナーに登録
myMCL.addListener(_root);
//
// ---マスクをピースに追従させる処理------------
// マウス監視用オブジェクト myMS を作成
var myMS = new Object();
// マウスが動いたとき
myMS.onMouseMove = function() {
	// マスクとピースの座標をマウスとともに移動
	_root.puzzle["msk"+n]._x = _root._xmouse-nmx-30;
	_root.puzzle["img"+n]._x = _root._xmouse-p[n][0]-nmx-30;
	_root.puzzle["msk"+n]._y = _root._ymouse-nmy-30;
	_root.puzzle["img"+n]._y = _root._ymouse-p[n][1]-nmy-30;
	// 即更新
	updateAfterEvent();
};
// myMS をマウスクラスのリスナーに登録
Mouse.addListener(myMS);

BitmapData 関連の部分には,コメント行に ★ 印を書きました。
Suzuka では,例のごとく import文 を使用せず,クラスを完全修飾名で参照するスタイルで書けば BitmapDataクラス のスクリプトも使用可能です。

本当は,各ピース画像の作成のしかたや,スプライトの大きさや位置や基準点などなど,色々なものが絡み合って上のスクリプトが無事に動作するのですが,その辺の説明は困難を極めるため割愛させていただきます。

このサンプルでは,何が本題かがさらにわからなくなるのでしていませんが,「スタートボタン」やカウントダウンまたはカウントアップする「タイマー」などを付けると,よりゲーム性が増すと思います。