• Flash/Flex学习笔记(57):实用技巧


    布朗运动:

    varnumDots:uint=50;
    varfriction:Number=0.9;
    vardots:Array;
    varlife:uint=0;
    
    functioninit(){
    	graphics.lineStyle(0,0xffffff,.5);
    	dots=newArray();
    	for(vari:uint=0;i<numDots;i++){
    		vardot: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(vari:uint=0;i<numDots;i++){
    		vardot: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();
    

    矩形分布:

    vardotNumber:uint=500;
    vardots:Array;
    varcenterX:uint=stage.stageWidth/2;
    varcenterY:uint=stage.stageHeight/2;
    varlimitX:uint=50;
    varlimitY:uint=100;
    
    functioninit():void{
    	dots=newArray();	
    	for(vari:uint=0;i<dotNumber;i++){
    		vardot: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(vari:uint=0;i<dotNumber;i++){
    		vardot: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();
    

    圆形随机分布:

    vardotNumber:uint=500;
    vardots:Array;
    varcenterX:uint=stage.stageWidth/2;
    varcenterY:uint=stage.stageHeight/2;
    varradius:uint=75;
    
    functioninit():void{
    	dots=newArray();
    	for(vari:uint=0;i<dotNumber;i++){
    		vardot:Ball=newBall(3*Math.random(),0x00ff00);
    		varangle:Number=2*Math.random()*Math.PI;
    		varr: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(vari:uint=0;i<dotNumber;i++){
    		vardot:Ball=dots[i];
    		varangle:Number=2*Math.random()*Math.PI;
    		varr:Number=Math.random()*radius;
    		dot.x=centerX+r*Math.cos(angle);
    		dot.y=centerY+r*Math.sin(angle);
    	}
    }
    
    init();
    

    更均匀的圆形随机分布:

    vardotNumber:uint=200;
    
    varcenterX:uint=stage.stageWidth/2;
    varcenterY:uint=100;
    varradius:uint=50;
    
    functioninit():void{
    	
    	for(vari:uint=0;i<dotNumber;i++){
    		vardot:Ball=newBall(2,0x00ff00);
    		varangle:Number=2*Math.random()*Math.PI;		
    		varr: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++){
    		vardot1:Ball=newBall(2,0x00ff00);
    		varangle1:Number=2*Math.random()*Math.PI;
    		varr1: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();
    

    偏向分布:(即在指定的区域内,中心位置分布最密集,离中心越远,分布越稀疏)

    vardotNumber:uint=600;
    varcenterX:uint=stage.stageWidth/2;
    varmaxWidth:uint=75;
    varballs:Array=newArray();
    
    functioninit():void{
    
    	for(vari:uint=0;i<dotNumber;i++){
    		vardot:Ball=newBall(2,0x00ff00);
    
    		//在y轴方向上随便取二个值,然后计算平均值做为y坐标
    		vary1=stage.stageHeight*Math.random();
    		vary2=stage.stageHeight*Math.random();
    
    		varty=(y1+y2)/2;
    
    		//x轴做类似的处理
    		varx1=centerX+(Math.random()*2-1)*maxWidth;
    		varx2=centerX+(Math.random()*2-1)*maxWidth;
    
    		vartx=(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(vari:uint=0;i<dotNumber;i++){
    		vardot:Ball=balls[i];
    
    
    		vary1=stage.stageHeight*Math.random();
    		vary2=stage.stageHeight*Math.random();
    
    		varty=(y1+y2)/2;
    
    
    		varx1=centerX+(Math.random()*2-1)*maxWidth;
    		varx2=centerX+(Math.random()*2-1)*maxWidth;
    
    		vartx=(x1+x2)/2;
    
    
    		dot.x=tx;
    		dot.y=ty;
    
    
    	}
    }
    

    多次迭代的偏向分布(类似星云分布)

    vardotNumber:uint=100;
    variterations:uint=6;
    varballs:Array=newArray();
    
    functioninit():void{
    
    	for(vari:uint=0;i<dotNumber;i++){
    		vardot:Ball=newBall(2,0x00ff00);
    
    		varxpos:Number=0;
    		varypos:Number=0;
    		for(varj: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(vari:uint=0;i<dotNumber;i++){
    		vardot:Ball=balls[i];
    	
    		
    		varxpos:Number=0;
    		varypos:Number=0;
    		for(varj:uint=0;j<iterations;j++){
    			xpos+=stage.stageWidth*Math.random();
    			ypos+=stage.stageHeight*Math.random();
    		}
    
    		dot.x=xpos/iterations;
    		dot.y=ypos/iterations;
    
    		
    	}
    }
    

    Timer类的重绘设置:

    varball:Ball=newBall();
    varvx:Number=5;
    vartimer=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)

    varball:Ball=newBall();
    varvx:Number=5;
    
    stage.frameRate=100;//通常在基于时间的动画中,帧数可以设置得高一点(尽管机器最终可能达不到这个帧数.)
    
    ball.y=stage.stageHeight/2;
    ball.vx=10;
    addChild(ball);
    
    vartimer=getTimer();
    
    addEventListener(Event.ENTER_FRAME,enterFrameHandler);
    
    functionenterFrameHandler(e:Event):void{
    	varelapsed: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的对比代码:

    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来模拟小球的运量守恒,但计算也是很复杂的,对于相同质量的碰撞,其实可以实现得更简单一些。基本原理是,两个物体沿着碰撞的线路交换它们的速度(想深究的同学们,可以自己去解方程验证)。这样我们在处理这种特殊情况时,就可以简化一部分计算,完整代码如下:(注意加★的部分)

    package{
    
    	importflash.display.Sprite;
    	importflash.events.Event;
    	importflash.geom.Point;
    
    	publicclassSameMassextendsSprite{
    
    		privatevarballs:Array;
    		privatevarnumBalls:uint=8;
    		privatevarbounce:Number=-1.0;
    
    		publicfunctionSameMass(){
    			init();
    		}
    
    		privatefunctioninit():void{
    			balls=newArray();
    			for(vari:uint=0;i<numBalls;i++){
    				//varradius:Number=Math.random()*40+10;
    				varradius:Number=20;//★★★★★把所有质量强制为相同
    				varball: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(vari:uint=0;i<numBalls;i++){
    				varball:Ball=balls[i];
    				ball.x+=ball.vx;
    				ball.y+=ball.vy;
    				checkWalls(ball);
    			}
    
    			for(i=0;i<numBalls-1;i++){
    				varballA:Ball=balls[i];
    				for(varj:Number=i+1;j<numBalls;j++){
    					varballB: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{
    			varresult: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{
    			vardx:Number=ball1.x-ball0.x;
    			vardy:Number=ball1.y-ball0.y;
    			vardist:Number=Math.sqrt(dx*dx+dy*dy);
    			if(dist<ball0.radius+ball1.radius){
    				//计算角度和正余弦值
    				varangle:Number=Math.atan2(dy,dx);
    				varsin:Number=Math.sin(angle);
    				varcos:Number=Math.cos(angle);
    				//旋转ball0的位置
    				varpos0:Point=newPoint(0,0);
    				//旋转ball1的速度
    				varpos1:Point=rotate(dx,dy,sin,cos,true);
    				//旋转ball0的速度
    				varvel0:Point=rotate(ball0.vx,ball0.vy,sin,cos,true);
    				//旋转ball1的速度
    				varvel1: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;*/
    				//★★★★★改成速度交换★★★★★
    				vartemp:Point=vel0;
    				vel0=vel1;
    				vel1=temp;
    				
    				//更新位置
    				varabsV:Number=Math.abs(vel0.x)+Math.abs(vel1.x);
    				varoverlap:Number=(ball0.radius+ball1.radius)-Math.abs(pos0.x-pos1.x);
    				pos0.x+=vel0.x/absV*overlap;
    				pos1.x+=vel1.x/absV*overlap;
    				//将位置旋转回来
    				varpos0F:Object=rotate(pos0.x,pos0.y,sin,cos,false);
    				varpos1F: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;
    				//将速度旋转回来
    				varvel0F:Object=rotate(vel0.x,vel0.y,sin,cos,false);
    				varvel1F: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一个该类的实例了。除此之外,还可以直接加载远程声音,完整代码如下:

    varbgMusic=newSound(newURLRequest("http://210.51.38.234/music/sophie_zelmani_Going_Home.mp3"));
    varstf:SoundTransform=newSoundTransform();
    stf.volume=0.3;
    bgMusic.play(0,0,stf);
    
    varbing:Bing=newBing();
    varball: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
    本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。
  • 相关阅读:
    一步一步教你认识闭包
    爬虫入门系列(三):用 requests 构建知乎 API
    爬虫入门系列(二):优雅的HTTP库requests
    爬虫入门系列(一):快速理解HTTP协议
    Python中参数是传值,还是传引用?
    切图及效果图管理
    在GlassFish应用服务器上创建并运行你的第一个Restful Web Service【翻译】
    hybrid开发设计
    Gson解析数组多类型元素
    eclipse项目迁移到android studio(图文最新版)
  • 原文地址:https://www.cnblogs.com/yjmyzz/p/1756400.html
Copyright © 2020-2023  润新知