制作游戏时,如何管理游戏资源? 逐行注释!

制作游戏时,如何管理游戏资源?

逐行注释!

开发环境:

CocosCreator v2.3.1

node.js v10.16.0

vscode 1.46.1

基本思路:使用插件脚本。
1.定义一张表,将资源名和路径一一映射。
2.选择按组加载资源,记录loadNum,配合ProgressBar节点可以实现一个画面流畅的资源加载界面
3.然后将资源以{类型:{资源名,…},…}的结构保存在对象中,再将其存储在全局window下,方便随时获取。

在这里插入图片描述

优点:

1.使用资源管理器(res.js)来统一加载资源,可以避免因资源数量过多、即时加载资源时间过短而导致的各种资源获取错误问题。

2.可以根据实时变化的loadNum设计你的加载界面

代码如下:

res.js

/**

 \* JavaScript里(()=>{})和(function(){})是标准的函数,

 \* 它们没有赋值给任何变量,没有函数名,被称为匿名函数。

 \* 因为没有名字,所以在定义完成就要调用,(()=>{})(),

 \* 后面的()是调用运行这个匿名函数

 */

(() => {
    
    

  //资源映射表

  let TABLE = {
    
    //音频类------一级key,一般取名资源的类型(自定义)

​    audio: {
    
    /**

​       \* 此资源的路径,通常我们会把项目中需要动态加载的资源放在 resources 目录下, 此处resources省略不写

​       \* 所有需要通过脚本动态加载的资源,都必须放置在 resources 文件夹或它的子文件夹下。

​       \* resources 文件夹需要在 assets 根目录 下手动创建

​       */

​      path: "audio/",//资源类型,Class for audio data handling.音频资源类

​      type: cc.AudioClip,//资源列表,即同路径下同类型的所有资源

​      list: ["MayRain", "别再问我什么是迪斯科", "思凡", "执迷不悔", "走钢索的人", "龙卷风"]},//预制类

​    prefab: {
    
    

​      path: "prefab/",

​      type: cc.Prefab,

​      list: ["chapter", "menu", "block", "tip1", "tip2"]},//teture2D纹理类

​    authorImage: {
    
    

​      path: "texture/author/",

​      type: cc.SpriteFrame,

​      list: ["MayRain", "别再问我什么是迪斯科", "思凡", "执迷不悔", "走钢索的人", "龙卷风"]}

  }



  /**新建一个Cres资源加载类,实例化为g_Res并存在window下

   \* window对象:

   \* 所有浏览器都支持 window 对象。它代表浏览器的窗口。

   \* 所有全局 JavaScript 对象,函数和变量自动成为 window 对象的成员。

   \* 全局变量是 window 对象的属性。

   \* 全局函数是 window 对象的方法。

   \* 甚至(HTML DOM 的)document 对象也是 window 对象属性

   */

  window.g_Res = new class CRes {
    
    //构造函数中,初始化一个用于存放资源的_data对象,初始化需要加载的资源数量loadNumconstructor() {
    
    this._data = {
    
    };this.loadNum = -1;}//资源加载入口函数loadRes() {
    
    this.loadNum = 0;for (let key in TABLE) {
    
    //统计资源映射TABLE中有多少个一级key,即有多少种资源this.loadNum++;//按类加载资源this.doLoadRes(key);}}//实际的资源加载函数,加载key类资源doLoadRes(key) {
    
    //拼凑资源类型和名称,结构为["audio/MayRain","..."],作为按组加载资源的第一个参数let resList = [];for (let name of TABLE[key].list) {
    
    let resName = TABLE[key].path + name;

​        resList.push(resName);}//在_data对象中开辟一级结构,结构为this._data = {audio: {},...}this._data[key] = {
    
    };//定义加载资源方法,5个资源调用一次let func = () => {
    
    //从中资源列表中从首切分5个let tempList = resList.splice(0, 5);/**

​         \* 按组加载资源方法,

​         \* 第一个参数:资源组,

​         \* 第二个参数:资源类型,

​         \* 第三个参数:回调函数(err,data)=>{},err:错误信息,data:加载后的资源

​         */

​        cc.loader.loadResArray(

​          tempList,TABLE[key].type,

          (err, data) => {
    
    //判断此类资源是否加载完成,是,则让loadNum-1,外部脚本可以通过获取loadNum的值来判断资源加载的进度;if (resList.length <= 0) {
    
    this.loadNum--;} else {
    
    //如果此类资源没有加载完成,则继续选择5个一组的方式继续加载func();}//如果加载错误,则打印具体的加载错误信息if (err) {
    
    

​              console.log(err);}for (let res of data) {
    
    //在_data对象中开辟二级结构,结构为this._data = {"audio": {"MayRain":它的audioClip,...},...}this._data[key][res.name] = res;}});}//调用上面定义的资源加载方法funcfunc();}//定义获取资源加载数的函数getLoadNum() {
    
    return this.loadNum;}//定义获取资源方法,通过资源的类型key和名称name来获取你已经加载好的任和资源getRes(key, name) {
    
    //判断获取资源时时,是否所有的资源都已经加载完毕,否,则打印它的类型和名字方便开发者找错if (this.loadNum != 0) {
    
    

​        console.log("资源未加载完毕!", key, name);}//安全验证if (this._data[key]) {
    
    return this._data[key][name];} else {
    
    

​        console.log("目标资源不存在,请检查资源名!", key, name);}}

  }

})()

附赠加载界面的loading.js脚本

loading.js

cc.Class({
    
    

  extends: cc.Component,



  properties: {
    
    

  },



  loadRes() {
    
    let curResNum = g_Res.getLoadNum();   //未加载资源let readyResNum = this.resNum - curResNum;    //已加载资源this.goal = readyResNum / this.resNum / 2;   //前50%是用来加载资源的,所以进度最多到50%//判断资源是否加载完毕if (this.progressBar.progress >= 0.5) {
    
    this.loadScene();    //预加载场景函数}

  },



  loadScene() {
    
    this.step = 2;

​    cc.director.preloadScene(    //预加载场景(只加载场景,场景中的onload()在场景打开后才加载)"main",

      (cur, all) => {
    
       // cur:已经加载的资源数 all:总共有多少资源数this.goal = cur / all / 2 + 0.5;},

      () => {
    
     },);

  },



  init() {
    
    this.step = 3;

​    cc.director.loadScene("main");

  },



  playAnim() {
    
    this.whiteBlock.getComponent(cc.Animation).play("whiteBlock");

  },



  // LIFE-CYCLE CALLBACKS:



  // onLoad() {},



  start() {
    
    

​    g_Res.loadRes();this.progressBar = cc.find("Canvas/UILayer/temporatyUI/progressBar").getComponent(cc.ProgressBar);this.proLabel = cc.find("Canvas/UILayer/temporatyUI/proLabel").getComponent(cc.Label);this.whiteBlock = cc.find("Canvas/UILayer/permanentUI/title/whiteBlock");this.progressBar.progress = 0;this.goal = 0;this.speed = 0.01;this.step = 1;this.resNum = g_Res.getLoadNum();this.playAnim();

  },



  update(dt) {
    
    if (this.progressBar.progress < this.goal) {
    
    this.progressBar.progress += this.speed;this.proLabel.string = "进度" + Math.floor(this.progressBar.progress * 100) + "%"}if (this.step == 1) {
    
       //第一步,加载资源this.loadRes();} else if (this.step == 2 && this.progressBar.progress >= 1) {
    
    this.init();}

  },

});


this.progressBar.progress < this.goal) {
    
    this.progressBar.progress += this.speed;this.proLabel.string = "进度" + Math.floor(this.progressBar.progress * 100) + "%"}if (this.step == 1) {
    
       //第一步,加载资源this.loadRes();} else if (this.step == 2 && this.progressBar.progress >= 1) {
    
    this.init();}

  },

});

在这里插入图片描述
在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/qq_45236472/article/details/108586552