标签:
显示列表
starling和flash本地的显示列表有一样的规则,在没有东西添加进stage之前,stage是null的。在本地flash中,为了能更安全的使用stage,我们通常使用一些Flash中的重要的事件,这些事件在starling中同样可用:
• Event.ADDED : the object was added to a parent. • Event.ADDED_TO_STAGE : the object was added to a parent that is connected to the stage, thus becoming visible now. • Event.REMOVED : the object was removed from a parent. • Event.REMOVED_FROM_STAGE : the object was removed from a parent that is connected to the stage, thus becoming invisible now.
在下面的例子中,我们会经常用到这些事件,就像在flash中一样,这些事件可以用在初始化,组件销毁等很多重要的地方。
下面是DisplayObject类声明的部分方法列表:
• removeFromParent : Removes the object from its parent, if it has one. • getTransformationMatrixToSpace : Creates a matrix that represents the transformation from the local coordinate system to another. • getBounds : Returns a rectangle that completely encloses the object as it appears in another coordinate system. • hitTestPoint : Returns the object that is found topmost on a point in local coordinates, or nil if the test fails. • globalToLocal : Transforms a point from global (stage) coordinates to the local coordinate system. • localToGlobal : Transforms a point from the local coordinate system to global (stage) coordinates.
下面是DisplayObject类声明的部分属性,让人高兴的是大部分的属性都和flash本事的display一样,并且还有一些拓展的属性,比如用来动态改变一个DisplayObject类注册点的pivotX和pivotY,如下:
• transformationMatrix : The transformation matrix of the object relative to its parent. • bounds : The bounds of the object relative to the local coordinates of the parent. • width : The width of the object in points. • height : The height of the object in points. • root : The topmost object in the display tree the object is part of. • x : The x coordinate of the object relative to the local coordinates of the parent. • y : The y coordinate of the object relative to the local coordinates of the parent. • pivotX : The x coordinate of the object’s origin in its own coordinate space (default: 0). • pivotY : The y coordinate of the object’s origin in its own coordinate space (default: 0). • scaleX : The horizontal scale factor. “1” means no scale, negative values flip the object. • scaleY : The vertical scale factor. “1” means no scale, negative values flip the object. • rotation : The rotation of the object in radians. (In Sparrow, all angles are measured in radians.) • alpha : The opacity of the object. • visible : The visibility of the object. An invisible object will be untouchable. • touchable : Indicates if this object (and its children) will receive touch events. • parent : The display object container that contains this display object. • stage : The stage the display object is connected to, or null if it is not connected to a stage.
就像在flash本地的api中一样,Sprite是你可以使用的最轻量级的容器。Sprite继承自DisplayObjectContainer, 而DisplayObjectContainer继承自DisplayObject,我们的例子中的Game都是集成字Sprite的,是一个DisplayObjectContainer。
下面是DisplayObjectContainer的一部分api:
• addChild : Adds a child to the container. It will be at the topmost position. • addChildAt : Adds a child to the container at a certain index. • dispose : Removes the GPU buffers and all the listeners registered to the o • removeFromParent : Removes the child from its parent. • removeChild : Removes a child from the container. If the object is not a ch • removeChildAt : Removes a child at a certain index. Children above the c • removeChildren : Removes all children from the container. • getChildAt : Returns a child object at a certain index. • getChildByName : Returns a child object with a certain name (non-recursi • getChildIndex : Returns the index of a child within the container. • setChildIndex : Changes the index of the specified child.
• swapChildren : Swaps the indexes of two children. • swapChildrenAt : Swaps the indexes of two children. • contains : Determines if a certain object is a child of the container (recursively).
一旦你进入了stage之后你就可以使用绝大部分DisplayObjectContainer的api,当然了你可以为stage设置一个颜色。Starling默认会采用SWF的背景色,你可以通过设置下面的SWF标签来实现:
[SWF(width="1280", height="752", frameRate="60", backgroundColor="#990000")]
你也可以通过stage对象来手工设置一个颜色,stage对象可以通过任意一个添加到显示列表中的DisplayObject对象中获得:
1 package
2 {
3 import starling.display.Quad;
4 import starling.display.Sprite;
5 import starling.events.Event;
6
7 public class Game extends Sprite
8 {
9 private var q:Quad;
10
11 public function Game()
12 {
13 addEventListener(Event.ADDED_TO_STAGE, onAdded);
14 }
15
16 private function onAdded ( e:Event ):void
17 {
18 // set the background color to blue
19 stage.color = 0x002143;
20
21 q = new Quad(200, 200);
22 q.setVertexColor(0, 0x000000);
23 q.setVertexColor(1, 0xAA0000);
24 q.setVertexColor(2, 0x00FF00);
25 q.setVertexColor(3, 0x0000FF);
26 addChild ( q );
27 }
28 }
29 }
现在我们还没有使用任何texture(纹理),我们主要是用两个三角形拼了一个Quad,并且每个顶点拥有不同的颜色(会自动篡改成gpu可识别的颜色)。
当然了你可以调用quad的color属性来实现纯色的quad:
1 package 2 { 3 import starling.display.Quad; 4 import starling.display.Sprite; 5 import starling.events.Event; 6 7 public class Game extends Sprite 8 { 9 private var q:Quad; 10 11 public function Game() 12 { 13 addEventListener(Event.ADDED_TO_STAGE, onAdded); 14 } 15 16 private function onAdded ( e:Event ):void 17 { 18 q = new Quad(200, 200); 19 q.color = 0x00FF00; 20 q.x = stage.stageWidth - q.width >> 1; 21 q.y = stage.stageHeight - q.height >> 1; 22 addChild ( q ); 23 } 24 } 25 }
效果如下:
下面我们来使用Event.ENTER_FRAME事件修改quad的颜色来实现一个简单缓动特效:
1 package
2 {
3 import starling.display.Quad;
4 import starling.display.Sprite;
5 import starling.events.Event;
6
7 public class Game extends Sprite
8 {
9 private var q:Quad;
10
11 private var r:Number = 0;
12 private var g:Number = 0;
13 private var b:Number = 0;
14
15 private var rDest:Number;
16 private var gDest:Number;
17 private var bDest:Number;
18
19 public function Game()
20 {
21 addEventListener(Event.ADDED_TO_STAGE, onAdded);
22 }
23
24 private function onAdded ( e:Event ):void
25 {
26 resetColors();
27
28 q = new Quad(200, 200);
29 q.x = stage.stageWidth - q.width >> 1;
30 q.y = stage.stageHeight - q.height >> 1;
31 addChild ( q );
32
33 s.addEventListener(Event.ENTER_FRAME, onFrame);
34 }
35
36 private function onFrame (e:Event):void
37 {
38 r -= (r - rDest) * .01;
39 g -= (g - gDest) * .01;
40 b -= (b - bDest) * .01;
41
42 var color:uint = r << 16 | g << 8 | b;
43 q.color = color;
44
45 // when reaching the color, pick another one
46 if ( Math.abs( r - rDest) < 1 && Math.abs( g - gDest) < 1 && Math.abs( b - bDest) )
47 resetColors();
48 }
49
50 private function resetColors():void
51 {
52 rDest = Math.random()*255;
53 gDest = Math.random()*255;
54 bDest = Math.random()*255;
55 }
56 }
57 }
我们可以使用rotation这个属性来旋转quad,但是注意,在Starling中使用的是弧度而Flash Player中使用的是角度。这样做是为了保持Sparrow和Starling的一致性(Sparrow是Strarling的姊妹篇,同一作者)。如果你想使用度数来实现旋转的话,只要使用 starling.utils.deg2rad 这个放来来转换一下就可以了:
sprite.rotation = deg2rad(Math.random()*360);
我们可以在运行时设置DisplayObject的pivotX和pivotY属性来改变注册点:
q.pivotX = q.width >> 1; q.pivotY = q.height >> 1;
对于as3开发者来说使用starling会感觉很自然,下面的这个例子,一个quad和一个textfield被添加到一个sprite中,并且可以作为一个组合一起移动,这和我们使用本地的显示列表时一样的:
package { import starling.display.DisplayObject; import starling.display.Quad; import starling.display.Sprite; import starling.events.Event; import starling.text.TextField; public class Game extends Sprite { private var q:Quad; private var s:Sprite; private var r:Number = 0; private var g:Number = 0; private var b:Number = 0; private var rDest:Number; private var gDest:Number; private var bDest:Number; public function Game() { addEventListener(Event.ADDED_TO_STAGE, onAdded); } private function onAdded ( e:Event ):void { resetColors(); q = new Quad(200, 200); s = new Sprite(); var legend:TextField = new TextField(100, 20, "Hello Starling!", "Arial", 14, 0xFFFFFF); s.addChild(q); s.addChild(legend); s.pivotX = s.width >> 1; s.pivotY = s.height >> 1; s.x = (stage.stageWidth - s.width >> 1 ) + (s.width >> 1); s.y = (stage.stageHeight - s.height >> 1) + (s.height >> 1); addChild(s); s.addEventListener(Event.ENTER_FRAME, onFrame); } private function onFrame (e:Event):void { r -= (r - rDest) * .01; g -= (g - gDest) * .01; b -= (b - bDest) * .01; var color:uint = r << 16 | g << 8 | b; q.color = color; // when reaching the color, pick another one if ( Math.abs( r - rDest) < 1 && Math.abs( g - gDest) < 1 && Math.abs( b - bDest) ) resetColors(); (e.currentTarget as DisplayObject).rotation += .01; } private function resetColors():void { rDest = Math.random()*255; gDest = Math.random()*255; bDest = Math.random()*255; } } }
我们现在围绕着注册点旋转这个包含quad和textfield的sprite:
我们的代码现在看起来开始有些杂乱了,那么我们提取一些代码来组建一个CustomSprite类,用这个类封装颜色的变化、quad和textfield。代码如下:
1 package
2 {
3 import starling.display.Quad;
4 import starling.display.Sprite;
5 import starling.events.Event;
6 import starling.text.TextField;
7 public class CustomSprite extends Sprite
8 {
9 private var quad:Quad;
10 private var legend:TextField;
11
12 private var quadWidth:uint;
13 private var quadHeight:uint;
14
15 private var r:Number = 0;
16 private var g:Number = 0;
17 private var b:Number = 0;
18
19 private var rDest:Number;
20 private var gDest:Number;
21 private var bDest:Number;
22
23 public function CustomSprite(width:Number, height:Number, colo
24 {
25 // reset the destination color component
26 resetColors();
27
28 // set the width and height
29 quadWidth = width;
30 quadHeight = height;
31
32 // when added to stage, activate it
33 addEventListener(Event.ADDED_TO_STAGE, activate);
34 }
35
36 private function activate(e:Event):void
37 {
38 // create a quad of the specified width
39 quad = new Quad(quadWidth, quadHeight);
40 // add the legend
41 legend = new TextField(100, 20, "Hello Starling!", "Arial
42
43 // add the children
44 addChild(quad);
45 addChild(legend);
46
47 // change the registration point
48 pivotX = width >> 1;
49 pivotY = height >> 1;
50 }
51
52 private function resetColors():void
53 {
54 // pick random color components
55 rDest = Math.random()*255;
56 gDest = Math.random()*255;
57 bDest = Math.random()*255;
58 }
59
60 /**
61 * Updates the internal behavior
62 *
63 */
64 public function update ():void
65 {
66 // easing on the components
67 r -= (r - rDest) * .01;
68 g -= (g - gDest) * .01;
69 b -= (b - bDest) * .01;
70
71 // assemble the color
72 var color:uint = r << 16 | g << 8 | b;
73 quad.color = color;
74
75 // when reaching the color, pick another one
76 if ( Math.abs( r - rDest) < 1 && Math.abs( g - gDest) < 1 && Math.abs( b - bDest) )
77 resetColors();
78
79 // rotate it!
80 //rotation += .01;
81 }
82 }
83 }
这样的话,我们的Game类变为这样:
1 package 2 { 3 import starling.display.Sprite; 4 import starling.events.Event; 5 6 public class Game extends Sprite 7 { 8 private var customSprite:CustomSprite; 9 10 public function Game() 11 { 12 addEventListener(Event.ADDED_TO_STAGE, onAdded); 13 } 14 15 private function onAdded ( e:Event ):void 16 { 17 // create the custom sprite 18 customSprite = new CustomSprite(200, 200); 19 20 // positions it by default in the center of the stage 21 // we add half width because of the registration point of the custom sprite (middle) 22 customSprite.x = (stage.stageWidth - customSprite.width >> 1 ) + (customSprite.width >> 1); 23 customSprite.y = (stage.stageHeight - customSprite.height >> 1) + (customSprite.height >> 1); 24 25 // show it 26 addChild(customSprite); 27 28 // need to comment this one ? ;) 29 stage.addEventListener(Event.ENTER_FRAME, onFrame); 30 } 31 32 private function onFrame (e:Event):void 33 { 34 // we update our custom sprite 35 customSprite.update(); 36 } 37 } 38 }
注意,我们使用CustomSprite中的update方法来在主sprite中进行循环操作(即一个组建提取的概念), 通过使用这样的方法,我们增加一个全局暂停的方法将会变的很简单。
让我们来给我们的小测试增加一些功能,让我们的quad跟随鼠标移动。在下面的代码中,我们新增了一小段代码来实现这个功能:
1 package
2 {
3 import flash.geom.Point;
4
5 import starling.display.Sprite;
6 import starling.events.Event;
7 import starling.events.Touch;
8 import starling.events.TouchEvent;
9
10 public class Game extends Sprite
11 {
12 private var customSprite:CustomSprite;
13 private var mouseX:Number = 0;
14 private var mouseY:Number = 0;
15
16 public function Game()
17 {
18 addEventListener(Event.ADDED_TO_STAGE, onAdded);
19 }
20
21 private function onAdded ( e:Event ):void
22 {
23 // create the custom sprite
24 customSprite = new CustomSprite(200, 200);
25
26 // positions it by default in the center of the stage
27 // we add half width because of the registration point of the custom sprite (middle)
28 customSprite.x = (stage.stageWidth - customSprite.width >> 1 ) + (customSprite.width >> 1);
29 customSprite.y = (stage.stageHeight - customSprite.height >> 1) + (customSprite.height >> 1);
30
31 // show it
32 addChild(customSprite);
33
34 // we listen to the mouse movement on the stage
35 stage.addEventListener(TouchEvent.TOUCH, onTouch);
36 // need to comment this one ? ;)
37 stage.addEventListener(Event.ENTER_FRAME, onFrame);
38 }
39
40 private function onFrame (e:Event):void
41 {
42 // easing on the custom sprite position
43 customSprite.x -= ( customSprite.x - mouseX ) * .1;
44 customSprite.y -= ( customSprite.y - mouseY ) * .1;
45
46 // we update our custom sprite
47 customSprite.update();
48 }
49
50 private function onTouch (e:TouchEvent):void
51 {
52 // get the mouse location related to the stage
53 var touch:Touch = e.getTouch(stage);
54 var pos:Point = touch.getLocation(stage);
55 // store the mouse coordinates
56 mouseX = pos.x;
57 mouseY = pos.y;
58 }
59 }
60 }
这里需要注意的是,我们没有使用任何鼠标事件,实际上在starling中没有鼠标的概念。下面将会很快提到这里(event模块)。
通过监听 TouchEvent.TOUCH事件,我们可以处理任何鼠标/手指的运动(starling的设计其实目标很明确就是照着平板去的,让你的程序技能在pc有很好的交互,到了平板上依旧ok,不用重复编码)。比如典型的MousEvent.MOUSE_MOVE事件。上例中,我们使用TouchEvent监听来获得鼠标位置,并存贮到变量中,然后在frame监听中使用简单的赋值来移动customSprite。
就像前面提到的,Starling不只是可以简化gpu编程,并且简化了对象的释放操作。假设我们想要在点击的quad的时候将它从场景中移除,代码如下:
1 package 2 { 3 import flash.geom.Point; 4 5 import starling.display.DisplayObject; 6 import starling.display.Sprite; 7 import starling.events.Event; 8 import starling.events.Touch; 9 import starling.events.TouchEvent; 10 import starling.events.TouchPhase; 11 12 public class Game extends Sprite 13 { 14 private var customSprite:CustomSprite; 15 private var mouseX:Number = 0; 16 private var mouseY:Number = 0; 17 18 public function Game() 19 { 20 addEventListener(Event.ADDED_TO_STAGE, onAdded); 21 } 22 23 private function onAdded ( e:Event ):void 24 { 25 // create the custom sprite 26 customSprite = new CustomSprite(200, 200); 27 28 // positions it by default in the center of the stage 29 // we add half width because of the registration point of the custom sprite (middle) 30 customSprite.x = (stage.stageWidth - customSprite.width >> 1 ) + (customSprite.width >> 1); 31 customSprite.y = (stage.stageHeight - customSprite.height >> 1) + (customSprite.height >> 1); 32 33 // show it 34 addChild(customSprite); 35 36 // we listen to the mouse movement on the stage 37 stage.addEventListener(TouchEvent.TOUCH, onTouch); 38 // need to comment this one ? ;) 39 stage.addEventListener(Event.ENTER_FRAME, onFrame); 40 // when the sprite is touched 41 customSprite.addEventListener(TouchEvent.TOUCH, onTouchedSprite); 42 } 43 44 private function onFrame (e:Event):void 45 { 46 // easing on the custom sprite position 47 customSprite.x -= ( customSprite.x - mouseX ) * .1; 48 customSprite.y -= ( customSprite.y - mouseY ) * .1; 49 50 // we update our custom sprite 51 customSprite.update(); 52 } 53 54 private function onTouch (e:TouchEvent):void 55 { 56 // get the mouse location related to the stage 57 var touch:Touch = e.getTouch(stage); 58 var pos:Point = touch.getLocation(stage); 59 60 // store the mouse coordinates 61 mouseX = pos.x; 62 mouseY = pos.y; 63 } 64 65 private function onTouchedSprite(e:TouchEvent):void 66 { 67 // get the touch points (can be multiple because of multitouch) 68 var touch:Touch = e.getTouch(stage); 69 var clicked:DisplayObject = e.currentTarget as DisplayObject; 70 71 // detect the click/release phase 72 if ( touch.phase == TouchPhase.ENDED ) 73 { 74 // remove the clicked object 75 removeChild(clicked); 76 } 77 } 78 } 79 }
注意在这里我们移除了子对象但是并没有移除Event.ENTER_FRAME监听,我们可以使用hasEventListener来看看customSprite的监听是否被移除掉了:
1 private function onTouchedSprite(e:TouchEvent):void
2 {
3 // get the touch points (can be multiple because of multitouch)
4 var touch:Touch = e.getTouch(stage);
5 var clicked:DisplayObject = e.currentTarget as DisplayObject;
6
7 // detect the click/release phase
8 if ( touch.phase == TouchPhase.ENDED )
9 {
10 // remove the clicked object
11 removeChild(clicked);
12
13 // outputs : true
14 trace ( clicked.hasEventListener(e.type) );
15 }
16 }
为了能安全的移除子对象,你可以启用removeChild方法中的第二个参数dispose。它可以自动的将被删除的子对象的所有监听移除:
1 private function onTouchedSprite(e:TouchEvent):void 2 { 3 // get the touch points (can be multiple because of multitouch) 4 var touch:Touch = e.getTouch(stage); 5 var clicked:DisplayObject = e.currentTarget as DisplayObject; 6 7 // detect the click/release phase 8 if ( touch.phase == TouchPhase.ENDED ) 9 { 10 // remove and dispose all the listeners 11 removeChild(clicked, true); 12 13 // outputs : false 14 trace ( clicked.hasEventListener(e.type) ); 15 } 16 }
如果子对象也是一个容器,还包含着其他子对象,那么这些所有的对象也都将被移除掉(是不是非常方便!)。其他用来移除对象的api也可以使用dispose参数,比如:removeChildren或者removeChildAt。这里需要注意的是dispose操作也会清除掉gpu针对该对象的缓冲,但是该对象的texture不会被清除(为了复用嘛,并且starling中的texture和本地对象中的bitmapdata类似)。你可以通过调用Texture/TextureAtlas的dispose方法来释放texture。
你也可以通过调用任何DisplayObject对象的dispose方法来移除对象的所有监听:
1 clicked.dispose()
starling教程-显示列表(The Display List )(二)
标签:
原文地址:http://www.cnblogs.com/huangxiaoyi/p/4442289.html