Starling实现的3D云彩效果

Starling本身是一个2D框架,不过引入一些3D计算,就可以实现简单的3D效果。这次我们要演示的是一个3D云彩效果,您就像一个战斗机飞行员,驾驶爱机在空中腾云驾雾,享受在云层中急速穿梭的感觉。因为只是简单的引入了Z轴排序,效果看起来还有不少瑕疵,期待3D高手不吝赐教,继续优化一下这个效果:)

示意图:

演示地址: http://www.todoair.com/demo/cover/CloudDemo.html

附上源代码:

package cloud
{
	import flash.display.Bitmap;
	import flash.geom.Point;
	import flash.geom.Rectangle;
 
	import starling.display.BlendMode;
	import starling.display.Image;
	import starling.display.QuadBatch;
	import starling.display.Sprite;
	import starling.events.Event;
	import starling.events.Touch;
	import starling.events.TouchEvent;
	import starling.events.TouchPhase;
	import starling.textures.Texture;
	import starling.textures.TextureAtlas;
 
	import test.pf.PageFlipContainer;
	/**
	 * Starling实现的3D云彩效果
	 * @author shaorui
	 */	
	public class Game extends Sprite
	{
		/**云彩的素材图片*/
		[Embed(source="../assets/cloud10.png")]
		protected const cloudImgClass:Class;
 
		/**承载纹理用*/
		protected var img:Image;
		/**用批次处理来显示*/
		private var quadBatch:QuadBatch;
		/**存储云朵信息*/
		private var imgArr:Vector.<CloudItem>;
		/**创建多少个云朵*/
		private var imgCount:int = 300;
		/**屏幕宽度*/
		private var screenWidth:Number = 960;
		/**屏幕高度*/
		private var screenHeight:Number = 640;
		/**缩放的阈值*/
		private var focal:Number=250;
		/**屏幕可见区域*/
		private var stageRect:Rectangle;
		/**@private*/
		private var vpX:Number;
		/**@private*/
		private var vpY:Number;
 
		/**@private*/
		public function Game()
		{
			super();
			addEventListener(Event.ADDED_TO_STAGE,initGame);
		}
		/**初始化*/
		private function initGame(...args):void
		{
			removeEventListener(Event.ADDED_TO_STAGE,initGame);
			//计算Z轴用
			vpX=stage.stageWidth/2;
			vpY=stage.stageHeight/2;
			stageRect = new Rectangle(0,0,stage.stageWidth,stage.stageHeight);
			centerPoint = new Point(screenWidth/2,screenHeight/4*3);
			//设置蓝天颜色
			stage.color = 0x0008a7;
			//创建一个注册点在中心的图片
			img = Image.fromBitmap(new cloudImgClass(),false);
			img.pivotX = img.width/2;
			img.pivotY = img.height/2;
			//批次用于渲染
			quadBatch = new QuadBatch();
			addChild(quadBatch);
			//用数组存储云朵属性
			imgArr = new Vector.<CloudItem>();
			for (var i:int = 0; i < imgCount; i++) 
			{
				var item:CloudItem = new CloudItem();
				item.rotation = Math.random()*Math.PI;
				setAShape(item);
				imgArr.push(item);
			}
			addEventListener(Event.ENTER_FRAME,enterFrameHandler);
			addEventListener(TouchEvent.TOUCH,onTouchHandler);
		}
		/**重置位置*/
		private function setAShape(shape:CloudItem):void
		{
			shape.scale = 0.001;
			shape.startX=screenWidth*2*Math.random()-screenWidth;
			shape.startY=screenHeight/2+screenHeight/2*Math.random()-100;
			shape.x = shape.startX;
			shape.y = shape.startY;
			shape.zpos = Math.random()*800+400;
		}
		/**Z排序*/
		private function sortArray():void
		{
			imgArr.sort(zSortFunction);
		}
		/**排序方法*/
		private function zSortFunction(a:CloudItem,b:CloudItem):Number
		{
			if(a.zpos > b.zpos)
				return -1;
			else if(a.zpos < b.zpos)
				return 1;
			else
				return 0;
		}
		/**判断一个对象是否已经不在屏幕区域*/
		private function shapeAvisible(shape:CloudItem):Boolean
		{
			var shapeRect:Rectangle = shape.getBounds(this);
			return shapeRect.intersects(stageRect);
		}
		/**每帧调用*/
		private function enterFrameHandler(event:Event=null):void
		{
			quadBatch.reset();
			var xpos:Number;
			var ypos:Number;
			var item:CloudItem;
			for (var i:int = 0; i < imgCount; i++) 
			{
				item = imgArr[i];
				//reset properties
				item.zpos-=4;
				var x1:Number = screenWidth-item.startX*2;
				var y1:Number = screenHeight/2-item.startY;
				if (item.zpos>-focal && shapeAvisible(item))
				{
					xpos=centerPoint.x-vpX-x1;//x维度
					ypos=centerPoint.y-vpY-y1;//y维度
					item.scale=focal/(focal+item.zpos);//缩放产生近大远小,取值在0-1之间;
					item.x=vpX+xpos*item.scale;
					item.y=vpY+ypos*item.scale;
				}
				else
				{
					setAShape(item);
				}
			}
			//每次进行Z排序
			sortArray();
			for (i = 0; i < imgCount; i++) 
			{
				item = imgArr[i];
				img.x = item.x;
				img.y = item.y;
				img.scaleX = img.scaleY = item.scale;
				img.rotation = item.rotation;
				quadBatch.addImage(img);
			}
		}
		/**@private*/
		private var centerPoint:Point;
		/**触碰处理*/
		private function onTouchHandler(event:TouchEvent):void
		{
			var touch:Touch = event.getTouch(this);
			if(touch == null)
				return;
			if(touch.phase == TouchPhase.HOVER)
			{
				centerPoint.x = touch.globalX/4+screenWidth/8;
				centerPoint.y = touch.globalY/4+screenHeight/8+280;
			}
		}
	}
}
import flash.geom.Rectangle;
 
import starling.display.DisplayObject;
/**
 * 存储云朵属性的类
 * @author shaorui
 */
class CloudItem
{
	private var itemWidth:Number = 256;
	private var itemHeight:Number = 256;
 
	public var startX:Number;
	public var startY:Number;
	public var zpos:Number=0;
 
	public var x:Number = 0;
	public var y:Number = 0;
	public var scale:Number = 1;
	public var rotation:Number = 0;
 
	public function getBounds(targetSpace:DisplayObject):Rectangle
	{
		var w:Number = itemWidth*scale;
		var h:Number = itemHeight*scale;
		var rect:Rectangle = new Rectangle(x-w/2,y-h/2,w/2,h/2);
		return rect;
	}
}

 类中引用的图片下载:

 

原文链接 : Starling实现的3D云彩效果

posted @ 2013-02-23 09:40  【Winco】  阅读(596)  评论(0编辑  收藏  举报