CocosCreator之手动加载远程图片减少黑屏时间
小游戏,只所以为小,因为它的体积确实小,下载起来快,随用随走。
在微信小游戏中, 游戏包体大小是有限制的,首包是4M,分包的话,在cocoscrator中,也只能分包js文件,所以,图片文件还是只能通过远程加载。但是,creator构建出来的图片资源,会一次性被小游戏加载回来,这样,就会造成小游戏在加载图片资源时,会有黑屏,资源过大时,黑屏时间就更长。所以,这时候使用手动动态加载大图,可以有效的减少初始化游戏时的网络压力。
下面通过以下几个方法,来优化我们的游戏
1、手动加载超大图
将游戏中使用到的大图(超过50kb的),采用低分辨率小图作为初始图,然后在节点onLoad以后,采用cc.loader.load() 方法,来动态加载原图。 这样既不会造成初始没有图,也可以展示更清晰的原图。
/**
* 从远程加载图片
* @param {图片路径} imgPath
* @param {当前节点} targetNode
*/
export const loadRemoteImage = function (imgPath, targetNode, cb) {
if (!imgPath) return
let type = imgPath.slice(imgPath.lastIndexOf('.') + 1) || 'png'
cc.loader.load({url: imgPath, type: type}, function (error, texture) {
targetNode.getComponent(cc.Sprite).spriteFrame = new cc.SpriteFrame(texture)
cb && cb()
})
}
// 并且修改一下libs下的wx-downloader.js
function downloadRemoteFile(item, callback) {
// Download from remote server 判断传进来的item 是否是要自定义下载
var relatUrl = item.url;
// filter protocol url (E.g: https:// or http:// or ftp://)
if (REGEX.test(relatUrl)) {
callback(null, null);
return
}
var remoteUrl = '';
if (relatUrl.indexOf('http') === 0) {
remoteUrl = relatUrl;
} else {
remoteUrl = wxDownloader.REMOTE_SERVER_ROOT + '/' + relatUrl;
}
item.url = remoteUrl;
wx.downloadFile({
url: remoteUrl,
success: function (res) {
// 这里面不变
},
fail: function (res) {
// Continue to try download with downloader, most probably will also fail
callback(null, null);
}
})
};
// js代码中使用 第一个参数是要下载的图片地址, 第二个参数值使用图片的Node节点
loadRemoteImage(Config.REMOTE_HOST + '/res/gzh.jpg', this.bg)
### 2、动画图片使用手动加载
这两种方法有个共同点,就是这些资源存放在一个固定的目录下, 叫: resources
目录的名字不能改,只能是这个名
1、游戏中如果大量使用帧动画的话,图片资源肯定小不了,这样在场景初始化时,也可能造成黑屏。所有我们就采用动态加载动画图片的方法。
/**
* 加载动画的序列帧
* @param {object} param0
* cc.loader.loadResDir 加载指定的目录,目录下的文件会以一个资源数组asstes返回
*/
export const loadAnimFrames = function ({ dir = 'watch', callback} ) {
let frames = []
let clip = null
cc.loader.loadResDir(dir, function (err, assets) {
if (assets && assets.length) {
assets.forEach(ass => {
if (ass.name) {
frames.push(ass)
}
})
clip = cc.AnimationClip.createWithSpriteFrames(frames, 5) // 创建动画clip, 默认帧率为5, 越大越快
clip.name = dir
clip.wrapMode = cc.WrapMode.Loop // 设置为永久循环
callback && callback(clip)
}
})
}
// 使用
let anim = this.node.getComponent(cc.Animation)
Util.loadAnimFrames({
dir: 'eat',
callback: (clip) => {
// 将加载回来的clip设置到当前节点
anim.addClip(clip)
anim.play('eat')
}
})
2、另一种情况就是,图片在游戏场景中本身就是根据数据动态来渲染的,比如:等级不同渲染不同的图标
// loadRes 加载资源,第一个参数:资源路径(resources下), 参数2:回调
let iconMap = {'4': 'icon-level-1.png', '3': 'icon-level-2.png',
'2': 'icon-level-3.png','1': 'icon-level-4.png'}
cc.loader.loadRes(iconMap[prize.level], function (error, texture) {
levelIcon.getComponent('cc.Sprite').spriteFrame = new cc.SpriteFrame(texture)
})
光做以上步骤还不行, 因为有些游戏中图片还是很多,每一个图片都这样去设置低分辨率小图也不是办法,还有关键的一步。
3、手动加载所有图片资源包 wx.donwloadFile
这里需要做些准备,
1、在构建打包以后,要将build目录下,wechatgame/res/raw-assets 目录打包成zip压缩包,并且上传到远程oss服务器上,
2、再将这个raw-assets目录删除, 这样小游戏启动时加载图片资源就加载不到。
3、再将删除了资源文件的小游戏源码,通过微信开发者工具上传到微信服务器上。
这时候,小游戏控制台可能会报一些错误 donwloadfile:ok 这样的错误。 不过这个不用管,它是小游戏自动去下载raw-assets中资源找不到(因为我们把目录删除了)
4、然后我们需要在小游戏的主入口场景中加上以下代码,就可以把资源文件手动下载到我们的小游戏文件目录下(这个时候,还需要展示一个加载资源的loading图片覆盖在主场景之上,这样就友好的展示了资源加载过程。)
/**
* 加载远程资源
* wx.env.USER_DATA_PATH: 这个是小游戏在手机上的临时目录
**/
loadRemoteAssets () {
const self = this
const fs = wx.getFileSystemManager() // 获取微信小游戏sdk中的 文件系统
// 然后
const downloadTask = wx.downloadFile({
url: Config.REMOTE_HOST + '/res/raw-assets.zip', // 我们上传到服务器的资源文件压缩包地址
header: {
'content-type': 'application/json'
},
filePath: '',
success: function (res){ // 资源下载成功以后,我们将文件解压到小游戏的运行目录
console.log('资源下载成功', res)
let zip_res = res.tempFilePath
fs.unzip({
zipFilePath: zip_res,
targetPath: wx.env.USER_DATA_PATH + '/res/',
success: function (result) {
console.log('解压缩成功---', result)
wx.setStorageSync('downloaded', true)
self.MainScene.init() // 解压成功以后再让主场景初始化数据
setTimeout(() => {
self.hideLoading()
}, 700)
}
})
},
fail: function(err){
console.error('资源下载失败', err)
},
complete: function (res) {
console.log('资源下载 complete')
}
})
if (downloadTask) { // 资源下载的时候,在界面上展示下载的进度,让用户能感知游戏进程
downloadTask.onProgressUpdate(function(res){
self.loadFileProgress.progress = res.progress / 100
self.proLabel.string = '资源加载: ' + res.progress + '%'
})
}
},