水面。画像がゆがむはずだが・・・
水面を作成する。
@author SIBA
package
{
import flash.display.Bitmap;
import flash.display.BitmapData;
import flash.display.BitmapDataChannel;
import flash.display.Sprite;
import flash.events.Event;
import flash.events.MouseEvent;
import flash.filters.DisplacementMapFilter;
import flash.filters.DisplacementMapFilterMode;
import flash.geom.Matrix;
import flash.geom.Point;
import flash.display.Loader;
import flash.display.LoaderInfo;
import flash.system.LoaderContext;
import flash.system.Security;
import flash.net.URLRequest;
[SWF(width=800, height=600, backgroundColor=0xAADDFF)]
/**
* 水面を作成する。
* @author SIBA
*/
public class Main03 extends Sprite
{
// ----------------------------
// 定数
// ----------------------------
private const C1:Number = 0.5;
private const C2:Number = 0.005;
private const CC:Number = 1 / (1 + C2);
private const SCALE:int = 10;
private const FIELD_SIZE_X:int = 800 / SCALE + 2;
private const FIELD_SIZE_Y:int = 600 / SCALE + 2;
// ----------------------------
// メンバ変数
// ----------------------------
private var map:Bitmap; // 水面の画像
private var bitmapData:BitmapData; // 水面のデータ
private var field1:Array = []; // 前回の水面データ
private var field2:Array = []; // 現在の水面データ
private var dmf:DisplacementMapFilter; // 水面のゆがみを作るFilter
private var woterLayer:Sprite = new Sprite(); // 水面のレイヤ
private var objectLayer:Sprite = new Sprite(); // オブジェクトのレイヤ
// ----------------------------
// 初期化
// ----------------------------
public function Main03()
{
// レイヤーの配置
addChild(objectLayer);
addChild(woterLayer);
objectLayer.graphics.drawRect(0, 0, 800, 600);
// 水面の揺らぎを作るためのFilterを作成
var channel:int = BitmapDataChannel.ALPHA;
dmf = new DisplacementMapFilter(null, new Point(), channel, channel, 50, 50, DisplacementMapFilterMode.COLOR)
// 画像の配置
Security.loadPolicyFile("http://farm2.static.flickr.com/crossdomain.xml");
var context:LoaderContext = new LoaderContext(true);
var loader:Loader = new Loader();
loader.contentLoaderInfo.addEventListener(Event.COMPLETE, onComplete);
loader.load(new URLRequest("http://farm4.static.flickr.com/3180/3115974098_d1b27674ef.jpg?v=0"), context);
// 水面を表示するための画像を作成
bitmapData = new BitmapData(FIELD_SIZE_X, FIELD_SIZE_Y, true, 0xFFFFFFFF);
map = new Bitmap(bitmapData);
map.scaleX = SCALE;
map.scaleY = SCALE;
woterLayer.addChild(map);
// フィールドの初期化
for (var i:int=0; i<FIELD_SIZE_X; i++)
{
field1[i] = [];
field2[i] = [];
for (var j:int=0; j<FIELD_SIZE_Y; j++)
{
field1[i][j] = 0.0;
field2[i][j] = 0.0;
}
}
}
// ----------------------------
// 内部メソッド
// ----------------------------
/**
* 波を立てる。
* @param px 波を立てる位置(x座標)
* @param py 波を立てる位置(y座標)
* @param power
*/
private function put(px:Number, py:Number, power:Number):void
{
// 立てる波の情報
const r:uint = 5;
const beginX:int = (px - r < 1) ? 1 : px - r;
const endX:int = (px + r > FIELD_SIZE_X - 1) ? FIELD_SIZE_X - 1 : px + r;
const beginY:int = (py - r < 1) ? 1 : py - r;
const endY:int = (py + r > FIELD_SIZE_Y - 1) ? FIELD_SIZE_Y - 1 : py + r;
// 波の起点を作成
for (var xx:int=beginX; xx<endX; xx++)
{
for (var yy:int=beginY; yy<endY; yy++)
{
const d:Number = Point.distance(new Point(px, py), new Point(xx, yy));
if (d < r)
{
var p:Number = power * Math.cos(Math.PI/2 * d/r);
field1[xx][yy] += p;
field2[xx][yy] += p;
}
}
}
}
// ----------------------------
// イベント
// ----------------------------
private function onComplete(event:Event):void {
var loaderInfo:LoaderInfo = event.currentTarget as LoaderInfo;
var loader:Loader = loaderInfo.loader;
var bmp:BitmapData = new BitmapData(loader.width, loader.height, true, 0x00FFFFFF);
bmp.draw(loader);
var image:Bitmap = new Bitmap(bmp);
image.x = 400 - image.width/2;
image.y = 300 - image.height/2;
objectLayer.addChild(image);
addEventListener(Event.ENTER_FRAME, onEnterFrame);
stage.addEventListener(MouseEvent.MOUSE_MOVE, onMouseMove);
}
private function onMouseMove(event:MouseEvent):void
{
put(event.stageX/SCALE, event.stageY/SCALE, 15);
}
private function onEnterFrame(event:Event):void
{
// 初期化
var xx:int = 0;
var yy:int = 0;
// 波を描く
bitmapData.lock();
for (xx=1; xx<FIELD_SIZE_X; xx++)
{
for (yy=1; yy<FIELD_SIZE_Y; yy++)
{
var c:uint = Math.abs(field2[xx][yy]);
var a:uint = (c + 32 > 255) ? 255 : c + 32;
var r:uint = (c + 128 > 255) ? 255 : c + 128;
var g:uint = (c + 160 > 255) ? 255 : c + 160;
var b:uint = (c + 192 > 255) ? 255 : c + 192;
bitmapData.setPixel32(xx-1, yy-1, (a << 24) | (r << 16) | (g << 8) | b);
}
}
bitmapData.unlock();
// 波の動きを計算
for (xx=1; xx<FIELD_SIZE_X-1; xx++)
{
for (yy=1; yy<FIELD_SIZE_Y-1; yy++)
{
field1[xx][yy] = (field2[xx][yy] * (2 - 4 * C1) - field1[xx][yy] * (1 - C2)
+ (field2[xx][yy+1] + field2[xx][yy-1]
+ field2[xx-1][yy] + field2[xx+1][yy]) * C1) * CC;
}
}
// 次へ
const temp:Array = field1;
field1 = field2;
field2 = temp;
// 全体に水面エフェクト
var tempBmp:BitmapData = new BitmapData(map.width, map.height, true, 0x00FFFFFF);
var mat:Matrix = new Matrix();
mat.scale(map.scaleX, map.scaleY);
tempBmp.draw(map, mat);
dmf.mapBitmap = tempBmp
objectLayer.filters = [dmf];
}
}
}