制作游戏时,如何管理游戏资源? 逐行注释!
程序员文章站
2024-01-01 08:42:46
制作游戏时,如何管理游戏资源?逐行注释开发环境:CocosCreator v2.3.1node.js v10.16.0vscode 1.46.1基本思路:使用插件脚本。1.定义一张表,将资源名和路径一一映射。2.选择按组加载资源,记录loadNum,配合ProgressBar节点可以实现一个画面流畅的资源加载界面3.然后将资源以{类型:{资源名,…},…}的结构保存在对象中,再将其存储在全局window下,方便随时获取。优点:1.使用资源管理器(res.js)来统一加载资源,可以避免因...
制作游戏时,如何管理游戏资源?
逐行注释!
开发环境:
基本思路:使用插件脚本。
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对象,初始化需要加载的资源数量loadNum
constructor() {
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;
}
}
);
}
//调用上面定义的资源加载方法func
func();
}
//定义获取资源加载数的函数
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();
}
},
});
本文地址:https://blog.csdn.net/qq_45236472/article/details/108586552