设为首页收藏本站|繁體中文

Project1

 找回密码
 注册会员
搜索
查看: 3592|回复: 1
打印 上一主题 下一主题

[交流讨论] RPG Maker MV 的源码研究 其五

[复制链接]

Lv3.寻梦者

梦石
0
星屑
1912
在线时间
1554 小时
注册时间
2013-4-13
帖子
917
跳转到指定楼层
1
发表于 2019-8-13 21:59:12 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式

加入我们,或者,欢迎回来。

您需要 登录 才可以下载或查看,没有帐号?注册会员

x
下班了~继续水~
每天我都是一边码, 一边研究, 先从好啃得地方一点点来吧
==================================
第四章 图书管理员DataManager

正如预告的一样, 今天来啃一啃DataManagerDataManager总共分为两部分, 数据加载和游戏对象管理
我们这次主要讲关于数据加载的部分
其实就是对Scene_Boot的补充
对象管理的部分等到我们真正进入游戏场景, 初始化游戏数据的时候再说
( 一个对象分两部分水, 我真是个小机智鬼呢~

上一篇提到在Scene_Boot中执行了DataManager.loadDatabase
为了灌水方便回忆, 我再把这部分相关的源码贴上来
  1. DataManager._databaseFiles = [
  2.     { name: '$dataActors', src: 'Actors.json' },
  3.     { name: '$dataClasses', src: 'Classes.json' },
  4.     { name: '$dataSkills', src: 'Skills.json' },
  5.     { name: '$dataItems', src: 'Items.json' },
  6.     { name: '$dataWeapons', src: 'Weapons.json' },
  7.     { name: '$dataArmors', src: 'Armors.json' },
  8.     { name: '$dataEnemies', src: 'Enemies.json' },
  9.     { name: '$dataTroops', src: 'Troops.json' },
  10.     { name: '$dataStates', src: 'States.json' },
  11.     { name: '$dataAnimations', src: 'Animations.json' },
  12.     { name: '$dataTilesets', src: 'Tilesets.json' },
  13.     { name: '$dataCommonEvents', src: 'CommonEvents.json' },
  14.     { name: '$dataSystem', src: 'System.json' },
  15.     { name: '$dataMapInfos', src: 'MapInfos.json' }
  16. ];

  17. DataManager.loadDatabase = function () {
  18.     var test = this.isBattleTest() || this.isEventTest();
  19.     var prefix = test ? 'Test_' : '';
  20.     for (var i = 0; i < this._databaseFiles.length; i++) {
  21.         var name = this._databaseFiles[i].name;
  22.         var src = this._databaseFiles[i].src;
  23.         this.loadDataFile(name, prefix + src);
  24.     }
  25.     if (this.isEventTest()) {
  26.         this.loadDataFile('$testEvent', prefix + 'Event.json');
  27.     }
  28. };
复制代码
嗯, 之前分析过了, 这里重点来看看loadDataFile方法
  1. DataManager.loadDataFile = function (name, src) {
  2.     var xhr = new XMLHttpRequest();
  3.     var url = 'data/' + src;
  4.     xhr.open('GET', url);
  5.     xhr.overrideMimeType('application/json');
  6.     xhr.onload = function () {
  7.         if (xhr.status < 400) {
  8.             window[name] = JSON.parse(xhr.responseText);
  9.             DataManager.onLoad(window[name]);
  10.         }
  11.     };
  12.     xhr.onerror = this._mapLoader || function () {
  13.         DataManager._errorUrl = DataManager._errorUrl || url;
  14.     };
  15.     window[name] = null;
  16.     xhr.send();
  17. };
复制代码

这是一个化石级别的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()方法
也就是不只是加载到全局变量中就完事了, 还需要进行一个初始化
然我们看看这个方法

  1. DataManager.onLoad = function (object) {
  2.     var array;
  3.     if (object === $dataMap) {
  4.         this.extractMetadata(object);
  5.         array = object.events;
  6.     } else {
  7.         array = object;
  8.     }
  9.     if (Array.isArray(array)) {
  10.         for (var i = 0; i < array.length; i++) {
  11.             var data = array[i];
  12.             if (data && data.note !== undefined) {
  13.                 this.extractMetadata(data);
  14.             }
  15.         }
  16.     }
  17.     if (object === $dataSystem) {
  18.         Decrypter.hasEncryptedImages = !!object.hasEncryptedImages;
  19.         Decrypter.hasEncryptedAudio = !!object.hasEncryptedAudio;
  20.         Scene_Boot.loadSystemImages();
  21.     }
  22. };
复制代码
在这里主要是要提取注释中的元数据(meta data) 比如<a>或者<a:b>这类的
(其实后面还有对system.json里记录加密资源flag相关的, 和上一篇提到过的loadSystemImages, 这里就先跳过~)
一般数据本身就是个Array, 每个元素的注释存储在每个元素的note上
而map文件就直接在map.note上了

我们来重点看看extractMetadata方法

  1. DataManager.extractMetadata = function (data) {
  2.     var re = /<([^<>:]+)(:?)([^>]*)>/g;
  3.     data.meta = {};
  4.     for (; ;) {
  5.         var match = re.exec(data.note);
  6.         if (match) {
  7.             if (match[2] === ':') {
  8.                 data.meta[match[1]] = match[3];
  9.             } else {
  10.                 data.meta[match[1]] = true;
  11.             }
  12.         } else {
  13.             break;
  14.         }
  15.     }
  16. };
复制代码
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的值是一个字符串

再看看其他的方法, 有没有我们熟悉的面孔
  1. DataManager.isDatabaseLoaded = function () {
  2.     this.checkError();
  3.     for (var i = 0; i < this._databaseFiles.length; i++) {
  4.         if (!window[this._databaseFiles[i].name]) {
  5.             return false;
  6.         }
  7.     }
  8.     return true;
  9. };
复制代码
这个方法就是看看是不是所有文件都加载完毕了
是Scene_Boot.isReady满足的条件之一

好, 这次就到这里啦, 下一期预计是Scene_Title
当然, 前提是我没在上班的路上被台风干掉...


夏普的道具店

塞露提亚-道具屋的经营妙方同人作品
发布帖:点击这里

Lv4.逐梦者

梦石
0
星屑
14619
在线时间
718 小时
注册时间
2011-7-16
帖子
1428

开拓者

2
发表于 2019-8-21 19:20:52 | 只看该作者
化石级意思应该是很老很旧了,还请大佬科普下现代级的用法是什么?
RMMV网络插件,开源免费,内含服务器端,无需强制登录,云数据,弹幕,云存档,排名,兑换码,版本检测,可自由上架下架删除。q群399090587
免打包运行MV游戏,云游戏,安卓App雷神游戏厅,在线玩游戏,上传下载游戏
开源游戏:重装机兵之重装归来【RMMV制作】全球首款按照美剧分季分集的方式发布的游戏
体素画 -- MV画3D像素图的画板
RMMV显示3D模型和场景的插件
RMMV显示spine骨骼动画的插件
RMMV秘密通道插件
突破敌群数量上限8个的插件
在rmmv中显示gif动态图片的插件
一款可以在mv游戏界面的任意位置显示任意文字的插件
RMMV Toast 插件 带物品得失提示,可以设置开启关闭 兼容yep itemcore
制作一个改名卡道具插件、调整标题页面菜单的插件、在标题页面之前显示大段文字的插件、标题页面显示版本号的插件
物品得失自动提示自动上色自动换行插件
我的Q群 663889472
另外,我的插件、范例、游戏都在这里
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 注册会员

本版积分规则

拿上你的纸笔,建造一个属于你的梦想世界,加入吧。
 注册会员
找回密码

站长信箱:[email protected]|手机版|小黑屋|无图版|Project1游戏制作

GMT+8, 2024-11-12 13:23

Powered by Discuz! X3.1

© 2001-2013 Comsenz Inc.

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