/** * @author Richard Davey * @copyright 2020 Photon Storm Ltd. * @license {@link https://opensource.org/licenses/MIT|MIT License} */ var MATH_CONST = require('../../math/const'); var TransformMatrix = require('./TransformMatrix'); var WrapAngle = require('../../math/angle/Wrap'); var WrapAngleDegrees = require('../../math/angle/WrapDegrees'); // global bitmask flag for GameObject.renderMask (used by Scale) var _FLAG = 4; // 0100 /** * Provides methods used for getting and setting the position, scale and rotation of a Game Object. * * @namespace Phaser.GameObjects.Components.Transform * @since 3.0.0 */ var Transform = { /** * Private internal value. Holds the horizontal scale value. * * @name Phaser.GameObjects.Components.Transform#_scaleX * @type {number} * @private * @default 1 * @since 3.0.0 */ _scaleX: 1, /** * Private internal value. Holds the vertical scale value. * * @name Phaser.GameObjects.Components.Transform#_scaleY * @type {number} * @private * @default 1 * @since 3.0.0 */ _scaleY: 1, /** * Private internal value. Holds the rotation value in radians. * * @name Phaser.GameObjects.Components.Transform#_rotation * @type {number} * @private * @default 0 * @since 3.0.0 */ _rotation: 0, /** * The x position of this Game Object. * * @name Phaser.GameObjects.Components.Transform#x * @type {number} * @default 0 * @since 3.0.0 */ x: 0, /** * The y position of this Game Object. * * @name Phaser.GameObjects.Components.Transform#y * @type {number} * @default 0 * @since 3.0.0 */ y: 0, /** * The z position of this Game Object. * * Note: The z position does not control the rendering order of 2D Game Objects. Use * {@link Phaser.GameObjects.Components.Depth#depth} instead. * * @name Phaser.GameObjects.Components.Transform#z * @type {number} * @default 0 * @since 3.0.0 */ z: 0, /** * The w position of this Game Object. * * @name Phaser.GameObjects.Components.Transform#w * @type {number} * @default 0 * @since 3.0.0 */ w: 0, /** * This is a special setter that allows you to set both the horizontal and vertical scale of this Game Object * to the same value, at the same time. When reading this value the result returned is `(scaleX + scaleY) / 2`. * * Use of this property implies you wish the horizontal and vertical scales to be equal to each other. If this * isn't the case, use the `scaleX` or `scaleY` properties instead. * * @name Phaser.GameObjects.Components.Transform#scale * @type {number} * @default 1 * @since 3.18.0 */ scale: { get: function () { return (this._scaleX + this._scaleY) / 2; }, set: function (value) { this._scaleX = value; this._scaleY = value; if (value === 0) { this.renderFlags &= ~_FLAG; } else { this.renderFlags |= _FLAG; } } }, /** * The horizontal scale of this Game Object. * * @name Phaser.GameObjects.Components.Transform#scaleX * @type {number} * @default 1 * @since 3.0.0 */ scaleX: { get: function () { return this._scaleX; }, set: function (value) { this._scaleX = value; if (value === 0) { this.renderFlags &= ~_FLAG; } else { this.renderFlags |= _FLAG; } } }, /** * The vertical scale of this Game Object. * * @name Phaser.GameObjects.Components.Transform#scaleY * @type {number} * @default 1 * @since 3.0.0 */ scaleY: { get: function () { return this._scaleY; }, set: function (value) { this._scaleY = value; if (value === 0) { this.renderFlags &= ~_FLAG; } else { this.renderFlags |= _FLAG; } } }, /** * The angle of this Game Object as expressed in degrees. * * Phaser uses a right-hand clockwise rotation system, where 0 is right, 90 is down, 180/-180 is left * and -90 is up. * * If you prefer to work in radians, see the `rotation` property instead. * * @name Phaser.GameObjects.Components.Transform#angle * @type {integer} * @default 0 * @since 3.0.0 */ angle: { get: function () { return WrapAngleDegrees(this._rotation * MATH_CONST.RAD_TO_DEG); }, set: function (value) { // value is in degrees this.rotation = WrapAngleDegrees(value) * MATH_CONST.DEG_TO_RAD; } }, /** * The angle of this Game Object in radians. * * Phaser uses a right-hand clockwise rotation system, where 0 is right, PI/2 is down, +-PI is left * and -PI/2 is up. * * If you prefer to work in degrees, see the `angle` property instead. * * @name Phaser.GameObjects.Components.Transform#rotation * @type {number} * @default 1 * @since 3.0.0 */ rotation: { get: function () { return this._rotation; }, set: function (value) { // value is in radians this._rotation = WrapAngle(value); } }, /** * Sets the position of this Game Object. * * @method Phaser.GameObjects.Components.Transform#setPosition * @since 3.0.0 * * @param {number} [x=0] - The x position of this Game Object. * @param {number} [y=x] - The y position of this Game Object. If not set it will use the `x` value. * @param {number} [z=0] - The z position of this Game Object. * @param {number} [w=0] - The w position of this Game Object. * * @return {this} This Game Object instance. */ setPosition: function (x, y, z, w) { if (x === undefined) { x = 0; } if (y === undefined) { y = x; } if (z === undefined) { z = 0; } if (w === undefined) { w = 0; } this.x = x; this.y = y; this.z = z; this.w = w; return this; }, /** * Sets the position of this Game Object to be a random position within the confines of * the given area. * * If no area is specified a random position between 0 x 0 and the game width x height is used instead. * * The position does not factor in the size of this Game Object, meaning that only the origin is * guaranteed to be within the area. * * @method Phaser.GameObjects.Components.Transform#setRandomPosition * @since 3.8.0 * * @param {number} [x=0] - The x position of the top-left of the random area. * @param {number} [y=0] - The y position of the top-left of the random area. * @param {number} [width] - The width of the random area. * @param {number} [height] - The height of the random area. * * @return {this} This Game Object instance. */ setRandomPosition: function (x, y, width, height) { if (x === undefined) { x = 0; } if (y === undefined) { y = 0; } if (width === undefined) { width = this.scene.sys.scale.width; } if (height === undefined) { height = this.scene.sys.scale.height; } this.x = x + (Math.random() * width); this.y = y + (Math.random() * height); return this; }, /** * Sets the rotation of this Game Object. * * @method Phaser.GameObjects.Components.Transform#setRotation * @since 3.0.0 * * @param {number} [radians=0] - The rotation of this Game Object, in radians. * * @return {this} This Game Object instance. */ setRotation: function (radians) { if (radians === undefined) { radians = 0; } this.rotation = radians; return this; }, /** * Sets the angle of this Game Object. * * @method Phaser.GameObjects.Components.Transform#setAngle * @since 3.0.0 * * @param {number} [degrees=0] - The rotation of this Game Object, in degrees. * * @return {this} This Game Object instance. */ setAngle: function (degrees) { if (degrees === undefined) { degrees = 0; } this.angle = degrees; return this; }, /** * Sets the scale of this Game Object. * * @method Phaser.GameObjects.Components.Transform#setScale * @since 3.0.0 * * @param {number} x - The horizontal scale of this Game Object. * @param {number} [y=x] - The vertical scale of this Game Object. If not set it will use the `x` value. * * @return {this} This Game Object instance. */ setScale: function (x, y) { if (x === undefined) { x = 1; } if (y === undefined) { y = x; } this.scaleX = x; this.scaleY = y; return this; }, /** * Sets the x position of this Game Object. * * @method Phaser.GameObjects.Components.Transform#setX * @since 3.0.0 * * @param {number} [value=0] - The x position of this Game Object. * * @return {this} This Game Object instance. */ setX: function (value) { if (value === undefined) { value = 0; } this.x = value; return this; }, /** * Sets the y position of this Game Object. * * @method Phaser.GameObjects.Components.Transform#setY * @since 3.0.0 * * @param {number} [value=0] - The y position of this Game Object. * * @return {this} This Game Object instance. */ setY: function (value) { if (value === undefined) { value = 0; } this.y = value; return this; }, /** * Sets the z position of this Game Object. * * Note: The z position does not control the rendering order of 2D Game Objects. Use * {@link Phaser.GameObjects.Components.Depth#setDepth} instead. * * @method Phaser.GameObjects.Components.Transform#setZ * @since 3.0.0 * * @param {number} [value=0] - The z position of this Game Object. * * @return {this} This Game Object instance. */ setZ: function (value) { if (value === undefined) { value = 0; } this.z = value; return this; }, /** * Sets the w position of this Game Object. * * @method Phaser.GameObjects.Components.Transform#setW * @since 3.0.0 * * @param {number} [value=0] - The w position of this Game Object. * * @return {this} This Game Object instance. */ setW: function (value) { if (value === undefined) { value = 0; } this.w = value; return this; }, /** * Gets the local transform matrix for this Game Object. * * @method Phaser.GameObjects.Components.Transform#getLocalTransformMatrix * @since 3.4.0 * * @param {Phaser.GameObjects.Components.TransformMatrix} [tempMatrix] - The matrix to populate with the values from this Game Object. * * @return {Phaser.GameObjects.Components.TransformMatrix} The populated Transform Matrix. */ getLocalTransformMatrix: function (tempMatrix) { if (tempMatrix === undefined) { tempMatrix = new TransformMatrix(); } return tempMatrix.applyITRS(this.x, this.y, this._rotation, this._scaleX, this._scaleY); }, /** * Gets the world transform matrix for this Game Object, factoring in any parent Containers. * * @method Phaser.GameObjects.Components.Transform#getWorldTransformMatrix * @since 3.4.0 * * @param {Phaser.GameObjects.Components.TransformMatrix} [tempMatrix] - The matrix to populate with the values from this Game Object. * @param {Phaser.GameObjects.Components.TransformMatrix} [parentMatrix] - A temporary matrix to hold parent values during the calculations. * * @return {Phaser.GameObjects.Components.TransformMatrix} The populated Transform Matrix. */ getWorldTransformMatrix: function (tempMatrix, parentMatrix) { if (tempMatrix === undefined) { tempMatrix = new TransformMatrix(); } if (parentMatrix === undefined) { parentMatrix = new TransformMatrix(); } var parent = this.parentContainer; if (!parent) { return this.getLocalTransformMatrix(tempMatrix); } tempMatrix.applyITRS(this.x, this.y, this._rotation, this._scaleX, this._scaleY); while (parent) { parentMatrix.applyITRS(parent.x, parent.y, parent._rotation, parent._scaleX, parent._scaleY); parentMatrix.multiply(tempMatrix, tempMatrix); parent = parent.parentContainer; } return tempMatrix; }, /** * Gets the sum total rotation of all of this Game Objects parent Containers. * * The returned value is in radians and will be zero if this Game Object has no parent container. * * @method Phaser.GameObjects.Components.Transform#getParentRotation * @since 3.18.0 * * @return {number} The sum total rotation, in radians, of all parent containers of this Game Object. */ getParentRotation: function () { var rotation = 0; var parent = this.parentContainer; while (parent) { rotation += parent.rotation; parent = parent.parentContainer; } return rotation; } }; module.exports = Transform;