0

我尝试结合 Lee Brimlow 的 blitting 教程系列和 Rex Van der spuy 的“带有 Flash 的高级游戏设计”中的技术

我是一名开发人员,致力于在 Flash 中制作的网络在线虚拟世界。我做了一个电话应用程序(类似于侠盗猎车手游戏中的电话)。无论如何,当发送消息时,我们想要播放一个信封飞来飞去并在其周围闪闪发光的疯狂动画。它很滞后(尤其是在较旧的计算机上),所以我认为这将是一个使用 blitting 的好机会。然而,blitting 动画实际上比普通的movieclip 慢!!这到底是怎么回事?blitting 是否只对移动设备更好,而在计算机上实际上更慢?也许我做错了什么。这是我的代码:

// 这部分发生在电话初始化时

//**                
//---------------- Blitting stuff ----------------------------------
// add this bitmap stage to the display list so we can see it
            _bitmapStage = new BitmapData(550, 400, true, 0xD6D6D6);


        _phoneItself.addChild(new Bitmap(_bitmapStage));

        var _spritesheetClass:Class = getDefinitionByName("ESpritesheet_1") as Class;
        _spritesheet = new _spritesheetClass() as BitmapData;

        _envelopeBlit = new BlitSprite(_spritesheet, BlitConfig.envelopeAnimAry , _bitmapStage);
        _envelopeBlit.x = -100;
        _envelopeBlit.y = 0;

        _envelopePlayTimer = new Timer(5, 0);
        _envelopePlayTimer.addEventListener(TimerEvent.TIMER, onEnterTimerFrame);
        _envelopeBlit.addEventListener("ENV_ANIM_DONE", onEnvAnimFinished);

// “BlitSprite”是我创建的一个类。它看起来像这样:

package com.fs.util_j.blit_utils
{
    import flash.display.BitmapData;
    import flash.events.Event;
    import flash.events.EventDispatcher;
    import flash.geom.Point;
    import flash.geom.Rectangle;

    public class BlitSprite extends EventDispatcher
    {

        private var _fullSpriteSheet:BitmapData;
        private var _rects:Array;
        private var _bitmapStage:BitmapData;

        private var pos:Point = new Point ();
        public var x:Number = 0;
        public var y:Number = 0;

        public var _animIndex:

整数 = 0; 私有变量_count:int = 0;

    public var animate:Boolean = true;
    private var _whiteTransparent:BitmapData;
    private var _envelopeAnimAry:Array;
    private var _model:Object;



    public function BlitSprite(fullSpriteSheet:BitmapData, envelopeAnimAry:Array, bitmapStage:BitmapData, model:Object = null) 
    {
        _fullSpriteSheet = fullSpriteSheet;
        _envelopeAnimAry = envelopeAnimAry;
            _bitmapStage = bitmapStage;
            _model= model;

            init();
        }

        private function init():void
        {
//          _whiteTransparent = new BitmapData(100, 100, true, 0x80FFffFF);

            this.addEventListener("ENV_ANIM_DONE", onEvnAnimDone);

        }       

        protected function onEvnAnimDone(event:Event):void
        {

        }       

        public function render():void
        {

//          pos.x = x - _rects[_animIndex].width*.5;
//          pos.y = y - _rects[_animIndex].width*.5;

//          if (_count % 1 == 0 && animate == true)
//          {

//              trace("rendering");

                if (_animIndex == (_envelopeAnimAry.length - 1) )
                {
//                  _animIndex = 0;
                    dispatchEvent(new Event("ENV_ANIM_DONE", true));
                    animate = false;
//                  trace("!!!!animate over " + _model.animOver);

//                  if (_model != null)
//                  {
//                      _model.animOver = true;
//                  }

//                  trace("!!!!animate over " + _model.animOver);

                }

                else 
                {
                    _animIndex++;
                }


                pos.x = x + _envelopeAnimAry[_animIndex][1];
                pos.y = y + _envelopeAnimAry[_animIndex][2];


                _bitmapStage.copyPixels(_fullSpriteSheet, _envelopeAnimAry[_animIndex][0], pos, null, null, true);

        }



    }
}




// THIS PART HAPPENS WHEN PHONE'S SEND BUTTON IS CLICKED


                _envelopeBlit.animate = true;
                _envelopeBlit._animIndex = 0;
                _darkSquare.visible = true;
                _envelopePlayTimer.addEventListener(TimerEvent.TIMER, onEnterTimerFrame);
                _envelopePlayTimer.start();

它还使用 BlitConfig 存储有关由 TexturePacker 吐出的 spritesheet 的信息

    package com.fs.pack.phone.configuration
    {
        import flash.geom.Rectangle;

        public final class BlitConfig
        {




            public static var _sending_message_real_20001:Rectangle = new Rectangle(300,1020,144,102);
            public static var _sending_message_real_20002:Rectangle = new Rectangle(452,1012,144,102);
            public static var _sending_message_real_20003:Rectangle = new Rectangle(852,852,146,102);
            public static var _sending_message_real_20004:Rectangle = new Rectangle(2,1018,146,102);
            public static var _sending_message_real_20005:Rectangle = new Rectangle(702,822,148,102);
.
.
.
public static var _sending_message_real_20139:Rectangle = new Rectangle(932,144,1,1);

    public static var envelopeAnimAry:Array = [

                // rectangle, x offset, y offset
            [ _sending_message_real_20001, 184,155],
            [ _sending_message_real_20002, 184,155],
            [ _sending_message_real_20003, 183,155],
            [ _sending_message_real_20004, 183,155],
.
.
.
[ _sending_message_real_20139, 0,0]
        ]



        public function BlitConfig()
        {
        }


    }
}
4

1 回答 1

0

编辑:知道这不是移动的,我下面的回答是无关紧要的。不过,我会把它留在那里,以防将来有人在移动设备上遇到问题。

关于这个特定问题,您每 5 毫秒运行一次计时器。首先,计时器准确的最低范围是>15ms,因此这永远不是一个可行的解决方案。对于与在舞台上显示某些内容相关的任何 Timer,您不应少于一帧。(1000/stage.framerate对于 30fps 的应用程序来说,约 40 毫秒)

对于 blitting,目标是减少计算和渲染。按照您现在的设置方式,看起来您每 5 毫秒进行一次 blitting。这实际上是 MovieClip 渲染频率的 8 倍多。你应该减少你blit的频率。只有在实际发生超出翻译的更改时才这样做。比这更频繁地这样做是矫枉过正的,也是它如此缓慢的原因(同样,创建位图很慢)


通常,您不想在 AIR for Mobile 应用程序中进行 blit(我假设您正在这样做,因为您提到了正在初始化的电话)。我不确定使用其他/本机 SDK 是否可以,但请避免在 AIR 中使用。

从本质上讲,它归结为 blitting 的工作原理。Blitting 捕获屏幕并将其显示在舞台上而不是实际对象上。总的来说,这很棒。这意味着您的显示对象,尤其是渲染速度较慢的矢量,必须减少渲染频率。它在制作动画时特别好,因为每次以任何方式平移对象时都会重新渲染对象,而不是位图。

然而,在移动平台上,创建该位图非常慢。我从未研究过 SDK 如何创建位图,但它并没有有效地做到这一点(它经常让我怀疑它是否逐个像素地做到了)。在台式机上,这通常很好。有大量的 CPU 和大量的 RAM 可以快速实现这一点。然而,在移动设备上,这种奢侈目前并不存在。因此,当您 blit 并创建该位图时,运行该过程需要一段时间。

这个问题在高分辨率屏幕上更加严重。我在今年 1 月到 5 月期间开发的一个应用程序有选择地使用 blitting 在 GPU 加速环境中使用过滤器。在 iPad 2 上,blitting 将我的应用程序从 30fps 提高到 ~24fps。没什么大不了的,用户不会注意到任何事情。然而,在配备 Retina 显示屏的 iPad 3 上,它下降到 10fps。仔细想想,这是有道理的,因为视网膜 iPad 的像素是非视网膜 iPad 的 4 倍。

如果您确实想在移动设备上使用 blitting,我建议您做一些事情:

  1. 使用 GPU 渲染模式。没有它,你就没有机会。请注意,至少在 AIR 3.7 之前的版本中,GPU 模式不支持过滤器。我不确定是否仍然如此。但是,您应该避免在移动设备上使用过滤器,因为它们的渲染速度非常慢
  2. 确保测试发布模式应用程序。根据构建设置,调试模式和发布模式应用程序之间的差异可能很大,尤其是在 iOS 上。我刚刚开发的一个应用程序从View在调试模式下花费 2-3 秒创建一个新的 Flex 到在 iPhone 4 上在发布模式下不到一帧 (~40 毫秒) 完成
  3. 谨慎使用 blitting。仅在绝对必要的情况下进行
  4. 寻找简化显示列表的方法。让一个有 40 个子对象的对象创建一个按钮很容易。相反,寻找方法将其简化为更少的对象和更少的过滤器(即使删除过滤器需要您添加另一个对象)。我不相信这将有助于实际的 blitting 过程,但它应该有助于首先渲染对象。

所以一般来说,在移动设备上谨慎使用 blitting,因为位图创建速度很慢。

于 2013-08-30T17:53:52.217 回答