createjs高级教程:createjs的位图渲染(非常重要)

  • 内容
  • 评论
  • 相关

今天给大家讲的东西,大家请画个重点,要“考的”,当然不是真的要考试,只是说他对于createjs编程非常重要。

今天给大家讲的是位图渲染,开讲之前先给大家普及一下,什么叫做位图渲染。位图渲染,从flash时代就是很有名的增加游戏同屏数量的方法。从名字上来说,就是把素材渲染成位图。大家都知道mc也就是movieclip的性能非常差,矢量动画的性能也非常差,但是图片的性能却还不错,所以之前我都推荐大家使用sprite。但是有些地方却不得不使用mc,或者矢量,其根本原因就是sprite也就是雪碧图真的太大了,他比一个同等时间的视频还要大。那么有没有,又能像矢量这么小,又能如sprite一样快的办法呢?有!位图渲染就是为此诞生的!他的基本原理就是把任何的素材都可以用copy像素的方式转化为位图,从而提升性能。这时候,做过as3的童鞋可能会说了:“不就是cacheAsBitmap吗?”。确实cacheAsBitmap就是渲染成位图而createjs的cache也是同样的道理(虽说道理一样但是实际原理还是不一样的,createjs的cache并没有变成位图),但是!!!cache的过程中也是非常消耗性能的,当你使用cache的时候可能性能不但没提升可能还会下降。所以我们的位图渲染并不是简单的cache,而是在它使用前,提前渲染成位图,也就是,俗称的用时间换效率的办法。具体的做法是,让动画自己运行一遍,然后不停的copy它每一帧的像素,使它成为一张sprite表,等到要用的时候他已经成为了sprite,也就不怎么耗性能了。这时候也许有人会问,虽然矢量的加载时间不多,但是算上渲染时间是不是和直接加载sprite相同了?答案是完全不同!我们计算机手机的性能非常强,渲染的速度是非常快的,并且渲染的过程是不耗流量的,尤其适合web和移动端开发。

讲完了位图渲染的原理,那我再讲讲怎么在createjs上做位图渲染。

之前我一直想自己封装一个位图渲染类,毕竟as3也就是flash他也没有自己的位图渲染类,靠自己封装的。但是就在我准备写的时候,惊奇的发现,createjs其实已经实现的这个类。这个类名就叫做SpriteSheetBuilder。期初我没有重视这个类,是因为我一直认为他是sprite类的一个底层分类,毕竟官方例子也没有着重写他,api也写的及其晦涩。后来看源代码的时候发现了这个类,正所谓是金子总会发光的真的没错。

来,新鲜的代码来了

<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <title></title>
    <style>
        *{
            margin: 0;
            padding: 0;
        }
    </style>
</head>
<body>
<canvas id="canvas" width="1920" height="1000" style="position: absolute"></canvas>
<script src="createjs-1.0.0.min.js" type="text/javascript"></script>
<script src="FPS.js" type="text/javascript"></script>
<script src="assets.js" type="text/javascript"></script>
<script>

    var canvas = document.getElementById("canvas")
    var stage = new createjs.StageGL(canvas);
    var huo = new lib.huo();//矢量影片剪辑
    var spritesheetBuilder = new createjs.SpriteSheetBuilder();
    spritesheetBuilder.addMovieClip(huo,new createjs.Rectangle(0,0,180,160),0.5);
    spritesheetBuilder.addEventListener("progress",function (event){
        console.log(event,"<<<<<<<<<<<<<<<<")//渲染进度
    })
    spritesheetBuilder.addEventListener("complete",function(event){
        console.log("complete",spritesheetBuilder.spriteSheet)
        spritesheetBuilder.stopAsync();
        renderCompleteHandler(spritesheetBuilder.spriteSheet)
    })
    spritesheetBuilder.buildAsync();

    createjs.Ticker.framerate = 65;//用RAF_SYNCHED模式帧频要多放几侦,不然掉一帧帧频就自动降级
    createjs.Ticker.timingMode =  createjs.Ticker.RAF_SYNCHED;
    createjs.Ticker.addEventListener("tick",function (){
        stage.update();
    })
    var spritesheet,sprite
    function renderCompleteHandler(sheet)
    {
        spritesheet = sheet;
        sprite = new createjs.Sprite(spritesheet);
        sprite.play();
        stage.addChild(sprite);//在这里矢量已经变成位图
        sprite.x = 500;
        sprite.y = 0;

        moreHandler();
    }
    function moreHandler()
    {
        for(var i = 0;i < 15000;i++)
        {
            var s = new createjs.Sprite(spritesheet);
            stage.addChild(s);
            s.x = Math.random()*1920-50;
            s.y = Math.random()*900+100;
            s.gotoAndPlay(parseInt(Math.random()*20));
        }
        FPS.startFPS(stage);
        FPS.showText = "COUNT:15000"
    }
</script>
</body>
</html>

代码非常简单,就是我创建了一个movieclip对象“huo”,然后用SpriteSheetBuilder类做了位图渲染,最后创建渲染后的sprite对象,并创建15000个对象来测试性能。

那性能怎么样呢?下面的例子点击看看。

http://www.ajexoop.com/test/SpriteSheetBuilder/index.html

15000个矢量火,太多了全屏都是橙色,我特意放了一个在最上面,让童鞋们看出来这是火……

可以看到帧频再15000个矢量对象并且还在有滤镜的情况下(从火的素材可以看出,加了发光滤镜),跑到了60帧,当然这是在我的机子上,不同的机子不同的性能结果也不同。这里还有一点值得注意的,在使用animateCC给movieclip加滤镜并进行位图渲染时,滤镜要在每个帧的对象上加,而不能直接在父mc上加,除非你用代码加滤镜

除了可以让movieclip做位图渲染外,还可以让代码生成的矢量对象做位图渲染,我下面再放一段代码:

<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <title></title>
    <style>
        *{
            margin: 0;
            padding: 0;
        }
    </style>
</head>
<body>
<canvas id="canvas" width="1920" height="1000" style="position: absolute"></canvas>
<script src="createjs-1.0.0.min.js" type="text/javascript"></script>
<script>

    var canvas = document.getElementById("canvas")
    var stage = new createjs.StageGL(canvas);
    var spritesheetBuilder = new createjs.SpriteSheetBuilder();
    var text = new createjs.Text()
    text.font = "bold 36px Arial";
    text.color = "#000000";
    var rect = new createjs.Rectangle(0,0,60,60);
    var str = "你今天真的好么,我今天真的非常好!"
    var txtFrameFunction = function (source, data)
    {
        source.text = str.charAt(data.i).toString();
    }
    for(var i= 0;i < str.length;i++)
    {
//        text.text = str.charAt(i).toString();//这样来加帧是没有的,调用的都是最后一个字母
        spritesheetBuilder.addFrame(text,rect,1,txtFrameFunction,{"i":i});
    }
//    spritesheetBuilder.addEventListener("progress",function (event){
//    })
    spritesheetBuilder.addEventListener("complete",function(event){
        console.log("complete",spritesheetBuilder.spriteSheet)
        spritesheetBuilder.stopAsync();
        renderCompleteHandler(spritesheetBuilder.spriteSheet)
    })
    spritesheetBuilder.buildAsync();

    var spritesheet,sprite
    function renderCompleteHandler(sheet)
    {
        spritesheet = sheet;
        sprite = new createjs.Sprite(spritesheet);
        sprite.play();
        stage.addChild(sprite);//在这里矢量已经变成位图
        sprite.x = 500;
        sprite.y = 0;

    }
    createjs.Ticker.framerate = 65;//用RAF_SYNCHED模式帧频要多放几侦,不然掉一帧帧频就自动降级
    createjs.Ticker.timingMode =  createjs.Ticker.RAF_SYNCHED;
    createjs.Ticker.addEventListener("tick",function (){
        stage.update();
    })
</script>
</body>
</html>

http://www.ajexoop.com/test/SpriteSheetBuilder/index2.html

可以点击链接,看一下效果,我把文字(text,shape都是矢量)做了位图渲染,这样就不需要bitmapText了。不过方法有些特别,重点是看那个引入的方法,有了这个方法txtFrameFunction,才能边播放边渲染,才能最后把整个动画渲染出来(坑爹的官方居然一点例子都没有,不是看源代码我也不知道怎么用)。

那么位图渲染的范围只限于矢量和滤镜么?答案是不止的,还有复杂对象动画。比如:带了很多装备武器的人物骨骼动画。说到这里我提一下,egret,也就是白鹭,有个渲染龙骨的例子,同屏可以渲染很多对象,但是我们自己用龙骨却不可以,原因就是,他做了位图渲染。用了位图渲染,带了再多装备,做再复杂的动作对它来说也只是一张图。那怎么看出来有没有做位图渲染呢?看有没有做位图渲染,只需要看他第二次加载的时候是不是瞬间加载完毕的就可以了,如果不是瞬间加载完毕的,说明他这不是在加载,而是在渲染。因为第二次肯定是加载缓存的,缓存可以很快的加载完成。

接下来,还要说一个重要的事:“不是用了位图渲染,性能就一定能变好了”。一台设备如果连只渲染sprite也卡的话,位图渲染也是没用的,程序员做些不适宜位图渲染的事,位图渲染也不会使程序变快,这点换别的引擎也是一样的。下面我例举一下:

1:位图渲染中,把本身不需要渲染的背景部分一起渲染进去。

我这篇文章一出,有些童鞋可能会把自己舞台上所有的对象全部放进movieclip里,一整个做个位图渲染,这样子并没有用的,只会增加重绘区域,并不会使程序变快。只需要渲染矢量的部分,滤镜的部分,复杂对象的部分(比如带了装备的骨骼)渲染就够了。

2:矢量对象形状是随机的。

矢量对象形状如果是随机的,就变得经常要渲染,这时候不仅不会使程序变快,还会有内存泄漏的隐患。这样还不如不停的cache。

3:本身就可以做进位图里。

本身可以做进位图里,还用位图渲染,除非你为了省加载时间。不然就是没事找事。

4:渲染后,源对象还在舞台上的。

这个就不解释了,低级错误。

5:其他原因造成的卡顿。

比如算法啊,内存泄漏啊,嵌套太多啊,死循环啊等等。

最后……大家都学会了么。

demo下载地址:https://pan.baidu.com/s/1YzJIxQzoHuNjMLiv_KQjFw

dashang.jpg

评论

4条评论
  1. Gravatar 头像

    支雅 回复

    好厉害,学到了。

  2. Gravatar 头像

    匿名 回复

    最开始没关注api的时候 一直是用双缓冲来操作 生成位图渲染 一个隐藏的复杂mc 画到一个显示的容器里面

    • Gravatar 头像

      ajex 回复

      @匿名 我刚开始的时候也是准备这么封装,结果发现了这个api

发表评论

电子邮件地址不会被公开。