前言
大家好,我又开始给大家释放屎山了! 这次的内容是仙剑中的状态菜单;这么几天没有发新的博文,是因为在组合各种的精灵图(Sprite),现代互联网时代的便利,感觉既有好处也又坏处,坏处就是前期准备工作比较多,比较繁琐,好处呢——一大堆。
第一个遇到的问题
刚开始做的时候,这样想过,不再场景中画背景图了,直接在游戏的状态窗口中进行绘制,答案是可以的,不过效果嘛!!!
第二次进入时才显示出来而且能够发现背景图片不完整,这是怎么回事呢!!!猜测是绘制的窗口有着填充的属性,或是限制了绘制的区域;在不考虑修改对应源码情况下如何处理呢?
Window_Selectable.prototype.initialize.call(this, -16, -18, width+60, height+60);
考虑了这个方式,修改了窗口的位置和大小来处理;但结果左边多一条线,应该是计算的问题,但x轴-17和-16,但结果不如人意,好像是图片截取的大小问题,但检查过宽高和box是一样的640x480,这就奇怪了。看来该考虑其他办法了!
处理图片边缝
通过一番查找后终于发现了问题的原因,之前的图片组合成大图时出现了错误,导致了边缝的出现,整体向左偏移了一个像素,导致之后的拼图如何也拼不对!同时原始图片的左边缘像素也是有一点问题的,颜色不对,因为不是专业PS,因此该问题暂时不进行处理。
背景图片占用问题
这个问题通过一番的测试发现了standardPadding()这个函数的用处,暂译名标准填充,该函数设置了一个18像素的返回值;和创建内容createContents()函数一起设定了窗口对应的宽高和内边距。几十内容创建函数返回了标准的宽高,但由于内边距已经设置了,因此图片还是会被占用掉,看着就像是被裁剪了一样。ps:现在所有的函数名称均是百度机翻,后期会重新根据函数的作用重新解释函数名;希望大家原谅我的渣英语!!!
Window_Base.prototype.createContents = function() {
this.contents = new Bitmap(this.contentsWidth(), this.contentsHeight());
this.resetFontSettings();
};
该函数组成是设置窗口内容,和使用的字体;其中Bitmap是图片里面的内容高度和内容宽度的具体运算是 return this.width-18*2 其中18就是standardPadding()的返回值,高度也是类似的计算方式,将width换出height即可。
首次打开不显示图片问题
内容部分还没有进行处理,不过人物状态部分弄好了,还是通过状态场景的背景来实现的;虽然通过窗口的方式也能(我践行这一点),但是现在能力不足只能通过其他方式绕过了。预计会出现的问题:通过改变人物可能会导致对应的背景出现错误。
Scene_Status.prototype.createBackground = function() {
var ssbit= ImageManager.loadMenu("人物状态大图");//获取背景图片
this._backgroundSprite=new Sprite(ssbit);//将图片精灵给背景
var actor =$gameParty.menuActor();
var sx = actor._statusFace % 3 * 640; //精灵图中需要的部分起始x轴
var sy = Math.floor(actor._statusFace / 3) * 480; //精灵图中需要的部分起始y轴
this._backgroundSprite.y = 0; //屏幕上精灵图的x轴
this._backgroundSprite.x = 0; //屏幕上精灵图的y轴
this._backgroundSprite.setFrame(sx, sy, 640, 480); //后两个参数是精灵图的大小(宽高)
this.addChild(this._backgroundSprite);//将图片给菜单场景子对象
};
这部分代码就是状态的背景代码,由于状态大图用的是九宫格的方式进行的处理,因此计算上也需要计算对应的位置。
数据添加
在RPG Maker MV/MZ 中数据存储在data下的对应名称的json文件中,若我们需要进行添加对应的数据该如使用呢?比如角色背景的头像,由于数据不同,位置不同因此对应的也不相同,需要新的数据项或是叫做字段表示。
,“profile”:“”,“statusName”:0,“statusFace”:2},
statusName和statusFace就是新添加的数据项各表示状态的人物名称和状态背景头像,里面的值表示是第几张图片;但就只是添加上数据还不行,在游戏的队伍对象中的角色中是找不到对应的字段的,那该如何呢? 通过一番的跟踪查找,发现在Object的js中发现了角色创建的操作,在那里面就可以初始化新的字段出来,当然原始的不能修改。
Game_Actor.prototype.initMembers = function() {
Game_Battler.prototype.initMembers.call(this);
this._actorId = 0; this._name = ''; this._nickname = '';
this._classId = 0; this._level = 0; this._characterName = '';
this._characterIndex = 0; this._faceName = ''; this._faceIndex = 0;
this._battlerName = ''; this._exp = {}; this._skills = [];
this._equips = []; this._actionInputIndex = 0;
this._lastMenuSkill = new Game_Item();
this._lastBattleSkill = new Game_Item();
this._lastCommandSymbol = '';
this._statusName=0; this._statusFace=0;
};
该代码片段中最后一行就是新添加的字段,之后再在开始游戏时修改即可成原始数据即可。
第二个遇到的问题
现在发现除了背景的状态头像,人物名称也是一样,首次打开加载时,没有正常渲染显示。
如图显示,复用了之前的图片,不好意思!
场景背景实现
由于一直找不到好的方法,因此将背景状态图和人物名称均在状态场景中绘制。
Scene_Status.prototype.loadingActorStatusFace = function() {
var actorStatusFace= ImageManager.loadMenu("人物状态大图");//获取背景图片
this._actorStatusFace=new Sprite(actorStatusFace);//将图片精灵给背景
var actor =$gameParty.menuActor();
var sx = actor._statusFace % 3 * 640; //精灵图中需要的部分起始x轴
var sy = Math.floor(actor._statusFace / 3) * 480; //精灵图中需要的部分起始y轴
this._actorStatusFace.y = 0; //屏幕上精灵图的x轴
this._actorStatusFace.x = 0; //屏幕上精灵图的y轴
this._actorStatusFace.setFrame(sx, sy, 640, 480); //后两个参数是精灵图的大小(宽高)
this.addChild(this._actorStatusFace);//将图片给菜单场景子对象
};
Scene_Status.prototype.loadingActorName = function() {
var actorName= ImageManager.loadMenu("ActorStateName");//获取背景图片
this._actorName=new Sprite(actorName);//将图片精灵给背景
var actor =$gameParty.menuActor();
var sx = 0; //精灵图中需要的部分起始x轴
var sy = Math.floor(actor._statusName % 5) * 64; //精灵图中需要的部分起始y轴
this._actorName.y = 11; //屏幕上精灵图的x轴
this._actorName.x = 27; //屏幕上精灵图的y轴
this._actorName.setFrame(sx, sy, 192, 64); //后两个参数是精灵图的大小(宽高)
this.addChild(this._actorName);//将图片给菜单场景子对象
};
之后再在Scene_Status的创建方法中调用对应的函数。可以看出队伍的对象调用了两次,来获取人物的对应属性。
窗口方式实现
由于考虑到还有多个需要进行显示的对象(内容),及后面人物转换,装备显示,全在场景中绘制不太好,甚至可能会比较难以实现,因此通过不断地百度,前往RPG Maker的专站(经常访问不进去的那个)!最终还是没有找到对应的实现方式,回过头来,看了下代码,才又恍然大悟。
什么情况下,第一次加载时会没有显示呢… 答案是没有加载上(没有加载完成)因此第一次渲染时会没有及时渲染到图片到屏幕上。为什么没有加载完成呢?图片大小,分辨率,截取的范围都会影响最终的渲染结果;可想而知每次是使用时才加载,有着IO的开销,从硬盘中读取出来还是比较慢的。因此决定在窗口初始化时进行加载。
Window_Status.prototype.initialize = function() {
var width = Graphics.boxWidth;
var height = Graphics.boxHeight;
Window_Selectable.prototype.initialize.call(this, 0, 0, width, height);
this.bitmapActorName=ImageManager.loadMenu("ActorStateName");
this.bitmapActorStatusFace=ImageManager.loadMenu("人物状态大图");
this._actor = null;
this.refresh();
this.activate();
};
Window_Status.prototype.drawActorFace = function(statusFace, x, y, width, height) {
width = width || Window_Status._faceWidth;
height = height || Window_Status._faceHeight;
var bitmap = this.bitmapActorStatusFace;
var pw = Window_Status._faceWidth;
var ph = Window_Status._faceHeight;
var sw = Math.min(width, pw);
var sh = Math.min(height, ph);
var dx = x;
var dy = y;
var sx = statusFace % 3 * 640;;
var sy = Math.floor(statusFace / 3) * 480;
this.contents.blt(bitmap, sx, sy, sw, sh, dx, dy);
};
Window_Status.prototype.drawActorName = function(statusName, x, y, width, height) {
width = width || Window_Status._nameWidth;
height = height || Window_Status._nameHeight;
var bitmap = this.bitmapActorName;
var pw = Window_Status._nameWidth;
var ph = Window_Status._nameHeight;
var sw = Math.min(width, pw);
var sh = Math.min(height, ph);
var dx = x;
var dy = y;
var sx = 0;
var sy = Math.floor(statusName % 5) * sh;
this.contents.blt(bitmap, sx, sy, sw, sh, dx, dy);
};
核心代码就是这些,ImageManager.loadMenu获取了对应文件夹中的指定的文件名的文件;通过一定的计算后用this.contents.blt(bitmap, sx, sy, sw, sh, dx, dy);来进行绘制相应的图片。