[转]小日本写的模拟波浪的波动图,可以抽象出來做雙疊波

[url]http://bbs.9ria.com/viewthread.php?tid=71325&extra=page%3D1%26amp;orderby%3Ddateline%26amp;filter%3D86400[/url]

這個波形算法的抽象原型可以寫成類結構
package wave {
import flash.display.Sprite;
import flash.display.StageAlign;
import flash.display.StageScaleMode;
import flash.events.Event;
import flash.events.TimerEvent;
import flash.utils.Timer;
import flash.utils.getTimer;
import flash.geom.Point;

public class Wavef extends Sprite {
public var STAGE_W:uint;
public var STAGE_H:uint;
public var oriPointA:Point;
public var oriPointB:Point;

public const NUM:uint=200;//頂点数
protected var MOUSE_DIFF_RATIO:Number=.2;// (0<) 大きい程マウスに反応する--波动的比率
private const AUTO_INTERVAL:uint=3000;//オート波が起きる間隔 msec
private var vertexes:Array=[];//頂点
private var mdlPt:Array=[];//頂点の中点
//頂点の基本波からの位相差分
// 0:マウス
// 1:オート
private var diffPt:Array=[[],[]];// 鼠标推动后,在原先的位相上所要增加的位相值。
// 二维数组中,第一个数组存储根据鼠标拖动后产生的位相差,第二个存储自动产生的波动的位相差。
//波が起こるインデックス
// 0:マウス
// 1:オート
private var startIndex:Array=[0,0];
private var mouseOldY:int;
private var mouseNewY:int;
private var mouseDiff:Number=0;//mouseDiffGoal的缓冲
private var mouseDiffGoal:Number=0;//鼠标拖动后产生的位相差
private var autoTimer:Timer;
private var autoDiff:Number=0;//计时器自动生成的位相差
public function Wavef ( w:int = 800 , h:int = 300 ):void {
STAGE_W = w;
STAGE_H = h;

oriPointA = new Point ( 0 , STAGE_H );
oriPointB = new Point ( STAGE_W , STAGE_H );
for (var i:uint=0; i<NUM; i++) {
var vertex:Vertex=new Vertex(i,this);
vertexes.push( vertex );
//中点作成
if (i>1) {
mdlPt.push( new Point( (vertexes[i-1].x+vertexes[i].x)*0.5, (vertexes[i-1].y+vertexes[i].y)*0.5 ) );
}
//差分
diffPt[0].push( 0 );
diffPt[1].push( 0 );
}
mouseNewY=mouseY;
if (mouseNewY<0) {
mouseNewY=0;
} else if (mouseNewY > STAGE_H) {
mouseNewY=STAGE_H;
}
mouseOldY=mouseNewY;
addEventListener(Event.ENTER_FRAME, updateMouseDiff);
addEventListener(Event.ENTER_FRAME, updateWave);
autoTimer=new Timer(AUTO_INTERVAL);
autoTimer.addEventListener(TimerEvent.TIMER, generateAutoWave);
autoTimer.start();
}
private function generateAutoWave(tEvt:TimerEvent):void {
autoDiff=200;//自动生成100的位相差
startIndex[1] = Math.round( Math.random()*(NUM-1) );//在波形的随机位置自动产生波形抖动(产生位相差)
}
//--------------------------------------
// マウスY座標の差を計算
//--------------------------------------
private function updateMouseDiff(evt:Event):void {
mouseOldY=mouseNewY;
mouseNewY=mouseY;
if (mouseNewY<0) {
mouseNewY=0;
} else if (mouseNewY > STAGE_H) {
mouseNewY=STAGE_H;
}
mouseDiffGoal = (mouseNewY - mouseOldY) * MOUSE_DIFF_RATIO;//根据鼠标前后位移差设置波动起伏的位相差
}
//---------------------------------------
// 各種更新
//---------------------------------------
private function updateWave(evt:Event):void {
//それぞれの波の減衰
mouseDiff -= (mouseDiff - mouseDiffGoal)*0.3;
autoDiff-=autoDiff*0.9;//波形自动波动时的速率
//-------------------------------------
//波の基点
//-------------------------------------
//マウス波
var mX:int=mouseX;
if (mX<0) {
mX=0;
} else if (mX > STAGE_W-2) {
mX=STAGE_W-2;
}//-2はみ出さないための保険
startIndex[0] = 1+Math.floor( (NUM-2) * mX / STAGE_W );//startIndex[0]表示波形图上,鼠标拖动的那个点,用Math.floor是
//可以取到NUM个点里面x坐标小于当前鼠标x坐标的最大值
diffPt[0][startIndex[0]] -= ( diffPt[0][startIndex[0]] - mouseDiff )*0.99;
//自动波
diffPt[1][startIndex[1]] -= ( diffPt[1][startIndex[1]] - autoDiff )*0.99;
var i:int;
//------------------------------------
//差分更新
//-------------------------------------
//マウス波
//左側
var d:uint;
for (i=startIndex[0]-1; i >=0; i--) {
d=startIndex[0]-i;
if (d>15) {
d=15;
}
diffPt[0][i] -= ( diffPt[0][i] - diffPt[0][i+1] )*(1-0.01*d);
}
//右側
for (i=startIndex[0]+1; i < NUM; i++) {
d=i-startIndex[0];
if (d>15) {
d=15;
}
diffPt[0][i] -= ( diffPt[0][i] - diffPt[0][i-1] )*(1-0.01*d);
}
//オート波
//左側
for (i=startIndex[1]-1; i >=0; i--) {
d=startIndex[1]-i;
if (d>15) {
d=15;
}
diffPt[1][i] -= ( diffPt[1][i] - diffPt[1][i+1] )*(1-0.01*d);
}
//右側
for (i=startIndex[1]+1; i < NUM; i++) {
d=i-startIndex[1];
if (d>15) {
d=15;
}
diffPt[1][i] -= ( diffPt[1][i] - diffPt[1][i-1] )*(1-0.01*d);
}
//-------------------------------------
//各頂点更新
//-------------------------------------
for (i=0; i < NUM; i++) {
vertexes[i].updatePos( diffPt[0][i]+diffPt[1][i]);//更新波形上各点的位相,位相差等于鼠标抖动的和自动产生的,即为diffPt[0][i]+diffPt[1][i]
}
//-------------------------------------
//中点更新
//-------------------------------------
for (i=0; i < NUM-2; i++) {
mdlPt[i].y = (vertexes[i+1].y + vertexes[i+2].y)*0.5;//更新波形图上两点中点的位相,使波形图看起来更流畅
}
drawWave();
}
//---------------------------------------
// 描画
//---------------------------------------
private function drawWave():void {
var arr:Array = [];
var o:Operation;
arr [ arr.length ] = new Operation ( Operation.CLEAR );
//根据存储的vertexes和mdlPt数组里的各点位相,画贝塞尔曲线
o = new Operation ( Operation.FILL );
o.color = 0xFFFFFF;
arr [ arr.length ] = o;
//填充范圍邊界點
o = new Operation ( Operation.MOVE );
o.tox = oriPointB.x;
o.toy = oriPointB.y;
arr [ arr.length ] = o;
//畫
o = new Operation ( Operation.L_TO );
o.tox = oriPointA.x;
o.toy = oriPointA.y;
arr [ arr.length ] = o;
o = new Operation ( Operation.L_TO );
o.tox = vertexes[0].x;
o.toy = vertexes[0].y;
arr [ arr.length ] = o;
o = new Operation ( Operation.C_TO );
o.tox = mdlPt[0].x;
o.toy = mdlPt[0].y;
o.controlx = vertexes[1].x;
o.controly = vertexes[1].y;
arr [ arr.length ] = o;

for (var i:uint=2; i<NUM-2; i++) {
o = new Operation ( Operation.C_TO );
o.tox = mdlPt[i-1].x;
o.toy = mdlPt[i-1].y;
o.controlx = vertexes[i].x;
o.controly = vertexes[i].y;
arr [ arr.length ] = o;
}
o = new Operation ( Operation.C_TO );
o.tox = vertexes[NUM-1].x;
o.toy = vertexes[NUM-1].y;
o.controlx = vertexes[NUM-2].x;
o.controly = vertexes[NUM-2].y;
arr [ arr.length ] = o;

o = new Operation ( Operation.CLEAR );
dispatchEvent ( new DrawRequest ( arr ) );
}

}
}
class Vertex {
static const BASE_Y:uint=150;
static const BASE_R:uint=10;
static const PI:Number=Math.PI;
static const FRICTION:Number=0.1;//波形抖动后回复到正常状态的速率指数
static const DECELERATION:Number=0.95;
static const SPEED_OF_BASE_WAVE:uint=3;
private var theta:uint=0;
private var goalY:Number=0;
private var amp:Number=0;
public var x:Number;
public var y:Number;
public function Vertex(prmID:uint, parent:Object):void {
theta = 360 * prmID/( parent.NUM-1) ;//角度的弧度值。根据NUM值将舞台上分为NUM块,然后将2π的弧度分配给各块,这样舞台上平静的时候正好是一段完整的波形。
x = prmID * parent.STAGE_W / (parent.NUM-1);
y=BASE_Y+BASE_R*Math.sin(theta*PI/180);
}
//让波形不断波动的函数,不断更新各点的y坐标
public function updatePos(diffVal:Number):void {
theta+=SPEED_OF_BASE_WAVE;
if (theta>=360) {
theta-=360;
}
goalY=BASE_Y+BASE_R*Math.sin(theta*PI/180);
goalY+=diffVal;
amp+=goalY-y;
y+=amp*FRICTION;//y坐标以FRICTION的缓冲速率缓冲到正常状态
amp*=DECELERATION;
}
}
复制代码
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值