Project1
标题:
MV插件开发杂谈之Mixin与继承
[打印本页]
作者:
沉滞的剑
时间:
2019-10-21 00:06
标题:
MV插件开发杂谈之Mixin与继承
本帖最后由 沉滞的剑 于 2019-10-21 00:12 编辑
当在JS拓展功能的时候会面临两个选择:
1. 修改现有的类(Mixin)
本质上是将原有类的原型上增加新的属性
亦或
2. 从现有的类的基础上派生出信的类(继承)
本质上是将新的类的原型指向旧类的原型
这两种方法是RM中插件拓展的基础, 必须要掌握
我现在要做一个拥有Window_Base的功能且能拖拽的窗口
最常见的做法就是新建一个继承于Window_Base的新类
可能的写法就是:
class Window_Draggable extends Window_Base {
update() {...}
}
复制代码
但如果我要让全部继承于Window_Base的窗口都可以拖拽
我就需要拓展Window_Base的原型
可能的写法
const update = Window_Base.prototype.update;
Window_Base.prototype.update = function() {
update.call(this);
...
};
复制代码
但是如果我们要提供给其他插件作者基于任意窗口的可拖拽拓展呢?
如果是新的类, 我们可以选择高阶类(HighOrderClass)来动态生成
高阶类传入一个类, 返回一个继承于该类的新类
const useDraggableWindow = WindowClass => {
return class extends WindowClass {
update() {...}
}
}
复制代码
如果要改变现有类的行为我们就要用混合(Mixin)
const makeWindowDragable = WindowClass => {
const update = WindowClass.prototype.update;
WindowClass.prototype.update = function() {
update.call(this);
...
};
}
复制代码
继承会创造新的类, 加深继承链的深度, 所以性能上略逊
但是继承也因为在原型链上留下了痕迹, 所以能追踪到每个属性的来源
并且可以和instanceOf这样的操作符配合使用
插播广告:
自制基于高阶类型的插件
[line]1[/line]
另附本次插件
const makeWindowDragable = WindowClass => {
const update = WindowClass.prototype.update;
WindowClass.prototype.update = function() {
update.call(this);
this.updateDrag();
};
WindowClass.prototype.updateDrag = function() {
const isInside = this.rect.contains(TouchInput.x, TouchInput.y);
if (TouchInput.isTriggered() && isInside) {
this._dragX = this.canvasToLocalX(TouchInput.x);
this._dragY = this.canvasToLocalY(TouchInput.y);
this._dragging = true;
const windowList = SceneManager._scene._windowLayer.children;
$gameTemp.draggingWin = this;
windowList.sort(x => x === this);
} else if (
TouchInput.isPressed() &&
this._dragging &&
$gameTemp.draggingWin == this
) {
this.x = TouchInput.x - this._dragX;
this.y = TouchInput.y - this._dragY;
} else if (TouchInput.isReleased()) {
this._dragging = false;
}
};
Object.defineProperty(WindowClass.prototype, "rect", {
get() {
if (
!this._rect ||
this._rect.x !== this.x ||
this._rect.y !== this.y ||
this._rect.width !== this.width ||
this._rect.height !== this.height
) {
this._rect = new Rectangle(this.x, this.y, this.width, this.height);
}
return this._rect;
}
});
};
const useDraggableWindow = WindowClass => {
const hoc = class extends WindowClass {};
makeWindowDragable(hoc);
return hoc;
};
//解决重叠时边角覆盖问题
const _maskWindow = WindowLayer.prototype._maskWindow;
WindowLayer.prototype._maskWindow = function(window, shift) {
_maskWindow.call(this, window, shift);
const rect = this._windowRect;
rect.x += 4;
rect.y += 4;
rect.width -= 8;
rect.height -= 8;
};
WindowLayer.prototype._canvasClearWindowRect = function(
renderSession,
window
) {
var rx = this.x + window.x;
var ry =
this.y + window.y + (window.height / 2) * (1 - window._openness / 255);
var rw = window.width;
var rh = (window.height * window._openness) / 255;
renderSession.context.clearRect(rx + 4, ry + 4, rw - 8, rh - 8);
};
复制代码
使用方法:
makeWindowDragable(Window_Base);
const Window_Draggable = useDraggableWindow(Window_Base);
复制代码
作者:
MichaelPolo
时间:
2019-10-21 19:05
给大佬端茶
作者:
fux2
时间:
2019-10-21 19:52
兼容性警告,目测这样的语法部署到移动端之后无法正常工作
尽量还是不使用es5,6的语法吧
欢迎光临 Project1 (https://rpg.blue/)
Powered by Discuz! X3.1