スポンサーサイト

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

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

アマゾンのトップページ風セレクト

正式には何て言うんだか知らないのですが、amazonのトップページにあらわれる商品画像がグルグル回るフラッシュ風のサンプルです。





マウスカーソルの位置によって、回転の速度/向きが変化します。あと、画像の上にマウスカーソルもってくと画像が青くふちどられます。

やってることは、透視変換を使った位置/サイズの調整、床反射、ロールオーバー時フィルタぐらいでしょうか。今回は、透視変換を使った位置/サイズの調整はクラスをわけてみました。

スクリプトですが、まずフレームアクションの方です。

// 回転速度係数
var speed:Number = 0.02;
// 回転半径
var r:Number = 250;
// 床反射アルファ
var reflectAlpha:Number = 0.6;
// 表示画像配列
var mc_array:Array = [image1_mc,
image2_mc,
image3_mc,
image4_mc,
image5_mc,
image6_mc];
// 表示スプライト配列を生成
var sp_array:Array = new Array();
for (var idx:uint = 0, iEnd = mc_array.length;
idx < iEnd;
idx++) {
sp_array.push(createSprite(mc_array[idx]));
}
// ロールオーバー時グローフィルタ
var gFilter:GlowFilter = new GlowFilter(0x0000FF,
0.6,
8,
8,
4,
1,
false,
false);
// 透視変換ボックス
var box:PerspectiveBox = new PerspectiveBox(300);
addChild(box);
box.x = stage.stageWidth / 2;
box.y = stage.stageHeight / 2;
// 回転処理
var angle:Number = 0;
addEventListener(Event.ENTER_FRAME,
function(e:Event) {
var dx:Number = stage.stageWidth / 2
- stage.mouseX;
angle += dx * speed;
var cnt:uint = sp_array.length;
for (var i:uint = 0; i < cnt; i++) {
var ang:Number = angle + i * 360 / cnt;
if (ang < 0) {
ang += 360;
} else if (ang > 360) {
ang -= 360;
}
var cos = Math.cos(ang * Math.PI / 180);
var sin = Math.sin(ang * Math.PI / 180);
box.removeObject(sp_array[i]);
sp_array[i].x = r * sin;
box.addObject(sp_array[i], r * -cos + 200);
}
});
// 指定したムービークリップを元に表示用スプライトを生成し、
// 戻します。
function createSprite(mc:MovieClip):Sprite {
var sp:Sprite = new Sprite();
// 床面反射
var bd:BitmapData
= new BitmapData(mc.width, mc.height, true, 0x000000);
var mtx:Matrix = new Matrix();
mtx.scale(1.0, -1.0);
mtx.ty = mc.height;
var rect:Rectangle = new Rectangle(0, 0, mc.width, mc.height);
bd.draw(mc,
mtx,
new ColorTransform(),
BlendMode.NORMAL,
rect,
true);
var bitmap:Bitmap = new Bitmap(bd);
bitmap.smoothing = true;
sp.addChild(bitmap);
bitmap.x = -mc.width / 2;
bitmap.y = 0;
// グラデーション
var msk:Sprite = new Sprite();
var g:Graphics = msk.graphics;
mtx = new Matrix();
mtx.createGradientBox(bitmap.width,
bitmap.height,
Math.PI / 2);
g.beginGradientFill(GradientType.LINEAR,
[0xFFFFFF, 0xFFFFFF],
[reflectAlpha, 1.0],
[0, 255],
mtx);
g.moveTo(0, 0);
g.lineTo(0, bitmap.height);
g.lineTo(bitmap.width, bitmap.height);
g.lineTo(bitmap.width, 0);
g.lineTo(0, 0);
g.endFill();
sp.addChild(msk);
msk.x = bitmap.x;
msk.y = bitmap.y;
// ムービークリップ
sp.addChild(mc);
mc.x = -mc.width / 2;
mc.y = -mc.height;
mc.addEventListener(MouseEvent.MOUSE_OVER,
function (e:Event) {
e.target.filters = [gFilter];
});
mc.addEventListener(MouseEvent.MOUSE_OUT,
function (e:Event) {
e.target.filters = [];
});
// y座標
sp.y = 100;
return sp;
}
image1_mc, image2_mc, ...というのは表示する画像をシンボル化したモノです。ですが、実際表示するのはコレ+床反射画像を含むスプライトで、これはcreateSpriteメソッドで作ってsp_array配列に入れてます。

createSpriteメソッドでは、表示画像を上下反転した画像を作ってその上に白いグラデーション画像をかぶせるのと、表示画像のマウスオーバーでフィルタをセット/マウスアウトでフィルタ解除の設定をしてます。あと、作ったスプライトのy座標も設定しています。サンプルではy座標に100を設定してるので、視点の中心よりも下に画像が表示されます。また生成したスプライトは、表示画像の下辺の中央が基準点になります。

画像マウスオーバー時のふちどりにはGlowFilterを使ってマス。パラメータはテキトーです。

PerspectiveBoxは今回作成したクラスで、子を透視変換して表示するスプライトです。コイツをステージ中央に配備しています。

回転についてはENTER_FRAMEイベントハンドラで、マウスカーソルの位置からx座標/z座標を算出しています。y座標は生成時のままです。ココで算出した座標をPerspectiveBoxが透視変換して最終的なx座標/y座標/幅/高さが決定します。

そんで、PerspacetiveBoxのソースコードです。
package {
import flash.display.*;
/**
* 表示オブジェクトを遠近法表現するボックス。
*/
public class PerspectiveBox extends Sprite {
/** 表示オブジェクトの配列 */
private var _obj_array:Array;
/** スクリーンまでの距離 */
private var _distance:Number;
/**
* コンストラクタ。
*/
public function PerspectiveBox(distance:Number = 100) {
_obj_array = new Array();
_distance = distance;
}
/**
* オブジェクトを追加します。
* @param obj 追加する表示オブジェクト
* @param z 表示オブジェクトのz座標
*/
public function addObject(obj:DisplayObject, z:Number) {
removeObject(obj);
var item:Object = new Object();
_obj_array.push(item);
addChild(obj);
item.obj = obj;
item.orgX = obj.x;
item.orgY = obj.y;
item.orgW = obj.width;
item.orgH = obj.height;
item.z = z;
doPerspective();
}
/**
* 指定したオブジェクトをボックスから削除します。
* @param obj 削除するオブジェクト
*/
public function removeObject(obj:DisplayObject) {
var idx:int = indexOf(obj);
if (idx >= 0) {
var item:Object = _obj_array[idx];
item.obj.width = item.orgW;
item.obj.height = item.orgH;
item.obj.x = item.orgX;
item.obj.y = item.orgY;
_obj_array.splice(idx, 1);
removeChild(item.obj);
}
}
/**
* 指定したオブジェクトのインデックスを戻します。
* @return オブジェクトのインデックス。
*/
public function indexOf(obj:DisplayObject):int {
for (var i:uint = 0, iEnd:uint = _obj_array.length;
i < iEnd;
i++) {
var item:Object = _obj_array[i];
if (item.obj == obj) {
return i;
}
}
return -1;
}
/**
* 遠近法に基づき表示オブジェクトの位置/サイズを調整します。
*/
private function doPerspective() {
for each (var item:Object in _obj_array) {
// 縮小率
var s:Number = _distance / (_distance + item.z);
// 位置
item.obj.x = item.orgX * s;
item.obj.y = item.orgY * s;
// サイズ
item.obj.width = item.orgW * s;
item.obj.height = item.orgH * s;
}
// depth
_obj_array.sortOn("z", Array.DESCENDING | Array.NUMERIC);
for (var i:uint = 0, iEnd:uint = _obj_array.length;
i < iEnd;
i++) {
setChildIndex(_obj_array[i].obj, i);
}
}
}
}
_obj_arrayフィールドは表示オブジェクトの情報の配列で、表示オブジェクト(サンプルではフレームアクションで生成したスプライト)/元の位置とサイズ/z座標を持つオブジェクトの配列です。_distanceは視点から表示スクリーンまでの距離でコンストラクタで指定します。透視変換で縮小率を決定するのに使いマス。

addObjectメソッドで、透視変換して表示するオブジェクトを追加します。このときにz座標も指定します。表示オブジェクトや元のサイズやz座標をプロパティに持つオブジェクトを生成して、_obj_arrayに追加しています。

removeObjectメソッドは、addObjectメソッドで追加した表示オブジェクトを透視変換の対象から外します。このとき、位置/サイズはaddObject時の状態に戻しています。

indexObjectメソッドは、指定した表示オブジェクトが_obj_array配列のどこに保持されているかを戻します。見つからなかったら-1デス。

doPerspectiveメソッドが透視変換をするメソッドです。_distanceとz座標から縮小率を算出して、位置とサイズを調整してます。あと、z座標に従って重なり順も調整しています。

スポンサーサイト

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

2007.07.22 | | Comments(1) | Trackback(0) | Flash CS3

Flash CS3でアフィン変換

以前エントリしたアフィン変換のFlash CS3バージョンです。





画像の左上/右上/左下にある丸のいずれかをドラッグすると、それにあわせて画像が変形します。

やってること自体は以前のエントリと同じで、対象のtransform.matrixプロパティに3つの丸の座標をモトに算出した値をセットしています。

フレームアクションはこんなカンジです。

// ポインタにイベントリスナを登録する
topleft_mc.addEventListener(MouseEvent.MOUSE_DOWN,
onPointMouseDown);
topleft_mc.addEventListener(MouseEvent.MOUSE_UP,
onPointMouseUp);
topright_mc.addEventListener(MouseEvent.MOUSE_DOWN,
onPointMouseDown);
topright_mc.addEventListener(MouseEvent.MOUSE_UP,
onPointMouseUp);
bottomleft_mc.addEventListener(MouseEvent.MOUSE_DOWN,
onPointMouseDown);
bottomleft_mc.addEventListener(MouseEvent.MOUSE_UP,
onPointMouseUp);
// 対象の幅と高さ
var w:Number = image_mc.width;
var h:Number = image_mc.height;
// ポインタをドラッグ可能にするイベントハンドラ
function onPointMouseDown(evt:Event) {
evt.target.addEventListener(Event.ENTER_FRAME,
onPointEnterFrame);
}
function onPointMouseUp(evt:Event) {
evt.target.removeEventListener(Event.ENTER_FRAME,
onPointEnterFrame);
}
// フレーム毎の処理
function onPointEnterFrame(evt:Event) {
if (evt.target.x != stage.mouseX ||
evt.target.y != stage.mouseY) {
evt.target.x = stage.mouseX;
evt.target.y = stage.mouseY;
// アフィン変換
image_mc.transform.matrix
= new Matrix((topright_mc.x - topleft_mc.x) / w,
(topright_mc.y - topleft_mc.y) / w,
(bottomleft_mc.x - topleft_mc.x) / h,
(bottomleft_mc.y - topleft_mc.y) / h,
topleft_mc.x,
topleft_mc.y);
}
}
topleft_mc、topright_mc、bottomleft_mcは左上/右上/左下の青い円で、MOUSE_DOWNイベントハンドラとしてonPointMouseDownメソッド、MOUSE_UPイベントハンドラとしてonPointMouseUpメソッドを登録しています。

onPointMouseDownメソッドでは、イベントターゲット(3つの青丸のいずれか。クリックしたヤツ)にonPointEnterFrameメソッドをENTER_FRAMEイベントハンドラとして登録しています。onPointMouseUpメソッドではソレを外してマス。なので、青丸のいずれかをドラッグしている間だけonPointEnterFrameメソッドは実行されます。

onPointEnterFrameメソッドにアフィン変換を行う処理を記述しています。イベントターゲットの座標としてマウスカーソル位置をセットし、image_mc.transform.matrixプロパティを設定しています。image_mcは画像のムービークリップです。

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

2007.07.19 | | Comments(2) | Trackback(0) | Flash CS3

パースのついた回転

y軸を中心に画像がグルグル回転するサンプルです。





マウスカーソルの位置によって、回転の向き/速度が変わります。

基本的な考え方は、画像をスライスして変形させる円筒っぽい画像表示エントリと同様に、画像を細かく刻んでソレゾレを移動/変形するモノです。

今回のサンプルでは、2枚の画像を幅1ピクセルで切り刻んでソイツラに3次元座標をもたせて透視変換して表示というカンジです。

スクリプトは、切り刻んだ画像を保持するSpriteの継承クラスを用意して、フレームアクションでそのクラスのインスタンスを生成という格好にしました。

スクリプトのソースは、こんなカンジです。

package {
import flash.display.*;
import flash.geom.*;
/**
* 表示オブジェクトを水平回転するためのクラス。
*/
public class HorizontalRotater extends Sprite {
/** スクリーンまでの距離 */
private var _distance:Number;
/** 元になる表示オブジェクト */
private var _src:DisplayObject;
/** スライスした画像 */
private var _slice_array:Array;
/**
* コンストラクタ。
* @param src 元になる表示オブジェクト
* @param distance スクリーンまでの距離
*/
public function HorizontalRotater(src:DisplayObject,
distance:Number) {
this._src = src;
this._distance = distance;
_slice_array = createSliceArray();
rotate(0);
this.x = src.x + src.width / 2;
this.y = src.y + src.height / 2;
}
/**
* スライス画像を生成し、戻します。
*/
private function createSliceArray():Array {
var ary:Array = new Array();
// z座標
var oz:Number = _src.width / 2;
// 縮小率
var s:Number = _distance / (_distance + oz);
// 縮小前のサイズ
var sw:Number = _src.width / s;
var sh:Number = _src.height / s;
// 切り出し用マトリックス
var mtx:Matrix = new Matrix();
mtx.scale(1 / s, 1 / s);
var ct:ColorTransform = new ColorTransform();
var rect:Rectangle = new Rectangle(0, 0, 1, sh);
// 幅1ピクセルにスライスする
for (var i:int = 0; i < sw; i++) {
// BitmapData切り出し
var bd:BitmapData = new BitmapData(1, _src.height / s);
mtx.tx = -i;
bd.draw(_src, mtx, ct, BlendMode.NORMAL, rect, false);
// ビットマップを生成し、配列に保存
var bitmap:Bitmap = new Bitmap(bd);
bitmap.x = i - sw / 2;
bitmap.y = - bitmap.height / 2;
bitmap.visible = _src.visible;
addChild(bitmap);
ary.push({bitmap:bitmap,
orgx:bitmap.x,
orgy:bitmap.y,
orgheight:bitmap.height,
oz:oz});
}
return ary;
}
/**
* 指定した角度に画像を回転します。
* @param angle 角度
*/
public function rotate(angle):void {
var cos:Number = Math.cos(angle * Math.PI / 180);
var sin:Number = Math.sin(angle * Math.PI / 180);
var d:Number = _distance;
for each (var item:Object in _slice_array) {
var bitmap:Bitmap = item.bitmap;
var orgx:Number = item.orgx;
var orgy:Number = item.orgy;
// 角度から、x座標/z座標を求める
var x:Number = orgx * cos;
var z:Number = item.oz - orgx * sin;
// 縮小率
var s:Number = d / (d + z);
// 位置/高さを設定
bitmap.x = Math.round(x * s);
bitmap.height = item.orgheight * s;
bitmap.y = Math.round(orgy * s);
}
}
}
}
ファイル名はHorizontalRotater.asになります。回転させたい画像と仮想スクリーンまでの距離を指定してインスタンスを生成して、角度を指定してrotateメソッドを実行すると、指定した角度で画像が表示されマス。

createSliceArrayは画像を幅1ピクセルずつ切り出すメソッドで、コンストラクタから実行します。初期のz座標もここで指定してるのですが、その値は0ではなく画像の幅の半分です。これは画像を回転させてもz座標がマイナスにならないようにするためデス。

z座標が0ではないので、そのまま透視変換して表示すると表示サイズが元のものより小さくなってしまいます。元と同じ大きさで表示するために画像切り出し時にMatrix#scaleを使って拡大して切り出しています。

rotateメソッドは角度をつけて表示するためのメソッドで、まず指定された角度からx座標とz座標を算出します(回転してもy座標はかわらない)。その後ソレゾレのz座標の値を元に透視変換後の位置/高さを設定しています。

で、フレームアクションからこのクラスを使っています。
var front:HorizontalRotater
= new HorizontalRotater(obj_mc, 350);
addChild(front);
obj_mc.visible = false;
var back:HorizontalRotater
= new HorizontalRotater(onion_mc, 350);
addChild(back);
onion_mc.visible = false;
back.visible = false;
var ox:Number = front.x;
var rate:Number = 0.05;
var angle:Number = 0;
addEventListener(Event.ENTER_FRAME,
function(e:Event) {
if (angle < 0) {
angle += 360;
}
angle = (angle + (stage.mouseX - ox) * rate)
% 360;
if (angle > 90 && angle <= 270) {
front.visible = false;
back.visible = true;
back.rotate((angle + 180) % 360);
} else {
front.visible = true;
back.visible = false;
front.rotate(angle);
}
});
obj_mc/onion_mcは画像をムービークリップシンボル化したものデス。それぞれのHorizontalRotaterインスタンスを生成して、それをaddChildしています。

ENTER_FRAMEイベントで、マウスカーソルの位置から角度を変化させてrotateメソッドを実行しています。角度によってどちらのHorizontalRotaterインスタンスを表示するかを切り替えています。

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

2007.07.11 | | Comments(0) | Trackback(0) | Flash CS3

Flash CS3でレンズ

マウスカーソルを画像の上にもってくと、レンズっぽく拡大されます。
レンズで部分拡大のCS3版デス。





以前エントリしたモノと同じで、入力値にあわせてDisplacementMapFilterを作って、マウスカーソル周辺の画像に適用しています。
右側に出る青緑っぽい画像が、生成したマップ画像です。

今回は、レンズ用のDisplacementMapFilterを生成するファクトリクラスとフレームアクションで構成してみました。

ファクトリクラス(LensFilterFactory.as)はこんなカンジです。

package {
import flash.display.BitmapData;
import flash.filters.DisplacementMapFilter;
import flash.geom.Point;
/**
* レンズフィルタのファクトリ。
*/
public class LensFilterFactory {
/**
* レンズとしてはたらくDisplacementMapFilterを生成し、
* 戻します。
* @param size レンズの直径
* @param r レンズの曲率半径
* @param f レンズの焦点距離
* @return レンズとしてはたらくDisplacementMapFilter
*/
public static function create(size:Number,
r:Number,
f:Number)
:DisplacementMapFilter {
var mapData:BitmapData
= new BitmapData(size, size, false, 0xFF008080);
var o:Number = size / 2;
var o2:Number = o * o;
var r2:Number = r * r;
var y:Number;
var dY:Number;
var dY2:Number;
var x:Number;
var dX:Number;
var dR2:Number;
var l:Number;
var d:Number
// 調整値を割り出す
var maxY:Number = 0;
var maxX:Number = 0;
for (y = 0; y < size; y++) {
dY = y - o;
dY2 = dY * dY;
for (x = 0; x < size; x++) {
dX = x - o;
dR2 = dX * dX + dY2;
// ピクセルが、レンズムービークリップの内接円に
// 入っている場合のみ処理
if (dR2 < o2) {
// ずれ
l = Math.sqrt(r2 - dR2) - Math.sqrt(r2 - o2);
d = l / (f + l);
// 最大値設定
maxY = Math.max(maxY, Math.abs(dY * d));
maxX = Math.max(maxX, Math.abs(dX * d));
}
}
}
var yAdj:Number = 128 / (maxY + 1);
var xAdj:Number = 128 / (maxX + 1);
// ビットマップ生成
for (y = 0; y < size; y++) {
dY = y - o;
dY2 = dY * dY;
for (x = 0; x < size; x++) {
dX = x - o;
dR2 = dX * dX + dY2;
// ピクセルが、レンズムービークリップの内接円に
// 入っている場合のみ処理
if (dR2 < o2) {
// ずれ
l = Math.sqrt(r2 - dR2) - Math.sqrt(r2 - o2);
d = l / (f + l);
// ピクセルの色
var yC:Number = -Math.floor(dY * d * yAdj);
var xC:Number = -Math.floor(dX * d * xAdj);
var c:Number = 0xFF000000
+ (0x80 + yC) * 0x100
+ (0x80 + xC);
// ピクセルを描画する
mapData.setPixel(x, y, c);
}
}
}
// フィルタ生成
var filter:DisplacementMapFilter
= new DisplacementMapFilter(mapData,
new Point(),
4,
2,
Math.ceil(256 / xAdj),
Math.ceil(256 / yAdj));
return filter;
}
}
}
staticなcreateメソッドを、レンズの直径/曲率半径/焦点距離をパラメータにして実行すると、レンズ用のマップ画像がセットされたDisplacementMapFilterを生成して戻します。
コレで作ったフィルタを、レンズ拡大したい画像に適用すればイイって寸法デス。

で、サンプルフラッシュのフレームアクションはこんなカンジです。
import flash.filters.DisplacementMapFilter;
// レンズ
var lens:Sprite = new Sprite();
lens.mouseEnabled = false;
lens.visible = false;
addChild(lens);
// レンズ部分画像
var clipImage:Bitmap;
// 置き換えビットマップ
var mapBitmap:Bitmap;
// 設定ボタンを押したとき
test_btn.addEventListener(MouseEvent.CLICK, setupFilter);
var size:Number;
var r:Number;
var f:Number;
setupFilter(null);
// 設定にしたがいレンズを生成しセットする
function setupFilter(evt:Event) {
size = Number(size_txt.text);
r = Number(r_txt.text);
f = Number(f_txt.text);
var filter:DisplacementMapFilter
= LensFilterFactory.create(size, r, f);
if (mapBitmap) {
removeChild(mapBitmap);
}
mapBitmap = new Bitmap(filter.mapBitmap);
addChild(mapBitmap);
mapBitmap.x = 360 - mapBitmap.width / 2;
mapBitmap.y = 160 - mapBitmap.height / 2;
lens.filters = [filter];
}
// マウスカーソルが画像の上にあったらレンズ処理
image_mc.addEventListener(MouseEvent.MOUSE_OVER,
function(e:Event) {
e.target.addEventListener(MouseEvent.MOUSE_MOVE, onLensMove);
lens.visible = true;
Mouse.hide();
});
image_mc.addEventListener(MouseEvent.MOUSE_OUT,
function(e:Event) {
e.target.addEventListener(MouseEvent.MOUSE_MOVE, onLensMove);
lens.visible = false;
Mouse.show();
});
// レンズが移動したら対象画像を更新する
function onLensMove(evt:Event) {
var bitmap:BitmapData = new BitmapData(size, size);
var mtx:Matrix = new Matrix();
mtx.tx = -image_mc.mouseX + size / 2;
mtx.ty = -image_mc.mouseY + size / 2;
bitmap.draw(image_mc,
mtx,
new ColorTransform(),
BlendMode.NORMAL,
new Rectangle(0, 0, size, size),
false);
if (clipImage) {
lens.removeChild(clipImage);
}
clipImage = new Bitmap(bitmap);
lens.addChild(clipImage);
lens.x = mouseX - lens.width / 2;
lens.y = mouseY - lens.height / 2;
}
lesというのがレンズ部分を示すスプライトで、先ほどのファクトリクラスを使って作ったDisplacementMapFilterオブジェクトをfiltersにセットしてあります。
画像の上でマウスカーソルを動かしたらonLensMoveメソッドでレンズの大きさ分画像を切り取り、lensにセットしています。
clipImageが、切り取った画像です。

mapBitmapは、作ったDisplacementMapFilterオブジェクトで使用しているマップ画像をBitmapオブジェクトにしたもので、画像の右側に表示しています。

size_txtがサイズ入力欄、r_txtが曲率半径入力欄、f_txtが焦点距離入力欄、test_btnが設定ボタンです。

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

2007.07.05 | | Comments(0) | Trackback(1) | Flash CS3

DisplacementMapFilterでパースをつけてみる

DisplacementMapFilterを使ってムービークリップ等にパースをつけるサンプル作ろうとしたんですが、あまりうまくいかなかったデス。




傾きに適当な数字(0~90)を入れて「実行」ボタンを押すと、画像がビミョウにそれっぽく変換されマス。
左側のは上辺を固定して奥に向かって傾けたカンジ、右側のは下辺を固定して奥に向かって傾けたカンジです。
マウスを画像の上にもっていくと、置き換えに使用したマップ画像が表示されます。

ソースですが、DisplacementMapFilterを使って変形する部分はPerspectiveUtil.asという名前にしてこんな風にしました。

package {
import flash.display.*;
import flash.filters.*;
import flash.geom.*;
/**
* 遠近処理加工をするクラス。
*/
public class PerspectiveUtil {
/** 上辺をスクリーンに接して傾けることを示す定数 */
public static const CONTACT_TOP = "top";
/** 下辺をスクリーンに接して傾けることを示す定数 */
public static const CONTACT_BOTTOM = "bottom";
/**
* 指定したオブジェクトに遠近処理を加えます。
* @param src 処理対象の表示オブジェクト
* @param angle 傾き角
* @param screenDepth スクリーンまでの距離
* @param contact どの辺をスクリーンに接して傾けるか?
*/
public static function lean(src:DisplayObject,
angle:Number,
screenDepth:Number,
contact:String = "top")
:BitmapData {
// 傾きが0ならなにもしない
if (angle == 0) {
return null;
}
var d:Number = screenDepth;
var rad:Number = angle * Math.PI / 180;
var cos:Number = Math.cos(rad);
var sin:Number = Math.sin(rad);
var tan:Number = Math.tan(rad);
// 最終的なサイズ
var w:Number = Math.ceil(src.width);
var h:Number = Math.ceil(src.height * cos);
src.width = w;
src.height = h;
// 仮想スクリーン上での座標
var vX:Function;
var vY:Function;
if (contact == CONTACT_TOP) {
vX = function(x:Number):Number {
return x - w / 2;
};
vY = function(y:Number):Number {
return y;
};
} else {
vX = function(x:Number):Number {
return x - w / 2;
}
vY = function(y:Number):Number {
return h - y;
};
}
// 置き換えビットマップ生成
var bitmap:BitmapData = new BitmapData(w, h);
// 変化量の最大値を求める
var y:int = 0;
var x:int = 0;
var s:Number;
var tY:Number;
var tX:Number;
var maxY:Number = 0;
var maxX:Number = 0;
for (y = 0; y < h; y++) {
tY = vY(y);
s = d / (d + tan * tY);
maxY = Math.max(maxY, Math.abs((1 - s) * tY));
for (x = 0; x < w; x++) {
tX = vX(x);
maxX = Math.max(maxX, Math.abs((1 - s) * tX));
}
}
// 調整値
var yAdj:Number = maxY == 0 ? 1 : (127 / maxY);
var xAdj:Number = maxX == 0 ? 1 : (127 / maxX);
// 色を求める
for (y = 0; y < h; y++) {
tY = vY(y);
s = d / (d + tan * tY);
var yC:int
= Math.round((contact == CONTACT_TOP ? 1 : -1)
* (1 - s) * tY * yAdj);
for (x = 0; x < w; x++) {
tX = vX(x);
var xC:int = Math.round((1 - s) * tX * xAdj);
var c:Number = 0xFF000000
+ (0x80 + yC) * 0x100
+ xC + 0x80;
bitmap.setPixel(x, y, c);
}
}
// フィルタを作成
var filter:DisplacementMapFilter
= new DisplacementMapFilter(bitmap,
new Point(),
BitmapDataChannel.BLUE,
BitmapDataChannel.GREEN,
256 / xAdj,
256 / yAdj,
"color",
0,
0);
src.filters = [filter];
return bitmap;
}
}
}
やってることは、まず透視変換抜きで変形(高さを変更)して、その後透視変換を行うDisplacementMapFilterを生成してマス。
戻り値はフィルタに使用した置き換えマップ画像デス。

そんでコレを使うフレームアクションのほーは、こんなカンジです。
import flash.display.*;
// 置き換えビットマップ
var topBitmap:Bitmap;
var bottomBitmap:Bitmap;
// 元のサイズ
var topHeight:Number = test_top_mc.height;
var bottomHeight:Number = test_bottom_mc.height;
// 実行ボタン
btn_mc.addEventListener(MouseEvent.CLICK, onBtnClick);
function onBtnClick(evt:Event) {
// 対象の状態をリセットする
test_top_mc.filters = null;
test_top_mc.height = topHeight;
test_bottom_mc.filters = null;
test_bottom_mc.height = bottomHeight;
// 角度
var angle:Number = Number(angle_txt.text);
// 上辺がスクリーンに接した傾き
if (topBitmap) {
removeChild(topBitmap);
topBitmap = null;
}
topBitmap = new Bitmap(PerspectiveUtil.lean(test_top_mc,
angle,
1000));
addChild(topBitmap);
topBitmap.x = test_top_mc.x;
topBitmap.y = test_top_mc.y;
topBitmap.visible = false;
test_top_mc.addEventListener(MouseEvent.ROLL_OVER,
function (e:Event) {
topBitmap.visible = true;
});
test_top_mc.addEventListener(MouseEvent.ROLL_OUT,
function (e:Event) {
topBitmap.visible = false;
});
// 下辺がスクリーンに接した傾き
if (bottomBitmap) {
removeChild(bottomBitmap);
bottomBitmap = null;
}
bottomBitmap
= new Bitmap(PerspectiveUtil.lean(test_bottom_mc,
angle,
1000,
PerspectiveUtil.CONTACT_BOTTOM));
addChild(bottomBitmap);
bottomBitmap.x = test_bottom_mc.x;
bottomBitmap.y = test_bottom_mc.y;
bottomBitmap.visible = false;
test_bottom_mc.addEventListener(MouseEvent.ROLL_OVER,
function (e:Event) {
bottomBitmap.visible = true;
});
test_bottom_mc.addEventListener(MouseEvent.ROLL_OUT,
function (e:Event) {
bottomBitmap.visible = false;
});
}
test_top_mcというのが左側の画像、test_bottom_mcというのが右側の画像デス。
topBitmap、bottomBitmapはそれぞれのPerspecriveUtil.leanメソッドの戻り値を保持する変数デス。画像にロールオーバーしたときに表示するようにしてます。

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

2007.07.01 | | Comments(0) | Trackback(0) | Flash CS3

«  | HOME |  »

プロフィール

HundredthMonkey

Author:HundredthMonkey
プログラマ。

ブロとも申請フォーム

この人とブロともになる

メールフォーム

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

ブログ内検索


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