スポンサーサイト

上記の広告は1ヶ月以上更新のないブログに表示されています。
新しい記事を書く事で広告が消せます。

--.--.-- | | スポンサー広告

Flash CS3で水面ぽい画像表示

Flash CS3が届いたということもあり、以前エントリしたDisplacementMapFilterを使った水面ぽい画像表示をCS3で書き直してみました。





某オブジェの写真がゆらゆら揺れます。速度/変化量に数値を入れて「設定」ボタンを押すと揺れ方が変わります。また、画像の上にマウスを持ってくとDisplacementMapFilterで使用している置き換えマップ画像が表示されます。

今回は、水面ぽく表示する表示オブジェクトのクラスを作ることにしました。せっかくCS3だし。作ったクラスのインスタンスにaddChildすることで、任意の表示オブジェクトを水面ぽく表示できるという寸法デス。

クラスはWaterSurfaceという名前でWaterSurface.asというファイル名デス。ソースはこんなカンジです。

package {
import flash.display.*;
import flash.geom.*;
import flash.events.*;
import flash.filters.*;
/**
* 水面処理をして描画するスプライト。
*/
public class WaterSurface extends Sprite {
/** 変化速度 */
private var _speed:Number;
/** 変化量 */
private var _scale:Number;
/** オクターブ数 */
private var _octave:uint;
/** 乱数シード */
private var _rndSeed:int;
/** オフセット値の配列 */
private var _offset_array:Array;
/** 変化速度の配列 */
private var _speed_array:Array;
/** 置き換えフィルタ */
private var _filter:DisplacementMapFilter;
/** 置き換えビットマップ */
private var _bitmapData:BitmapData = null;
/**
* コンストラクタ。
* @param speed 変化速度
* @param scale 変化量
* @param octave オクターブ数
*/
public function WaterSurface(speed:Number = 8,
scale:Number = 8,
octave:uint = 3) {
_speed = speed;
_scale = scale;
_octave = octave;
_rndSeed = Math.floor(Math.random() * 65536);
// フィルタの生成
_filter = new DisplacementMapFilter(null,
new Point(0, 0),
2,
4,
scale,
scale);
this.speed = speed;
// onEnterFrameイベントをリッスンする
addEventListener(Event.ENTER_FRAME, onEnterFrame);
}
/**
* 変化速度を設定します。
* @param val 変化速度
*/
public function set speed(val:Number):void {
// 配列の初期化
_offset_array = new Array();
_speed_array = new Array();
for (var i:int = 0; i < _octave; i++) {
_offset_array.push(new Point(0, 0));
_speed_array.push(new Point(
val * (Math.floor(Math.random() * 2) == 0 ? -1 : 1),
val * (Math.floor(Math.random() * 2) == 0 ? -1 : 1)));
}
}
/**
* 変化量を設定します。
* @param val 変化量
*/
public function set scale(val:Number):void {
_filter.scaleX = val;
_filter.scaleY = val;
}
/**
* フレーム毎の処理
* @param evt イベントオブジェクト
*/
private function onEnterFrame(evt:Event):void {
// オフセット位置の更新
for (var i:int = 0; i < _octave; i++) {
_offset_array[i].x += _speed_array[i].x;
_offset_array[i].y += _speed_array[i].y;
}
// フィルタのクリア
if (_filter.mapBitmap) {
_filter.mapBitmap.dispose();
}
// パーリンノイズビットマップ生成
var w:Number = width;
var h:Number = height;
if (w > 0 && h > 0) {
_bitmapData = new BitmapData(w, h);
_bitmapData.perlinNoise(w,
h,
_octave,
_rndSeed,
false,
true,
2 | 4,
false,
_offset_array);
// 置き換えフィルタにビットマップをセットする
_filter.mapBitmap = _bitmapData;
}
filters = [_filter];
}
/**
* 置き換えフィルタに使用しているビットマップデータを
* 戻します。
* @return ビットマップデータ
*/
public function get bitmapData():BitmapData {
return _bitmapData;
}
}
}
WaterSurfaceはSpriteを継承したクラスで、自身のEnterFrameイベントでパーリンノイズ画像を作ってDisplacementMapFilterに反映させる処理をします。あと、変化速度/変化量を設定するためのプロパティと置き換え画像のBitmapDataを取得するためのプロパティを追加してあります。

そんでコレを使うフレームアクションのほーはこんなカンジです。
// 水面処理スプライトを生成する。
var waterSurface:WaterSurface = new WaterSurface();
addChild(waterSurface);
// 水面処理したい表示オブジェクトをセット
var ix:Number = image_mc.x;
var iy:Number = image_mc.y;
image_mc.x = 0;
image_mc.y = 0;
waterSurface.addChild(image_mc);
waterSurface.x = ix;
waterSurface.y = iy;
// マウスオーバーで置き換えビットマップを表示
waterSurface.addEventListener(MouseEvent.ROLL_OVER,
function(evt:Event) {
addEventListener(Event.ENTER_FRAME, doShowBitmap);
});
waterSurface.addEventListener(MouseEvent.ROLL_OUT,
function(evt:Event) {
removeEventListener(Event.ENTER_FRAME, doShowBitmap);
hideBitmap();
});
var bitmap:Bitmap = new Bitmap();
addChild(bitmap);
bitmap.x = waterSurface.x;
bitmap.y = waterSurface.y;
function doShowBitmap(evt:Event) {
hideBitmap();
bitmap.bitmapData = waterSurface.bitmapData;
}
function hideBitmap() {
if (bitmap.bitmapData) {
bitmap.bitmapData.dispose();
}
}
// 設定ボタン
setting_mc.addEventListener(MouseEvent.CLICK,
function(evt:Event) {
waterSurface.speed = Number(speed_txt.text);
waterSurface.scale = Number(scale_txt.text);
});
image_mcというのが画像のインスタンスです。WaterSurfaceのインスタンスを作ってimage_mcをaddChildすることでimage_mcを揺らしています。

WaterSurfaceのインスタンスにはロールオーバー/ロールアウトのイベントリスナを追加しています。置き換え画像をWaterSurfaceのインスタンスから取得して表示するEnterFrameイベントハンドラをつけたり外したりします。

setting_mcは「設定」ボタンで、クリックしたらWaterSurfaceのspeed/scaleプロパティに入力値を設定してます。

スポンサーサイト

テーマ:Flash - ジャンル:コンピュータ

2007.06.24 | | Comments(4) | Trackback(0) | Flash CS3

カラーピッカー

カラーピッカーのサンプルを作ってみました。




上部のカラーパレットをクリックすると、クリックしたところの色が選択されて右下に表示されます。
R、G、B、色相、彩度、明度のテキストフィールドは、選択した色のソレゾレの値デス。コレの数値をいじると選択色はその値の色になります。

色相、彩度、明度はソレゾレHSV色空間のH値、S値、V値となってます。のハズです。

カラーパレットは、どんなのが標準的か知らないのでx方向にH値を変化させて、y方向は上半分がS値のグラデーション、下半分がV値のグラデーションになってマス。あ、描画はBitmapDataにsetPixelしてマス。

スクリプトはこんなカンジです。

import flash.display.BitmapData;
import flash.geom.Transform;
import flash.geom.ColorTransform;
// カラーパレット画像
var palette:BitmapData = createPaletteBitmap();
// カラーパレットムービークリップ
palette_mc.attachBitmap(palette, 1);
palette_mc._x = 10;
palette_mc._y = 10;
palette_mc.onRelease = function() {
// マウスポインタ位置の色を取得
var x:Number = this._xmouse;
var y:Number = this._ymouse;
var c:Number = palette.getPixel(x, y);
// RGB値のテキストを更新
updateRgb(c);
// HSV値のテキストを更新
updateHsv(c);
// 色を更新
updateColor(c);
}
// RGBを更新
function updateRgb(c:Number) {
r_txt.text = (c >> 16).toString();
g_txt.text = ((c >> 8) & 0xFF).toString();
b_txt.text = (c & 0xFF).toString();
}
// HSVを更新
function updateHsv(c:Number) {
var hsv:Object = colorToHsv(c);
h_txt.text = hsv.h.toString();
s_txt.text = hsv.s.toString();
v_txt.text = hsv.v.toString();
}
// 色を更新
function updateColor(c:Number) {
var cStr:String = c.toString(16).toUpperCase();
while (cStr.length < 6) {
cStr = "0" + cStr;
}
color_txt.text = "0x" + cStr;
var cTrans:ColorTransform = new ColorTransform();
cTrans.rgb = c;
var trans:Transform = new Transform(color_mc);
trans.colorTransform = cTrans;
}
// RGB値変更
r_txt.onChanged = doRgbChanged;
g_txt.onChanged = doRgbChanged;
b_txt.onChanged = doRgbChanged;
// RGBのテキストフィールドを更新したときの処理
function doRgbChanged() {
var r:Number = Number(r_txt.text);
var g:Number = Number(g_txt.text);
var b:Number = Number(b_txt.text);
if (r >= 0 && r <= 255 &&
g >=0 && g <= 255 &&
b >=0 && b <= 255) {
var c:Number = r << 16 | g << 8 | b;
updateHsv(c);
updateColor(c);
}
}
// HSV値変更
h_txt.onChanged = doHsvChanged;
s_txt.onChanged = doHsvChanged;
v_txt.onChanged = doHsvChanged;
// HSVのテキストフィールドを更新したときの処理
function doHsvChanged() {
var h:Number = Number(h_txt.text);
var s:Number = Number(s_txt.text);
var v:Number = Number(v_txt.text);
if (h >= 0 && h < 360 &&
s >= 0 && s <= 1 &&
v >= 0 && v <= 1) {
var c:Number = hsvToColor(h, s, v);
updateRgb(c);
updateColor(c);
}
}
// カラー値変更
color_txt.onChanged = doColorChanged;
// カラー値のテキストフィールドを更新したときの処理
function doColorChanged() {
var c:Number = Number(color_txt.text);
if (c >= 0 && c <= 0xFFFFFF) {
updateRgb(c);
updateHsv(c);
var cTrans:ColorTransform = new ColorTransform();
cTrans.rgb = c;
var trans:Transform = new Transform(color_mc);
trans.colorTransform = cTrans;
}
}
// カラーパレットのビットマップデータを生成し、戻します。
function createPaletteBitmap():BitmapData {
var bitmap:BitmapData = new BitmapData(360, 200);
var y:Number = 0;
var x:Number = 0;
// 上半分は彩度を変化させる
for (y = 0; y < 100; y++) {
for (x = 0; x < 360; x++) {
bitmap.setPixel(x, y, hsvToColor(x, y * 0.01, 1));
}
}
// 下半分は明度を変化させる
for (y = 100; y < 200; y++) {
for (x = 0; x < 360; x++) {
bitmap.setPixel(x,
y,
hsvToColor(x, 1, 1 - (y - 100) * 0.01));
}
}
return bitmap;
}
// HSVをカラー値に変換し、戻します。
function hsvToColor(h:Number, s:Number, v:Number):Number {
var cv:Number = Math.round(v * 255);
var r:Number = cv;
var g:Number = cv;
var b:Number = cv;
if (s > 0) {
var i:Number = Math.floor(h / 60);
var f:Number = h / 60 - i;
var m:Number = Math.round(v * (1 - s) * 255);
var n:Number = Math.round(v * (1 - s * f) * 255);
var k:Number = Math.round(v * (1 - s * (1 - f)) * 255);
switch(i) {
case 0:
g = k;
b = m;
break;
case 1:
r = n;
b = m;
break;
case 2:
r = m;
b = k;
break;
case 3:
r = m;
g = n;
break;
case 4:
r = k;
g = m;
break;
case 5:
g = m;
b = n;
break;
}
}
return r << 16 | g << 8 | b;
}
// カラー値をHSVに分解し、戻します。
function colorToHsv(color:Number):Object {
var r:Number = color >> 16;
var g:Number = (color >> 8) & 0xFF;
var b:Number = color & 0xFF;
var max:Number = Math.max(r, Math.max(g, b));
var min:Number = Math.min(r, Math.min(g, b));
var range:Number = max - min;
var h:Number = 0;
var s:Number = 0;
var v:Number = max / 255;
if (v > 0) {
s = range / max;
if (s > 0) {
var cr:Number = (max - r) / range;
var cg:Number = (max - g) / range;
var cb:Number = (max - b) / range;
if (r == max) {
h = cb - cg;
} else if (g == max) {
h = 2 + cr - cb;
} else {
h = 4 + cg - cr;
}
h *= 60;
if (h < 0) {
h += 360;
}
}
}
return {h:Math.round(h * 100) * 0.01,
s:Math.round(s * 100) * 0.01,
v:Math.round(v * 100) * 0.01};
}
palette_mcはカラーパレットのムービークリップです。このムービークリップにcreatePaletteBitmapメソッドで作ったBitmapDataをattachBitmapしてます。

createPaletteBitmapメソッドは、360×200のBitmapDataを作りマス。上半分はy方向に0.01ずつ彩度を変化させて、下半分はy方向に0.01ずつ明度を変化させてsetPixelしてマス。x方向は色相です。このときにHSV値から0xRRGGBBの値を作らないといけないのですが、コレはhsvToColorメソッドでやってます。

palette_mcのonReleaseイベントハンドラで、マウスカーソルの位置の色から7つのテキストフィールドと右下のムービークリップcolor_mcの色を設定しています。色相/明度/彩度はcolorToHsvメソッドでH/S/V値を算出してソレを表示してます。color_mcの色はColorTransformを使って変えてマス。

r_txt、g_txt、b_txtはR/G/BのテキストフィールドでonChangedイベントハンドラは同じです。他のテキストフィールドやcolor_mcの色を入力値で更新してます。

h_txt、s_txt、v_txtは色相/彩度/明度のテキストフィールドです。やっぱり同一のonChangedイベントハンドラを実装してます。

color_txtは色のテキストフィールドです。コイツもonChangedイベントハンドラを実装してます。なので色テキストフィールドを変更しても他の値が変わりマス。

テーマ:Flash - ジャンル:コンピュータ

2007.06.22 | | Comments(1) | Trackback(0) | Flash/ActionScript

ラバーバンドを描く

線を引くのにラバーバンドを使うGUIのサンプルです。




ステージをマウスでクリックすると、クリックした場所からマウスカーソルまで破線(蟻の行進?)のラバーバンドが描画されます。もう一度クリックするとラバーバンドは実線になって、その位置からまたラバーバンドが描画されます。線の色はランダムです。

やってるコトは単純で、クリックするたびに空のムービークリップを作成します。そしてonEnterFrameイベントハンドラでクリアして線を引くのを繰り返しています。

蟻の行進については、うまいやり方を知らないので短い線をマウスカーソル位置にむかってたくさん描いています。フレーム毎にオフセット位置を変えて行進してるっぽくみせてマス。

アクションスクリプトはこんなカンジです。

// 描画領域
var depth:Number = _root.getNextHighestDepth();
var canvas_mc:MovieClip
= _root.createEmptyMovieClip("canvas_" + depth, depth);
canvas_mc.beginFill(0xFFFFFF);
canvas_mc.moveTo(0, 0);
canvas_mc.lineTo(0, Stage.height);
canvas_mc.lineTo(Stage.width, Stage.height);
canvas_mc.lineTo(Stage.width, 0);
canvas_mc.lineTo(0, 0);
canvas_mc.endFill();
canvas_mc.onRelease = drawLine;
// 線の始点
var sx:Number;
var sy:Number;
// ラバーバンドムービークリップ
var band_mc:MovieClip;
// 線を描画する
function drawLine() {
// 線の確定処理
if (band_mc) {
delete band_mc.onEnterFrame;
band_mc.clear();
band_mc.lineStyle(1, band_mc.lineColor, 100, true,
"none", "round", "miter", 1);
band_mc.moveTo(0, 0);
band_mc.lineTo(_xmouse - sx, _ymouse - sy);
band_mc._x = sx;
band_mc._y = sy;
}
// ラバーバンド生成
sx = _xmouse;
sy = _ymouse;
var depth:Number = _root.getNextHighestDepth();
band_mc
= _root.createEmptyMovieClip("band_" + depth, depth);
band_mc.lineColor = Math.floor(Math.random() * 0x1000000);
band_mc.offset = 0;
band_mc.onEnterFrame = function() {
this.clear();
this.lineStyle(1, this.lineColor, 100, true,
"none", "round", "miter", 1);
dash(this, 0, 0, _xmouse - sx, _ymouse - sy, 3, 4, this.offset);
this.offset = (this.offset + 1) % 7;
this._x = sx;
this._y = sy;
}
}
// 破線を描画します。
function dash(mc:MovieClip, x1:Number, y1:Number,
x2:Number, y2:Number,
dash1:Number, dash2:Number, offset:Number) {
var l:Number
= Math.sqrt((x2 - x1) * (x2 - x1) + (y2 - y1) * (y2 - y1));
if (l < 2) {
return;
}
var sin:Number = (y2 - y1) / l;
var cos:Number = (x2 - x1) / l;
var d:Number = offset;
var x:Number = x1 + cos * offset;
var y:Number = y1 + sin * offset;
while (d <= l) {
mc.moveTo(x, y);
mc.lineTo(x + cos * dash1, y + sin * dash1);
x += cos * (dash1 + dash2);
y += sin * (dash1 + dash2);
d += dash1 + dash2;
}
}
最初に作ってるcanvas_mcは、描画領域になる矩形のムービークリップです。ステージと同サイズにしてます。onReleaseイベントハンドラで線を描画するdrawLineメソッドを実行するようにしてます。

band_mcというのはラバーバンドを描画中のムービークリップです。drawLineメソッドは、band_mcのonEnterFrameイベントハンドラをdeleteすることでラバーバンドの描画を中止して、代わりに実線をひきます。そんで新しいband_mcを作ってソイツのonEnterFrameイベントハンドラでラバーバンドを描画するようにしてます。

banc_mcのonEnterFrameハンドラ内で呼び出してるdashメソッドが破線をひくためのメソッドです。コイツを使わないでlineToすればラバーバンドは実線になります。

dashメソッドは、描画対象のムービークリップ/線の開始座標/終了座標/線分の長さ/空白の長さ/オフセット距離を引数にとります。やってるコトは、開始座標から終了座標に向かって指定された長さの線分を指定された間隔で描画デス。

band_mcではdashメソッドを実行する際にオフセット距離を変化させてます(0~6のループ)。そのせいで蟻の行列に見えるという寸法デス。

テーマ:Flash - ジャンル:コンピュータ

2007.06.13 | | Comments(0) | Trackback(0) | Flash/ActionScript

床面の反射を描画する

ツルツルの床っぽく、タイルが次々と落下してくるのが床面にうつりこんでいるようなサンプルです。




タイルをクリックすると、背景がそのタイルの色になります。

このサンプルでは、ステージの上部2/3に落下するタイルを描画するムービークリップを配置して、フレーム毎にそのムービークリップから上下反転/縮小した画像を切り取り、下部1/3に表示しています。

また、床面のムービークリップにはアルファマスクをかけてソレっぽく透過するようにしてます。

ActionScriptはこんなカンジです。

import flash.geom.Matrix;
import flash.display.BitmapData;
import flash.geom.Rectangle;
import flash.geom.ColorTransform;
// 背景
var depth:Number = _root.getNextHighestDepth();
var back_mc:MovieClip
= _root.createEmptyMovieClip("back_" + depth, depth);
back_mc.beginFill(0xFFFFFF);
back_mc.moveTo(0, 0);
back_mc.lineTo(0, Stage.height);
back_mc.lineTo(Stage.width, Stage.height);
back_mc.lineTo(Stage.width, 0);
back_mc.lineTo(0, 0);
back_mc.endFill();
// 表示スクリーン
depth = _root.getNextHighestDepth();
var screen_mc:MovieClip
= _root.createEmptyMovieClip("screen_" + depth, depth);
screen_mc._x = 0;
screen_mc._y = 0;
// スクリーンと床の境界y座標
var oY:Number = Stage.height * 2 / 3;
// スクリーンマスク
depth = _root.getNextHighestDepth();
var screen_mask_mc:MovieClip
= _root.createEmptyMovieClip("screen_mask_" + depth, depth);
screen_mask_mc.beginFill(0xFFFFFF);
screen_mask_mc.moveTo(0, 0);
screen_mask_mc.lineTo(0, oY);
screen_mask_mc.lineTo(Stage.width, oY);
screen_mask_mc.lineTo(Stage.width, 0);
screen_mask_mc.lineTo(0, 0);
screen_mask_mc.endFill();
screen_mc.setMask(screen_mask_mc);
// 床面
depth = _root.getNextHighestDepth();
var floor_mc:MovieClip
= _root.createEmptyMovieClip("floor_" + depth, depth);
floor_mc._x = 0;
floor_mc._y = oY;
// 床面マスク
depth = _root.getNextHighestDepth();
var floor_mask_mc:MovieClip
= _root.createEmptyMovieClip("floor_mask_" + depth, depth);
var mtx:Matrix = new Matrix();
mtx.createGradientBox(Stage.width,
Stage.height - oY,
Math.PI / 2);
floor_mask_mc.beginGradientFill("linear",
[0xFFFFFF, 0xFFFFFF],
[60, 0], [0, 255],
mtx);
floor_mask_mc.moveTo(0, 0);
floor_mask_mc.lineTo(0, Stage.height - oY);
floor_mask_mc.lineTo(Stage.width, Stage.height - oY);
floor_mask_mc.lineTo(Stage.width, 0);
floor_mask_mc.lineTo(0, 0);
floor_mask_mc.endFill();
floor_mask_mc._x = 0;
floor_mask_mc._y = oY;
floor_mask_mc.cacheAsBitmap = true;
floor_mc.setMask(floor_mask_mc);
floor_mc.cacheAsBitmap = true;
// タイルのサイズ
var tile_w:Number = 40;
var tile_h:Number = 40;
// タイル発生頻度
var r:Number = 5;
// フレーム毎の処理
function onEnterFrame() {
if (Math.random() * 100 < r) {
createTile(screen_mc);
}
reflect();
}
// 落下するタイルを生成します。
function createTile(parent_mc:MovieClip):Void {
var d:Number = parent_mc.getNextHighestDepth();
var mc:MovieClip
= parent_mc.createEmptyMovieClip("tile_" + d, d);
var c:Number = Math.floor(Math.random() * 0x1000000);
var speed:Number = 3 + Math.floor(Math.random() * 2);
// 色
mc.beginFill(c);
mc.moveTo(0, 0);
mc.lineTo(0, tile_h);
mc.lineTo(tile_w, tile_h);
mc.lineTo(tile_w, 0);
mc.lineTo(0, 0);
mc.endFill();
// グラデーション
var go:Number = 1;
var gw:Number = tile_w - 2 * go;
var gh:Number = tile_h - 2 * go;
var gMtx:Matrix = new Matrix();
gMtx.createGradientBox(gw, gh, Math.PI / 2);
mc.beginGradientFill("linear",
[0x000000, 0xFFFFFF],
[30, 70],
[0, 255],
gMtx);
mc.moveTo(go, go);
mc.lineTo(go, go + gh);
mc.lineTo(go + gw, go + gh);
mc.lineTo(go + gw, go);
mc.lineTo(go, go);
mc.endFill();
// ハイライト
var ho:Number = 1;
var hw:Number = tile_w - 2 * ho;
var hh:Number = Math.round(tile_h * 0.40);
var hMtx:Matrix = new Matrix();
hMtx.createGradientBox(hw, hh, Math.PI / 2);
mc.beginGradientFill("linear",
[0xFFFFFF, 0xFFFFFF],
[90, 30],
[0, 255],
hMtx);
mc.moveTo(ho, ho);
mc.lineTo(ho, ho + hh);
mc.lineTo(ho + hw, ho + hh);
mc.lineTo(ho + hw, ho);
mc.lineTo(ho, ho);
mc.endFill();
// 初期位置
mc._x = Math.floor(Math.random() * (Stage.width - tile_w));
mc._y = -tile_h;
// 落下
mc.speed = speed;
mc.onEnterFrame = function() {
this._y += this.speed;
if (this._y > Stage.height) {
this.removeMovieClip();
}
}
// 背景色変更
mc.c = c;
mc.back = back_mc;
mc.onRelease = function() {
var ct:ColorTransform = new ColorTransform();
ct.rgb = this.c;
this.back.transform.colorTransform = ct;
}
}
// スクリーンを床面に反射させます。
function reflect():Void {
// 反射画像の縮小率
var s:Number = 0.8;
// 反射画像切り取り
var bitmap:BitmapData
= new BitmapData(Stage.width,
Stage.height - oY,
true,
0x000000);
var mtx:Matrix = new Matrix();
mtx.scale(1.0, -s);
mtx.ty = oY * s;
var rect:Rectangle = new Rectangle(0,
0,
Stage.width,
(Stage.height - oY) / s);
bitmap.draw(screen_mc,
mtx,
new ColorTransform(),
"normal",
rect,
true);
floor_mc.attachBitmap(bitmap, 1);
}
最初に作ってるback_mcは背景のムービークリップで、初期状態では白い矩形デス。タイルがクリックされたときはコイツのtransform.colorTransformプロパティを設定して色を変えます。

screen_mcが落下するタイルを描画する領域のムービークリップで、同サイズのマスクをかけています。

foor_mcが床面反射を描画するムービークリップで、下に向かって透過するようにアルファマスクをかけています。

フレーム毎にしてる処理は2つあって、ひとつは一定の確率でタイルムービークリップを作るというモノです。タイルには落下するための処理と、クリックされたときに背景の色を変えるイベントハンドラをくっつけています。

もうヒトツの処理は最後のreflectメソッドで、床面の反射を描画してます。縮小率と下部の高さから上部ムービークリップから切り出すサイズを算出し、反転/縮小と位置をMatrixで指定して、BitmapDataとして切り出しています。

テーマ:Flash - ジャンル:コンピュータ

2007.06.08 | | Comments(0) | Trackback(0) | Flash/ActionScript

Flex2でも画像をタイル状に分割する

画像をタイル状に分割するエントリと同じようなモノをFlex2でも作ってみました。




フラッシュ版と同じように、横/縦の分割数を入力して「分割」ボタンを押すとタイルが生成されます。

ソースコードはこんなカンジ。

package {
import flash.display.*;
import flash.events.*;
// 画像をタイル状に分割するサンプル
public class Tile extends Sprite {
// 横方向分割数入力欄
private var colInput:LabelInput;
// 縦方向分割数入力欄
private var rowInput:LabelInput;
// 分割ボタン
private var splitBtn:LabelButton;
// 元画像
[Embed(source='image.jpg')]
private var ImageBitmap:Class;
private var imageBitmap:Bitmap;
// タイルの配列
private var tileArray:Array;
// コンストラクタ
public function Tile() {
// 横方向分割数入力欄作成
colInput = new LabelInput("横", "12");
addChild(colInput);
// 縦方向分割数入力欄作成
rowInput = new LabelInput("縦", "9");
rowInput.x = 70;
addChild(rowInput);
// 分割ボタン
splitBtn = new LabelButton(" 分割 ");
splitBtn.x = 140;
splitBtn.addEventListener(MouseEvent.CLICK,
onSplitBtnClick);
addChild(splitBtn);
// 画像読み込み
imageBitmap = new ImageBitmap();
imageBitmap.x = 10;
imageBitmap.y = 30;
addChild(imageBitmap);
}
// 分割ボタンクリック
private function onSplitBtnClick(evt:Event):void {
// すでに分割済みなら消去
if (tileArray) {
for each(var tile:Sprite in tileArray) {
tile.parent.removeChild(tile);
}
}
// タイルを生成
tileArray = TileBuilder.build(imageBitmap,
int(colInput.inputText),
int(rowInput.inputText),
this);
// 元画像のアルファ値を変化させる
imageBitmap.alpha = 0.25
}
}
}
import flash.display.*;
import flash.text.*;
import flash.geom.*;
import flash.events.*;
// タイル生成クラス
class TileBuilder {
// 指定したソース画像からタイルを生成し、戻します。
public static function build(src:Bitmap,
cols:int,
rows:int,
container:Sprite):Array {
var tileArray:Array = new Array();
// タイルのサイズ
var w:Number = src.width / cols;
var h:Number = src.height / rows;
// グラデーション用設定
var go:Number = 1;
var gw:Number = w - 2 * go;
var gh:Number = h - 2 * go;
var gMtx:Matrix = new Matrix();
gMtx.createGradientBox(gw, gh, Math.PI / 2);
// ハイライト用設定
var ho:Number = 1;
var hw:Number = w - 2 * ho;
var hh:Number = h * 0.4;
var hMtx:Matrix = new Matrix();
hMtx.createGradientBox(hw, hh, Math.PI / 2);
// タイル生成
for (var iy:int = 0; iy < rows; iy++) {
for (var ix:int = 0; ix < cols; ix++) {
// 画像データの切り出し
var bitmap:BitmapData
= Clipper.clip(src, w * ix, h * iy, w, h);
// Sprite作成
var tile:Sprite = new Sprite();
var g:Graphics = tile.graphics;
g.beginBitmapFill(bitmap);
g.moveTo(0, 0);
g.lineTo(0, h);
g.lineTo(w, h);
g.lineTo(w, 0);
g.lineTo(0, 0);
g.endFill();
// グラデーション
g.beginGradientFill("linear",
[0x000000, 0xFFFFFF, 0xFFFFFF],
[0.6, 0, 0.6],
[0, 127, 255],
gMtx);
g.moveTo(go, go);
g.lineTo(go, go + gh);
g.lineTo(go + gw, go + gh);
g.lineTo(go + gw, go);
g.lineTo(go, go);
g.endFill();
// ハイライト
g.beginGradientFill("linear",
[0xFFFFFF, 0xFFFFFF],
[0.95, 0.2],
[0, 255],
hMtx);
g.moveTo(ho, ho);
g.lineTo(ho, ho + hh);
g.lineTo(ho + hw, ho + hh);
g.lineTo(ho + hw, ho);
g.lineTo(ho, ho);
g.endFill();
// 位置
tile.x = src.x + w * ix;
tile.y = src.y + h * iy;
// ドラッグを可能にする
tile.useHandCursor = true;
tile.addEventListener(MouseEvent.MOUSE_DOWN,
function(evt:MouseEvent):void {
// このタイルを最前面に
evt.target.parent.setChildIndex(evt.target,
evt.target.parent.numChildren - 1);
// ドラッグ開始
evt.target.startDrag();
});
tile.addEventListener(MouseEvent.MOUSE_UP,
function(evt:MouseEvent):void {
// ドラッグ終了
evt.target.stopDrag();
});
// 親と配列に追加
tileArray.push(tile);
container.addChild(tile);
}
}
return tileArray;
}
}
// 画像クリッピングクラス
class Clipper {
// 指定した位置/サイズで画像を切り取ります。
public static function clip(src:Bitmap,
x:Number,
y:Number,
w:Number,
h:Number):BitmapData {
// 切り取りサイズ
var rect:Rectangle = new Rectangle(0, 0, w, h);
// 位置
var mtx:Matrix = new Matrix();
mtx.tx = -x;
mtx.ty = -y;
// 切り取り
var bitmap:BitmapData = new BitmapData(w, h, true);
bitmap.draw(src,
mtx,
new ColorTransform(),
"normal",
rect,
true);
return bitmap;
}
}
// ラベル付き入力フィールド
class LabelInput extends Sprite {
// ラベル
private var label:TextField;
// 入力フィールド
private var input:TextField;
// コンストラクタ
public function LabelInput(labelText:String,
inputDefault:String) {
// フォーマット
var format:TextFormat=new TextFormat();
format.font = "_等幅";
format.size = 10;
format.color = 0x000000;
// ラベル生成
label = new TextField();
label.setTextFormat(format);
label.autoSize = TextFieldAutoSize.LEFT;
label.text = labelText;
addChild(label);
// 入力欄生成
input = new TextField();
input.border = true;
input.type = TextFieldType.INPUT;
input.setTextFormat(format);
input.x = label.x + label.width;
input.width = 50;
input.height = label.height;
input.text = inputDefault;
addChild(input);
}
// 入力文字列を戻します。
public function get inputText():String {
return input.text;
}
}
// ラベル付きボタン
class LabelButton extends Sprite {
// コンストラクタ
public function LabelButton(labelText:String) {
// フォーマット
var format:TextFormat=new TextFormat();
format.font = "_等幅";
format.size = 10;
format.color = 0x000000;
// ラベル生成
var label:TextField = new TextField();
label.setTextFormat(format);
label.text = labelText;
label.autoSize = TextFieldAutoSize.CENTER;
label.border = true;
label.background = true;
label.backgroundColor = 0xdddddd;
label.selectable = false;
label.mouseEnabled = false;
addChild(label);

buttonMode = true;
}
}
Tileがメインのクラスです。コンストラクタで入力欄やらボタンやら元画像を配置しています。

onSplitBtnClick(Event)が「分割」ボタンをクリックしたときに実行するメソッドで、タイルを全消去してからTileBuilderクラスを使ってタイルを生成しています。

TileBuilderクラスのbuildメソッドでタイルとなるスプライトをnewしています。Sprite#graphicsプロパティのメソッドを使って画像/グラデーション/ハイライトを描画していますが、内容的にはFlashでMovieClipのドローメソッドを使うのと変わんないカンジです。
アルファが0~1なのがチガウといえばチガウ点。

タイルをドラッグするためのイベントハンドラはSprite#addEventListenerを使ってマス。マウスボタン押下時にはstartDrag以外にSpriteを前面に持ってくる処理をしてますが、このやり方もFlashとはチガウ点ですねー。

元画像からタイル用の画像を切り出す処理はClipper#clipでやってます。コレはflashとまったく同じやり方で、BitmapData#drawを使ってマス。

上記ソースコードを
mxmlc -default-size 450 400 -default-frame-rate=12 -default-background-color=0xFFFFFF Tile.as
とかやってswfにしてます。

テーマ:プログラミング - ジャンル:コンピュータ

2007.06.01 | | Comments(0) | Trackback(0) | Flex2

«  | HOME |  »

プロフィール

HundredthMonkey

Author:HundredthMonkey
プログラマ。

ブロとも申請フォーム

この人とブロともになる

メールフォーム

名前:
メール:
件名:
本文:

ブログ内検索


上記広告は1ヶ月以上更新のないブログに表示されています。新しい記事を書くことで広告を消せます。