Skip to content

Commit

Permalink
Updated InputPlugin event specificity flow and added stopPropagation …
Browse files Browse the repository at this point in the history
…support
  • Loading branch information
photonstorm committed Sep 12, 2018
1 parent 14881bb commit b1771a1
Show file tree
Hide file tree
Showing 2 changed files with 181 additions and 23 deletions.
26 changes: 26 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,32 @@

## Version 3.13.0 - Yuuki - in development

## Pointer and Input Event Updates

The specificity if the input events has been changed to allow you more control over event handling. Previously, the InputPlugin would emit the global `pointerdown` event first, and then the Game Object itself would emit the `pointerdown` event and finally the InputPlugin would emit the `gameobjectdown` event.

The order has now changed. The Game Object will dispatch its `pointerdown` event first. The InputPlugin will then dispatch `gameobjectdown` and finally the less specific of them all, `pointerdown` will be dispatched.

New in 3.13 is the ability to cancel this at any stage. All events are now sent an event object which you can call `event.stopPropagation()` on. This will immediately stop any further listeners from being invoked. If you call `stopPropagation()` after the first Game Object `pointerdown` event, then no more Game Object's will receive their callbacks and the InputPlugin will not dispatch either of its events.

This change has been introduced for `pointerdown`, `pointerup`, `pointermove`, `pointerover` and `pointerout`. No other data is included in the `event` object in this release.

* The Game Object `pointerdown` callback signature has changed. It used to send `pointer, x, y, camera` to the listener. It now sends `pointer, x, y, event` to the listener. If you still need the `camera` property you can get it from `pointer.camera`.
* The Game Object `gameobjectdown` callback signature has a new argument. It now sends `event` as the 3rd argument.
* The `pointerdown` event, as dispatched by the InputPlugin, is now sent _after_ the Game Object specific events (`GameObject.pointerdown` and `gameobjectdown`). This gives you the chance to cancel the event before the global listener receives it.
* The Game Object `pointerup` callback signature has a new argument. It now sends the `event` as the 4th argument.
* The Game Object `gameobjectup` callback signature has a new argument. It now sends `event` as the 3rd argument.
* The `pointerup` event, as dispatched by the InputPlugin, is now sent _after_ the Game Object specific events (`GameObject.pointerup` and `gameobjectup`). This gives you the chance to cancel the event before the global listener receives it.
* The Game Object `pointermove` callback signature has a new argument. It now sends the `event` as the 4th argument.
* The Game Object `gameobjectmove` callback signature has a new argument. It now sends `event` as the 3rd argument.
* The `pointermove` event, as dispatched by the InputPlugin, is now sent _after_ the Game Object specific events (`GameObject.pointermove` and `gameobjectmove`). This gives you the chance to cancel the event before the global listener receives it.
* The Game Object `pointerover` callback signature has a new argument. It now sends the `event` as the 4th argument.
* The Game Object `gameobjectover` callback signature has a new argument. It now sends `event` as the 3rd argument.
* The `pointerover` event, as dispatched by the InputPlugin, is now sent _after_ the Game Object specific events (`GameObject.pointerover` and `gameobjectover`). This gives you the chance to cancel the event before the global listener receives it.
* The Game Object `pointerout` callback signature has a new argument. It now sends the `event` as the 2nd argument.
* The Game Object `gameobjectout` callback signature has a new argument. It now sends `event` as the 3rd argument.
* The `pointerout` event, as dispatched by the InputPlugin, is now sent _after_ the Game Object specific events (`GameObject.pointerout` and `gameobjectout`). This gives you the chance to cancel the event before the global listener receives it.

## New Features

* The `Color` object has a new property `h` which represents the hue of the color. You can tween or adjust this property in real-time and it will automatically update the internal RGB values with it.
Expand Down
178 changes: 155 additions & 23 deletions src/input/InputPlugin.js
Original file line number Diff line number Diff line change
Expand Up @@ -201,6 +201,33 @@ var InputPlugin = new Class({
*/
this._pollTimer = 0;

var _eventData = { cancelled: false };

/**
* Internal event propagation callback container.
*
* @name Phaser.Input.InputPlugin#_eventContainer
* @type {object}
* @private
* @since 3.13.0
*/
this._eventContainer = {
stopPropagation: function ()
{
_eventData.cancelled = true;
}
};

/**
* Internal event propagation data object.
*
* @name Phaser.Input.InputPlugin#_eventData
* @type {object}
* @private
* @since 3.13.0
*/
this._eventData = _eventData;

/**
* The distance, in pixels, a pointer has to move while being held down, before it thinks it is being dragged.
*
Expand Down Expand Up @@ -727,12 +754,15 @@ var InputPlugin = new Class({
*/
processDownEvents: function (pointer)
{
var total = 0;
var currentlyOver = this._temp;

// Contains ALL Game Objects currently over in the array
this.emit('pointerdown', pointer, currentlyOver);
var _eventData = this._eventData;
var _eventContainer = this._eventContainer;

var total = 0;
_eventData.cancelled = false;

var aborted = false;

// Go through all objects the pointer was over and fire their events / callbacks
for (var i = 0; i < currentlyOver.length; i++)
Expand All @@ -746,9 +776,27 @@ var InputPlugin = new Class({

total++;

gameObject.emit('pointerdown', pointer, gameObject.input.localX, gameObject.input.localY, pointer.camera);
gameObject.emit('pointerdown', pointer, gameObject.input.localX, gameObject.input.localY, _eventContainer);

if (_eventData.cancelled)
{
aborted = true;
break;
}

this.emit('gameobjectdown', pointer, gameObject, _eventContainer);

this.emit('gameobjectdown', pointer, gameObject);
if (_eventData.cancelled)
{
aborted = true;
break;
}
}

// Contains ALL Game Objects currently over in the array
if (!aborted)
{
this.emit('pointerdown', pointer, currentlyOver);
}

return total;
Expand Down Expand Up @@ -1035,11 +1083,15 @@ var InputPlugin = new Class({
*/
processMoveEvents: function (pointer)
{
var total = 0;
var currentlyOver = this._temp;

this.emit('pointermove', pointer, currentlyOver);
var _eventData = this._eventData;
var _eventContainer = this._eventContainer;

var total = 0;
_eventData.cancelled = false;

var aborted = false;

// Go through all objects the pointer was over and fire their events / callbacks
for (var i = 0; i < currentlyOver.length; i++)
Expand All @@ -1053,16 +1105,33 @@ var InputPlugin = new Class({

total++;

gameObject.emit('pointermove', pointer, gameObject.input.localX, gameObject.input.localY);
gameObject.emit('pointermove', pointer, gameObject.input.localX, gameObject.input.localY, _eventContainer);

this.emit('gameobjectmove', pointer, gameObject);
if (_eventData.cancelled)
{
aborted = true;
break;
}

this.emit('gameobjectmove', pointer, gameObject, _eventContainer);

if (_eventData.cancelled)
{
aborted = true;
break;
}

if (this.topOnly)
{
break;
}
}

if (!aborted)
{
this.emit('pointermove', pointer, currentlyOver);
}

return total;
},

Expand Down Expand Up @@ -1131,12 +1200,17 @@ var InputPlugin = new Class({

var totalInteracted = 0;

var _eventData = this._eventData;
var _eventContainer = this._eventContainer;

_eventData.cancelled = false;

var aborted = false;

if (total > 0)
{
this.sortGameObjects(justOut);

this.emit('pointerout', pointer, justOut);

// Call onOut for everything in the justOut array
for (i = 0; i < total; i++)
{
Expand All @@ -1147,25 +1221,44 @@ var InputPlugin = new Class({
continue;
}

this.emit('gameobjectout', pointer, gameObject);

gameObject.emit('pointerout', pointer);
gameObject.emit('pointerout', pointer, _eventContainer);

manager.resetCursor(gameObject.input);

totalInteracted++;

if (_eventData.cancelled)
{
aborted = true;
break;
}

this.emit('gameobjectout', pointer, gameObject, _eventContainer);

if (_eventData.cancelled)
{
aborted = true;
break;
}
}

if (!aborted)
{
this.emit('pointerout', pointer, justOut);
}
}

// Process the Just Over objects
total = justOver.length;

_eventData.cancelled = false;

aborted = false;

if (total > 0)
{
this.sortGameObjects(justOver);

this.emit('pointerover', pointer, justOver);

// Call onOver for everything in the justOver array
for (i = 0; i < total; i++)
{
Expand All @@ -1176,13 +1269,30 @@ var InputPlugin = new Class({
continue;
}

this.emit('gameobjectover', pointer, gameObject);

gameObject.emit('pointerover', pointer, gameObject.input.localX, gameObject.input.localY);
gameObject.emit('pointerover', pointer, gameObject.input.localX, gameObject.input.localY, _eventContainer);

manager.setCursor(gameObject.input);

totalInteracted++;

if (_eventData.cancelled)
{
aborted = true;
break;
}

this.emit('gameobjectover', pointer, gameObject, _eventContainer);

if (_eventData.cancelled)
{
aborted = true;
break;
}
}

if (!aborted)
{
this.emit('pointerover', pointer, justOver);
}
}

Expand Down Expand Up @@ -1210,8 +1320,12 @@ var InputPlugin = new Class({
{
var currentlyOver = this._temp;

// Contains ALL Game Objects currently up in the array
this.emit('pointerup', pointer, currentlyOver);
var _eventData = this._eventData;
var _eventContainer = this._eventContainer;

_eventData.cancelled = false;

var aborted = false;

// Go through all objects the pointer was over and fire their events / callbacks
for (var i = 0; i < currentlyOver.length; i++)
Expand All @@ -1225,9 +1339,27 @@ var InputPlugin = new Class({

// pointerupoutside

gameObject.emit('pointerup', pointer, gameObject.input.localX, gameObject.input.localY);
gameObject.emit('pointerup', pointer, gameObject.input.localX, gameObject.input.localY, _eventContainer);

this.emit('gameobjectup', pointer, gameObject);
if (_eventData.cancelled)
{
aborted = true;
break;
}

this.emit('gameobjectup', pointer, gameObject, _eventContainer);

if (_eventData.cancelled)
{
aborted = true;
break;
}
}

if (!aborted)
{
// Contains ALL Game Objects currently up in the array
this.emit('pointerup', pointer, currentlyOver);
}

return currentlyOver.length;
Expand Down

0 comments on commit b1771a1

Please sign in to comment.