找回密码
 立即注册
查看: 226|回复: 0

【游戏开发随笔】使用云存储为小游戏“瘦身”

[复制链接]
发表于 2022-12-27 10:23 | 显示全部楼层 |阅读模式
我们在游戏迭代的过程中,可能会遇到这样的问题:随着游戏内容的不断扩展,游戏资源会越来越庞大。而目前微信小游戏对包体有20M的限制,一旦游戏包体积超出20M,游戏就无法上传发布了。
微信小游戏早期的包体限制只有4M。随着时代发展,小程序的体量越来越大,微信官方也引入了小程序分包加载机制,将包体总限制提升到如今的20M。



现行的微信小程序包体限制规则

以我开发的微信小游戏《护战少女》为例,平均一张角色立绘有300KB,除掉其它音效、粒子、背景图和其他UI等资源,剩余空间大约只能容纳下三十张立绘。虽然可以通过压缩多媒体素材来节约一些空间,但长远来看,这始终都会是制约游戏发展的一个问题。
但是我们依然可以发现,有许多微信小游戏显然是极其庞大的,它们不大可能把体积压缩在20M以内,例如有大量骨骼动画的2D游戏,和有复杂建模的3D游戏。
本文将介绍如何利用云存储功能为我们的小游戏“瘦身”,突破20M的包体限制。本文案例将会基于Cocos Creator 2引擎和Web版云开发来讲解,但方法和思路是通用的。
“瘦身”思路  

首先观察一下,其他游戏是怎样解决这个问题的?
诸如《王者荣耀》《原神》这类大型手游,客户端或许只有两三百M,但实际运行内存可能多达几个G。当玩家启动游戏后,会首先进入一个类似“资源加载中”的等待界面,此时的程序后台则在从服务器上下载游戏资源,存储到玩家的手机上。
所以,我们也将大量的素材资源存放在服务器上,而不是直接打包进代码包中。在玩家启动游戏后,触发加载远程资源的代码,实现游戏资源的动态加载、代码包的“瘦身”。
实际上,将资源分离、动态加载的好处有很多!这一做法不仅仅能够帮助微信小游戏绕过代码包限制,还能够:(1) 减少首包体积。缩短游戏启动时间,降低首屏等待时的玩家流失。(2) 将资源下载进程隐藏到幕后。玩家无须等待所有资源加载完成,例如在后台下载素材的同时,玩家可以正常浏览游戏菜单。(3) 方便游戏资源的替换和修改。开发者无需重新发布版本更新,可以直接在后台替换文件实现素材更新。(4) 对于多个游戏共用同一个云开发账户的情况,可以实现资源的游戏间共享。
但是对于个人开发者来说,专门租一台服务器实在是太贵了。但也别忘了,云开发就是为解决这类问题而生的!微信小游戏开发者想必都已经和云开发打过交道了,因为其中的云数据库和云函数几乎可以说是微信小游戏的必接云功能了。如果没有使用它们来存储游戏记录数据,会可能对玩家的游戏体验造成很大影响。
而除了云数据库和云函数,云开发中的另一个功能看上去并不是那么“必需”,这就是云存储。云存储实际上就可以充当我们存放文件的服务器。接下来,我们就将借助云存储来实现游戏资源的动态加载。
上传资源到云端  

你首先需要为你的游戏开通一个腾讯云账号。开通云开发Cloudbase服务后,进入控制台界面,找到“云存储”,点击“上传文件”按钮,就可以通过后台上传你的游戏素材了。



云开发控制台中的云存储操作界面

当成功上传一个文件后,有两个关键的文件属性需要我们注意,那就是“fileid”和“临时链接”。这两项属性都可以用来下载对应的文件。下面我们具体地了解一下它们的区别和关系。
临时链接

文件的临时链接(FileURL)其实就是一个普通的网址。例如,当你上传一张名为example.png的图片后,该文件的临时链接可能形如:
https://your-env-xxx.tcb.qcloud.la/example.png?sign=yourappsign&t=somecode
当我们拿到一个文件的临时链接后,就可以像浏览网页一样,在浏览器里访问这个云文件了。当然,它也可以用于直接用在游戏程序中下载文件。
但是,顾名思义,临时链接是临时的!一个文件的临时链接可能定期发生变化,所以它仅用于测试你的文件是否是否上传成功、是否可以正常访问。要真正将下载功能实装在游戏中,我们需要使用fileid
fileid

文件的fileid是一个云开发专属格式的URL,它长得像是一个网址,但并不是一个真正的网址。仍以example.png为例,它的fileid可能形如:
cloud://your-env-xxx/example.png
这串cloud开头的字符串便是example.png在云开发中的专属id,只在云开发的业务中有效,并且是永久有效的。当我们拿到一个文件的fileid后,需要再用它换取文件的临时链接,从而可以下载云文件。
fileid仅由环境名文件名决定。也就是说,如果你在后台替换了一个同名文件,那么不需要改动fileid,通过相同的fileid就会下载到更新后的文件。
也许你会产生疑问:fileid像是多出来的一道工序,还是要用它换成临时链接,最后用临时链接来下载文件。那为什么云开发不直接开放一个永久链接用于文件下载呢?
这实际上是出于安全性的考虑。如果开发者直接将文件的真实链接写在程序包中,它有可能被用户破解,用户就可以直接凭链接随意读取你的资源了!如果你的云文件涉及到机密信息、隐私信息,这就将成为一个安全隐患。所以云开发需要对真实链接进行一道封装,不鼓励将它赤裸裸地写在代码中。这样一来,就算用户找出了fileid,但是未经过云开发的身份验证,也就无法换取文件的真实链接,无法读取你的云文件。
接下来,我们就按照“复制fileid”-“换取临时链接”-“用临时链接下载文件”这三步,来实现云文件的下载。
在脚本中添加代码  

接下来,我们回到Cocos Creator项目,在脚本中添加下载代码。
合理选择插入位置

我们需要在脚本中找到一个合适的位置,插入下载云端资源的代码。具体的插入位置是灵活可变的,你可以选择在整个游戏启动时就下载;也可以选择在切换到某个场景时再下载;甚至可以不自动下载,而是绑定一个交互事件,当用户点击按钮或打开某个面板时再触发下载。
在本文的案例中,我们将代码插入在一个全局脚本组件的onLoad()中。
复制fileid

从云存储后台复制文件的fileid,填写到代码中。如果需要用到云存储来转存游戏资源,往往不止一个文件,所以我们可以编写一个列表,写明所有需要下载的文件的fileid。建议将同一类型的资源(如图片)写在一起,这样方便后续处理:
onLoad () {
  this.spriteFrameList = [];  // 最终下载的、可以使用的图片对象
  this.fileIdList = [
    // 换成你的云文件fileid
    "cloud://your-environment-info-xxx/001-luokeke-s1.png",
    "cloud://your-environment-info-xxx/002-duanran-s1.png",
    "cloud://your-environment-info-xxx/003-chenermang-s1.png",
  ];
  // 要插入的“换取临时链接”代码位置
}
换取临时链接

接下来,我们使用云开发的自带功能getTempFileURL(),用fileid换取临时链接
// ...初始化this.app
// 换取临时链接
this.app.getTempFileURL({
  fileList: this.fileIdList
}).then((res) => {
  // 打印出结果
  console.log(res.fileList);
  // 要插入的“用临时链接下文件”代码位置
}).catch((err) => {
  console.log("换取临时链接失败,错误原因:", err);
});
注1:this.app是腾讯云开发的总变量,且是Web版SDK的用法。如果你用的是微信自带的云开发服务,则应使用wx.cloud。它们的初始化方法具体请参考官方文档[1]。
注2:getTempFileURL()是批量换取的,但是一次最多可换取50个文件。如果文件数超过50个,则需要分批换取[1]。
用临时链接下载文件

拿到所有文件的临时链接后,我们就可以下载它们了。在Cocos Creator 2.4.x中,下载远程资源的函数是cc.assetManager.loadRemote()[2],如果你使用其他游戏引擎或其他开发环境,请查找对应工具的网络资源加载方法。
由于换到的临时链接也是一个列表,所以我们编写一个循环,逐个进行下载:
// 用临时链接下载文件
for (let i in res.fileList) {
  // res.fileList是一个有如下结构的对象数组
  // [{fileID: 'cloud://xxx', tempFileURL: 'https://xxx'}]
  let remoteUrl = res.fileList.tempFileURL;
  cc.assetManager.loadRemote(remoteUrl, (err, texture) => {
    // 下载到的图片即texture,要转换为Cocos Creator的spriteFrame才能使用
    let spriteFrame = new cc.SpriteFrame(texture);
    this.spriteFrameList.push(spriteFrame);
  });
};
console.log(this.spriteFrameList);
至此,资源下载部分的代码就已添加完成啦!这里为了导入下载到的原始图片,使用了cc.SpriteFrame()函数。如果你下载的是音频、视频等其他多媒体资源,则需要查找对应的资源动态加载方法,将下载到的资源导入到游戏场景中。
设置小游戏的合法域名  

脚本部分编写好了,如果你使用的是微信小程序自带的云开发服务,就已经可以正常运行啦!
但是,如果你使用的云开发环境是经过移植的,或者你尝试使用Web版云开发SDK并发布至其他小游戏平台(如字节小游戏),那么很有可能在打开小游戏工具调试时或者上线后,发现报下面这样的错误:



可能出现的域名非法错误

这是因为云存储的网络通信域名没有被添加到白名单中,导致这次通信受到了限制。我们只需要上小游戏的后台,将云存储的域名添加到白名单中即可。
前往微信小游戏后台,通过“开发”-“开发管理”-“开发设置”找到“服务器域名”,点击修改。



前往微信小游戏后台修改downloadFile合法域名

在其中的“downloadFile合法域名”一项,增添上http://your-env-xxx.tcb.qcloud.la这一格式的域名,具体内容以报错信息为准,或以你实际的文件临时链接为准(可以参考本文第2节的获取方式,截取链接的前半段即可)。如果是发布至字节等其他小游戏平台,也遵循类似的操作。
基本的“瘦身”现在就已经实现了!当然,利用云存储来优化游戏的技巧不仅限于此。值得我们进一步考虑的问题其实还有很多,例如:
如果因为网络问题,有部分云文件下载失败了、部分成功了,这种情况应该如何处理?
如果你要下载的云文件有很多,如何保证分批加载时的先后排列顺序符合预期?
<hr/>欢迎关注我的微信公众号“Kita游戏小基地”,一起做游戏,聊开发!也欢迎来玩一玩我的小游戏!



微信小游戏《护战少女》



微信小游戏《焕焕骑士:卡牌传说》

参考


  • ^ab云开发 CloudBase 获取临时链接-开发指南-文档中心-腾讯云 (tencent.com)https://cloud.tencent.com/document/product/876/19374
  • ^资源加载 · Cocos Creatorhttps://docs.cocos.com/creator/3.0/manual/zh/asset/dynamic-load-resources.html

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

×
懒得打字嘛,点击右侧快捷回复 【右侧内容,后台自定义】
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

小黑屋|手机版|Unity开发者联盟 ( 粤ICP备20003399号 )

GMT+8, 2024-11-24 15:03 , Processed in 0.065061 second(s), 23 queries .

Powered by Discuz! X3.5 Licensed

© 2001-2024 Discuz! Team.

快速回复 返回顶部 返回列表