Jump to content

[SOLVED] Dragged sprite onInputUp not firing until mouse moves?


GiniWren
 Share

Recommended Posts

I've created a "sprite spawner" that, when the mouse presses down on it, it spawns a new sprite that the mouse is then dragging. I use it for things like menus, where you have an image of something you want to add to the game stage, and by clicking and dragging from the image you create a new instance that can then be placed by the mouse.

However, it appears that the onDragStop event isn't being fired until the mouse moves. This only happens on the initial creation of the dragged sprite; behavior works as expected after the first time.

Steps to duplicate:

  1. Mouse down on sprite spawner.
  2. Drag mouse some distance away from the sprite spawner.
  3. Keeping the mouse position stationary, release the mouse button.
  4. Observe the event hasn't fired yet.
  5. Move the mouse in any direction; observe the event is then fired.

This also can be reproduced by omitting step 2 (which may be helpful if it's hard to see it happening -- can just click and release the mouse).

Here's a gif of the problem:

phaser-mouse-up.gif.0096b0736b660fbb8111c0a42c555c82.gif

Here's the minimum, runnable game code to see the issue (used to create the above gif):

var game = new Phaser.Game(400, 300, Phaser.AUTO, 'game-container',
  { preload: preload, create: create, render: render });

function preload() {
  // load game images
  game.load.image('star', 'img/star.png');
  game.load.image('blueStar', 'img/blue-star.png');
}

function create() {
  // text indicating whether a spawned sprite is actively being dragged
  var dragIndicatorText = game.add.text(10, 10, 'Drag from the yellow star to spawn a new sprite.', {fontSize: 16, fill: '#ffffff'});

  // create sprite that spawns blue stars on mouse down that are
  // immediately dragged by the mouse  on spawn
  var spriteSpawner = game.add.sprite(50, 100, 'star');

  // enable input to access events
  spriteSpawner.inputEnabled = true;

  // expected behavior is when input is pressed down, a sprite spawns
  // under the mouse, and mouse is then immediately dragging that new sprite.
  spriteSpawner.events.onInputDown.add(function (spawner, pointer) {
    // spawn new sprite
    var newSprite = game.add.sprite(game.input.worldX, game.input.worldY, 'blueStar');

    // enable sprite dragging interaction
    newSprite.inputEnabled = true;
    newSprite.input.enableDrag();
    newSprite.input.bringToTop = true;

    // recenter sprite on mouse input (taking sprite size into account)
    newSprite.x = game.input.worldX - newSprite.width / 2;
    newSprite.y = game.input.worldY - newSprite.height / 2;

    // hook up sprite drag start/stop events
    newSprite.events.onDragStart.add(function() {
      dragIndicatorText.text = 'Sprite being dragged';
    }, this);
    newSprite.events.onDragStop.add(function() {
      dragIndicatorText.text = 'Sprite dropped';
    }, this);

    // start drag on spawned sprite immediately
    newSprite.input.startDrag(pointer);
  }, this);
}

function render() {
  game.debug.pointer(game.input.activePointer);
}

I'm not sure whether this is a bug or something simple I'm forgetting to do to ensure the proper events are firing. Let me know if I can clarify or add any other needed information.

Edit: Using Phaser CE v2.10.5

Seen in browsers:

  • Google Chrome, Version 66.0.3359.170 (Official Build) (64-bit)
  • Firefox Quantum, Version 60.0 (64-bit)
  • Safari, Version 11.1 (13605.1.33.1.2)

Thanks for any help!

Link to comment
Share on other sites

Seen in browsers:
Google Chrome, Version 66.0.3359.170 (Official Build) (64-bit)
Firefox Quantum, Version 60.0 (64-bit)
Safari, Version 11.1 (13605.1.33.1.2)

Here's with the input debug:

phaser-mouse-up-2.gif.1cca22e5b1bfa3a3b97e210d4f0e7671.gif

looks like is Up and duration debugging info is all correct, but the event itself isn't firing until the mouse moves.

Link to comment
Share on other sites

Dug into the Phaser source code, and I think I may be onto an explanation.

It looks like InputHandler's stopDrag function (responsible for calling onDragStop) is being called in two different places on first spawn vs normal event. Normally, when a sprite is dragged, the _releaseHandler calls stopDrag, provided the _draggedPointerId on the sprite matches the pointer.id of the event. However, perhaps because startDrag is called manually, when the sprite is first spawned the _draggedPointerId is -1 (while my pointer is 0), so stopDrag ends up being called by a check in InputHandler's updateDrag. Because updateDrag is only called when the pointer moves, the onDragStop function isn't dispatched until the pointer moves again.

I'm stuck figuring out where _draggedPointerId is being set to -1, because when startDrag is called manually, it does get set properly to 0. Something must be changing it along the line...?

Link to comment
Share on other sites

Alright, got a workable solution, posting for posterity...

The following can be added within the onInputDown code after the spawned sprite is created to ensure proper behavior:

spawner.events.onInputUp.addOnce(function(spawner, pointer) {
  newSprite.input.stopDrag(pointer);
});

Explanation: From the previous post, I wrongly suspected that the _draggedPointerId was being set to -1, when in reality it was the _releaseHandler calling release for the spawner, not the new sprite; because the pointer wasn't dragging the spawner, it was correct in being -1. So, by adding a one-time event for that release/onInputUp that releases drag on the new sprite, it behaves as expected. After that first time, the event is destroyed, and things can go on normally. Here's the result:

phaser-mouse-up-3.gif.46f0cfed9c9d59be905c26da51b1ef76.gif

Link to comment
Share on other sites

  • GiniWren changed the title to [SOLVED] Dragged sprite onInputUp not firing until mouse moves?

I don't know enough about the codebase atm to know whether changing the way this works would cause further confusion or unexpected behavior. (This is only the second time I've really had to dig into the source code even after working with it nearly every day for 10 months now. I can't sing Phaser's praises enough, everything just works, and it's the least trouble I've had working with any game engine.)

While, I'd expect as a result of startDrag() that the pointer's target (targetObject?) reference would reflect whatever the inputHandler belongs to, in this particular case it would mean you've left the original sprite+inputHandler hanging for its own onInputUp event. Maybe there's a cleaner/easier solution?

I'd speak in favor of at least putting a working example out there so people can find it, simply because the behavior and solution aren't immediately apparent. I've found some older threads mentioning the same/a similar concept, so the drag-to-spawn-sprite behavior as a whole seems to be desirable. Here's a few:

http://www.html5gamedevs.com/topic/28982-how-to-transfer-drag-input-control-from-one-sprite-to-another/
http://www.html5gamedevs.com/topic/10523-create-and-move-sprite-oninputdown/
https://gamedev.stackexchange.com/questions/138508/how-to-transfer-drag-control-from-one-sprite-to-another-phaser
http://www.html5gamedevs.com/topic/15181-drag-sprite-on-spawn/

That said, I haven't seen anyone run into this particular sticking point yet.

Link to comment
Share on other sites

 Share

  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...