赞 | 65 |
VIP | 231 |
好人卡 | 2 |
积分 | 19 |
经验 | 35171 |
最后登录 | 2024-9-15 |
在线时间 | 1554 小时 |
Lv3.寻梦者
- 梦石
- 0
- 星屑
- 1912
- 在线时间
- 1554 小时
- 注册时间
- 2013-4-13
- 帖子
- 917
|
加入我们,或者,欢迎回来。
您需要 登录 才可以下载或查看,没有帐号?注册会员
x
下班了~继续水~
每天我都是一边码, 一边研究, 先从好啃得地方一点点来吧
==================================
第四章 图书管理员DataManager
正如预告的一样, 今天来啃一啃DataManagerDataManager总共分为两部分, 数据加载和游戏对象管理
我们这次主要讲关于数据加载的部分
其实就是对Scene_Boot的补充
对象管理的部分等到我们真正进入游戏场景, 初始化游戏数据的时候再说
( 一个对象分两部分水, 我真是个小机智鬼呢~
上一篇提到在Scene_Boot中执行了DataManager.loadDatabase
为了灌水方便回忆, 我再把这部分相关的源码贴上来
- DataManager._databaseFiles = [
- { name: '$dataActors', src: 'Actors.json' },
- { name: '$dataClasses', src: 'Classes.json' },
- { name: '$dataSkills', src: 'Skills.json' },
- { name: '$dataItems', src: 'Items.json' },
- { name: '$dataWeapons', src: 'Weapons.json' },
- { name: '$dataArmors', src: 'Armors.json' },
- { name: '$dataEnemies', src: 'Enemies.json' },
- { name: '$dataTroops', src: 'Troops.json' },
- { name: '$dataStates', src: 'States.json' },
- { name: '$dataAnimations', src: 'Animations.json' },
- { name: '$dataTilesets', src: 'Tilesets.json' },
- { name: '$dataCommonEvents', src: 'CommonEvents.json' },
- { name: '$dataSystem', src: 'System.json' },
- { name: '$dataMapInfos', src: 'MapInfos.json' }
- ];
- DataManager.loadDatabase = function () {
- var test = this.isBattleTest() || this.isEventTest();
- var prefix = test ? 'Test_' : '';
- for (var i = 0; i < this._databaseFiles.length; i++) {
- var name = this._databaseFiles[i].name;
- var src = this._databaseFiles[i].src;
- this.loadDataFile(name, prefix + src);
- }
- if (this.isEventTest()) {
- this.loadDataFile('$testEvent', prefix + 'Event.json');
- }
- };
复制代码 嗯, 之前分析过了, 这里重点来看看loadDataFile方法- DataManager.loadDataFile = function (name, src) {
- var xhr = new XMLHttpRequest();
- var url = 'data/' + src;
- xhr.open('GET', url);
- xhr.overrideMimeType('application/json');
- xhr.onload = function () {
- if (xhr.status < 400) {
- window[name] = JSON.parse(xhr.responseText);
- DataManager.onLoad(window[name]);
- }
- };
- xhr.onerror = this._mapLoader || function () {
- DataManager._errorUrl = DataManager._errorUrl || url;
- };
- window[name] = null;
- xhr.send();
- };
复制代码
这是一个化石级别的AJax请求
简单啰嗦几句XMLHttpRequest是个什么东西, 毕竟这个和JS的关系比较大
XMLHttpRequest就相当于你作为旅店老板发布一个任务
你创建一个任务对象
然后再描述了任务类型, 任务地点, 任务内容, 任务结束或失败后该做什么
最后你将这个任务发布
你不知道勇者什么时候会完成任务, 但是他们一旦完成就会执行你预定好的行为
url描述了对象的路径地址
'GET'是http请求的方法名之一, 代表我要读取某一个资源
'application/json' 描述了目标格式, 提醒浏览器用什么方式接受这个资源
请求还可以携带一些参数, 不过我们并没有一个后台服务器所以可以忽略这些
onload和onerror分别是我们对任务完成或失败后的回调函数
window[name] = JSON.parse(xhr.responseText);
这个相当于将返回的Json字符串格式的结果(responseText)解析为对象存储在全局变量下(你控制台就可以直接看到啦$dataXXX的那一帮
嗯, 还有一个需要注意的一点AJax有一个同源策略,
你不需要了解这个策略, 但是你要记住在本地环境下(就是直接在文件中打开index.html)的时候
Ajax请求会失败, 你可以用一个web容器或者服务器来解决这个问题
当然了纯web还会有fs模块不支持等大坑需要自己搞定
跑题了, 继续回到DataManage上来
注意在回调函数上有一个onload()方法
也就是不只是加载到全局变量中就完事了, 还需要进行一个初始化
然我们看看这个方法
- DataManager.onLoad = function (object) {
- var array;
- if (object === $dataMap) {
- this.extractMetadata(object);
- array = object.events;
- } else {
- array = object;
- }
- if (Array.isArray(array)) {
- for (var i = 0; i < array.length; i++) {
- var data = array[i];
- if (data && data.note !== undefined) {
- this.extractMetadata(data);
- }
- }
- }
- if (object === $dataSystem) {
- Decrypter.hasEncryptedImages = !!object.hasEncryptedImages;
- Decrypter.hasEncryptedAudio = !!object.hasEncryptedAudio;
- Scene_Boot.loadSystemImages();
- }
- };
复制代码 在这里主要是要提取注释中的元数据(meta data) 比如<a>或者<a:b>这类的
(其实后面还有对system.json里记录加密资源flag相关的, 和上一篇提到过的loadSystemImages, 这里就先跳过~)
一般数据本身就是个Array, 每个元素的注释存储在每个元素的note上
而map文件就直接在map.note上了
我们来重点看看extractMetadata方法
- DataManager.extractMetadata = function (data) {
- var re = /<([^<>:]+)(:?)([^>]*)>/g;
- data.meta = {};
- for (; ;) {
- var match = re.exec(data.note);
- if (match) {
- if (match[2] === ':') {
- data.meta[match[1]] = match[3];
- } else {
- data.meta[match[1]] = true;
- }
- } else {
- break;
- }
- }
- };
复制代码 extractMetadata表示并不想和你说话, 并朝你扔了一串正则表达式...
不太熟悉正则的童鞋不要怕, 我暂且啰嗦一下基本用法,
首先正则表达式是用//包裹起来定义的,
末尾还可以加一些标识符, 常用的比如i是忽略大小写g就是全局查找之类的
[^<>:], 一对中括号代表匹配一个中括号括起来的字符
如果前面带有^代表匹配这些字符以外的
?+*是三个特殊符号
?表示前一个字符存在1个或没有
+表示前一个字符存在1个或多个
*表示前一个字符存在0个或多个
()表示捕获匹配的字符串
一些匹配方法会将捕获的字符串返回到结果中
比如match = re.exec(data.note);
那么match[0]就是整个匹配的字符串
match[1]就是第一个括号中的内容
match[2]就是第二个括号中的内容
match[3]就是第三个括号中的内容
/<([^<>:]+)(:?)([^>]*)>/g 就是全局匹配满足<xxx:yyy>的字符串
由于后两个是?和*代表也可以匹配<zzz>格式的字符串
啊, 这不就是note里元数据的格式吗, so easy~
另外一个知识点是正则表达式会保存状态的, 类似一个迭代器
match = re.exec(data.note);
第一次执行会从字符串开头, 如果匹配了一个字符串则保留一个lastIndex
如果再次执行则会从传入的字符串的lastIndex处继续匹配
如果匹配到了字符串结尾, 则返回null
这个就是为啥有一个for死循环的原因了
最终匹配的结果会以键值对的格式保存在meta里
如果是<a:b>的话就是meta.a = b
如果是<a>的话就是meta.a = true
嗯, 由于是字符串匹配, 所以保存的b的值是一个字符串
再看看其他的方法, 有没有我们熟悉的面孔
- DataManager.isDatabaseLoaded = function () {
- this.checkError();
- for (var i = 0; i < this._databaseFiles.length; i++) {
- if (!window[this._databaseFiles[i].name]) {
- return false;
- }
- }
- return true;
- };
复制代码 这个方法就是看看是不是所有文件都加载完毕了
是Scene_Boot.isReady满足的条件之一
好, 这次就到这里啦, 下一期预计是Scene_Title
当然, 前提是我没在上班的路上被台风干掉...
|
|