From 4304811dde99e340fe207021fae0e865f496aa74 Mon Sep 17 00:00:00 2001 From: Richard Davey Date: Fri, 8 Jun 2018 17:50:47 +0100 Subject: [PATCH] Added new Pixel Perfect input handler and `makePixelPerfect` method. --- CHANGELOG.md | 2 ++ src/input/CreatePixelPerfectHandler.js | 33 +++++++++++++++++ src/input/InputPlugin.js | 49 ++++++++++++++++++++++++++ 3 files changed, 84 insertions(+) create mode 100644 src/input/CreatePixelPerfectHandler.js diff --git a/CHANGELOG.md b/CHANGELOG.md index 918915e5a..d6cd38478 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -28,6 +28,7 @@ TODO - Out of Canvas events * Setting `enabled` to false on either the TouchManager, MouseManager or KeyboardManager will prevent it from handling any native DOM events until you set it back again. * InputPlugin has the following new read-only properties: `mousePointer`, `pointer1`, `pointer2`, `pointer3`, `pointer4`, `pointer5`, `pointer6`, `pointer7`, `pointer8`, `pointer9` and `pointer10`. Most of these will be undefined unless you call `addPointer` first, or set the active pointers quantity in your Game Config. * InputManager has a new method `transformPointer` which will set the transformed x and y properties of a Pointer in one call, rather than the 2 calls it took before. This is now used by all Pointer event handlers. +* InputPlugin has a new method `makePixelPerfect` which allows you to specify a texture-based Game Object as being pixel perfect when performing all input checks against it. You use it like this: `this.add.sprite(x, y, key).setInteractive(this.input.makePixelPerfect())` - you can also pass in an optional alpha tolerance level. See the method docs for full details and the new examples to see it in action. Note that as a pointer interacts with the Game Object it will constantly poll the texture, extracting a single pixel from the given coordinates and checking its color values. This is an expensive process, so should only be enabled on Game Objects that really need it. ### Input - Keyboard Manager Updates @@ -102,6 +103,7 @@ TODO - Out of Canvas events * Camera has a new method `setVisible` which toggles its visible property. * `CameraManager.fromJSON` will now set the visible property is defined in the config. * `ScenePlugin.run` is a new method that will run the given Scene and not change the state of the current Scene at all. If the scene is asleep, it will be woken. If it's paused, it will be resumed. If not running at all, it will be started. +* `TextureManager.getPixelAlpha` is a new method that will return the alpha value of a pixel from the given texture and frame. It will return `null` if the coordinates were out of bounds, otherwise a value between 0 and 255. ### Updates diff --git a/src/input/CreatePixelPerfectHandler.js b/src/input/CreatePixelPerfectHandler.js new file mode 100644 index 000000000..f7f08811a --- /dev/null +++ b/src/input/CreatePixelPerfectHandler.js @@ -0,0 +1,33 @@ +/** + * @author Richard Davey + * @copyright 2018 Photon Storm Ltd. + * @license {@link https://github.com/photonstorm/phaser/blob/master/license.txt|MIT License} + */ + +/** + * Creates a new Interactive Object. + * + * This is called automatically by the Input Manager when you enable a Game Object for input. + * + * The resulting Interactive Object is mapped to the Game Object's `input` property. + * + * @function Phaser.Input.CreatePixelPerfectHandler + * @since 3.10.0 + * + * @param {Phaser.GameObjects.GameObject} gameObject - The Game Object to which this Interactive Object is bound. + * @param {any} hitArea - The hit area for this Interactive Object. Typically a geometry shape, like a Rectangle or Circle. + * @param {HitAreaCallback} hitAreaCallback - The 'contains' check callback that the hit area shape will use for all hit tests. + * + * @return {Phaser.Input.InteractiveObject} The new Interactive Object. + */ +var CreatePixelPerfectHandler = function (textureManager, alphaTolerance) +{ + return function (hitArea, x, y, gameObject) + { + var alpha = textureManager.getPixelAlpha(x, y, gameObject.texture.key, gameObject.frame.key); + + return (alpha && alpha >= alphaTolerance) + }; +}; + +module.exports = CreatePixelPerfectHandler; diff --git a/src/input/InputPlugin.js b/src/input/InputPlugin.js index 960f1e528..d85043617 100644 --- a/src/input/InputPlugin.js +++ b/src/input/InputPlugin.js @@ -8,6 +8,7 @@ var Circle = require('../geom/circle/Circle'); var CircleContains = require('../geom/circle/Contains'); var Class = require('../utils/Class'); var CreateInteractiveObject = require('./CreateInteractiveObject'); +var CreatePixelPerfectHandler = require('./CreatePixelPerfectHandler'); var DistanceBetween = require('../math/distance/DistanceBetween'); var Ellipse = require('../geom/ellipse/Ellipse'); var EllipseContains = require('../geom/ellipse/Contains'); @@ -1297,6 +1298,48 @@ var InputPlugin = new Class({ return this; }, + /** + * Creates a function that can be passed to `setInteractive`, `enable` or `setHitArea` that will handle + * pixel-perfect input detection on an Image or Sprite based Game Object, or any custom class that extends them. + * + * The following will create a sprite that is clickable on any pixel that has an alpha value >= 1. + * + * ```javascript + * this.add.sprite(x, y, key).setInteractive(this.input.makePixelPerfect()); + * ``` + * + * The following will create a sprite that is clickable on any pixel that has an alpha value >= 150. + * + * ```javascript + * this.add.sprite(x, y, key).setInteractive(this.input.makePixelPerfect(150)); + * ``` + * + * Once you have made an Interactive Object pixel perfect it impacts all input related events for it: down, up, + * dragstart, drag, etc. + * + * As a pointer interacts with the Game Object it will constantly poll the texture, extracting a single pixel from + * the given coordinates and checking its color values. This is an expensive process, so should only be enabled on + * Game Objects that really need it. + * + * You cannot make non-texture based Game Objects pixel perfect. So this will not work on Graphics, BitmapText, + * Render Textures, Text, Tilemaps, Containers or Particles. + * + * @method Phaser.Input.InputPlugin#makePixelPerfect + * @since 3.10.0 + * + * @param {integer} [alphaTolerance=1] - The alpha level that the pixel should be above to be included as a successful interaction. + * + * @return {function} A Pixel Perfect Handler for use as a hitArea shape callback. + */ + makePixelPerfect: function (alphaTolerance) + { + if (alphaTolerance === undefined) { alphaTolerance = 1; } + + var textureManager = this.systems.textures; + + return CreatePixelPerfectHandler(textureManager, alphaTolerance); + }, + /** * Sets the hit area for the given array of Game Objects. * @@ -1331,6 +1374,12 @@ var InputPlugin = new Class({ gameObjects = [ gameObjects ]; } + if (typeof shape === 'function' && !callback) + { + callback = shape; + shape = {}; + } + for (var i = 0; i < gameObjects.length; i++) { var gameObject = gameObjects[i];