Flash/Flex学习笔记(57):实用技巧
布朗运动:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 | var numDots: uint = 50 ; var friction: Number = 0.9 ; var dots: Array ; var life: uint = 0 ; functioninit(){ graphics.lineStyle( 0 , 0xffffff ,. 5 ); dots=newArray(); for ( var i: uint = 0 ;i<numDots;i++){ var dot:Ball=newBall( 2 , 0x00ff00 ); dot.x=Math.random()*stage.stageWidth; dot.y=Math.random()*stage.stageHeight; dot.vx= 0 ; dot.vy= 0 ; dots.push(dot); addChild(dot); checkBound(dot); } addEventListener(Event.ENTER_FRAME,enterFrameHandler); } //检查边界 functioncheckBound(b:Ball){ if (b.x<b.width/ 2 ){ b.x=b.width/ 2 ; } elseif(b.x>stage.stageWidth-b.width/ 2 ){ b.x=stage.stageWidth-b.width/ 2 ; } if (b.y<b.height/ 2 ){ b.y=b.height/ 2 ; } elseif(b.y>stage.stageHeight-b.height/ 2 ){ b.y=stage.stageHeight-b.height/ 2 ; } } functionenterFrameHandler(e:Event): void { //trace(life); if (life>= 200 ){ graphics.clear(); graphics.lineStyle( 0 , 0xffffff ,. 5 ); life= 0 ; } for ( var i: uint = 0 ;i<numDots;i++){ var dot:Ball=dots[i]; graphics.moveTo(dot.x,dot.y); dot.vx+=Math.random()- 0.5 ; dot.vy+=Math.random()- 0.5 ; dot.x+=dot.vx; dot.y+=dot.vy; dot.vx*=friction; dot.vy*=friction; checkBound(dot); graphics.lineTo(dot.x,dot.y); } life++; } init(); |
矩形分布:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 | var dotNumber: uint = 500 ; var dots: Array ; var centerX: uint =stage.stageWidth/ 2 ; var centerY: uint =stage.stageHeight/ 2 ; var limitX: uint = 50 ; var limitY: uint = 100 ; functioninit(): void { dots=newArray(); for ( var i: uint = 0 ;i<dotNumber;i++){ var dot:Ball=newBall( 3 *Math.random(), 0x00ff00 ); dot.x=centerX+(Math.random()* 2 - 1 )*limitX; dot.y=centerY+(Math.random()* 2 - 1 )*limitY; addChild(dot); dots.push(dot); } addEventListener(Event.ENTER_FRAME,enterframeHandler); } functionenterframeHandler(e:Event): void { for ( var i: uint = 0 ;i<dotNumber;i++){ var dot:Ball=dots[i]; dot.x=centerX+(Math.random()* 2 - 1 )*limitX; dot.y=centerY+(Math.random()* 2 - 1 )*limitY; /*varix:Number=dot.x; variy:Number=dot.y; dot.y=ix; dot.x=iy*/ } } init(); |
圆形随机分布:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 | var dotNumber: uint = 500 ; var dots: Array ; var centerX: uint =stage.stageWidth/ 2 ; var centerY: uint =stage.stageHeight/ 2 ; var radius: uint = 75 ; functioninit(): void { dots=newArray(); for ( var i: uint = 0 ;i<dotNumber;i++){ var dot:Ball=newBall( 3 *Math.random(), 0x00ff00 ); var angle: Number = 2 *Math.random()*Math.PI; var r: Number =Math.random()*radius; dot.x=centerX+r*Math.cos(angle); dot.y=centerY+r*Math.sin(angle); addChild(dot); dots.push(dot); } addEventListener(Event.ENTER_FRAME,enterframeHandler); } functionenterframeHandler(e:Event): void { for ( var i: uint = 0 ;i<dotNumber;i++){ var dot:Ball=dots[i]; var angle: Number = 2 *Math.random()*Math.PI; var r: Number =Math.random()*radius; dot.x=centerX+r*Math.cos(angle); dot.y=centerY+r*Math.sin(angle); } } init(); |
更均匀的圆形随机分布:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 | var dotNumber: uint = 200 ; var centerX: uint =stage.stageWidth/ 2 ; var centerY: uint = 100 ; var radius: uint = 50 ; functioninit(): void { for ( var i: uint = 0 ;i<dotNumber;i++){ var dot:Ball=newBall( 2 , 0x00ff00 ); var angle: Number = 2 *Math.random()*Math.PI; var r: Number =Math.random()*radius; dot.x=centerX+r*Math.cos(angle); dot.y=centerY+r*Math.sin(angle); addChild(dot); } //更均匀的随机分布 for (i= 0 ;i<dotNumber;i++){ var dot1:Ball=newBall( 2 , 0x00ff00 ); var angle1: Number = 2 *Math.random()*Math.PI; var r1: Number =Math.sqrt(Math.random())*radius; //关键在这里,对Math.random()取平方根后,分布变得更均匀了 dot1.x=centerX+r1*Math.cos(angle1); dot1.y=centerY+ 200 +r1*Math.sin(angle1); addChild(dot1); } } init(); |
偏向分布:(即在指定的区域内,中心位置分布最密集,离中心越远,分布越稀疏)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 | var dotNumber: uint = 600 ; var centerX: uint =stage.stageWidth/ 2 ; var maxWidth: uint = 75 ; var balls: Array =newArray(); functioninit(): void { for ( var i: uint = 0 ;i<dotNumber;i++){ var dot:Ball=newBall( 2 , 0x00ff00 ); //在y轴方向上随便取二个值,然后计算平均值做为y坐标 var y1=stage.stageHeight*Math.random(); var y2=stage.stageHeight*Math.random(); var ty=(y1+y2)/ 2 ; //x轴做类似的处理 var x1=centerX+(Math.random()* 2 - 1 )*maxWidth; var x2=centerX+(Math.random()* 2 - 1 )*maxWidth; var tx=(x1+x2)/ 2 ; dot.x=tx; dot.y=ty; addChild(dot); balls.push(dot); } stage.frameRate= 1 ; addEventListener(Event.ENTER_FRAME,enterFrameHandler); } init(); functionenterFrameHandler(e:Event){ for ( var i: uint = 0 ;i<dotNumber;i++){ var dot:Ball=balls[i]; var y1=stage.stageHeight*Math.random(); var y2=stage.stageHeight*Math.random(); var ty=(y1+y2)/ 2 ; var x1=centerX+(Math.random()* 2 - 1 )*maxWidth; var x2=centerX+(Math.random()* 2 - 1 )*maxWidth; var tx=(x1+x2)/ 2 ; dot.x=tx; dot.y=ty; } } |
多次迭代的偏向分布(类似星云分布)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 | var dotNumber: uint = 100 ; var iterations: uint = 6 ; var balls: Array =newArray(); functioninit(): void { for ( var i: uint = 0 ;i<dotNumber;i++){ var dot:Ball=newBall( 2 , 0x00ff00 ); var xpos: Number = 0 ; var ypos: Number = 0 ; for ( var j: uint = 0 ;j<iterations;j++){ xpos+=stage.stageWidth*Math.random(); ypos+=stage.stageHeight*Math.random(); } dot.x=xpos/iterations; dot.y=ypos/iterations; addChild(dot); balls.push(dot); } stage.frameRate= 1 ; addEventListener(Event.ENTER_FRAME,enterFrameHandler); } init(); functionenterFrameHandler(e:Event){ for ( var i: uint = 0 ;i<dotNumber;i++){ var dot:Ball=balls[i]; var xpos: Number = 0 ; var ypos: Number = 0 ; for ( var j: uint = 0 ;j<iterations;j++){ xpos+=stage.stageWidth*Math.random(); ypos+=stage.stageHeight*Math.random(); } dot.x=xpos/iterations; dot.y=ypos/iterations; } } |
Timer类的重绘设置:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | var ball:Ball=newBall(); var vx: Number = 5 ; var timer=newTimer( 20 ); stage.frameRate= 1 ; //设置flash动画的帧数为1帧/秒 ball.y=stage.stageHeight/ 2 ; ball.vx= 5 ; addChild(ball); timer.addEventListener(TimerEvent.TIMER,TimerHandler); functionTimerHandler(e:TimerEvent): void { ball.x+=ball.vx; if (ball.x>stage.stageWidth+ball.width/ 2 ){ ball.x=-ball.width/ 2 ; } e.updateAfterEvent(); //事件触发后,重绘整个stage(建议大家去掉这一行,再看看效果) } timer.start(); |
注意: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)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | var ball:Ball=newBall(); var vx: Number = 5 ; stage.frameRate= 100 ; //通常在基于时间的动画中,帧数可以设置得高一点(尽管机器最终可能达不到这个帧数.) ball.y=stage.stageHeight/ 2 ; ball.vx= 10 ; addChild(ball); var timer=getTimer(); addEventListener(Event.ENTER_FRAME,enterFrameHandler); functionenterFrameHandler(e:Event): void { var elapsed: Number =getTimer()-timer; //计算每帧之间间隔的时间差(以毫秒为单位) ball.x+=(ball.vx*elapsed/ 1000 ); //将毫秒换算成秒,再乘“速度”,最终的效果即:如果帧数低,动画播放得太慢,则一次多移动一些距离;反之则少移动一些距离,起到了动态调整的目的. if (ball.x>stage.stageWidth+ball.width/ 2 ){ ball.x=-ball.width/ 2 ; } timer=getTimer(); } |
大家可以尝试把上面的帧数设置,改成200或50,然后再测试下播放效果,会发现小球的移动速度是一致的,不受帧数的影响。(但帧数建议不要低于10,因为人眼的视觉暂留极限大概是0.1秒,低于这个值动画看起来会很卡)
另外,这里对比给出Silverlight的对比代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 | usingSystem; usingSystem.Windows; usingSystem.Windows.Controls; usingSystem.Windows.Interop; usingSystem.Windows.Threading; namespaceSilverlightApplication1 { publicpartialclassMainPage:UserControl { DispatcherTimertmr; Ballb; publicMainPage() { InitializeComponent(); this .Loaded+=newRoutedEventHandler(MainPage_Loaded); } voidMainPage_Loaded(objectsender,RoutedEventArgse) { Settingssettings=Application.Current.Host.Settings; settings.EnableFrameRateCounter= true ; settings.MaxFrameRate=1; b=newBall(); //ball是一个自定义控件,里面就一个圆 c.Children.Add(b); b.SetValue(Canvas.LeftProperty,c.Width/2); b.SetValue(Canvas.TopProperty,c.Height/2); tmr=newDispatcherTimer(); tmr.Interval=newTimeSpan(0,0,0,0,20); tmr.Tick+=newEventHandler(tmr_Tick); tmr.Start(); } voidtmr_Tick(objectsender,EventArgse) { double_left=( double )b.GetValue(Canvas.LeftProperty); b.SetValue(Canvas.LeftProperty,_left+5); } } } |
相同质量的小球碰撞:
Flash/Flex学习笔记(43):动量守恒与能量守恒 里,我们学习了如何用AS3.0来模拟小球的运量守恒,但计算也是很复杂的,对于相同质量的碰撞,其实可以实现得更简单一些。基本原理是,两个物体沿着碰撞的线路交换它们的速度(想深究的同学们,可以自己去解方程验证)。这样我们在处理这种特殊情况时,就可以简化一部分计算,完整代码如下:(注意加★的部分)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 | package { importflash.display.Sprite; importflash.events.Event; importflash.geom.Point; publicclassSameMassextendsSprite{ private var balls: Array ; private var numBalls: uint = 8 ; private var bounce: Number =- 1.0 ; publicfunctionSameMass(){ init(); } privatefunctioninit(): void { balls=newArray(); for ( var i: uint = 0 ;i<numBalls;i++){ //varradius:Number=Math.random()*40+10; var radius: Number = 20 ; //★★★★★把所有质量强制为相同 var ball:Ball=newBall(radius,Math.random()* 0xffffff ); ball.mass=radius; ball.x=i* 100 ; ball.y=i* 50 ; ball.vx=Math.random()* 10 - 5 ; ball.vy=Math.random()* 10 - 5 ; addChild(ball); balls.push(ball); } addEventListener(Event.ENTER_FRAME,onEnterFrame); } privatefunctiononEnterFrame(event:Event): void { for ( var i: uint = 0 ;i<numBalls;i++){ var ball:Ball=balls[i]; ball.x+=ball.vx; ball.y+=ball.vy; checkWalls(ball); } for (i= 0 ;i<numBalls- 1 ;i++){ var ballA:Ball=balls[i]; for ( var j: Number =i+ 1 ;j<numBalls;j++){ var ballB:Ball=balls[j]; checkCollision(ballA,ballB); } } } //舞台边界检测 functioncheckWalls(b:Ball){ if (b.x<b.radius){ b.x=b.radius; b.vx*=bounce; } elseif(b.x>stage.stageWidth-b.radius){ b.x=stage.stageWidth-b.radius; b.vx*=bounce; } if (b.y<b.radius){ b.y=b.radius; b.vy*=bounce; } elseif(b.y>stage.stageHeight-b.radius){ b.y=stage.stageHeight-b.radius; b.vy*=bounce; } } privatefunctionrotate(x: Number ,y: Number ,sin: Number ,cos: Number ,reverse: Boolean ):Point{ var result:Point=newPoint(); if (reverse){ result.x=x*cos+y*sin; result.y=y*cos-x*sin; } else { result.x=x*cos-y*sin; result.y=y*cos+x*sin; } returnresult; } privatefunctioncheckCollision(ball0:Ball,ball1:Ball): void { var dx: Number =ball1.x-ball0.x; var dy: Number =ball1.y-ball0.y; var dist: Number =Math.sqrt(dx*dx+dy*dy); if (dist<ball0.radius+ball1.radius){ //计算角度和正余弦值 var angle: Number =Math.atan2(dy,dx); var sin: Number =Math.sin(angle); var cos: Number =Math.cos(angle); //旋转ball0的位置 var pos0:Point=newPoint( 0 , 0 ); //旋转ball1的速度 var pos1:Point=rotate(dx,dy,sin,cos, true ); //旋转ball0的速度 var vel0:Point=rotate(ball0.vx,ball0.vy,sin,cos, true ); //旋转ball1的速度 var vel1:Point=rotate(ball1.vx,ball1.vy,sin,cos, true ); /*//碰撞的作用力 varvxTotal:Number=vel0.x-vel1.x; vel0.x=((ball0.mass-ball1.mass)*vel0.x+2*ball1.mass*vel1.x)/(ball0.mass+ball1.mass); vel1.x=vxTotal+vel0.x;*/ //★★★★★改成速度交换★★★★★ var temp:Point=vel0; vel0=vel1; vel1=temp; //更新位置 var absV: Number =Math.abs(vel0.x)+Math.abs(vel1.x); var overlap: Number =(ball0.radius+ball1.radius)-Math.abs(pos0.x-pos1.x); pos0.x+=vel0.x/absV*overlap; pos1.x+=vel1.x/absV*overlap; //将位置旋转回来 var pos0F: Object =rotate(pos0.x,pos0.y,sin,cos, false ); var pos1F: Object =rotate(pos1.x,pos1.y,sin,cos, false ); //将位置调整为屏幕的实际位置 ball1.x=ball0.x+pos1F.x; ball1.y=ball0.y+pos1F.y; ball0.x=ball0.x+pos0F.x; ball0.y=ball0.y+pos0F.y; //将速度旋转回来 var vel0F: Object =rotate(vel0.x,vel0.y,sin,cos, false ); var vel1F: Object =rotate(vel1.x,vel1.y,sin,cos, false ); ball0.vx=vel0F.x; ball0.vy=vel0F.y; ball1.vx=vel1F.x; ball1.vy=vel1F.y; } } } } |
声音的使用:
声音的使用其实没什么特别的,跟图片,视频等其它资源都差不多.
如上图,在导入一个声音时,可以指定一个类名,然后在代码中,就可以new一个该类的实例了。除此之外,还可以直接加载远程声音,完整代码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 | var bgMusic=newSound(newURLRequest( "http://210.51.38.234/music/sophie_zelmani_Going_Home.mp3" )); var stf:SoundTransform=newSoundTransform(); stf.volume= 0.3 ; bgMusic.play( 0 , 0 ,stf); var bing:Bing=newBing(); var ball:Ball=newBall( 30 ); ball.vx= 5 ; ball.vy= 5 ; ball.x=stage.stageWidth/ 2 ; ball.y=stage.stageHeight/ 2 ; addChild(ball); addEventListener(Event.ENTER_FRAME,EnterFrameHandler); functionEnterFrameHandler(e:Event): void { ball.x+=ball.vx; ball.y+=ball.vy; if (ball.x>=stage.stageWidth-ball.radius){ ball.x=stage.stageWidth-ball.radius; ball.vx*=- 1 ; bing.play(); } elseif(ball.x<=ball.radius){ ball.x=ball.radius; ball.vx*=- 1 ; bing.play(); } if (ball.y>=stage.stageHeight-ball.radius){ ball.y=stage.stageHeight-ball.radius; ball.vy*=- 1 ; bing.play(); } elseif(ball.y<=ball.radius){ ball.y=ball.radius; ball.vy*=- 1 ; bing.play(); } } |
AnimationinActionScript3.0/MakingThingsMove!一书终于全部啃完了,感谢作者“KeithPeters”大师写出这么好的书,感谢[FL基理文]历时4个月的用心翻译!强烈推荐给想研究Silverlight/Flash动画的朋友们,里面的很多思想和处理方法都是动画编程通用的,并不局限于某一种特定的语言!“师傅领进门,修行在各人”,以后在动画编程的道路上能走多远,就只能看自己的造化了。
出处:http://yjmyzz.cnblogs.com
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· 10年+ .NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义
· 地球OL攻略 —— 某应届生求职总结
· 提示词工程——AI应用必不可少的技术
· 字符编码:从基础到乱码解决
· Open-Sora 2.0 重磅开源!
2009-06-11 img标签的src=""会引起的Page_Load多次执行