Project1
标题:
RPG Maker MV 的源码研究 其十
[打印本页]
作者:
沉滞的剑
时间:
2019-8-20 22:25
标题:
RPG Maker MV 的源码研究 其十
本帖最后由 沉滞的剑 于 2019-8-20 22:32 编辑
希望论坛能支持直接写Markdown啊
==============================
在Window_Selectable之后,
RM还再次拓展了Window_Command类, 引入了Command的概念
将item封装成名称, 对应handler, 可用状态等属性的新对象
下面我们将按照惯例通过各个生命周期来了解它的原理
Window_Command.prototype.initialize = function (x, y) {
this.clearCommandList();
this.makeCommandList();
var width = this.windowWidth();
var height = this.windowHeight();
Window_Selectable.prototype.initialize.call(this, x, y, width, height);
this.refresh();
this.select(0);
this.activate();
};
复制代码
Window_Command具有_list属性
代表其维护的Command列表
Window_Command.prototype.clearCommandList = function () {
this._list = [];
};
Window_Command.prototype.makeCommandList = function () {
};
Window_Command.prototype.addCommand = function (name, symbol, enabled, ext) {
if (enabled === undefined) {
enabled = true;
}
if (ext === undefined) {
ext = null;
}
this._list.push({ name: name, symbol: symbol, enabled: enabled, ext: ext });
};
复制代码
基础的对command列表的各种操作
makeCommandList是个虚函数, 需要各个子类对其进行实现
在addCommand里可以看出来Command总共有4个属性
name, symbol, enabled 和 ext
name对应的是绘制名
symbol对应的是选择后对应的handler
enabled控制是否可选
ext应该是携带的 拓展信息
对于单个command, 也有相应的获取其属性的方法
Window_Command.prototype.commandName = function (index) {
return this._list[index].name;
};
Window_Command.prototype.commandSymbol = function (index) {
return this._list[index].symbol;
};
Window_Command.prototype.isCommandEnabled = function (index) {
return this._list[index].enabled;
};
复制代码
对于当前Command获取属性的方法
Window_Command.prototype.currentData = function () {
return this.index() >= 0 ? this._list[this.index()] : null;
};
Window_Command.prototype.isCurrentItemEnabled = function () {
return this.currentData() ? this.currentData().enabled : false;
};
Window_Command.prototype.currentSymbol = function () {
return this.currentData() ? this.currentData().symbol : null;
};
Window_Command.prototype.currentExt = function () {
return this.currentData() ? this.currentData().ext : null;
};
复制代码
还有一些检索特定属性, 找到command的方法
Window_Command.prototype.findSymbol = function (symbol) {
for (var i = 0; i < this._list.length; i++) {
if (this._list[i].symbol === symbol) {
return i;
}
}
return -1;
};
Window_Command.prototype.selectSymbol = function (symbol) {
var index = this.findSymbol(symbol);
if (index >= 0) {
this.select(index);
} else {
this.select(0);
}
};
Window_Command.prototype.findExt = function (ext) {
for (var i = 0; i < this._list.length; i++) {
if (this._list[i].ext === ext) {
return i;
}
}
return -1;
};
复制代码
讲讲绘制, 首先在Window_Selectable里有item的矩形区域的定义
Window_Selectable.prototype.itemRect = function (index) {
var rect = new Rectangle();
var maxCols = this.maxCols();
rect.width = this.itemWidth();
rect.height = this.itemHeight();
rect.x = index % maxCols * (rect.width + this.spacing()) - this._scrollX;
rect.y = Math.floor(index / maxCols) * rect.height - this._scrollY;
return rect;
};
复制代码
每个item按照横向铺满换行的方式排列
对于每一个itemRect, 还有一个由textPadding控制的textRect
Window_Selectable.prototype.itemRectForText = function (index) {
var rect = this.itemRect(index);
rect.x += this.textPadding();
rect.width -= this.textPadding() * 2;
return rect;
};
复制代码
在Window_Command中, 我们就是在这个textRect中绘制name
Window_Command.prototype.drawItem = function (index) {
var rect = this.itemRectForText(index);
var align = this.itemTextAlign();
this.resetTextColor();
this.changePaintOpacity(this.isCommandEnabled(index));
this.drawText(this.commandName(index), rect.x, rect.y, rect.width, align);
};
复制代码
其中resetTextColor:
Window_Base.prototype.resetTextColor = function () {
this.changeTextColor(this.normalColor());
};
Window_Base.prototype.changeTextColor = function (color) {
this.contents.textColor = color;
};
Window_Base.prototype.normalColor = function () {
return this.textColor(0);
};
复制代码
嗯, 还记得Window_Base里讲的那个复古的取色写法么...
Window_Base.prototype.changePaintOpacity = function (enabled) {
this.contents.paintOpacity = enabled ? 255 : this.translucentOpacity();
};
Window_Base.prototype.translucentOpacity = function () {
return 160;
};
复制代码
这个就是根据当前command是否是enabled来确定字体的透明度了
update其实没有多少变化不过Window_Command覆写了callOkHandler
先来看一下这个方法在Window_Selectable中的调用栈
Window_Selectable.prototype.update = function () {
// ...略
this.processHandling();
// ...略
};
Window_Selectable.prototype.processHandling = function () {
// 略....
if (this.isOkEnabled() && this.isOkTriggered()) {
this.processOk();
}
// 略....
};
Window_Selectable.prototype.processOk = function () {
if (this.isCurrentItemEnabled()) {
// ... 略
this.callOkHandler();
// ... 略
}
};
复制代码
Window_Command修改了callOkHandler的方法:
Window_Command.prototype.callOkHandler = function () {
var symbol = this.currentSymbol(); // 获取当前command的symbol
if (this.isHandled(symbol)) { // 如果存在该symbol的handler
this.callHandler(symbol); // 则呼叫这个handler
} else if (this.isHandled('ok')) { // 否则判断是否有ok
Window_Selectable.prototype.callOkHandler.call(this); // 呼叫ok
} else {
this.activate(); // 否则就重新选择一下
}
};
复制代码
这里贴个activate供大家参考一下
Window_Selectable.prototype.activate = function () {
Window_Base.prototype.activate.call(this);
this.reselect();
};
Window_Selectable.prototype.reselect = function () {
this.select(this._index);
};
复制代码
最后一个refresh重绘也没有太多内容
Window_Command.prototype.refresh = function () {
this.clearCommandList();
this.makeCommandList();
this.createContents();
Window_Selectable.prototype.refresh.call(this);
};
复制代码
需要注意的是每次重绘Command list都会被清空重新添加
内容也要重绘, 绘制部分参见上面的drawItem
这里把相关的父类函数贴一下
Window_Selectable.prototype.refresh = function () {
if (this.contents) {
this.contents.clear();
this.drawAllItems();
}
};
Window_Selectable.prototype.drawAllItems = function () {
var topIndex = this.topIndex();
for (var i = 0; i < this.maxPageItems(); i++) {
var index = topIndex + i;
if (index < this.maxItems()) {
this.drawItem(index);
}
}
};
复制代码
收工~收工~
下次应该有新的练手内容
明天见...大概吧
作者:
chinx
时间:
2019-8-21 13:09
太真实了 技术贴没人看系列。 顶一发
作者:
walf_man
时间:
2019-8-21 20:30
楼上你说的也很真实呀
欢迎光临 Project1 (https://rpg.blue/)
Powered by Discuz! X3.1