phaser/src/physics/matter-js/PointerConstraint.js

383 lines
11 KiB
JavaScript
Raw Normal View History

2018-02-12 16:01:20 +00:00
/**
* @author Richard Davey <rich@photonstorm.com>
2020-01-15 12:07:09 +00:00
* @copyright 2020 Photon Storm Ltd.
2019-05-10 15:15:04 +00:00
* @license {@link https://opensource.org/licenses/MIT|MIT License}
2018-02-12 16:01:20 +00:00
*/
var Bounds = require('./lib/geometry/Bounds');
var Class = require('../../utils/Class');
var Composite = require('./lib/body/Composite');
var Constraint = require('./lib/constraint/Constraint');
var Detector = require('./lib/collision/Detector');
2019-01-18 13:41:43 +00:00
var Events = require('./events');
var InputEvents = require('../../input/events');
var Merge = require('../../utils/object/Merge');
var Sleeping = require('./lib/core/Sleeping');
var Vector2 = require('../../math/Vector2');
var Vertices = require('./lib/geometry/Vertices');
2018-02-12 13:14:38 +00:00
/**
* @classdesc
* A Pointer Constraint is a special type of constraint that allows you to click
* and drag bodies in a Matter World. It monitors the active Pointers in a Scene,
* and when one is pressed down it checks to see if that hit any part of any active
* body in the world. If it did, and the body has input enabled, it will begin to
* drag it until either released, or you stop it via the `stopDrag` method.
*
* You can adjust the stiffness, length and other properties of the constraint via
* the `options` object on creation.
2018-02-12 13:14:38 +00:00
*
* @class PointerConstraint
2018-10-10 09:49:13 +00:00
* @memberof Phaser.Physics.Matter
2018-02-12 13:14:38 +00:00
* @constructor
* @since 3.0.0
*
* @param {Phaser.Scene} scene - A reference to the Scene to which this Pointer Constraint belongs.
* @param {Phaser.Physics.Matter.World} world - A reference to the Matter World instance to which this Constraint belongs.
* @param {object} [options] - A Constraint configuration object.
2018-02-12 13:14:38 +00:00
*/
var PointerConstraint = new Class({
initialize:
function PointerConstraint (scene, world, options)
{
if (options === undefined) { options = {}; }
// Defaults
var defaults = {
label: 'Pointer Constraint',
pointA: { x: 0, y: 0 },
pointB: { x: 0, y: 0 },
length: 0.01,
stiffness: 0.1,
angularStiffness: 1,
collisionFilter: {
category: 0x0001,
mask: 0xFFFFFFFF,
group: 0
}
};
2018-02-12 13:14:38 +00:00
/**
* A reference to the Scene to which this Pointer Constraint belongs.
* This is the same Scene as the Matter World instance.
2018-02-12 13:14:38 +00:00
*
* @name Phaser.Physics.Matter.PointerConstraint#scene
* @type {Phaser.Scene}
* @since 3.0.0
*/
this.scene = scene;
2018-02-12 13:14:38 +00:00
/**
* A reference to the Matter World instance to which this Constraint belongs.
2018-02-12 13:14:38 +00:00
*
* @name Phaser.Physics.Matter.PointerConstraint#world
* @type {Phaser.Physics.Matter.World}
* @since 3.0.0
*/
this.world = world;
2018-02-12 13:14:38 +00:00
/**
* The Camera the Pointer was interacting with when the input
* down event was processed.
2018-02-12 13:14:38 +00:00
*
* @name Phaser.Physics.Matter.PointerConstraint#camera
* @type {Phaser.Cameras.Scene2D.Camera}
* @since 3.0.0
*/
this.camera = null;
2018-02-12 13:14:38 +00:00
/**
* A reference to the Input Pointer that activated this Constraint.
* This is set in the `onDown` handler.
2018-02-12 13:14:38 +00:00
*
* @name Phaser.Physics.Matter.PointerConstraint#pointer
* @type {Phaser.Input.Pointer}
* @default null
* @since 3.0.0
*/
this.pointer = null;
2018-02-12 13:14:38 +00:00
/**
* Is this Constraint active or not?
*
* An active constraint will be processed each update. An inactive one will be skipped.
* Use this to toggle a Pointer Constraint on and off.
2018-02-12 13:14:38 +00:00
*
* @name Phaser.Physics.Matter.PointerConstraint#active
* @type {boolean}
* @default true
* @since 3.0.0
*/
this.active = true;
2018-02-12 13:14:38 +00:00
/**
* The internal transformed position.
2018-02-12 13:14:38 +00:00
*
* @name Phaser.Physics.Matter.PointerConstraint#position
* @type {Phaser.Math.Vector2}
* @since 3.0.0
*/
this.position = new Vector2();
2018-02-12 13:14:38 +00:00
/**
* The body that is currently being dragged, if any.
*
* @name Phaser.Physics.Matter.PointerConstraint#body
2020-01-14 17:11:07 +00:00
* @type {?MatterJS.BodyType}
* @since 3.16.2
*/
this.body = null;
/**
* The part of the body that was clicked on to start the drag.
*
* @name Phaser.Physics.Matter.PointerConstraint#part
2020-01-14 17:11:07 +00:00
* @type {?MatterJS.BodyType}
* @since 3.16.2
*/
this.part = null;
/**
* The native Matter Constraint that is used to attach to bodies.
2018-02-12 13:14:38 +00:00
*
* @name Phaser.Physics.Matter.PointerConstraint#constraint
2020-01-14 17:11:07 +00:00
* @type {MatterJS.ConstraintType}
2018-02-12 13:14:38 +00:00
* @since 3.0.0
*/
this.constraint = Constraint.create(Merge(options, defaults));
2019-01-18 13:41:43 +00:00
this.world.on(Events.BEFORE_UPDATE, this.update, this);
2019-01-18 13:41:43 +00:00
scene.sys.input.on(InputEvents.POINTER_DOWN, this.onDown, this);
scene.sys.input.on(InputEvents.POINTER_UP, this.onUp, this);
},
2018-02-12 13:14:38 +00:00
/**
* A Pointer has been pressed down onto the Scene.
*
2019-12-17 13:05:37 +00:00
* If this Constraint doesn't have an active Pointer then a hit test is set to
* run against all active bodies in the world during the _next_ call to `update`.
* If a body is found, it is bound to this constraint and the drag begins.
2018-02-12 13:14:38 +00:00
*
* @method Phaser.Physics.Matter.PointerConstraint#onDown
* @since 3.0.0
*
* @param {Phaser.Input.Pointer} pointer - A reference to the Pointer that was pressed.
2018-02-12 13:14:38 +00:00
*/
onDown: function (pointer)
{
if (!this.pointer)
{
this.pointer = pointer;
this.camera = pointer.camera;
}
},
2019-12-17 13:05:37 +00:00
/**
* A Pointer has been released from the Scene. If it was the one this constraint was using, it's cleared.
*
* @method Phaser.Physics.Matter.PointerConstraint#onUp
* @since 3.22.0
*
* @param {Phaser.Input.Pointer} pointer - A reference to the Pointer that was pressed.
*/
onUp: function (pointer)
{
2019-12-17 13:05:37 +00:00
if (pointer === this.pointer)
{
this.pointer = null;
}
},
2018-02-12 13:14:38 +00:00
/**
* Scans all active bodies in the current Matter World to see if any of them
* are hit by the Pointer. The _first one_ found to hit is set as the active contraint
* body.
2018-02-12 13:14:38 +00:00
*
* @method Phaser.Physics.Matter.PointerConstraint#getBody
2019-12-17 13:05:37 +00:00
* @fires Phaser.Physics.Matter.Events#DRAG_START
* @since 3.16.2
*
* @return {boolean} `true` if a body was found and set, otherwise `false`.
2018-02-12 13:14:38 +00:00
*/
getBody: function (pointer)
{
var pos = this.position;
var constraint = this.constraint;
2019-12-17 13:05:37 +00:00
this.camera.getWorldPoint(pointer.x, pointer.y, pos);
var bodies = Composite.allBodies(this.world.localWorld);
for (var i = 0; i < bodies.length; i++)
{
var body = bodies[i];
if (!body.ignorePointer &&
Bounds.contains(body.bounds, pos) &&
Detector.canCollide(body.collisionFilter, constraint.collisionFilter))
{
if (this.hitTestBody(body, pos))
{
this.world.emit(Events.DRAG_START, body, this.part, this);
return true;
}
}
}
return false;
},
2018-02-12 13:14:38 +00:00
/**
* Scans the current body to determine if a part of it was clicked on.
* If a part is found the body is set as the `constraint.bodyB` property,
* as well as the `body` property of this class. The part is also set.
2018-02-12 13:14:38 +00:00
*
* @method Phaser.Physics.Matter.PointerConstraint#hitTestBody
* @since 3.16.2
2018-02-12 13:14:38 +00:00
*
2020-01-14 17:11:07 +00:00
* @param {MatterJS.BodyType} body - The Matter Body to check.
* @param {Phaser.Math.Vector2} position - A translated hit test position.
2018-02-12 13:14:38 +00:00
*
* @return {boolean} `true` if a part of the body was hit, otherwise `false`.
2018-02-12 13:14:38 +00:00
*/
hitTestBody: function (body, position)
{
var constraint = this.constraint;
var partsLength = body.parts.length;
var start = (partsLength > 1) ? 1 : 0;
for (var i = start; i < partsLength; i++)
{
var part = body.parts[i];
if (Vertices.contains(part.vertices, position))
{
2019-12-17 13:05:37 +00:00
constraint.pointA = position;
constraint.pointB = { x: position.x - body.position.x, y: position.y - body.position.y };
2019-12-17 13:05:37 +00:00
constraint.bodyB = body;
constraint.angleB = body.angle;
Sleeping.set(body, false);
this.part = part;
this.body = body;
return true;
}
}
2018-03-19 00:10:32 +00:00
return false;
},
2018-02-12 13:14:38 +00:00
/**
* Internal update handler. Called in the Matter BEFORE_UPDATE step.
2018-02-12 13:14:38 +00:00
*
* @method Phaser.Physics.Matter.PointerConstraint#update
* @fires Phaser.Physics.Matter.Events#DRAG
2018-02-12 13:14:38 +00:00
* @since 3.0.0
*/
update: function ()
{
var pointer = this.pointer;
var body = this.body;
if (!this.active || !pointer)
{
if (body)
{
this.stopDrag();
}
return;
}
if (!pointer.isDown && body)
{
this.stopDrag();
return;
}
else if (pointer.isDown)
{
if (!body && !this.getBody(pointer))
{
return;
}
body = this.body;
var pos = this.position;
var constraint = this.constraint;
this.camera.getWorldPoint(pointer.x, pointer.y, pos);
// Drag update
2019-12-16 17:12:12 +00:00
constraint.pointA.x = pos.x;
constraint.pointA.y = pos.y;
Sleeping.set(body, false);
this.world.emit(Events.DRAG, body, this);
}
},
/**
* Stops the Pointer Constraint from dragging the body any further.
*
* This is called automatically if the Pointer is released while actively
* dragging a body. Or, you can call it manually to release a body from a
* constraint without having to first release the pointer.
*
* @method Phaser.Physics.Matter.PointerConstraint#stopDrag
* @fires Phaser.Physics.Matter.Events#DRAG_END
* @since 3.16.2
*/
stopDrag: function ()
{
var body = this.body;
var constraint = this.constraint;
constraint.bodyB = null;
constraint.pointB = null;
this.pointer = null;
this.body = null;
this.part = null;
if (body)
{
this.world.emit(Events.DRAG_END, body, this);
}
},
2018-02-12 13:14:38 +00:00
/**
* Destroys this Pointer Constraint instance and all of its references.
2018-02-12 13:14:38 +00:00
*
* @method Phaser.Physics.Matter.PointerConstraint#destroy
* @since 3.0.0
*/
destroy: function ()
{
2018-02-12 13:36:55 +00:00
this.world.removeConstraint(this.constraint);
this.pointer = null;
this.constraint = null;
this.body = null;
this.part = null;
2019-01-18 13:41:43 +00:00
this.world.off(Events.BEFORE_UPDATE, this.update);
2019-01-18 13:41:43 +00:00
this.scene.sys.input.off(InputEvents.POINTER_DOWN, this.onDown, this);
2019-12-17 13:05:37 +00:00
this.scene.sys.input.off(InputEvents.POINTER_UP, this.onUp, this);
}
});
module.exports = PointerConstraint;