GiniWren Posted May 10, 2018 Share Posted May 10, 2018 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: Mouse down on sprite spawner. Drag mouse some distance away from the sprite spawner. Keeping the mouse position stationary, release the mouse button. Observe the event hasn't fired yet. 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: 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 More sharing options...
samme Posted May 10, 2018 Share Posted May 10, 2018 Add game.debug.pointer(…) to see if it's showing up/down. Which browser is this? Link to comment Share on other sites More sharing options...
GiniWren Posted May 10, 2018 Author Share Posted May 10, 2018 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: looks like is Up and duration debugging info is all correct, but the event itself isn't firing until the mouse moves. samme 1 Link to comment Share on other sites More sharing options...
GiniWren Posted May 10, 2018 Author Share Posted May 10, 2018 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...? samme 1 Link to comment Share on other sites More sharing options...
GiniWren Posted May 10, 2018 Author Share Posted May 10, 2018 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: samme 1 Link to comment Share on other sites More sharing options...
samme Posted May 10, 2018 Share Posted May 10, 2018 Is this worth making a change in Phaser CE? Link to comment Share on other sites More sharing options...
GiniWren Posted May 11, 2018 Author Share Posted May 11, 2018 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 More sharing options...
Recommended Posts