我写过一个跳棋游戏模型,它有一个Board对象,里面有一堆Piece对象。 Piece对象有一个事件(pieceMoved),每次移动时都会触发它。
我正在使用EaselJS在canvas元素中渲染此游戏模型。
我要做的第一件事是创建一个画架形状对象,以图形方式表示每件作品。
我希望在棋子的相应形状对象上处理pieceMoved事件,以便我可以更新形状位置。
我创建形状并分配事件处理程序的代码看起来像这样 -
for (x=0;x<=(board_.getColCount()-1);x++) {
for (y=0;y<=(board_.getRowCount()-1);y++) {
var piece = board_.getPieceAt(x, y);
if (!piece) continue;
var circ = new Shape();
circ.eventHandler = function(pieceObj) {
this.x = pieceObj.x*squareSize;
this.y = pieceObj.y*squareSize;
}
piece.addEventHandler(circ.eventHandler);
....
问题是事件处理程序中的'this'关键字没有引用正确的东西。我也尝试了以下内容 -
piece.addEventHandler(function(px) { return circ.eventHandler; });
但同样,“这个”指的是错误的对象。
做这样的事情的正确方法是什么?
答案 0 :(得分:1)
在事件处理程序中,this
引用触发事件的对象。有各种各样的方法,但我的理念是你应该接受公约,而不是反对它。所以,只需将方法与事件处理程序分开:
piece.addEventHandler (function (e) {
circ.eventHandler(e);
});
在您的情况下,由于看起来您有循环问题,请创建一个处理程序工厂:
function getHandler (circ) {
return function(e) {
circ.eventHandler(e);
};
}
for (var i = 0; i < circles.length; i++) {
piece.addEventHandler(getHandler(circles[i]));
}
编辑:使用Array.forEach()
对其进行整理。我猜测circles
不是数组,所以你可能不得不使用.call()
:
[].forEach.call(circles, function(circ) {
piece.addEventHandler(function(e) {
circ.eventHandler(e);
});
});
答案 1 :(得分:1)
尝试移动代码以将圆形创建为方法,例如
function addShape(piece) {
var circ = new Shape();
piece.addEventHandler(function (pieceObj) {
circ.x = pieceObj.x * squareSize;
circ.y = pieceObj.y * squareSize;
});
return circ;
}
这将使循环看起来像,
for (x = 0; x <= (board_.getColCount() - 1); x++) {
for (y = 0; y <= (board_.getRowCount() - 1); y++) {
var piece = board_.getPieceAt(x, y);
if (!piece) continue;
var circ = addShape(piece);
...
}
}
我意识到这并不是真的使用它,但在这种情况下,它会使代码更复杂,你真的不需要它。
答案 2 :(得分:0)
piece.addEventHandler(function(px) {
circ.eventHandler(px);
});
当你直接传递它们时,函数会丢失它们的上下文。这是因为它是添加上下文的调用的点语法。因此,当您只是传递对该函数的引用时,它将被直接调用,并且您将失去上下文。
因此对于依赖于上下文的回调,通常明智的做法是将匿名函数作为回调传递,然后在其中执行您需要做的任何事情。
或者,如果要编辑回调的调用方式,可以执行以下操作:
// event happened invoke handler!
myEventHandler.call(this)
将执行函数对象,其中包含您调用它的上下文(例如,您的Piece isntance)。
答案 3 :(得分:0)
尝试使用bind
(无参数):
piece.addEventHandler(circ.eventHandler.bind(circ));
或使用匿名函数,因为这是一个闭包问题:
piece.addEventHandler((function(circ) {
return function() {
circ.eventHandler.apply(circ, arguments);
};
})(circ));
答案 4 :(得分:0)
你必须简单地做一个关闭:
var that = this;
circ.eventHandler = function(pieceObj) {
that.x = pieceObj.x*squareSize; // we will "remember" the correct scope now!
that.y = pieceObj.y*squareSize;
}
由于函数在与其创建的范围不同的范围内触发,因此在某种程度上会混淆。您需要通过关闭变量来直接设置它。您可以通过在函数外部引用它,然后在函数内使用该引用来完成此操作。这将允许该函数始终使用正确的“this”。