【问题标题】:A loop in enterframe?enterframe 中的循环?
【发布时间】:2011-08-18 21:06:17
【问题描述】:

我在 AS3 中为一堆单词制作动画。因为我将在移动设备上使用它,所以我想使用位图而不是 Sprites。所以我创建了 WordObjects,它有一个可以访问的 .bitmap 属性。

我有以下代码,它会触发 click 事件并循环遍历 enterframe 事件中的数组。这可能是一个坏主意,但我不确定如何做得更好。 (令人惊讶的是,它在 Flashbuilder 中运行良好,但在 Flash CS5 中运行缓慢。)

有没有更好的方法来做到这一点?我只是想要一种有效的方式来为位图数组设置动画。

    private function clickhandler (e:MouseEvent){

        this.addEventListener(Event.ENTER_FRAME, blowemup);
    }
    private function blowemup(e:Event){
        var newPosition:Number;
        for(var i:int=0; i<arrWordObjects.length; i++)
        {
            newPosition = updatePosition(arrWordObjects[i].bitmap);
            arrWordObjects[i].bitmap.x += newPosition;
            arrWordObjects[i].bitmap.y += getRandomNumber();

        }
    }

【问题讨论】:

    标签: actionscript-3 enterframeevent


    【解决方案1】:

    使用for each(Object in Array) 而不是标准的for 循环会产生巨大的影响。

    private function blowemup(e:Event):void
    {
        var newPosition:Number;
    
        var i:ArrWordsObjectClass; // <-- don't know what the class for this is, just replace
        for each(i in arrWordObjects)
        {
            newPosition = updatePosition(i.bitmap);
            i.bitmap.x += newPosition;
            i.bitmap.y += getRandomNumber();
        }
    }
    

    键入了for each 循环,这意味着节省了大量时间,通常它会在每次迭代时尝试计算arrWordObjects[i] 是什么。

    另外,附注:使用一个 ENTER_FRAME 驱动的函数并循环遍历应用程序中要处理每一帧的所有内容,比为对象应用数百个侦听器效率高得多。

    我通常会创建一个处理程序类,其中包含 ENTER_FRAME 和一个存储我的对象的数组,如下所示:

    package
    {
        import flash.events.Event;
        import flash.display.Sprite;
    
        public class Handler extends Sprite
        {
            // vars
            public var elements:Array = [];
    
            /**
             * Constructor
             */
            public function Handler()
            {
                addEventListener(Event.ENTER_FRAME, _handle);
            }
    
            /**
             * Called on each dispatch of Event.ENTER_FRAME
             */
            private function _handle(e:Event):void
            {
                var i:Element;
                for each(i in elements)
                {
                    i.step();
                }
            }
        }
    }
    

    然后我为我想要处理的所有对象创建一个基类,其中包含上面调用的step() 函数。

    package
    {
        import flash.display.DisplayObject;
    
        public class Element extends Object
        {
            // vars
            public var skin:DisplayObject;
    
            /**
             * Called on each dispatch of Event.ENTER_FRAME at Handler
             */
            public function step():void
            {
                // override me
            }
        }
    }
    

    现在只需使用您的对象扩展 Element:

    package
    {
        import flash.display.Sprite;
    
        public class MyThing extends Element
        {
            /**
             * Constructor
             */
            public function MyThing()
            {
                skin = new Sprite();
    
                skin.graphics.beginFill(0);
                skin.graphics.drawCircle(0,0,40);
                skin.graphics.endFill();
            }
    
            /**
             * Override step
             */
            override public function step():void
            {
                skin.x += 4;
            }
        }
    }
    

    一切顺利!:

    var handler:Handler = new Handler();
    
    var m:MyThing;
    var i:uint = 0;
    for(i; i<10; i++)
    {
        m = new MyThing();
        m.y = Math.random()*stage.stageHeight;
    
        handler.elements.push(m);
        addChild(m.skin);
    }
    

    【讨论】:

    • 嗨,Marty,谢谢——请参阅我上面对 Dean 的评论。我确实切换到了每个(数组中的对象)。一个问题——如果我将这些作为对象,是否将它们转换为类有关系吗?如果你有 var i:ArrWordsObjectClass 我只会在代码中包含以下类 ArrWordsObjectClass {}。有什么理由认为这比这更好 - var i:Object;对于每个(arrWordObjects 中的 i)
    • 每个循环的速度将随着您使类型更严格而增加。例如 - 在充满 MovieClips 的数组上使用 Object 意味着对于每次迭代,您的循环都必须确定是的,该项目是一个对象,但它实际上是:MovieClip -> Sprite -> DisplayObjectContainer -> InteractiveObject -> DisplayObject -> EventDispatcher -> 对象。尽可能在继承链的上游定义您的类型是提高效率的原因。
    • “向上”继承链实际上意味着一直“向上”到 MovieClip,对吗?这总是让我感到倒退。我从祖父那里继承下来,祖父在我的家谱上比我高。但我离题了。 :) 通过简单地指定一个随机的类类型,例如“class ArrWordsObjectClass {}”,我将获得与直接引用 Sprite 等内置类相同的效率?
    【解决方案2】:

    您打算一次在舞台上放多少张位图?

    我有 40 个 900x16px 位图在舞台上使用 air 2.6 在我的 iPhone 上全速运行。

    我在 enterframe 事件中使用了一个 foreach 循环,我在鼠标单击时添加了该循环,并在动画完成后将其删除。

    记得在启用 gpu 渲染的情况下为移动设备编译它。 (如果您使用的是 air 2.6,请在 app.xml 中使用 gpu)

    这也值得一读,它解释了很多关于移动设备的性能 http://help.adobe.com/en_US/as3/mobile/WS901d38e593cd1bac-3d719af412b2b394529-8000.html

    这是我所拥有的一个基本示例......

    package
    {
        import flash.display.Bitmap;
        import flash.display.BitmapData;
        import flash.display.Sprite;
        import flash.display.StageAlign;
        import flash.display.StageScaleMode;
        import flash.events.Event;
        import flash.events.MouseEvent;
        import flash.geom.Rectangle;
    
        [SWF(frameRate="30", backgroundColor="#FF00FF")]
        public class Test extends Sprite
        {
            private var fields:Vector.<Bitmap> = new Vector.<Bitmap>();
    
            public function Test()
            {
                this.stage.scaleMode = StageScaleMode.NO_SCALE;
                this.stage.align = StageAlign.TOP_LEFT;
    
                for(var i:int = 0; i< 37; i++){
                    var bd:BitmapData = new BitmapData(960, 16, true, 0x000000);
    
                    bd.fillRect(new Rectangle(0, 0, 900, 16), Math.round( Math.random()*0xFFFFFFFF ));
    
                    var b:Bitmap = new Bitmap(bd);
    
                    b.x = 0;
                    b.y = i*16;
    
                    stage.addChild(b);
                    fields.push(b);
                }
    
                stage.addEventListener(MouseEvent.MOUSE_DOWN, onMouseDown);
            }
    
            private var inertia:Boolean = false;
            private var yCurrent:Number;
            private var ySpeed:Number;
            private var startY:Number;
    
            private var cy:Number = 0;
    
            private function onEnterFrame(e:Event):void{
                if(!inertia){
                    ySpeed = (startY - yCurrent) ; // / 16;
                    startY = yCurrent
                } else {
                    ySpeed *= 0.8;
    
                    if(ySpeed < 0.01 && ySpeed > -0.01){
                        inertia = false;
                        stage.removeEventListener(Event.ENTER_FRAME, onEnterFrame);
                    }
                }
    
                cy += ySpeed;
                if(cy > 640)
                    cy -= 640;
    
                var ty:Number = cy;
                for each(var tf:Bitmap in fields){
                    tf.y = ty;
                    ty += 16;
    
                    if(ty > 640)
                        ty -= 640;
                }
            }
    
            private function onMouseDown(e:MouseEvent):void{
                inertia = false;
                startY = e.stageY;
                yCurrent = e.stageY;
                stage.addEventListener(Event.ENTER_FRAME, onEnterFrame);
                stage.addEventListener(MouseEvent.MOUSE_MOVE, onMouseMove);
                stage.addEventListener(MouseEvent.MOUSE_UP, onMouseUp);
            }
    
            private function onMouseMove(e:MouseEvent):void{
                yCurrent = e.stageY;
            }
    
            private function onMouseUp(e:Event):void{
                inertia = true;
                stage.removeEventListener(MouseEvent.MOUSE_MOVE, onMouseMove);
                stage.removeEventListener(MouseEvent.MOUSE_UP, onMouseUp);
            }
    
        }
    }
    

    【讨论】:

    • 嗨,院长,谢谢!这是我发现的。我不断收到这个疯狂的“断点未设置”;在第 xx 行没有可执行代码错误,我认为这不会有多大作用。原来这是问题所在。断点没有在 FB4 中设置,而是在 CS5.5 中设置。当我清除它们时,它运行正常。感谢您对 GPU 的提醒——它确实有所作为。 ——大卫
    【解决方案3】:

    我建议考虑在 Adob​​e 的网站上编写自定义效果,而不是注册 ENTER_FRAME 事件。您在此处放置的内容意味着只要程序正在运行,此代码将永远运行。如果您想停止效果或运行 10 帧并停止,那么您将不得不编写更多代码。如果要将其应用于多个实例,它会变得更加复杂。您将不得不解决自定义效果框架解决的问题。

    我会在这里阅读如何编写自定义效果:

    http://livedocs.adobe.com/flex/3/html/help.html?content=createeffects_1.html

    【讨论】:

    • 谢谢——但这都是动作脚本,所以我不想进入 Flex 框架!
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-06-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多