手把手教你制作微信小游戏的下载进度条-适用于cocos3D

###1.为什么要制作微信小游戏的下载进度条?
众所周知,微信小游戏的要求不能超过12M,如果超出去的部分需要把你打包构建出来的res文件夹放到腾讯云上边。然后只保留src文件夹。那么再进入游戏的时候再进入第一个场景之前会去下载这部分的资源。只有在下载完成后才会进去你的第一个游戏场景。那么可能就会出现很大的问题。
(1).假设我的资源很大,或者说玩家的网络不好,需要下载10s甚至20s才能下载完成的话,那么在这10s,20s的等待时间里,玩家会看到什么呢?是黑屏,没错,屏幕上什么都没有。一片黑,或者只会停留在“Power by cocos3D”这个插屏上。那么如果玩家是个没有耐心的人的话,可能就直接骂一句:“什么垃圾游戏,卡着不动啊”然后流失了。
(2)我们的res文件夹里有大量的散列的json文件,随便就几百个,下载这些文件难免不会出错。如果有哪怕其中的一个文件下载失败了,那么在控制台会输出一句话,“download failed”。然后就停了,玩家是看不到控制台的信息的,他只会看到,游戏又卡着不动了,等了30s.然后又骂一句:“什么垃圾游戏,卡着不动啊”然后又流失了。

###2. 开始正式的教程。我们的计划就是再进入第一个场景之前制作一个专门显示下载进度条的场景并立刻呈现在玩家眼前,让玩家有东西能看到。不是黑黑的傻等着然后被流失。
(1)首先我们只需要关注下图里的那个红色框框里的东西。这个2个代码会再最后作为附件上传的,大家可以先下载下来把他们导入到你的项目里配合本教程使用。
##附件在这里 归档.zip (127.9 KB)

####(2).打开我们的main.js文件。找到 onStart() 这个函数,作出如下的修改

var onStart = function() {
    window._CCSettings = undefined;
    cc.loader.downloader._subpackages = settings.subpackages;

    cc.view.enableRetina(true);
    cc.view.resizeWithBrowserSize(true);

    var launchScene = settings.launchScene;

    //新追加的3行代码。
    var loadingScene = require('loading-scene/loading-scene');
    cc.director.runSceneImmediate(loadingScene);
    loadingScene.loadinglaunchScene(launchScene);

    // load scene 被我们注释掉的函数
    // cc.director.loadScene(launchScene, null,
    //     function () {
    //         if (cc.sys.isBrowser) {
    //             // show canvas
    //             var canvas = document.getElementById('GameCanvas');
    //             canvas.style.visibility = '';
    //             var div = document.getElementById('GameDiv');
    //             if (div) {
    //                 div.style.backgroundImage = '';
    //             }
    //         }

    //         cc.view.setDesignResolutionSize(640, 1136, 4);

    //         cc.loader.onProgress = null;
    //         console.log('Success to load scene: ' + launchScene);
    //     }
    // );
  };

####(3)然后我们打开这个js文件

注意里边的 33行和110行。有2句

cc.view.setDesignResolutionSize(640, 1136, 4);

设置设计分辨率的,注意把这个里的640,1136改成你自己的游戏的设计分辨率哦。千万不要忘记。

####(4)接着运行你的游戏,不出意外的话,在进入你的第一个场景之前,会有一个这样子的加载的场景。那么就大功告成了。

####(5)接着我们来分析一下loading-scene.js里的一些代码。

/*
 这段代码的作用是直接创建一个场景,并且再场景上加上背景图片,进度条,
现在当前进度到多少的label。其中用到的图片就在这个文件夹下,
大家可以根据自己的需求去替换文件。
*/
var scene = new cc.Scene();
console.log(scene);

let visibleSize = cc.view.getVisibleSize();

//1.新增Canvas组件
var root = new cc.Node();
root.name = 'Canvas';
var canvas = root.addComponent(cc.CanvasComponent);
canvas.clearFlag = cc.GFXClearFlag.COLOR;
root.parent = scene;
let rootTrans = root.addComponent(cc.UITransformComponent);

var bgSpriteNode = new cc.Node();
bgSpriteNode.parent = root;
var bgSprite = bgSpriteNode.addComponent(cc.SpriteComponent);
createImage(bgSprite, "loading-scene/startScene_bg.png");


let pos = cc.v3(0,-200,0);

let loadingBgNode = new cc.Node();
loadingBgNode.parent = root;
loadingBgNode.position = pos;
let loadingBgSprite = loadingBgNode.addComponent(cc.SpriteComponent);
createImage(loadingBgSprite, 'loading-scene/loadingBg.png');

let loadingBarNode = new cc.Node();
loadingBarNode.parent = root;
loadingBarNode.position = pos;
let loadingBarSprite = loadingBarNode.addComponent(cc.SpriteComponent);
createImage(loadingBarSprite, 'loading-scene/loadingBar.png', function (sprite){
  sprite.type = cc.SpriteComponent.Type.FILLED;
  sprite.fillType = cc.SpriteComponent.FillType.HORIZONTAL;
  sprite.fillStart = 0;
  sprite.fillRange = 0;
});

//新增进度条的label
var labelNode = new cc.Node();
labelNode.position = pos;
// labelNode.addComponent(cc.UITransformComponent);
var label = labelNode.addComponent(cc.LabelComponent);
label.fontSize = 30;
label.color = cc.color(0,0,0,255);
label.lineHeight = label.fontSize;
label.string = '资源加载中...0%'
labelNode.parent = root;

//3.预加载场景 如果网络不好的话,会有“加载失败,请检查网络的通知”
scene.loadinglaunchScene = function(launchScene) {

  cc.director.preloadScene(launchScene, (completedCount, totalCount, item) => {
    //todo 这个地方加载进度条
    loadingBarSprite.fillRange = completedCount / totalCount;
    label.string = ("资源加载中..." + parseInt((completedCount / totalCount) * 100) + "%")
  }, (error) => {
    if (error) {
      //todo 这个地方提示网络环境不好,请检查网络后重试
      console.log('==preloadScene error==', launchScene, error)
      label.string = '加载失败,请检查网络';
      return;
    }
    cc.director.loadScene(launchScene, null, function() {
      if (cc.sys.isBrowser) {
        // show canvas
        var canvas = document.getElementById('GameCanvas');
        canvas.style.visibility = '';
        var div = document.getElementById('GameDiv');
        if (div) {
          div.style.backgroundImage = '';
        }
      }

      cc.view.setDesignResolutionSize(640, 1136, 4);
      cc.loader.onProgress = null;
      console.log('Success to load scene: ' + launchScene);
    });
  })
}
4赞

合法的

mark mark

mark

###分包加载包大小的限制
目前小游戏分包大小有以下限制:

  • 整个小游戏所有分包大小不超过 8M(已经扩展到12M)
  • 单个分包/主包大小不能超过 4M

微信小游戏的分包限制,文档上是这样的。
按楼主的处理方式,确实是可以在第一时间看到加载界面,体验会比黑屏好很多。
看完之后,我突然有个想法,制作起来应该会更方便一点。
思路如下:

  1. 把加载界面做到第一个场景里去,包括logo,进度条,还有相关的加载代码。当然,除了代码资源,全部放远程加载也没问题。原则上是第一场景总资源不要太大,如楼主所说,以保证玩家第一时间看到加载界面。
  2. 把非第一场景的其它资源都放到分包里,分包有限制大小,所以分的时候,要保证每个分包的代码小于4M。如果你们项目的脚本比较多的话,建议分包只放代码,然后其它的美术资源音乐资源放远程服务器上。
  3. 以上两点准备工作做完后,就可以像平常开发一样,直接在creator里面写启动界面的代码了。

相关的接口:

1赞

mark

mark

这样的话对于资源需要放CDN的来说,可能还要多一步脚本操作,将加载场景从import和raw-assets中找出

这样还是有个问题没解决,preloadScene只会判断绑定到编辑器上的资源,但是实际上很多资源都不会绑定到编辑器上,而是在脚本的onload里面去异步下载的。

比如音乐,你总不可能把所有的音乐音效全部绑定到编辑器上吧,肯定是有一个专门的音乐加载模块,但是那部分不会进入preloadScene的进度,进去后,仍然存在部分资源还在下载。

所以这个方案只能解决不黑屏,但是进入游戏后,由于还有异步资源没有下载完成,如果这个时候用户就点击了一些功能,可能就会出错。

你说得对。
可以出个功能,把加载场景分离出来。

恩,你说的没错,这种情况经常出现在 cc.loader.loadRes这个函数上,可能动态加载resources文件夹下的资源的时候,所以在回调函数里一定要处理好有error的情况下。

mark mark

这是我在 3.3 上跑起来的效果请问这是为什么


还有就是3.3 没有那个 main.js 我是在 application.js 里加的

然而对于资源很多的微信小游戏 主要的时间都花在loadAssetBundle上,load
scene很快