Phaser 3:检查可拖动对象是否在 Sprite 的交互区域上方
Phaser 3: Check if draggable Object is over interactive area of a Sprite
我想实现的是能够拖动一个Sprite,当它移动到另一个Sprite的交互区域时,它会发射粒子。
但是,如果我正在拖动另一个精灵,则不会调用 Pointermove 事件(可能是因为我的指针位于可拖动精灵上方,而不是交互式精灵上方。)我尝试向我的拖动事件添加 If-Condition ,它测试我的可拖动对象是否位于交互式 Sprite 上方,这种方法可行,但它会在 sprite 的任何区域上做出反应,而不是仅在交互式区域上。这很重要,因为我的 Sprite 的交互区域使用 pixel perfect
.
有什么方法可以达到我想要的结果吗?
我对 Pointermove 的尝试:
gameState.chara.setInteractive({cursor: "pointer", pixelPerfect: true});
gameState.chara.on('pointermove', function(activePointer){
if (activePointer.isDown && gameState.clean_cursor) {
switch(gameState.clean_cursor.frame.name.split('_')[0]){
case "sponge":
gameState.bubble.emitParticle(1, activePointer.x, activePointer.y);
break;
case "showerhead":
gameState.splash.emitParticle(1, activePointer.x-50, activePointer.y+50);
break;
}
}
});
this.input.on('drag', (activePointer, gameObject, dragX, dragY) => {
switch(gameObject.frame.name.split('_')[0]){
case "sponge":
gameState.clean_cursor.play('sponge_cursor', true);
break;
case "showerhead":
gameState.clean_cursor.play('shower_cursor', true);
break;
}
gameObject.x = dragX;
gameObject.y = dragY;
});
this.input.on('dragend', function(pointer, gameObject) {
gameObject.destroy();
gameState.clean_cursor = false;
});
(一旦我拖动另一个精灵,Pointermove 事件就会停止反应)
我只尝试拖动:
gameState.chara.setInteractive({cursor: "pointer", pixelPerfect: true});
this.input.on('drag', (activePointer, gameObject, dragX, dragY) => {
if(gameState.chara.getBounds().contains(dragX, dragY)) {
switch(gameState.clean_cursor.frame.name.split('_')[0]){
case "sponge":
gameState.bubble.emitParticle(1, activePointer.x, activePointer.y);
break;
case "showerhead":
gameState.splash.emitParticle(1, activePointer.x-50, activePointer.y+50);
break;
}
}
switch(gameObject.frame.name.split('_')[0]){
case "sponge":
gameState.clean_cursor.play('sponge_cursor', true);
break;
case "showerhead":
gameState.clean_cursor.play('shower_cursor', true);
break;
}
gameObject.x = dragX;
gameObject.y = dragY;
});
this.input.on('dragend', function(pointer, gameObject) {
gameObject.destroy();
});
(有效,但在整个精灵上,而不是仅 Pixel Perfect 交互区域)
有了解决方法如何拖动 button/image
这个题的解法应该很简单
- 只需检查精灵是否与边界重叠。 (不是像素完美的,因为它匹配框)here the documentation
如果需要pixel-perfect,这个就比较难了
这是“简单”解决方案的代码:
(代码需要一些调整)
let Example = {
preload () {
this.load.spritesheet('brawler', 'https://labs.phaser.io/assets/animations/brawler48x48.png', { frameWidth: 48, frameHeight: 48 });
this.load.atlas('flares', 'https://labs.phaser.io/assets/particles/flares.png', 'https://labs.phaser.io/assets/particles/flares.json');
},
create () {
this._particles = this.add.particles('flares');
this._emitter = this._particles.createEmitter({
frame: 'blue',
lifespan: 2000,
speed: { min: 50, max: 400 },
angle: 330,
gravityY: 300,
scale: { start: 0.4, end: 0 },
quantity: 2,
blendMode: 'ADD',
on: false
});
let buttonPos = { x:20, y:20};
let buttonPlaceholder = this.add.image(buttonPos.x, buttonPos.y, 'brawler', ).setOrigin(0.5);
let button = this.add.image(buttonPos.x, buttonPos.y, 'brawler', ).setOrigin(0.5);
let interact = this.add.image(200, 100, 'brawler', 3).setOrigin(0.5);
interact.setDepth(-1);
button.setInteractive({ useHandCursor: true });
this.input.setDraggable(button);
this.input.on('drag', function(pointer, gameObject, dragX, dragY) {
gameObject.x = dragX;
gameObject.y = dragY;
if(Phaser.Geom.Intersects.RectangleToRectangle(gameObject.getBounds(), interact.getBounds() )){
this._emitter.start()
this._particles.x = interact.x;
this._particles.y = interact.y;
} else {
if (this._emitter.active){
this._emitter.stop();
}
}
}, this);
this.input.on('dragend', function(pointer, gameObject) {
gameObject.x = buttonPos.x;
gameObject.y = buttonPos.y;
this._emitter.stop();
}, this);
}
}
const config = {
type: Phaser.AUTO,
width: 400,
height: 200,
scene: [ Example ]
};
const game = new Phaser.Game(config);
<script src="https://cdn.jsdelivr.net/npm/phaser@3.55.2/dist/phaser.js"></script>
Extra info, to improve: You could check overlap with CircleToCircle, and keeping the radius abit smaller. (Or other intersection functions, that fit your needs better https://photonstorm.github.io/phaser3-docs/Phaser.Geom.Intersects.html)
像素完美版,可以这样写:
(刚找到这个属性this.input.topOnly
,docs)
如果设置为 false
,此 属性 允许将输入事件传递给位于最顶层对象下的其他对象。
let Example = {
preload () {
this.load.spritesheet('brawler', 'https://labs.phaser.io/assets/animations/brawler48x48.png', { frameWidth: 48, frameHeight: 48 });
this.load.atlas('flares', 'https://labs.phaser.io/assets/particles/flares.png', 'https://labs.phaser.io/assets/particles/flares.json');
},
create () {
this.input.topOnly = false;
let isDragging = false;
this._particles = this.add.particles('flares');
this._emitter = this._particles.createEmitter({
frame: 'blue',
lifespan: 2000,
speed: { min: 400, max: 600 },
angle: 330,
gravityY: 300,
scale: { start: 0.4, end: 0 },
quantity: 2,
blendMode: 'ADD',
on: false
});
let buttonPos = { x:20, y:20};
let buttonPlaceholder = this.add.image(buttonPos.x, buttonPos.y, 'brawler', )
.setOrigin(0.5);
let button = this.add.image(buttonPos.x, buttonPos.y, 'brawler', )
.setOrigin(0.5);
let interact = this.add.image(200, 100, 'brawler', 3)
.setOrigin(0.5);
interact
.setInteractive(this.input.makePixelPerfect());
interact.on('pointerover', function(pointer){
if(isDragging){
this._particles.x = interact.x;
this._particles.y = interact.y;
this._emitter.start();
}
}, this);
interact.on('pointerout', function(pointer){
this._emitter.stop();
}, this);
interact.setDepth(-1);
button.setInteractive({ useHandCursor: true });
this.input.setDraggable(button);
this.input.on('drag', function(pointer, gameObject, dragX, dragY) {
isDragging = true;
gameObject.x = dragX;
gameObject.y = dragY;
}, this);
this.input.on('dragend', function(pointer, gameObject) {
gameObject.x = buttonPos.x;
gameObject.y = buttonPos.y;
this._emitter.stop();
isDragging = false;
}, this);
}
}
const config = {
type: Phaser.AUTO,
width: 400,
height: 200,
scene: [ Example ]
};
const game = new Phaser.Game(config);
<script src="https://cdn.jsdelivr.net/npm/phaser@3.55.2/dist/phaser.js"></script>
我想实现的是能够拖动一个Sprite,当它移动到另一个Sprite的交互区域时,它会发射粒子。
但是,如果我正在拖动另一个精灵,则不会调用 Pointermove 事件(可能是因为我的指针位于可拖动精灵上方,而不是交互式精灵上方。)我尝试向我的拖动事件添加 If-Condition ,它测试我的可拖动对象是否位于交互式 Sprite 上方,这种方法可行,但它会在 sprite 的任何区域上做出反应,而不是仅在交互式区域上。这很重要,因为我的 Sprite 的交互区域使用 pixel perfect
.
有什么方法可以达到我想要的结果吗?
我对 Pointermove 的尝试:
gameState.chara.setInteractive({cursor: "pointer", pixelPerfect: true});
gameState.chara.on('pointermove', function(activePointer){
if (activePointer.isDown && gameState.clean_cursor) {
switch(gameState.clean_cursor.frame.name.split('_')[0]){
case "sponge":
gameState.bubble.emitParticle(1, activePointer.x, activePointer.y);
break;
case "showerhead":
gameState.splash.emitParticle(1, activePointer.x-50, activePointer.y+50);
break;
}
}
});
this.input.on('drag', (activePointer, gameObject, dragX, dragY) => {
switch(gameObject.frame.name.split('_')[0]){
case "sponge":
gameState.clean_cursor.play('sponge_cursor', true);
break;
case "showerhead":
gameState.clean_cursor.play('shower_cursor', true);
break;
}
gameObject.x = dragX;
gameObject.y = dragY;
});
this.input.on('dragend', function(pointer, gameObject) {
gameObject.destroy();
gameState.clean_cursor = false;
});
(一旦我拖动另一个精灵,Pointermove 事件就会停止反应)
我只尝试拖动:
gameState.chara.setInteractive({cursor: "pointer", pixelPerfect: true});
this.input.on('drag', (activePointer, gameObject, dragX, dragY) => {
if(gameState.chara.getBounds().contains(dragX, dragY)) {
switch(gameState.clean_cursor.frame.name.split('_')[0]){
case "sponge":
gameState.bubble.emitParticle(1, activePointer.x, activePointer.y);
break;
case "showerhead":
gameState.splash.emitParticle(1, activePointer.x-50, activePointer.y+50);
break;
}
}
switch(gameObject.frame.name.split('_')[0]){
case "sponge":
gameState.clean_cursor.play('sponge_cursor', true);
break;
case "showerhead":
gameState.clean_cursor.play('shower_cursor', true);
break;
}
gameObject.x = dragX;
gameObject.y = dragY;
});
this.input.on('dragend', function(pointer, gameObject) {
gameObject.destroy();
});
(有效,但在整个精灵上,而不是仅 Pixel Perfect 交互区域)
有了解决方法如何拖动 button/image
这个题的解法应该很简单
- 只需检查精灵是否与边界重叠。 (不是像素完美的,因为它匹配框)here the documentation
如果需要pixel-perfect,这个就比较难了
这是“简单”解决方案的代码:
(代码需要一些调整)
let Example = {
preload () {
this.load.spritesheet('brawler', 'https://labs.phaser.io/assets/animations/brawler48x48.png', { frameWidth: 48, frameHeight: 48 });
this.load.atlas('flares', 'https://labs.phaser.io/assets/particles/flares.png', 'https://labs.phaser.io/assets/particles/flares.json');
},
create () {
this._particles = this.add.particles('flares');
this._emitter = this._particles.createEmitter({
frame: 'blue',
lifespan: 2000,
speed: { min: 50, max: 400 },
angle: 330,
gravityY: 300,
scale: { start: 0.4, end: 0 },
quantity: 2,
blendMode: 'ADD',
on: false
});
let buttonPos = { x:20, y:20};
let buttonPlaceholder = this.add.image(buttonPos.x, buttonPos.y, 'brawler', ).setOrigin(0.5);
let button = this.add.image(buttonPos.x, buttonPos.y, 'brawler', ).setOrigin(0.5);
let interact = this.add.image(200, 100, 'brawler', 3).setOrigin(0.5);
interact.setDepth(-1);
button.setInteractive({ useHandCursor: true });
this.input.setDraggable(button);
this.input.on('drag', function(pointer, gameObject, dragX, dragY) {
gameObject.x = dragX;
gameObject.y = dragY;
if(Phaser.Geom.Intersects.RectangleToRectangle(gameObject.getBounds(), interact.getBounds() )){
this._emitter.start()
this._particles.x = interact.x;
this._particles.y = interact.y;
} else {
if (this._emitter.active){
this._emitter.stop();
}
}
}, this);
this.input.on('dragend', function(pointer, gameObject) {
gameObject.x = buttonPos.x;
gameObject.y = buttonPos.y;
this._emitter.stop();
}, this);
}
}
const config = {
type: Phaser.AUTO,
width: 400,
height: 200,
scene: [ Example ]
};
const game = new Phaser.Game(config);
<script src="https://cdn.jsdelivr.net/npm/phaser@3.55.2/dist/phaser.js"></script>
Extra info, to improve: You could check overlap with CircleToCircle, and keeping the radius abit smaller. (Or other intersection functions, that fit your needs better https://photonstorm.github.io/phaser3-docs/Phaser.Geom.Intersects.html)
像素完美版,可以这样写:
(刚找到这个属性this.input.topOnly
,docs)
如果设置为 false
,此 属性 允许将输入事件传递给位于最顶层对象下的其他对象。
let Example = {
preload () {
this.load.spritesheet('brawler', 'https://labs.phaser.io/assets/animations/brawler48x48.png', { frameWidth: 48, frameHeight: 48 });
this.load.atlas('flares', 'https://labs.phaser.io/assets/particles/flares.png', 'https://labs.phaser.io/assets/particles/flares.json');
},
create () {
this.input.topOnly = false;
let isDragging = false;
this._particles = this.add.particles('flares');
this._emitter = this._particles.createEmitter({
frame: 'blue',
lifespan: 2000,
speed: { min: 400, max: 600 },
angle: 330,
gravityY: 300,
scale: { start: 0.4, end: 0 },
quantity: 2,
blendMode: 'ADD',
on: false
});
let buttonPos = { x:20, y:20};
let buttonPlaceholder = this.add.image(buttonPos.x, buttonPos.y, 'brawler', )
.setOrigin(0.5);
let button = this.add.image(buttonPos.x, buttonPos.y, 'brawler', )
.setOrigin(0.5);
let interact = this.add.image(200, 100, 'brawler', 3)
.setOrigin(0.5);
interact
.setInteractive(this.input.makePixelPerfect());
interact.on('pointerover', function(pointer){
if(isDragging){
this._particles.x = interact.x;
this._particles.y = interact.y;
this._emitter.start();
}
}, this);
interact.on('pointerout', function(pointer){
this._emitter.stop();
}, this);
interact.setDepth(-1);
button.setInteractive({ useHandCursor: true });
this.input.setDraggable(button);
this.input.on('drag', function(pointer, gameObject, dragX, dragY) {
isDragging = true;
gameObject.x = dragX;
gameObject.y = dragY;
}, this);
this.input.on('dragend', function(pointer, gameObject) {
gameObject.x = buttonPos.x;
gameObject.y = buttonPos.y;
this._emitter.stop();
isDragging = false;
}, this);
}
}
const config = {
type: Phaser.AUTO,
width: 400,
height: 200,
scene: [ Example ]
};
const game = new Phaser.Game(config);
<script src="https://cdn.jsdelivr.net/npm/phaser@3.55.2/dist/phaser.js"></script>