02
|
varfriction:Number=0.9;
|
07
|
graphics.lineStyle(0,0xffffff,.5);
|
09
|
for(vari:uint=0;i<numDots;i++){
|
10
|
vardot:Ball=newBall(2,0x00ff00);
|
11
|
dot.x=Math.random()*stage.stageWidth;
|
12
|
dot.y=Math.random()*stage.stageHeight;
|
19
|
addEventListener(Event.ENTER_FRAME,enterFrameHandler);
|
23
|
functioncheckBound(b:Ball){
|
27
|
elseif(b.x>stage.stageWidth-b.width/2){
|
28
|
b.x=stage.stageWidth-b.width/2;
|
33
|
elseif(b.y>stage.stageHeight-b.height/2){
|
34
|
b.y=stage.stageHeight-b.height/2;
|
38
|
functionenterFrameHandler(e:Event):void{
|
42
|
graphics.lineStyle(0,0xffffff,.5);
|
45
|
for(vari:uint=0;i<numDots;i++){
|
47
|
graphics.moveTo(dot.x,dot.y);
|
48
|
dot.vx+=Math.random()-0.5;
|
49
|
dot.vy+=Math.random()-0.5;
|
55
|
graphics.lineTo(dot.x,dot.y);
|
矩形分布:
show sourceview source print?
01
|
vardotNumber:uint=500;
|
03
|
varcenterX:uint=stage.stageWidth/2;
|
04
|
varcenterY:uint=stage.stageHeight/2;
|
10
|
for(vari:uint=0;i<dotNumber;i++){
|
11
|
vardot:Ball=newBall(3*Math.random(),0x00ff00);
|
12
|
dot.x=centerX+(Math.random()*2-1)*limitX;
|
13
|
dot.y=centerY+(Math.random()*2-1)*limitY;
|
17
|
addEventListener(Event.ENTER_FRAME,enterframeHandler);
|
20
|
functionenterframeHandler(e:Event):void{
|
21
|
for(vari:uint=0;i<dotNumber;i++){
|
23
|
dot.x=centerX+(Math.random()*2-1)*limitX;
|
24
|
dot.y=centerY+(Math.random()*2-1)*limitY;
|
圆形随机分布:
show sourceview source print?
01
|
vardotNumber:uint=500;
|
03
|
varcenterX:uint=stage.stageWidth/2;
|
04
|
varcenterY:uint=stage.stageHeight/2;
|
09
|
for(vari:uint=0;i<dotNumber;i++){
|
10
|
vardot:Ball=newBall(3*Math.random(),0x00ff00);
|
11
|
varangle:Number=2*Math.random()*Math.PI;
|
12
|
varr:Number=Math.random()*radius;
|
13
|
dot.x=centerX+r*Math.cos(angle);
|
14
|
dot.y=centerY+r*Math.sin(angle);
|
18
|
addEventListener(Event.ENTER_FRAME,enterframeHandler);
|
21
|
functionenterframeHandler(e:Event):void{
|
22
|
for(vari:uint=0;i<dotNumber;i++){
|
24
|
varangle:Number=2*Math.random()*Math.PI;
|
25
|
varr:Number=Math.random()*radius;
|
26
|
dot.x=centerX+r*Math.cos(angle);
|
27
|
dot.y=centerY+r*Math.sin(angle);
|
更均匀的圆形随机分布:
show sourceview source print?
01
|
vardotNumber:uint=200;
|
03
|
varcenterX:uint=stage.stageWidth/2;
|
09
|
for(vari:uint=0;i<dotNumber;i++){
|
10
|
vardot:Ball=newBall(2,0x00ff00);
|
11
|
varangle:Number=2*Math.random()*Math.PI;
|
12
|
varr:Number=Math.random()*radius;
|
13
|
dot.x=centerX+r*Math.cos(angle);
|
14
|
dot.y=centerY+r*Math.sin(angle);
|
20
|
for(i=0;i<dotNumber;i++){
|
21
|
vardot1:Ball=newBall(2,0x00ff00);
|
22
|
varangle1:Number=2*Math.random()*Math.PI;
|
23
|
varr1:Number=Math.sqrt(Math.random())*radius;//关键在这里,对Math.random()取平方根后,分布变得更均匀了
|
24
|
dot1.x=centerX+r1*Math.cos(angle1);
|
25
|
dot1.y=centerY+200+r1*Math.sin(angle1);
|
偏向分布:(即在指定的区域内,中心位置分布最密集,离中心越远,分布越稀疏)
show sourceview source print?
01
|
vardotNumber:uint=600;
|
02
|
varcenterX:uint=stage.stageWidth/2;
|
04
|
varballs:Array=newArray();
|
08
|
for(vari:uint=0;i<dotNumber;i++){
|
09
|
vardot:Ball=newBall(2,0x00ff00);
|
11
|
//在y轴方向上随便取二个值,然后计算平均值做为y坐标
|
12
|
vary1=stage.stageHeight*Math.random();
|
13
|
vary2=stage.stageHeight*Math.random();
|
18
|
varx1=centerX+(Math.random()*2-1)*maxWidth;
|
19
|
varx2=centerX+(Math.random()*2-1)*maxWidth;
|
32
|
addEventListener(Event.ENTER_FRAME,enterFrameHandler);
|
38
|
functionenterFrameHandler(e:Event){
|
39
|
for(vari:uint=0;i<dotNumber;i++){
|
43
|
vary1=stage.stageHeight*Math.random();
|
44
|
vary2=stage.stageHeight*Math.random();
|
49
|
varx1=centerX+(Math.random()*2-1)*maxWidth;
|
50
|
varx2=centerX+(Math.random()*2-1)*maxWidth;
|
多次迭代的偏向分布(类似星云分布)
show sourceview source print?
01
|
vardotNumber:uint=100;
|
03
|
varballs:Array=newArray();
|
07
|
for(vari:uint=0;i<dotNumber;i++){
|
08
|
vardot:Ball=newBall(2,0x00ff00);
|
12
|
for(varj:uint=0;j<iterations;j++){
|
13
|
xpos+=stage.stageWidth*Math.random();
|
14
|
ypos+=stage.stageHeight*Math.random();
|
17
|
dot.x=xpos/iterations;
|
18
|
dot.y=ypos/iterations;
|
26
|
addEventListener(Event.ENTER_FRAME,enterFrameHandler);
|
32
|
functionenterFrameHandler(e:Event){
|
33
|
for(vari:uint=0;i<dotNumber;i++){
|
39
|
for(varj:uint=0;j<iterations;j++){
|
40
|
xpos+=stage.stageWidth*Math.random();
|
41
|
ypos+=stage.stageHeight*Math.random();
|
44
|
dot.x=xpos/iterations;
|
45
|
dot.y=ypos/iterations;
|
Timer类的重绘设置:
show sourceview source print?
01
|
varball:Ball=newBall();
|
03
|
vartimer=newTimer(20);
|
05
|
stage.frameRate=1;//设置flash动画的帧数为1帧/秒
|
07
|
ball.y=stage.stageHeight/2;
|
11
|
timer.addEventListener(TimerEvent.TIMER,TimerHandler);
|
13
|
functionTimerHandler(e:TimerEvent):void{
|
15
|
if(ball.x>stage.stageWidth+ball.width/2){
|
18
|
e.updateAfterEvent();//事件触发后,重绘整个stage(建议大家去掉这一行,再看看效果)
|
注意:timer类的计时并不象c#中那样精确,因为跟帧速有关联。
基于时间的动画:
Flash动画是基于帧的(即每进入一帧时,舞台上的对象才会重绘,并触发Enter_Frame事件),这跟Silverlight是基于时间的设计完全不同。一般情况下,这也不是什么问题,但是这样会在不同配置的机器上可能产生不一致的播放效果,比如“一个简单的小球从左运动到右”的简单动画,如果在ENTER_FRAME事件中,用ball.x+=ball.vx来处理,在老爷机上,可能swf动画只能达到每秒10帧的播放速度,而在4核的高配置机器上,能达到每秒100帧的播放速度。 问题就来了:假如ball.vx为5,则在老爷机上,小球最终每秒移动了5*10=50像素,而在高配置机器上,小球每秒移动了5*100=500像素,这与开发者期望的并不一样,下面的代码演示了如何制作基于时间的动画,最终让小球在不同配置的机器上运动速度达到一致。(注:在这一点上,不得不承认Silverlight的设计要优于Flash)
show sourceview source print?
01
|
varball:Ball=newBall();
|
04
|
stage.frameRate=100;//通常在基于时间的动画中,帧数可以设置得高一点(尽管机器最终可能达不到这个帧数.)
|
06
|
ball.y=stage.stageHeight/2;
|
12
|
addEventListener(Event.ENTER_FRAME,enterFrameHandler);
|
14
|
functionenterFrameHandler(e:Event):void{
|
15
|
varelapsed:Number=getTimer()-timer;//计算每帧之间间隔的时间差(以毫秒为单位)
|
17
|
ball.x+=(ball.vx*elapsed/1000);//将毫秒换算成秒,再乘“速度”,最终的效果即:如果帧数低,动画播放得太慢,则一次多移动一些距离;反之则少移动一些距离,起到了动态调整的目的.
|
18
|
if(ball.x>stage.stageWidth+ball.width/2){
|
大家可以尝试把上面的帧数设置,改成200或50,然后再测试下播放效果,会发现小球的移动速度是一致的,不受帧数的影响。(但帧数建议不要低于10,因为人眼的视觉暂留极限大概是0.1秒,低于这个值动画看起来会很卡)
另外,这里对比给出Silverlight的对比代码:
show sourceview source print?
03
|
usingSystem.Windows.Controls;
|
04
|
usingSystem.Windows.Interop;
|
05
|
usingSystem.Windows.Threading;
|
07
|
namespaceSilverlightApplication1
|
09
|
publicpartialclassMainPage:UserControl
|
16
|
InitializeComponent();
|
17
|
this.Loaded+=newRoutedEventHandler(MainPage_Loaded);
|
20
|
voidMainPage_Loaded(objectsender,RoutedEventArgse)
|
22
|
Settingssettings=Application.Current.Host.Settings;
|
23
|
settings.EnableFrameRateCounter=true;
|
24
|
settings.MaxFrameRate=1;
|
26
|
b=newBall();//ball是一个自定义控件,里面就一个圆
|
28
|
b.SetValue(Canvas.LeftProperty,c.Width/2);
|
29
|
b.SetValue(Canvas.TopProperty,c.Height/2);
|
31
|
tmr=newDispatcherTimer();
|
32
|
tmr.Interval=newTimeSpan(0,0,0,0,20);
|
33
|
tmr.Tick+=newEventHandler(tmr_Tick);
|
37
|
voidtmr_Tick(objectsender,EventArgse)
|
39
|
double_left=(double)b.GetValue(Canvas.LeftProperty);
|
40
|
b.SetValue(Canvas.LeftProperty,_left+5);
|
相同质量的小球碰撞:
Flash/Flex学习笔记(43):动量守恒与能量守恒 里,我们学习了如何用AS3.0来模拟小球的运量守恒,但计算也是很复杂的,对于相同质量的碰撞,其实可以实现得更简单一些。基本原理是,两个物体沿着碰撞的线路交换它们的速度(想深究的同学们,可以自己去解方程验证)。这样我们在处理这种特殊情况时,就可以简化一部分计算,完整代码如下:(注意加★的部分)
show sourceview source print?
003
|
importflash.display.Sprite;
|
004
|
importflash.events.Event;
|
005
|
importflash.geom.Point;
|
007
|
publicclassSameMassextendsSprite{
|
009
|
privatevarballs:Array;
|
010
|
privatevarnumBalls:uint=8;
|
011
|
privatevarbounce:Number=-1.0;
|
013
|
publicfunctionSameMass(){
|
017
|
privatefunctioninit():void{
|
019
|
for(vari:uint=0;i<numBalls;i++){
|
020
|
//varradius:Number=Math.random()*40+10;
|
021
|
varradius:Number=20;//★★★★★把所有质量强制为相同
|
022
|
varball:Ball=newBall(radius,Math.random()*0xffffff);
|
026
|
ball.vx=Math.random()*10-5;
|
027
|
ball.vy=Math.random()*10-5;
|
031
|
addEventListener(Event.ENTER_FRAME,onEnterFrame);
|
034
|
privatefunctiononEnterFrame(event:Event):void{
|
035
|
for(vari:uint=0;i<numBalls;i++){
|
036
|
varball:Ball=balls[i];
|
042
|
for(i=0;i<numBalls-1;i++){
|
043
|
varballA:Ball=balls[i];
|
044
|
for(varj:Number=i+1;j<numBalls;j++){
|
045
|
varballB:Ball=balls[j];
|
046
|
checkCollision(ballA,ballB);
|
053
|
functioncheckWalls(b:Ball){
|
058
|
elseif(b.x>stage.stageWidth-b.radius){
|
059
|
b.x=stage.stageWidth-b.radius;
|
066
|
elseif(b.y>stage.stageHeight-b.radius){
|
067
|
b.y=stage.stageHeight-b.radius;
|
072
|
privatefunctionrotate(x:Number,y:Number,sin:Number,cos:Number,reverse:Boolean):Point{
|
073
|
varresult:Point=newPoint();
|
075
|
result.x=x*cos+y*sin;
|
076
|
result.y=y*cos-x*sin;
|
079
|
result.x=x*cos-y*sin;
|
080
|
result.y=y*cos+x*sin;
|
085
|
privatefunctioncheckCollision(ball0:Ball,ball1:Ball):void{
|
086
|
vardx:Number=ball1.x-ball0.x;
|
087
|
vardy:Number=ball1.y-ball0.y;
|
088
|
vardist:Number=Math.sqrt(dx*dx+dy*dy);
|
089
|
if(dist<ball0.radius+ball1.radius){
|
091
|
varangle:Number=Math.atan2(dy,dx);
|
092
|
varsin:Number=Math.sin(angle);
|
093
|
varcos:Number=Math.cos(angle);
|
095
|
varpos0:Point=newPoint(0,0);
|
097
|
varpos1:Point=rotate(dx,dy,sin,cos,true);
|
099
|
varvel0:Point=rotate(ball0.vx,ball0.vy,sin,cos,true);
|
101
|
varvel1:Point=rotate(ball1.vx,ball1.vy,sin,cos,true);
|
103
|
varvxTotal:Number=vel0.x-vel1.x;
|
104
|
vel0.x=((ball0.mass-ball1.mass)*vel0.x+2*ball1.mass*vel1.x)/(ball0.mass+ball1.mass);
|
105
|
vel1.x=vxTotal+vel0.x;*/
|
112
|
varabsV:Number=Math.abs(vel0.x)+Math.abs(vel1.x);
|
113
|
varoverlap:Number=(ball0.radius+ball1.radius)-Math.abs(pos0.x-pos1.x);
|
114
|
pos0.x+=vel0.x/absV*overlap;
|
115
|
pos1.x+=vel1.x/absV*overlap;
|
117
|
varpos0F:Object=rotate(pos0.x,pos0.y,sin,cos,false);
|
118
|
varpos1F:Object=rotate(pos1.x,pos1.y,sin,cos,false);
|
120
|
ball1.x=ball0.x+pos1F.x;
|
121
|
ball1.y=ball0.y+pos1F.y;
|
122
|
ball0.x=ball0.x+pos0F.x;
|
123
|
ball0.y=ball0.y+pos0F.y;
|
125
|
varvel0F:Object=rotate(vel0.x,vel0.y,sin,cos,false);
|
126
|
varvel1F:Object=rotate(vel1.x,vel1.y,sin,cos,false);
|
声音的使用:
声音的使用其实没什么特别的,跟图片,视频等其它资源都差不多.
如上图,在导入一个声音时,可以指定一个类名,然后在代码中,就可以new一个该类的实例了。除此之外,还可以直接加载远程声音,完整代码如下:
show sourceview source print?
01
|
varbgMusic=newSound(newURLRequest("http://210.51.38.234/music/sophie_zelmani_Going_Home.mp3"));
|
02
|
varstf:SoundTransform=newSoundTransform();
|
04
|
bgMusic.play(0,0,stf);
|
06
|
varbing:Bing=newBing();
|
07
|
varball:Ball=newBall(30);
|
10
|
ball.x=stage.stageWidth/2;
|
11
|
ball.y=stage.stageHeight/2;
|
14
|
addEventListener(Event.ENTER_FRAME,EnterFrameHandler);
|
16
|
functionEnterFrameHandler(e:Event):void{
|
20
|
if(ball.x>=stage.stageWidth-ball.radius){
|
21
|
ball.x=stage.stageWidth-ball.radius;
|
25
|
elseif(ball.x<=ball.radius){
|
31
|
if(ball.y>=stage.stageHeight-ball.radius){
|
32
|
ball.y=stage.stageHeight-ball.radius;
|
36
|
elseif(ball.y<=ball.radius){
|
AnimationinActionScript3.0/MakingThingsMove!一书终于全部啃完了,感谢作者“KeithPeters”大师写出这么好的书,感谢[FL基理文]历时4个月的用心翻译!强烈推荐给想研究Silverlight/Flash动画的朋友们,里面的很多思想和处理方法都是动画编程通用的,并不局限于某一种特定的语言!“师傅领进门,修行在各人”,以后在动画编程的道路上能走多远,就只能看自己的造化了。