Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Mobile Bug: Touch events no longer detected on iPhone if game pauses or hits breakpoint during pointerdown event #3887

Closed
maximtsai opened this issue Aug 2, 2018 · 9 comments

Comments

@maximtsai
Copy link

maximtsai commented Aug 2, 2018

On ios devices, 'pointerdown' events created using this.input.on('pointerdown', myFunc, this) or image.on('pointerdown', myFunc, this) will no longer fire if the game pauses during the execution of its callback function. This can happen if a debugger statement or breakpoint is placed inside the myFunc callback function. It can also happen to users if the drag down menu (http://ift.tt/1n2dgPw) is pressed while simultaneously pressing inside the game. The second case may take a few tries to reproduce but here is a video of me reproducing the bug: https://youtu.be/aCICmilOrz8

Reproduced on iPhone 6S+ (10.3.2), iPhone 6 Plus (11.1), and iPad Air 4G (10.3.2)
This issue does not occur on Android devices or any PCs (tested on Mac Safari and Windows Chrome)

Sample code that can trigger the bug:

var config = {
    width: 800,
    height: 600,
    backgroundColor: '#2d2d2d',
    parent: 'phaser-example',
    scene: {
        preload: preload,
        create: create
    }
};

var game = new Phaser.Game(config);

function preload ()
{
    this.load.image('button', 'button.png');
}

var image1;
function create ()
{
    var self = this
    window.addEventListener('touchstart', function(evt) {
        // this can still trigger even after the bug has occurred
        console.log("touch start");
    });
    image1 = this.add.image(400, 200, 'button');
    this.input.on('pointerdown', one, this);
    this.input.on('pointerup', two, this);
}

function one() {
    // This function no longer gets called after the bug has occurred
    console.log("button press");
    // this debugger statement can trigger the bug. Even without it, bug can happen by pressing the drop down menu
    debugger;
    image1.alpha = 0.2;
}
function two() {
    image1.alpha = 1;    
}

HTML:

<!doctype html> 
<html lang="en"> 
<head> 
    <meta charset="UTF-8" />
    <title>Lottso Express</title>
    <script src="phaser.min.js"></script>
    <script src="main.js"></script>
    <style type="text/css">
        body {
		background-color: grey;
        }
	canvas {
		display:block;
		margin: 0;
		position: absolute;
		top: 50%;
		left: 50%;
		transform: translate(-50%, -50%);
	}
	#phaser-app {
		margin: 0 auto;
	}
    </style>
</head>
<body>
</body>
</html>
@maximtsai maximtsai changed the title Mobile Bug: Touch events no longer detected on iPhone if game pauses/hits breakpoint during pointerdown event Mobile Bug: Touch events no longer detected on iPhone if game pauses or hits breakpoint during pointerdown event Aug 2, 2018
@maximtsai
Copy link
Author

maximtsai commented Aug 13, 2018

I've figured out a work-around for this bug, though it will likely break multi-touch. In phaser.js at function stopPointer, change the pointer.identifier === changedTouch.identifier check to pointer.identifier <= changedTouch.identifier.

Current Phaser.js code:

stopPointer: function (event, time)
{
    var pointers = this.pointers;

    for (var c = 0; c < event.changedTouches.length; c++)
    {
        var changedTouch = event.changedTouches[c];

        for (var i = 1; i < this.pointersTotal; i++)
        {
            var pointer = pointers[i];
            if (pointer.active && pointer.identifier === changedTouch.identifier)
            {
                pointer.touchend(changedTouch, time);
                break;
            }
        }
    }
},

Edited Phaser.js code:

stopPointer: function (event, time)
{
    var pointers = this.pointers;

    for (var c = 0; c < event.changedTouches.length; c++)
    {
        var changedTouch = event.changedTouches[c];

        for (var i = 1; i < this.pointersTotal; i++)
        {
            var pointer = pointers[i];
            // CHANGED === TO <=
            if (pointer.active && pointer.identifier <= changedTouch.identifier)
            {
                pointer.touchend(changedTouch, time);
                break;
            }
        }
    }
},

The game freeze happens because changedTouch.identifier becomes de-synced from pointer.identifier, which causes the current touch event to no longer terminate so new touch events cannot happen. I suspect that Safari might be cleaning up the most recent touch event when you open the drag down menu, which causes the de-sync when you also happen to touch something in a Phaser game at the exact same moment.

@sachinhosmani
Copy link

Thanks a lot for filing this and the detailed explanations @maximtsai .

As a workaround I tried to remove the input listener when the game loses focus and add it back when it returns. For me the problem is particularly with using Facebook instant platform's function which opens a modal dialog which causes my game to lose control.

This is what I tried:

function create() {
  // listen to mouse clicks at the start
  this.input.on('pointerdown', function() {
    // some code
  });
}
var doneChoosing = false;

// Invite friends - this makes the game lose focus
// When this is called, the problem starts
function inviteFriends(that) {
  // Remove listener so that the handler code doesn't get triggered
  that.input.removeListener('pointerdown');
  FBInstant.chooseAsync().then(function() {
    doneChoosing = true;
  }).catch(function() {
    doneChoosing = true;
  });
}

function update() {
  if (doneChoosing) {
    // control is back to the game and the dialog has been opened and closed
    // add back input listener
    this.input.on('pointerdown', function() {
      // some code
    });
  }
}

However this doesn't solve the problem. Any idea why?

@sachinhosmani
Copy link

Hi @photonstorm do you think the workaround suggested by @maximtsai would be safe to use as long as I don't use multi touch in my game? Or do you know of any other workarounds to use until this bug is fixed?

Thanks!

@photonstorm
Copy link
Collaborator

I've been looking at this all morning and I'm struggling to replicate it using Phaser 3.13 Beta 1. I added a call to debugger in my pointerdown callback and Safari on iPad (iOS 11) still keeps on triggering the event just fine.

I've pulled the drop-down menu down many, many times, tapping while doing so, letting go quickly, letting go slowly, etc.

I've even tried multi-tasking in iOS with another app docked alongside Safari, then pulling the drop-down and it still works.

Is there some other trick to doing this?! Or has it just been inadvertently fixed in a recent Phaser update without realizing it?

@sachinhosmani
Copy link

@photonstorm I used to be able to consistently reproduce it with FBInstant's APIs. If I can get my hands on 3.13 beta 1 I would be able to tell you if I can still reproduce it.

@photonstorm
Copy link
Collaborator

You can find 3.13 in the master branch, or if you need a pre-built file use this:
phaser.js.zip

@sachinhosmani
Copy link

@photonstorm I think the issue is not present anymore, however, the game runs at a very low FPS (like 6 fps on an iPhone) after bumping up Phaser. If I just replace phaser.min.js with the older version with no other change the game becomes fast again.

@photonstorm
Copy link
Collaborator

That’s nothing to do with this issue though, so I’m going to close this off.

@photonstorm
Copy link
Collaborator

Just to say that I've uploaded 3.15 Beta 1, which I'm hopeful resolves this bug fully. You can find it in the master branch, or if you need a pre-built file grab it from my comment in #3756

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

3 participants