为什么在缩放容器后 pointerdown 事件传递到错误的 PIXI.Container?附上测试用例
Why is pointerdown event delivered to a wrong PIXI.Container after scaling containers up and down? Test case attached
我有一个名为 Tile
的自定义 class 扩展 PIXI.Container。
它被实例化了3次并存储在变量中:r
、g
和b
。
首先我水平拖动 3 个方块(即将方块保持在第 4 行):
一段时间后,当我单击 中间 磁贴时,左 磁贴的 onDragStart
方法错误被调用(在下面的屏幕截图中你可以看到我点击了蓝色的瓷砖,但是绿色已经升起):
所以 pointerdown
事件在错误的对象上调用!
我觉得根本原因是 Tile
对象在单击时会放大,因此 Pixi.js 认为它应该将事件传递给仍然很大的对象。
但我还没有想出解决方法或解决方法。
下面是针对我的问题的完整而简单的测试用例。
这个错误对我来说总是可以重现的,只需将图块移动 5-10 次,您就能看到它。
function Tile(color, onDragStart, onDragMove, onDragEnd, x, y) {
PIXI.Container.call(this);
this.x = x;
this.y = y;
this.interactive = true;
this.buttonMode = true;
this.on('pointerdown', onDragStart)
.on('pointermove', onDragMove)
.on('pointerup', onDragEnd)
.on('pointerupoutside', onDragEnd);
this.graph = new PIXI.Graphics();
this.graph.beginFill(color);
this.graph.drawRect(0, 0, Tile.W, Tile.W);
this.graph.endFill();
this.addChild(this.graph);
this.cacheAsBitmap = true;
}
Tile.W = 100;
Tile.prototype = Object.create(PIXI.Container.prototype);
Tile.prototype.constructor = Tile;
Tile.prototype.startDragging = function() {
this.scale.x = 1.6;
this.scale.y = 1.6;
this.alpha = 0.8;
};
Tile.prototype.stopDragging = function() {
this.scale.x = 1;
this.scale.y = 1;
this.alpha = 1;
// align x, y to the checker board grid
this.x = Tile.W * Math.floor((this.x + Tile.W / 2) / Tile.W);
this.y = Tile.W * Math.floor((this.y + Tile.W / 2) / Tile.W);
};
var app = new PIXI.Application({
width: Tile.W * 8,
height: Tile.W * 8,
view: document.getElementById('pixiCanvas'),
backgroundColor: 0xFFFFFF
});
var background = new PIXI.Graphics();
for (var i = 0; i < 8; i++) {
for (var j = 0; j < 8; j++) {
if ((i + j) % 2 == 0) {
background.beginFill(0xCCCCFF);
background.drawRect(i * Tile.W, j * Tile.W, Tile.W, Tile.W);
background.endFill();
}
}
}
app.stage.addChild(background);
var r = new Tile(0xFF0000, onDragStart, onDragMove, onDragEnd, 3 * Tile.W, 3 * Tile.W);
var g = new Tile(0x00FF00, onDragStart, onDragMove, onDragEnd, 4 * Tile.W, 3 * Tile.W);
var b = new Tile(0x0000FF, onDragStart, onDragMove, onDragEnd, 5 * Tile.W, 3 * Tile.W);
app.stage.addChild(r);
app.stage.addChild(g);
app.stage.addChild(b);
function onDragStart(ev) {
this.data = ev.data;
var pos = this.data.getLocalPosition(this.parent);
this.x = pos.x - this.width / 2;
this.y = pos.y - this.height / 2;
// put the tile on top
app.stage.removeChild(this);
app.stage.addChild(this);
this.startDragging();
}
function onDragMove() {
if (this.data) {
var pos = this.data.getLocalPosition(this.parent);
this.x = pos.x - this.width / 2;
this.y = pos.y - this.height / 2;
}
}
function onDragEnd() {
if (this.data) {
var pos = this.data.getLocalPosition(this.parent);
this.data = null;
// the next 2 lines are not needed here, but
// in my real game I put the tile beneath the HUD
app.stage.removeChild(this);
app.stage.addChildAt(this, app.stage.children.length);
this.stopDragging();
}
}
#pixiCanvas {
width: 100%;
height: 100%;
background: #CCF;
box-sizing: border-box;
border: 4px red dotted;
}
<canvas id="pixiCanvas"></canvas>
<script src="https://cdn.jsdelivr.net/npm/pixi.js@5.3.7/dist/pixi.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/pixi.js-legacy@5.3.7/dist/pixi-legacy.min.js"></script>
另外我创建了 issue 7233 at Github and you can also see the bug in my real app:
到目前为止我已经尝试过但没有帮助的事情:
- 将
Tile
基础 class 从 PIXI.Container
切换到 PIXI.Sprite
- 将
startDragging
和 stopDragging
调用移到 removeChild
和 addChild(At)
之前
- 完全删除
removeChild
和 addChild(At)
调用
- 删除
this.scale.x = 1.6
和 this.scale.y = 1.6
- 正在 Pixi.js 仓库中搜索 pointerdown(不了解源代码)
用-
修复了它
this.hitArea = new PIXI.Rectangle(0, 0, Tile.W, Tile.W);
我有一个名为 Tile
的自定义 class 扩展 PIXI.Container。
它被实例化了3次并存储在变量中:r
、g
和b
。
首先我水平拖动 3 个方块(即将方块保持在第 4 行):
一段时间后,当我单击 中间 磁贴时,左 磁贴的 onDragStart
方法错误被调用(在下面的屏幕截图中你可以看到我点击了蓝色的瓷砖,但是绿色已经升起):
所以 pointerdown
事件在错误的对象上调用!
我觉得根本原因是 Tile
对象在单击时会放大,因此 Pixi.js 认为它应该将事件传递给仍然很大的对象。
但我还没有想出解决方法或解决方法。
下面是针对我的问题的完整而简单的测试用例。
这个错误对我来说总是可以重现的,只需将图块移动 5-10 次,您就能看到它。
function Tile(color, onDragStart, onDragMove, onDragEnd, x, y) {
PIXI.Container.call(this);
this.x = x;
this.y = y;
this.interactive = true;
this.buttonMode = true;
this.on('pointerdown', onDragStart)
.on('pointermove', onDragMove)
.on('pointerup', onDragEnd)
.on('pointerupoutside', onDragEnd);
this.graph = new PIXI.Graphics();
this.graph.beginFill(color);
this.graph.drawRect(0, 0, Tile.W, Tile.W);
this.graph.endFill();
this.addChild(this.graph);
this.cacheAsBitmap = true;
}
Tile.W = 100;
Tile.prototype = Object.create(PIXI.Container.prototype);
Tile.prototype.constructor = Tile;
Tile.prototype.startDragging = function() {
this.scale.x = 1.6;
this.scale.y = 1.6;
this.alpha = 0.8;
};
Tile.prototype.stopDragging = function() {
this.scale.x = 1;
this.scale.y = 1;
this.alpha = 1;
// align x, y to the checker board grid
this.x = Tile.W * Math.floor((this.x + Tile.W / 2) / Tile.W);
this.y = Tile.W * Math.floor((this.y + Tile.W / 2) / Tile.W);
};
var app = new PIXI.Application({
width: Tile.W * 8,
height: Tile.W * 8,
view: document.getElementById('pixiCanvas'),
backgroundColor: 0xFFFFFF
});
var background = new PIXI.Graphics();
for (var i = 0; i < 8; i++) {
for (var j = 0; j < 8; j++) {
if ((i + j) % 2 == 0) {
background.beginFill(0xCCCCFF);
background.drawRect(i * Tile.W, j * Tile.W, Tile.W, Tile.W);
background.endFill();
}
}
}
app.stage.addChild(background);
var r = new Tile(0xFF0000, onDragStart, onDragMove, onDragEnd, 3 * Tile.W, 3 * Tile.W);
var g = new Tile(0x00FF00, onDragStart, onDragMove, onDragEnd, 4 * Tile.W, 3 * Tile.W);
var b = new Tile(0x0000FF, onDragStart, onDragMove, onDragEnd, 5 * Tile.W, 3 * Tile.W);
app.stage.addChild(r);
app.stage.addChild(g);
app.stage.addChild(b);
function onDragStart(ev) {
this.data = ev.data;
var pos = this.data.getLocalPosition(this.parent);
this.x = pos.x - this.width / 2;
this.y = pos.y - this.height / 2;
// put the tile on top
app.stage.removeChild(this);
app.stage.addChild(this);
this.startDragging();
}
function onDragMove() {
if (this.data) {
var pos = this.data.getLocalPosition(this.parent);
this.x = pos.x - this.width / 2;
this.y = pos.y - this.height / 2;
}
}
function onDragEnd() {
if (this.data) {
var pos = this.data.getLocalPosition(this.parent);
this.data = null;
// the next 2 lines are not needed here, but
// in my real game I put the tile beneath the HUD
app.stage.removeChild(this);
app.stage.addChildAt(this, app.stage.children.length);
this.stopDragging();
}
}
#pixiCanvas {
width: 100%;
height: 100%;
background: #CCF;
box-sizing: border-box;
border: 4px red dotted;
}
<canvas id="pixiCanvas"></canvas>
<script src="https://cdn.jsdelivr.net/npm/pixi.js@5.3.7/dist/pixi.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/pixi.js-legacy@5.3.7/dist/pixi-legacy.min.js"></script>
另外我创建了 issue 7233 at Github and you can also see the bug in my real app:
到目前为止我已经尝试过但没有帮助的事情:
- 将
Tile
基础 class 从PIXI.Container
切换到PIXI.Sprite
- 将
startDragging
和stopDragging
调用移到removeChild
和addChild(At)
之前
- 完全删除
removeChild
和addChild(At)
调用 - 删除
this.scale.x = 1.6
和this.scale.y = 1.6
- 正在 Pixi.js 仓库中搜索 pointerdown(不了解源代码)
用-
修复了它this.hitArea = new PIXI.Rectangle(0, 0, Tile.W, Tile.W);