mirror of
https://github.com/photonstorm/phaser
synced 2024-12-23 19:43:28 +00:00
1325 lines
38 KiB
JavaScript
1325 lines
38 KiB
JavaScript
/**
|
||
* @author Richard Davey <rich@photonstorm.com>
|
||
* @copyright 2013-2023 Photon Storm Ltd.
|
||
* @license {@link https://opensource.org/licenses/MIT|MIT License}
|
||
*/
|
||
|
||
var Angle = require('../math/angle/Between');
|
||
var Class = require('../utils/Class');
|
||
var Distance = require('../math/distance/DistanceBetween');
|
||
var FuzzyEqual = require('../math/fuzzy/Equal');
|
||
var SmoothStepInterpolation = require('../math/interpolation/SmoothStepInterpolation');
|
||
var Vector2 = require('../math/Vector2');
|
||
var OS = require('../device/OS');
|
||
|
||
/**
|
||
* @classdesc
|
||
* A Pointer object encapsulates both mouse and touch input within Phaser.
|
||
*
|
||
* By default, Phaser will create 2 pointers for your game to use. If you require more, i.e. for a multi-touch
|
||
* game, then use the `InputPlugin.addPointer` method to do so, rather than instantiating this class directly,
|
||
* otherwise it won't be managed by the input system.
|
||
*
|
||
* You can reference the current active pointer via `InputPlugin.activePointer`. You can also use the properties
|
||
* `InputPlugin.pointer1` through to `pointer10`, for each pointer you have enabled in your game.
|
||
*
|
||
* The properties of this object are set by the Input Plugin during processing. This object is then sent in all
|
||
* input related events that the Input Plugin emits, so you can reference properties from it directly in your
|
||
* callbacks.
|
||
*
|
||
* @class Pointer
|
||
* @memberof Phaser.Input
|
||
* @constructor
|
||
* @since 3.0.0
|
||
*
|
||
* @param {Phaser.Input.InputManager} manager - A reference to the Input Manager.
|
||
* @param {number} id - The internal ID of this Pointer.
|
||
*/
|
||
var Pointer = new Class({
|
||
|
||
initialize:
|
||
|
||
function Pointer (manager, id)
|
||
{
|
||
/**
|
||
* A reference to the Input Manager.
|
||
*
|
||
* @name Phaser.Input.Pointer#manager
|
||
* @type {Phaser.Input.InputManager}
|
||
* @since 3.0.0
|
||
*/
|
||
this.manager = manager;
|
||
|
||
/**
|
||
* The internal ID of this Pointer.
|
||
*
|
||
* @name Phaser.Input.Pointer#id
|
||
* @type {number}
|
||
* @readonly
|
||
* @since 3.0.0
|
||
*/
|
||
this.id = id;
|
||
|
||
/**
|
||
* The most recent native DOM Event this Pointer has processed.
|
||
*
|
||
* @name Phaser.Input.Pointer#event
|
||
* @type {(TouchEvent|MouseEvent|WheelEvent)}
|
||
* @since 3.0.0
|
||
*/
|
||
this.event;
|
||
|
||
/**
|
||
* The DOM element the Pointer was pressed down on, taken from the DOM event.
|
||
* In a default set-up this will be the Canvas that Phaser is rendering to, or the Window element.
|
||
*
|
||
* @name Phaser.Input.Pointer#downElement
|
||
* @type {any}
|
||
* @readonly
|
||
* @since 3.16.0
|
||
*/
|
||
this.downElement;
|
||
|
||
/**
|
||
* The DOM element the Pointer was released on, taken from the DOM event.
|
||
* In a default set-up this will be the Canvas that Phaser is rendering to, or the Window element.
|
||
*
|
||
* @name Phaser.Input.Pointer#upElement
|
||
* @type {any}
|
||
* @readonly
|
||
* @since 3.16.0
|
||
*/
|
||
this.upElement;
|
||
|
||
/**
|
||
* The camera the Pointer interacted with during its last update.
|
||
*
|
||
* A Pointer can only ever interact with one camera at once, which will be the top-most camera
|
||
* in the list should multiple cameras be positioned on-top of each other.
|
||
*
|
||
* @name Phaser.Input.Pointer#camera
|
||
* @type {Phaser.Cameras.Scene2D.Camera}
|
||
* @default null
|
||
* @since 3.0.0
|
||
*/
|
||
this.camera = null;
|
||
|
||
/**
|
||
* A read-only property that indicates which button was pressed, or released, on the pointer
|
||
* during the most recent event. It is only set during `up` and `down` events.
|
||
*
|
||
* On Touch devices the value is always 0.
|
||
*
|
||
* Users may change the configuration of buttons on their pointing device so that if an event's button property
|
||
* is zero, it may not have been caused by the button that is physically left–most on the pointing device;
|
||
* however, it should behave as if the left button was clicked in the standard button layout.
|
||
*
|
||
* @name Phaser.Input.Pointer#button
|
||
* @type {number}
|
||
* @readonly
|
||
* @default 0
|
||
* @since 3.18.0
|
||
*/
|
||
this.button = 0;
|
||
|
||
/**
|
||
* 0: No button or un-initialized
|
||
* 1: Left button
|
||
* 2: Right button
|
||
* 4: Wheel button or middle button
|
||
* 8: 4th button (typically the "Browser Back" button)
|
||
* 16: 5th button (typically the "Browser Forward" button)
|
||
*
|
||
* For a mouse configured for left-handed use, the button actions are reversed.
|
||
* In this case, the values are read from right to left.
|
||
*
|
||
* @name Phaser.Input.Pointer#buttons
|
||
* @type {number}
|
||
* @default 0
|
||
* @since 3.0.0
|
||
*/
|
||
this.buttons = 0;
|
||
|
||
/**
|
||
* The position of the Pointer in screen space.
|
||
*
|
||
* @name Phaser.Input.Pointer#position
|
||
* @type {Phaser.Math.Vector2}
|
||
* @readonly
|
||
* @since 3.0.0
|
||
*/
|
||
this.position = new Vector2();
|
||
|
||
/**
|
||
* The previous position of the Pointer in screen space.
|
||
*
|
||
* The old x and y values are stored in here during the InputManager.transformPointer call.
|
||
*
|
||
* Use the properties `velocity`, `angle` and `distance` to create your own gesture recognition.
|
||
*
|
||
* @name Phaser.Input.Pointer#prevPosition
|
||
* @type {Phaser.Math.Vector2}
|
||
* @readonly
|
||
* @since 3.11.0
|
||
*/
|
||
this.prevPosition = new Vector2();
|
||
|
||
/**
|
||
* An internal vector used for calculations of the pointer speed and angle.
|
||
*
|
||
* @name Phaser.Input.Pointer#midPoint
|
||
* @type {Phaser.Math.Vector2}
|
||
* @private
|
||
* @since 3.16.0
|
||
*/
|
||
this.midPoint = new Vector2(-1, -1);
|
||
|
||
/**
|
||
* The current velocity of the Pointer, based on its current and previous positions.
|
||
*
|
||
* This value is smoothed out each frame, according to the `motionFactor` property.
|
||
*
|
||
* This property is updated whenever the Pointer moves, regardless of any button states. In other words,
|
||
* it changes based on movement alone - a button doesn't have to be pressed first.
|
||
*
|
||
* @name Phaser.Input.Pointer#velocity
|
||
* @type {Phaser.Math.Vector2}
|
||
* @readonly
|
||
* @since 3.16.0
|
||
*/
|
||
this.velocity = new Vector2();
|
||
|
||
/**
|
||
* The current angle the Pointer is moving, in radians, based on its previous and current position.
|
||
*
|
||
* The angle is based on the old position facing to the current position.
|
||
*
|
||
* This property is updated whenever the Pointer moves, regardless of any button states. In other words,
|
||
* it changes based on movement alone - a button doesn't have to be pressed first.
|
||
*
|
||
* @name Phaser.Input.Pointer#angle
|
||
* @type {number}
|
||
* @readonly
|
||
* @since 3.16.0
|
||
*/
|
||
this.angle = 0;
|
||
|
||
/**
|
||
* The distance the Pointer has moved, based on its previous and current position.
|
||
*
|
||
* This value is smoothed out each frame, according to the `motionFactor` property.
|
||
*
|
||
* This property is updated whenever the Pointer moves, regardless of any button states. In other words,
|
||
* it changes based on movement alone - a button doesn't have to be pressed first.
|
||
*
|
||
* If you need the total distance travelled since the primary buttons was pressed down,
|
||
* then use the `Pointer.getDistance` method.
|
||
*
|
||
* @name Phaser.Input.Pointer#distance
|
||
* @type {number}
|
||
* @readonly
|
||
* @since 3.16.0
|
||
*/
|
||
this.distance = 0;
|
||
|
||
/**
|
||
* The smoothing factor to apply to the Pointer position.
|
||
*
|
||
* Due to their nature, pointer positions are inherently noisy. While this is fine for lots of games, if you need cleaner positions
|
||
* then you can set this value to apply an automatic smoothing to the positions as they are recorded.
|
||
*
|
||
* The default value of zero means 'no smoothing'.
|
||
* Set to a small value, such as 0.2, to apply an average level of smoothing between positions. You can do this by changing this
|
||
* value directly, or by setting the `input.smoothFactor` property in the Game Config.
|
||
*
|
||
* Positions are only smoothed when the pointer moves. If the primary button on this Pointer enters an Up or Down state, then the position
|
||
* is always precise, and not smoothed.
|
||
*
|
||
* @name Phaser.Input.Pointer#smoothFactor
|
||
* @type {number}
|
||
* @default 0
|
||
* @since 3.16.0
|
||
*/
|
||
this.smoothFactor = 0;
|
||
|
||
/**
|
||
* The factor applied to the motion smoothing each frame.
|
||
*
|
||
* This value is passed to the Smooth Step Interpolation that is used to calculate the velocity,
|
||
* angle and distance of the Pointer. It's applied every frame, until the midPoint reaches the current
|
||
* position of the Pointer. 0.2 provides a good average but can be increased if you need a
|
||
* quicker update and are working in a high performance environment. Never set this value to
|
||
* zero.
|
||
*
|
||
* @name Phaser.Input.Pointer#motionFactor
|
||
* @type {number}
|
||
* @default 0.2
|
||
* @since 3.16.0
|
||
*/
|
||
this.motionFactor = 0.2;
|
||
|
||
/**
|
||
* The x position of this Pointer, translated into the coordinate space of the most recent Camera it interacted with.
|
||
*
|
||
* If you wish to use this value _outside_ of an input event handler then you should update it first by calling
|
||
* the `Pointer.updateWorldPoint` method.
|
||
*
|
||
* @name Phaser.Input.Pointer#worldX
|
||
* @type {number}
|
||
* @default 0
|
||
* @since 3.10.0
|
||
*/
|
||
this.worldX = 0;
|
||
|
||
/**
|
||
* The y position of this Pointer, translated into the coordinate space of the most recent Camera it interacted with.
|
||
*
|
||
* If you wish to use this value _outside_ of an input event handler then you should update it first by calling
|
||
* the `Pointer.updateWorldPoint` method.
|
||
*
|
||
* @name Phaser.Input.Pointer#worldY
|
||
* @type {number}
|
||
* @default 0
|
||
* @since 3.10.0
|
||
*/
|
||
this.worldY = 0;
|
||
|
||
/**
|
||
* Time when this Pointer was most recently moved (regardless of the state of its buttons, if any)
|
||
*
|
||
* @name Phaser.Input.Pointer#moveTime
|
||
* @type {number}
|
||
* @default 0
|
||
* @since 3.0.0
|
||
*/
|
||
this.moveTime = 0;
|
||
|
||
/**
|
||
* X coordinate of the Pointer when Button 1 (left button), or Touch, was pressed, used for dragging objects.
|
||
*
|
||
* @name Phaser.Input.Pointer#downX
|
||
* @type {number}
|
||
* @default 0
|
||
* @since 3.0.0
|
||
*/
|
||
this.downX = 0;
|
||
|
||
/**
|
||
* Y coordinate of the Pointer when Button 1 (left button), or Touch, was pressed, used for dragging objects.
|
||
*
|
||
* @name Phaser.Input.Pointer#downY
|
||
* @type {number}
|
||
* @default 0
|
||
* @since 3.0.0
|
||
*/
|
||
this.downY = 0;
|
||
|
||
/**
|
||
* The Event timestamp when the first button, or Touch input, was pressed. Used for dragging objects.
|
||
*
|
||
* @name Phaser.Input.Pointer#downTime
|
||
* @type {number}
|
||
* @default 0
|
||
* @since 3.0.0
|
||
*/
|
||
this.downTime = 0;
|
||
|
||
/**
|
||
* X coordinate of the Pointer when Button 1 (left button), or Touch, was released, used for dragging objects.
|
||
*
|
||
* @name Phaser.Input.Pointer#upX
|
||
* @type {number}
|
||
* @default 0
|
||
* @since 3.0.0
|
||
*/
|
||
this.upX = 0;
|
||
|
||
/**
|
||
* Y coordinate of the Pointer when Button 1 (left button), or Touch, was released, used for dragging objects.
|
||
*
|
||
* @name Phaser.Input.Pointer#upY
|
||
* @type {number}
|
||
* @default 0
|
||
* @since 3.0.0
|
||
*/
|
||
this.upY = 0;
|
||
|
||
/**
|
||
* The Event timestamp when the final button, or Touch input, was released. Used for dragging objects.
|
||
*
|
||
* @name Phaser.Input.Pointer#upTime
|
||
* @type {number}
|
||
* @default 0
|
||
* @since 3.0.0
|
||
*/
|
||
this.upTime = 0;
|
||
|
||
/**
|
||
* Is the primary button down? (usually button 0, the left mouse button)
|
||
*
|
||
* @name Phaser.Input.Pointer#primaryDown
|
||
* @type {boolean}
|
||
* @default false
|
||
* @since 3.0.0
|
||
*/
|
||
this.primaryDown = false;
|
||
|
||
/**
|
||
* Is _any_ button on this pointer considered as being down?
|
||
*
|
||
* @name Phaser.Input.Pointer#isDown
|
||
* @type {boolean}
|
||
* @default false
|
||
* @since 3.0.0
|
||
*/
|
||
this.isDown = false;
|
||
|
||
/**
|
||
* Did the previous input event come from a Touch input (true) or Mouse? (false)
|
||
*
|
||
* @name Phaser.Input.Pointer#wasTouch
|
||
* @type {boolean}
|
||
* @default false
|
||
* @since 3.0.0
|
||
*/
|
||
this.wasTouch = false;
|
||
|
||
/**
|
||
* Did this Pointer get canceled by a touchcancel event?
|
||
*
|
||
* Note: "canceled" is the American-English spelling of "cancelled". Please don't submit PRs correcting it!
|
||
*
|
||
* @name Phaser.Input.Pointer#wasCanceled
|
||
* @type {boolean}
|
||
* @default false
|
||
* @since 3.15.0
|
||
*/
|
||
this.wasCanceled = false;
|
||
|
||
/**
|
||
* If the mouse is locked, the horizontal relative movement of the Pointer in pixels since last frame.
|
||
*
|
||
* @name Phaser.Input.Pointer#movementX
|
||
* @type {number}
|
||
* @default 0
|
||
* @since 3.0.0
|
||
*/
|
||
this.movementX = 0;
|
||
|
||
/**
|
||
* If the mouse is locked, the vertical relative movement of the Pointer in pixels since last frame.
|
||
*
|
||
* @name Phaser.Input.Pointer#movementY
|
||
* @type {number}
|
||
* @default 0
|
||
* @since 3.0.0
|
||
*/
|
||
this.movementY = 0;
|
||
|
||
/**
|
||
* The identifier property of the Pointer as set by the DOM event when this Pointer is started.
|
||
*
|
||
* @name Phaser.Input.Pointer#identifier
|
||
* @type {number}
|
||
* @since 3.10.0
|
||
*/
|
||
this.identifier = 0;
|
||
|
||
/**
|
||
* The pointerId property of the Pointer as set by the DOM event when this Pointer is started.
|
||
* The browser can and will recycle this value.
|
||
*
|
||
* @name Phaser.Input.Pointer#pointerId
|
||
* @type {number}
|
||
* @since 3.10.0
|
||
*/
|
||
this.pointerId = null;
|
||
|
||
/**
|
||
* An active Pointer is one that is currently pressed down on the display.
|
||
* A Mouse is always considered as active.
|
||
*
|
||
* @name Phaser.Input.Pointer#active
|
||
* @type {boolean}
|
||
* @since 3.10.0
|
||
*/
|
||
this.active = (id === 0) ? true : false;
|
||
|
||
/**
|
||
* Is this pointer Pointer Locked?
|
||
*
|
||
* Only a mouse pointer can be locked and it only becomes locked when requested via
|
||
* the browsers Pointer Lock API.
|
||
*
|
||
* You can request this by calling the `this.input.mouse.requestPointerLock()` method from
|
||
* a `pointerdown` or `pointerup` event handler.
|
||
*
|
||
* @name Phaser.Input.Pointer#locked
|
||
* @readonly
|
||
* @type {boolean}
|
||
* @since 3.19.0
|
||
*/
|
||
this.locked = false;
|
||
|
||
/**
|
||
* The horizontal scroll amount that occurred due to the user moving a mouse wheel or similar input device.
|
||
*
|
||
* @name Phaser.Input.Pointer#deltaX
|
||
* @type {number}
|
||
* @default 0
|
||
* @since 3.18.0
|
||
*/
|
||
this.deltaX = 0;
|
||
|
||
/**
|
||
* The vertical scroll amount that occurred due to the user moving a mouse wheel or similar input device.
|
||
* This value will typically be less than 0 if the user scrolls up and greater than zero if scrolling down.
|
||
*
|
||
* @name Phaser.Input.Pointer#deltaY
|
||
* @type {number}
|
||
* @default 0
|
||
* @since 3.18.0
|
||
*/
|
||
this.deltaY = 0;
|
||
|
||
/**
|
||
* The z-axis scroll amount that occurred due to the user moving a mouse wheel or similar input device.
|
||
*
|
||
* @name Phaser.Input.Pointer#deltaZ
|
||
* @type {number}
|
||
* @default 0
|
||
* @since 3.18.0
|
||
*/
|
||
this.deltaZ = 0;
|
||
},
|
||
|
||
/**
|
||
* Takes a Camera and updates this Pointer's `worldX` and `worldY` values so they are
|
||
* the result of a translation through the given Camera.
|
||
*
|
||
* Note that the values will be automatically replaced the moment the Pointer is
|
||
* updated by an input event, such as a mouse move, so should be used immediately.
|
||
*
|
||
* @method Phaser.Input.Pointer#updateWorldPoint
|
||
* @since 3.19.0
|
||
*
|
||
* @param {Phaser.Cameras.Scene2D.Camera} camera - The Camera which is being tested against.
|
||
*
|
||
* @return {this} This Pointer object.
|
||
*/
|
||
updateWorldPoint: function (camera)
|
||
{
|
||
// Stores the world point inside of tempPoint
|
||
var temp = camera.getWorldPoint(this.x, this.y);
|
||
|
||
this.worldX = temp.x;
|
||
this.worldY = temp.y;
|
||
|
||
return this;
|
||
},
|
||
|
||
/**
|
||
* Takes a Camera and returns a Vector2 containing the translated position of this Pointer
|
||
* within that Camera. This can be used to convert this Pointers position into camera space.
|
||
*
|
||
* @method Phaser.Input.Pointer#positionToCamera
|
||
* @since 3.0.0
|
||
*
|
||
* @param {Phaser.Cameras.Scene2D.Camera} camera - The Camera to use for the translation.
|
||
* @param {(Phaser.Math.Vector2|object)} [output] - A Vector2-like object in which to store the translated position.
|
||
*
|
||
* @return {(Phaser.Math.Vector2|object)} A Vector2 containing the translated coordinates of this Pointer, based on the given camera.
|
||
*/
|
||
positionToCamera: function (camera, output)
|
||
{
|
||
return camera.getWorldPoint(this.x, this.y, output);
|
||
},
|
||
|
||
/**
|
||
* Calculates the motion of this Pointer, including its velocity and angle of movement.
|
||
* This method is called automatically each frame by the Input Manager.
|
||
*
|
||
* @method Phaser.Input.Pointer#updateMotion
|
||
* @private
|
||
* @since 3.16.0
|
||
*/
|
||
updateMotion: function ()
|
||
{
|
||
var cx = this.position.x;
|
||
var cy = this.position.y;
|
||
|
||
var mx = this.midPoint.x;
|
||
var my = this.midPoint.y;
|
||
|
||
if (cx === mx && cy === my)
|
||
{
|
||
// Nothing to do here
|
||
return;
|
||
}
|
||
|
||
// Moving towards our goal ...
|
||
var vx = SmoothStepInterpolation(this.motionFactor, mx, cx);
|
||
var vy = SmoothStepInterpolation(this.motionFactor, my, cy);
|
||
|
||
if (FuzzyEqual(vx, cx, 0.1))
|
||
{
|
||
vx = cx;
|
||
}
|
||
|
||
if (FuzzyEqual(vy, cy, 0.1))
|
||
{
|
||
vy = cy;
|
||
}
|
||
|
||
this.midPoint.set(vx, vy);
|
||
|
||
var dx = cx - vx;
|
||
var dy = cy - vy;
|
||
|
||
this.velocity.set(dx, dy);
|
||
|
||
this.angle = Angle(vx, vy, cx, cy);
|
||
|
||
this.distance = Math.sqrt(dx * dx + dy * dy);
|
||
},
|
||
|
||
/**
|
||
* Internal method to handle a Mouse Up Event.
|
||
*
|
||
* @method Phaser.Input.Pointer#up
|
||
* @private
|
||
* @since 3.0.0
|
||
*
|
||
* @param {MouseEvent} event - The Mouse Event to process.
|
||
*/
|
||
up: function (event)
|
||
{
|
||
if ('buttons' in event)
|
||
{
|
||
this.buttons = event.buttons;
|
||
}
|
||
|
||
this.event = event;
|
||
|
||
this.button = event.button;
|
||
|
||
this.upElement = event.target;
|
||
|
||
// Sets the local x/y properties
|
||
this.manager.transformPointer(this, event.pageX, event.pageY, false);
|
||
|
||
// 0: Main button pressed, usually the left button or the un-initialized state
|
||
if (event.button === 0)
|
||
{
|
||
this.primaryDown = false;
|
||
this.upX = this.x;
|
||
this.upY = this.y;
|
||
}
|
||
|
||
if (this.buttons === 0)
|
||
{
|
||
// No more buttons are still down
|
||
this.isDown = false;
|
||
|
||
this.upTime = event.timeStamp;
|
||
|
||
this.wasTouch = false;
|
||
}
|
||
},
|
||
|
||
/**
|
||
* Internal method to handle a Mouse Down Event.
|
||
*
|
||
* @method Phaser.Input.Pointer#down
|
||
* @private
|
||
* @since 3.0.0
|
||
*
|
||
* @param {MouseEvent} event - The Mouse Event to process.
|
||
*/
|
||
down: function (event)
|
||
{
|
||
if ('buttons' in event)
|
||
{
|
||
this.buttons = event.buttons;
|
||
}
|
||
|
||
this.event = event;
|
||
|
||
this.button = event.button;
|
||
|
||
this.downElement = event.target;
|
||
|
||
// Sets the local x/y properties
|
||
this.manager.transformPointer(this, event.pageX, event.pageY, false);
|
||
|
||
// 0: Main button pressed, usually the left button or the un-initialized state
|
||
if (event.button === 0)
|
||
{
|
||
this.primaryDown = true;
|
||
this.downX = this.x;
|
||
this.downY = this.y;
|
||
}
|
||
|
||
if (OS.macOS && event.ctrlKey)
|
||
{
|
||
// Override button settings on macOS
|
||
this.buttons = 2;
|
||
this.primaryDown = false;
|
||
}
|
||
|
||
if (!this.isDown)
|
||
{
|
||
this.isDown = true;
|
||
|
||
this.downTime = event.timeStamp;
|
||
}
|
||
|
||
this.wasTouch = false;
|
||
},
|
||
|
||
/**
|
||
* Internal method to handle a Mouse Move Event.
|
||
*
|
||
* @method Phaser.Input.Pointer#move
|
||
* @private
|
||
* @since 3.0.0
|
||
*
|
||
* @param {MouseEvent} event - The Mouse Event to process.
|
||
*/
|
||
move: function (event)
|
||
{
|
||
if ('buttons' in event)
|
||
{
|
||
this.buttons = event.buttons;
|
||
}
|
||
|
||
this.event = event;
|
||
|
||
// Sets the local x/y properties
|
||
this.manager.transformPointer(this, event.pageX, event.pageY, true);
|
||
|
||
if (this.locked)
|
||
{
|
||
// Multiple DOM events may occur within one frame, but only one Phaser event will fire
|
||
this.movementX = event.movementX || event.mozMovementX || event.webkitMovementX || 0;
|
||
this.movementY = event.movementY || event.mozMovementY || event.webkitMovementY || 0;
|
||
}
|
||
|
||
this.moveTime = event.timeStamp;
|
||
|
||
this.wasTouch = false;
|
||
},
|
||
|
||
/**
|
||
* Internal method to handle a Mouse Wheel Event.
|
||
*
|
||
* @method Phaser.Input.Pointer#wheel
|
||
* @private
|
||
* @since 3.18.0
|
||
*
|
||
* @param {WheelEvent} event - The Wheel Event to process.
|
||
*/
|
||
wheel: function (event)
|
||
{
|
||
if ('buttons' in event)
|
||
{
|
||
this.buttons = event.buttons;
|
||
}
|
||
|
||
this.event = event;
|
||
|
||
// Sets the local x/y properties
|
||
this.manager.transformPointer(this, event.pageX, event.pageY, false);
|
||
|
||
this.deltaX = event.deltaX;
|
||
this.deltaY = event.deltaY;
|
||
this.deltaZ = event.deltaZ;
|
||
|
||
this.wasTouch = false;
|
||
},
|
||
|
||
/**
|
||
* Internal method to handle a Touch Start Event.
|
||
*
|
||
* @method Phaser.Input.Pointer#touchstart
|
||
* @private
|
||
* @since 3.0.0
|
||
*
|
||
* @param {Touch} touch - The Changed Touch from the Touch Event.
|
||
* @param {TouchEvent} event - The full Touch Event.
|
||
*/
|
||
touchstart: function (touch, event)
|
||
{
|
||
if (touch['pointerId'])
|
||
{
|
||
this.pointerId = touch.pointerId;
|
||
}
|
||
|
||
this.identifier = touch.identifier;
|
||
this.target = touch.target;
|
||
this.active = true;
|
||
|
||
this.buttons = 1;
|
||
|
||
this.event = event;
|
||
|
||
this.downElement = touch.target;
|
||
|
||
// Sets the local x/y properties
|
||
this.manager.transformPointer(this, touch.pageX, touch.pageY, false);
|
||
|
||
this.primaryDown = true;
|
||
this.downX = this.x;
|
||
this.downY = this.y;
|
||
this.downTime = event.timeStamp;
|
||
|
||
this.isDown = true;
|
||
|
||
this.wasTouch = true;
|
||
this.wasCanceled = false;
|
||
|
||
this.updateMotion();
|
||
},
|
||
|
||
/**
|
||
* Internal method to handle a Touch Move Event.
|
||
*
|
||
* @method Phaser.Input.Pointer#touchmove
|
||
* @private
|
||
* @since 3.0.0
|
||
*
|
||
* @param {Touch} touch - The Changed Touch from the Touch Event.
|
||
* @param {TouchEvent} event - The full Touch Event.
|
||
*/
|
||
touchmove: function (touch, event)
|
||
{
|
||
this.event = event;
|
||
|
||
// Sets the local x/y properties
|
||
this.manager.transformPointer(this, touch.pageX, touch.pageY, true);
|
||
|
||
this.moveTime = event.timeStamp;
|
||
|
||
this.wasTouch = true;
|
||
|
||
this.updateMotion();
|
||
},
|
||
|
||
/**
|
||
* Internal method to handle a Touch End Event.
|
||
*
|
||
* @method Phaser.Input.Pointer#touchend
|
||
* @private
|
||
* @since 3.0.0
|
||
*
|
||
* @param {Touch} touch - The Changed Touch from the Touch Event.
|
||
* @param {TouchEvent} event - The full Touch Event.
|
||
*/
|
||
touchend: function (touch, event)
|
||
{
|
||
this.buttons = 0;
|
||
|
||
this.event = event;
|
||
|
||
this.upElement = touch.target;
|
||
|
||
// Sets the local x/y properties
|
||
this.manager.transformPointer(this, touch.pageX, touch.pageY, false);
|
||
|
||
this.primaryDown = false;
|
||
this.upX = this.x;
|
||
this.upY = this.y;
|
||
this.upTime = event.timeStamp;
|
||
|
||
this.isDown = false;
|
||
|
||
this.wasTouch = true;
|
||
this.wasCanceled = false;
|
||
|
||
this.active = false;
|
||
|
||
this.updateMotion();
|
||
},
|
||
|
||
/**
|
||
* Internal method to handle a Touch Cancel Event.
|
||
*
|
||
* @method Phaser.Input.Pointer#touchcancel
|
||
* @private
|
||
* @since 3.15.0
|
||
*
|
||
* @param {Touch} touch - The Changed Touch from the Touch Event.
|
||
* @param {TouchEvent} event - The full Touch Event.
|
||
*/
|
||
touchcancel: function (touch, event)
|
||
{
|
||
this.buttons = 0;
|
||
|
||
this.event = event;
|
||
|
||
this.upElement = touch.target;
|
||
|
||
// Sets the local x/y properties
|
||
this.manager.transformPointer(this, touch.pageX, touch.pageY, false);
|
||
|
||
this.primaryDown = false;
|
||
this.upX = this.x;
|
||
this.upY = this.y;
|
||
this.upTime = event.timeStamp;
|
||
|
||
this.isDown = false;
|
||
|
||
this.wasTouch = true;
|
||
this.wasCanceled = true;
|
||
|
||
this.active = false;
|
||
},
|
||
|
||
/**
|
||
* Checks to see if any buttons are being held down on this Pointer.
|
||
*
|
||
* @method Phaser.Input.Pointer#noButtonDown
|
||
* @since 3.0.0
|
||
*
|
||
* @return {boolean} `true` if no buttons are being held down.
|
||
*/
|
||
noButtonDown: function ()
|
||
{
|
||
return (this.buttons === 0);
|
||
},
|
||
|
||
/**
|
||
* Checks to see if the left button is being held down on this Pointer.
|
||
*
|
||
* @method Phaser.Input.Pointer#leftButtonDown
|
||
* @since 3.0.0
|
||
*
|
||
* @return {boolean} `true` if the left button is being held down.
|
||
*/
|
||
leftButtonDown: function ()
|
||
{
|
||
return (this.buttons & 1) ? true : false;
|
||
},
|
||
|
||
/**
|
||
* Checks to see if the right button is being held down on this Pointer.
|
||
*
|
||
* @method Phaser.Input.Pointer#rightButtonDown
|
||
* @since 3.0.0
|
||
*
|
||
* @return {boolean} `true` if the right button is being held down.
|
||
*/
|
||
rightButtonDown: function ()
|
||
{
|
||
return (this.buttons & 2) ? true : false;
|
||
},
|
||
|
||
/**
|
||
* Checks to see if the middle button is being held down on this Pointer.
|
||
*
|
||
* @method Phaser.Input.Pointer#middleButtonDown
|
||
* @since 3.0.0
|
||
*
|
||
* @return {boolean} `true` if the middle button is being held down.
|
||
*/
|
||
middleButtonDown: function ()
|
||
{
|
||
return (this.buttons & 4) ? true : false;
|
||
},
|
||
|
||
/**
|
||
* Checks to see if the back button is being held down on this Pointer.
|
||
*
|
||
* @method Phaser.Input.Pointer#backButtonDown
|
||
* @since 3.0.0
|
||
*
|
||
* @return {boolean} `true` if the back button is being held down.
|
||
*/
|
||
backButtonDown: function ()
|
||
{
|
||
return (this.buttons & 8) ? true : false;
|
||
},
|
||
|
||
/**
|
||
* Checks to see if the forward button is being held down on this Pointer.
|
||
*
|
||
* @method Phaser.Input.Pointer#forwardButtonDown
|
||
* @since 3.0.0
|
||
*
|
||
* @return {boolean} `true` if the forward button is being held down.
|
||
*/
|
||
forwardButtonDown: function ()
|
||
{
|
||
return (this.buttons & 16) ? true : false;
|
||
},
|
||
|
||
/**
|
||
* Checks to see if the left button was just released on this Pointer.
|
||
*
|
||
* @method Phaser.Input.Pointer#leftButtonReleased
|
||
* @since 3.18.0
|
||
*
|
||
* @return {boolean} `true` if the left button was just released.
|
||
*/
|
||
leftButtonReleased: function ()
|
||
{
|
||
return (this.button === 0 && !this.isDown);
|
||
},
|
||
|
||
/**
|
||
* Checks to see if the right button was just released on this Pointer.
|
||
*
|
||
* @method Phaser.Input.Pointer#rightButtonReleased
|
||
* @since 3.18.0
|
||
*
|
||
* @return {boolean} `true` if the right button was just released.
|
||
*/
|
||
rightButtonReleased: function ()
|
||
{
|
||
return (this.button === 2 && !this.isDown);
|
||
},
|
||
|
||
/**
|
||
* Checks to see if the middle button was just released on this Pointer.
|
||
*
|
||
* @method Phaser.Input.Pointer#middleButtonReleased
|
||
* @since 3.18.0
|
||
*
|
||
* @return {boolean} `true` if the middle button was just released.
|
||
*/
|
||
middleButtonReleased: function ()
|
||
{
|
||
return (this.button === 1 && !this.isDown);
|
||
},
|
||
|
||
/**
|
||
* Checks to see if the back button was just released on this Pointer.
|
||
*
|
||
* @method Phaser.Input.Pointer#backButtonReleased
|
||
* @since 3.18.0
|
||
*
|
||
* @return {boolean} `true` if the back button was just released.
|
||
*/
|
||
backButtonReleased: function ()
|
||
{
|
||
return (this.button === 3 && !this.isDown);
|
||
},
|
||
|
||
/**
|
||
* Checks to see if the forward button was just released on this Pointer.
|
||
*
|
||
* @method Phaser.Input.Pointer#forwardButtonReleased
|
||
* @since 3.18.0
|
||
*
|
||
* @return {boolean} `true` if the forward button was just released.
|
||
*/
|
||
forwardButtonReleased: function ()
|
||
{
|
||
return (this.button === 4 && !this.isDown);
|
||
},
|
||
|
||
/**
|
||
* If the Pointer has a button pressed down at the time this method is called, it will return the
|
||
* distance between the Pointer's `downX` and `downY` values and the current position.
|
||
*
|
||
* If no button is held down, it will return the last recorded distance, based on where
|
||
* the Pointer was when the button was released.
|
||
*
|
||
* If you wish to get the distance being travelled currently, based on the velocity of the Pointer,
|
||
* then see the `Pointer.distance` property.
|
||
*
|
||
* @method Phaser.Input.Pointer#getDistance
|
||
* @since 3.13.0
|
||
*
|
||
* @return {number} The distance the Pointer moved.
|
||
*/
|
||
getDistance: function ()
|
||
{
|
||
if (this.isDown)
|
||
{
|
||
return Distance(this.downX, this.downY, this.x, this.y);
|
||
}
|
||
else
|
||
{
|
||
return Distance(this.downX, this.downY, this.upX, this.upY);
|
||
}
|
||
},
|
||
|
||
/**
|
||
* If the Pointer has a button pressed down at the time this method is called, it will return the
|
||
* horizontal distance between the Pointer's `downX` and `downY` values and the current position.
|
||
*
|
||
* If no button is held down, it will return the last recorded horizontal distance, based on where
|
||
* the Pointer was when the button was released.
|
||
*
|
||
* @method Phaser.Input.Pointer#getDistanceX
|
||
* @since 3.16.0
|
||
*
|
||
* @return {number} The horizontal distance the Pointer moved.
|
||
*/
|
||
getDistanceX: function ()
|
||
{
|
||
if (this.isDown)
|
||
{
|
||
return Math.abs(this.downX - this.x);
|
||
}
|
||
else
|
||
{
|
||
return Math.abs(this.downX - this.upX);
|
||
}
|
||
},
|
||
|
||
/**
|
||
* If the Pointer has a button pressed down at the time this method is called, it will return the
|
||
* vertical distance between the Pointer's `downX` and `downY` values and the current position.
|
||
*
|
||
* If no button is held down, it will return the last recorded vertical distance, based on where
|
||
* the Pointer was when the button was released.
|
||
*
|
||
* @method Phaser.Input.Pointer#getDistanceY
|
||
* @since 3.16.0
|
||
*
|
||
* @return {number} The vertical distance the Pointer moved.
|
||
*/
|
||
getDistanceY: function ()
|
||
{
|
||
if (this.isDown)
|
||
{
|
||
return Math.abs(this.downY - this.y);
|
||
}
|
||
else
|
||
{
|
||
return Math.abs(this.downY - this.upY);
|
||
}
|
||
},
|
||
|
||
/**
|
||
* If the Pointer has a button pressed down at the time this method is called, it will return the
|
||
* duration since the button was pressed down.
|
||
*
|
||
* If no button is held down, it will return the last recorded duration, based on the time
|
||
* the last button on the Pointer was released.
|
||
*
|
||
* @method Phaser.Input.Pointer#getDuration
|
||
* @since 3.16.0
|
||
*
|
||
* @return {number} The duration the Pointer was held down for in milliseconds.
|
||
*/
|
||
getDuration: function ()
|
||
{
|
||
if (this.isDown)
|
||
{
|
||
return (this.manager.time - this.downTime);
|
||
}
|
||
else
|
||
{
|
||
return (this.upTime - this.downTime);
|
||
}
|
||
},
|
||
|
||
/**
|
||
* If the Pointer has a button pressed down at the time this method is called, it will return the
|
||
* angle between the Pointer's `downX` and `downY` values and the current position.
|
||
*
|
||
* If no button is held down, it will return the last recorded angle, based on where
|
||
* the Pointer was when the button was released.
|
||
*
|
||
* The angle is based on the old position facing to the current position.
|
||
*
|
||
* If you wish to get the current angle, based on the velocity of the Pointer, then
|
||
* see the `Pointer.angle` property.
|
||
*
|
||
* @method Phaser.Input.Pointer#getAngle
|
||
* @since 3.16.0
|
||
*
|
||
* @return {number} The angle between the Pointer's coordinates in radians.
|
||
*/
|
||
getAngle: function ()
|
||
{
|
||
if (this.isDown)
|
||
{
|
||
return Angle(this.downX, this.downY, this.x, this.y);
|
||
}
|
||
else
|
||
{
|
||
return Angle(this.downX, this.downY, this.upX, this.upY);
|
||
}
|
||
},
|
||
|
||
/**
|
||
* Takes the previous and current Pointer positions and then generates an array of interpolated values between
|
||
* the two. The array will be populated up to the size of the `steps` argument.
|
||
*
|
||
* ```javaScript
|
||
* var points = pointer.getInterpolatedPosition(4);
|
||
*
|
||
* // points[0] = { x: 0, y: 0 }
|
||
* // points[1] = { x: 2, y: 1 }
|
||
* // points[2] = { x: 3, y: 2 }
|
||
* // points[3] = { x: 6, y: 3 }
|
||
* ```
|
||
*
|
||
* Use this if you need to get smoothed values between the previous and current pointer positions. DOM pointer
|
||
* events can often fire faster than the main browser loop, and this will help you avoid janky movement
|
||
* especially if you have an object following a Pointer.
|
||
*
|
||
* Note that if you provide an output array it will only be populated up to the number of steps provided.
|
||
* It will not clear any previous data that may have existed beyond the range of the steps count.
|
||
*
|
||
* Internally it uses the Smooth Step interpolation calculation.
|
||
*
|
||
* @method Phaser.Input.Pointer#getInterpolatedPosition
|
||
* @since 3.11.0
|
||
*
|
||
* @param {number} [steps=10] - The number of interpolation steps to use.
|
||
* @param {array} [out] - An array to store the results in. If not provided a new one will be created.
|
||
*
|
||
* @return {array} An array of interpolated values.
|
||
*/
|
||
getInterpolatedPosition: function (steps, out)
|
||
{
|
||
if (steps === undefined) { steps = 10; }
|
||
if (out === undefined) { out = []; }
|
||
|
||
var prevX = this.prevPosition.x;
|
||
var prevY = this.prevPosition.y;
|
||
|
||
var curX = this.position.x;
|
||
var curY = this.position.y;
|
||
|
||
for (var i = 0; i < steps; i++)
|
||
{
|
||
var t = (1 / steps) * i;
|
||
|
||
out[i] = { x: SmoothStepInterpolation(t, prevX, curX), y: SmoothStepInterpolation(t, prevY, curY) };
|
||
}
|
||
|
||
return out;
|
||
},
|
||
|
||
/**
|
||
* Fully reset this Pointer back to its unitialized state.
|
||
*
|
||
* @method Phaser.Input.Pointer#reset
|
||
* @since 3.60.0
|
||
*/
|
||
reset: function ()
|
||
{
|
||
this.event = null;
|
||
this.downElement = null;
|
||
this.upElement = null;
|
||
|
||
this.button = 0;
|
||
this.buttons = 0;
|
||
|
||
this.position.set(0, 0);
|
||
this.prevPosition.set(0, 0);
|
||
this.midPoint.set(-1, -1);
|
||
this.velocity.set(0, 0);
|
||
this.angle = 0;
|
||
this.distance = 0;
|
||
this.worldX = 0;
|
||
this.worldY = 0;
|
||
this.downX = 0;
|
||
this.downY = 0;
|
||
this.upX = 0;
|
||
this.upY = 0;
|
||
this.moveTime = 0;
|
||
this.upTime = 0;
|
||
this.downTime = 0;
|
||
this.primaryDown = false;
|
||
this.isDown = false;
|
||
this.wasTouch = false;
|
||
this.wasCanceled = false;
|
||
this.movementX = 0;
|
||
this.movementY = 0;
|
||
this.identifier = 0;
|
||
this.pointerId = null;
|
||
this.deltaX = 0;
|
||
this.deltaY = 0;
|
||
this.deltaZ = 0;
|
||
|
||
this.active = (this.id === 0) ? true : false;
|
||
},
|
||
|
||
/**
|
||
* Destroys this Pointer instance and resets its external references.
|
||
*
|
||
* @method Phaser.Input.Pointer#destroy
|
||
* @since 3.0.0
|
||
*/
|
||
destroy: function ()
|
||
{
|
||
this.camera = null;
|
||
this.manager = null;
|
||
this.position = null;
|
||
},
|
||
|
||
/**
|
||
* The x position of this Pointer.
|
||
* The value is in screen space.
|
||
* See `worldX` to get a camera converted position.
|
||
*
|
||
* @name Phaser.Input.Pointer#x
|
||
* @type {number}
|
||
* @since 3.0.0
|
||
*/
|
||
x: {
|
||
|
||
get: function ()
|
||
{
|
||
return this.position.x;
|
||
},
|
||
|
||
set: function (value)
|
||
{
|
||
this.position.x = value;
|
||
}
|
||
|
||
},
|
||
|
||
/**
|
||
* The y position of this Pointer.
|
||
* The value is in screen space.
|
||
* See `worldY` to get a camera converted position.
|
||
*
|
||
* @name Phaser.Input.Pointer#y
|
||
* @type {number}
|
||
* @since 3.0.0
|
||
*/
|
||
y: {
|
||
|
||
get: function ()
|
||
{
|
||
return this.position.y;
|
||
},
|
||
|
||
set: function (value)
|
||
{
|
||
this.position.y = value;
|
||
}
|
||
|
||
},
|
||
|
||
/**
|
||
* Time when this Pointer was most recently updated by a DOM Event.
|
||
* This comes directly from the `event.timeStamp` property.
|
||
* If no event has yet taken place, it will return zero.
|
||
*
|
||
* @name Phaser.Input.Pointer#time
|
||
* @type {number}
|
||
* @readonly
|
||
* @since 3.16.0
|
||
*/
|
||
time: {
|
||
|
||
get: function ()
|
||
{
|
||
return (this.event) ? this.event.timeStamp : 0;
|
||
}
|
||
|
||
}
|
||
|
||
});
|
||
|
||
module.exports = Pointer;
|