• starling教程-显示列表(The Display List )


    显示列表

     

    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(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() 

     

  • 相关阅读:
    HTML5文件上传前本地预览
    sql(2) DISTINCT
    sql (1)
    delphi 第4课
    delphi 第3课
    Delphi 第2课
    delphi 用户可以点击格式修改进行模板修改
    delphi 流程单打印
    Delphi 第一课
    【BZOJ4530】[Bjoi2014]大融合 LCT维护子树信息
  • 原文地址:https://www.cnblogs.com/klh5211314/p/3158667.html
Copyright © 2020-2023  润新知