phaser
Version:
A fast, free and fun HTML5 Game Framework for Desktop and Mobile web browsers from the team at Phaser Studio Inc.
628 lines (540 loc) • 15.8 kB
JavaScript
/**
* @author Richard Davey <rich@phaser.io>
* @copyright 2013-2026 Phaser Studio Inc.
* @license {@link https://opensource.org/licenses/MIT|MIT License}
*/
// Based on the three.js Curve classes created by [zz85](http://www.lab4games.net/zz85/blog)
var Class = require('../utils/Class');
var Curve = require('./Curve');
var DegToRad = require('../math/DegToRad');
var GetValue = require('../utils/object/GetValue');
var RadToDeg = require('../math/RadToDeg');
var Vector2 = require('../math/Vector2');
/**
* @classdesc
* An Ellipse Curve is a smooth curve that describes the path of an ellipse. It can be used
* to move Game Objects along an elliptical path, generate points distributed around an ellipse,
* or draw elliptical arcs as part of a Path or Graphics object.
*
* You can control the center position, horizontal and vertical radii, start and end angles,
* rotation, and whether the curve runs clockwise or anti-clockwise. Passing only `xRadius`
* will create a circle (both radii are equal by default).
*
* This curve extends the base `Phaser.Curves.Curve` class and can be used anywhere a Curve
* is accepted in Phaser, such as `Phaser.Curves.Path` or a `PathFollower` Game Object.
*
* See https://en.wikipedia.org/wiki/Ellipse for more details.
*
* @class Ellipse
* @extends Phaser.Curves.Curve
* @memberof Phaser.Curves
* @constructor
* @since 3.0.0
*
* @param {(number|Phaser.Types.Curves.EllipseCurveConfig)} [x=0] - The x coordinate of the ellipse, or an Ellipse Curve configuration object.
* @param {number} [y=0] - The y coordinate of the ellipse.
* @param {number} [xRadius=0] - The horizontal radius of ellipse.
* @param {number} [yRadius=0] - The vertical radius of ellipse.
* @param {number} [startAngle=0] - The start angle of the ellipse, in degrees.
* @param {number} [endAngle=360] - The end angle of the ellipse, in degrees.
* @param {boolean} [clockwise=false] - Whether the ellipse angles are given as clockwise (`true`) or counter-clockwise (`false`).
* @param {number} [rotation=0] - The rotation of the ellipse, in degrees.
*/
var EllipseCurve = new Class({
Extends: Curve,
initialize:
function EllipseCurve (x, y, xRadius, yRadius, startAngle, endAngle, clockwise, rotation)
{
if (typeof x === 'object')
{
var config = x;
x = GetValue(config, 'x', 0);
y = GetValue(config, 'y', 0);
xRadius = GetValue(config, 'xRadius', 0);
yRadius = GetValue(config, 'yRadius', xRadius);
startAngle = GetValue(config, 'startAngle', 0);
endAngle = GetValue(config, 'endAngle', 360);
clockwise = GetValue(config, 'clockwise', false);
rotation = GetValue(config, 'rotation', 0);
}
else
{
if (yRadius === undefined) { yRadius = xRadius; }
if (startAngle === undefined) { startAngle = 0; }
if (endAngle === undefined) { endAngle = 360; }
if (clockwise === undefined) { clockwise = false; }
if (rotation === undefined) { rotation = 0; }
}
Curve.call(this, 'EllipseCurve');
// Center point
/**
* The center point of the ellipse. Used for calculating rotation.
*
* @name Phaser.Curves.Ellipse#p0
* @type {Phaser.Math.Vector2}
* @since 3.0.0
*/
this.p0 = new Vector2(x, y);
/**
* The horizontal radius of the ellipse.
*
* @name Phaser.Curves.Ellipse#_xRadius
* @type {number}
* @private
* @since 3.0.0
*/
this._xRadius = xRadius;
/**
* The vertical radius of the ellipse.
*
* @name Phaser.Curves.Ellipse#_yRadius
* @type {number}
* @private
* @since 3.0.0
*/
this._yRadius = yRadius;
// Radians
/**
* The starting angle of the ellipse in radians.
*
* @name Phaser.Curves.Ellipse#_startAngle
* @type {number}
* @private
* @since 3.0.0
*/
this._startAngle = DegToRad(startAngle);
/**
* The end angle of the ellipse in radians.
*
* @name Phaser.Curves.Ellipse#_endAngle
* @type {number}
* @private
* @since 3.0.0
*/
this._endAngle = DegToRad(endAngle);
/**
* Whether the ellipse arc is drawn clockwise (`true`) or anti-clockwise (`false`).
*
* @name Phaser.Curves.Ellipse#_clockwise
* @type {boolean}
* @private
* @since 3.0.0
*/
this._clockwise = clockwise;
/**
* The rotation of the ellipse arc, in radians.
*
* @name Phaser.Curves.Ellipse#_rotation
* @type {number}
* @private
* @since 3.0.0
*/
this._rotation = DegToRad(rotation);
},
/**
* Gets the starting point on the curve.
*
* @method Phaser.Curves.Ellipse#getStartPoint
* @since 3.0.0
*
* @generic {Phaser.Math.Vector2} O - [out,$return]
*
* @param {Phaser.Math.Vector2} [out] - A Vector2 object to store the result in. If not given will be created.
*
* @return {Phaser.Math.Vector2} The coordinates of the point on the curve. If an `out` object was given this will be returned.
*/
getStartPoint: function (out)
{
if (out === undefined) { out = new Vector2(); }
return this.getPoint(0, out);
},
/**
* Returns the resolution of this curve, which is the number of points used to approximate it. For an Ellipse, this is double the requested divisions to provide accurate arc length calculations.
*
* @method Phaser.Curves.Ellipse#getResolution
* @since 3.0.0
*
* @param {number} divisions - Optional divisions value.
*
* @return {number} The curve resolution.
*/
getResolution: function (divisions)
{
return divisions * 2;
},
/**
* Returns the point on this curve at the given normalized position `t`, where 0 is the start and 1 is the end. The result accounts for the start angle, end angle, clockwise direction, and rotation of the ellipse.
*
* @method Phaser.Curves.Ellipse#getPoint
* @since 3.0.0
*
* @generic {Phaser.Math.Vector2} O - [out,$return]
*
* @param {number} t - The position along the curve to return. Where 0 is the start and 1 is the end.
* @param {Phaser.Math.Vector2} [out] - A Vector2 object to store the result in. If not given will be created.
*
* @return {Phaser.Math.Vector2} The coordinates of the point on the curve. If an `out` object was given this will be returned.
*/
getPoint: function (t, out)
{
if (out === undefined) { out = new Vector2(); }
var twoPi = Math.PI * 2;
var deltaAngle = this._endAngle - this._startAngle;
var samePoints = Math.abs(deltaAngle) < Number.EPSILON;
// ensures that deltaAngle is 0 .. 2 PI
while (deltaAngle < 0)
{
deltaAngle += twoPi;
}
while (deltaAngle > twoPi)
{
deltaAngle -= twoPi;
}
if (deltaAngle < Number.EPSILON)
{
if (samePoints)
{
deltaAngle = 0;
}
else
{
deltaAngle = twoPi;
}
}
if (this._clockwise && !samePoints)
{
if (deltaAngle === twoPi)
{
deltaAngle = - twoPi;
}
else
{
deltaAngle = deltaAngle - twoPi;
}
}
var angle = this._startAngle + t * deltaAngle;
var x = this.p0.x + this._xRadius * Math.cos(angle);
var y = this.p0.y + this._yRadius * Math.sin(angle);
if (this._rotation !== 0)
{
var cos = Math.cos(this._rotation);
var sin = Math.sin(this._rotation);
var tx = x - this.p0.x;
var ty = y - this.p0.y;
// Rotate the point about the center of the ellipse.
x = tx * cos - ty * sin + this.p0.x;
y = tx * sin + ty * cos + this.p0.y;
}
return out.set(x, y);
},
/**
* Sets the horizontal radius of this curve.
*
* @method Phaser.Curves.Ellipse#setXRadius
* @since 3.0.0
*
* @param {number} value - The horizontal radius of this curve.
*
* @return {this} This curve object.
*/
setXRadius: function (value)
{
this.xRadius = value;
return this;
},
/**
* Sets the vertical radius of this curve.
*
* @method Phaser.Curves.Ellipse#setYRadius
* @since 3.0.0
*
* @param {number} value - The vertical radius of this curve.
*
* @return {this} This curve object.
*/
setYRadius: function (value)
{
this.yRadius = value;
return this;
},
/**
* Sets the width of this curve. The horizontal radius (`xRadius`) is set to half the given value.
*
* @method Phaser.Curves.Ellipse#setWidth
* @since 3.0.0
*
* @param {number} value - The width of this curve.
*
* @return {this} This curve object.
*/
setWidth: function (value)
{
this.xRadius = value / 2;
return this;
},
/**
* Sets the height of this curve. The vertical radius (`yRadius`) is set to half the given value.
*
* @method Phaser.Curves.Ellipse#setHeight
* @since 3.0.0
*
* @param {number} value - The height of this curve.
*
* @return {this} This curve object.
*/
setHeight: function (value)
{
this.yRadius = value / 2;
return this;
},
/**
* Sets the start angle of this curve.
*
* @method Phaser.Curves.Ellipse#setStartAngle
* @since 3.0.0
*
* @param {number} value - The start angle of this curve, in degrees.
*
* @return {this} This curve object.
*/
setStartAngle: function (value)
{
this.startAngle = value;
return this;
},
/**
* Sets the end angle of this curve.
*
* @method Phaser.Curves.Ellipse#setEndAngle
* @since 3.0.0
*
* @param {number} value - The end angle of this curve, in degrees.
*
* @return {this} This curve object.
*/
setEndAngle: function (value)
{
this.endAngle = value;
return this;
},
/**
* Sets if this curve extends clockwise or anti-clockwise.
*
* @method Phaser.Curves.Ellipse#setClockwise
* @since 3.0.0
*
* @param {boolean} value - The clockwise state of this curve.
*
* @return {this} This curve object.
*/
setClockwise: function (value)
{
this.clockwise = value;
return this;
},
/**
* Sets the rotation of this curve.
*
* @method Phaser.Curves.Ellipse#setRotation
* @since 3.0.0
*
* @param {number} value - The rotation of this curve, in radians.
*
* @return {this} This curve object.
*/
setRotation: function (value)
{
this.rotation = value;
return this;
},
/**
* The x coordinate of the center of the ellipse.
*
* @name Phaser.Curves.Ellipse#x
* @type {number}
* @since 3.0.0
*/
x: {
get: function ()
{
return this.p0.x;
},
set: function (value)
{
this.p0.x = value;
}
},
/**
* The y coordinate of the center of the ellipse.
*
* @name Phaser.Curves.Ellipse#y
* @type {number}
* @since 3.0.0
*/
y: {
get: function ()
{
return this.p0.y;
},
set: function (value)
{
this.p0.y = value;
}
},
/**
* The horizontal radius of the ellipse.
*
* @name Phaser.Curves.Ellipse#xRadius
* @type {number}
* @since 3.0.0
*/
xRadius: {
get: function ()
{
return this._xRadius;
},
set: function (value)
{
this._xRadius = value;
}
},
/**
* The vertical radius of the ellipse.
*
* @name Phaser.Curves.Ellipse#yRadius
* @type {number}
* @since 3.0.0
*/
yRadius: {
get: function ()
{
return this._yRadius;
},
set: function (value)
{
this._yRadius = value;
}
},
/**
* The start angle of the ellipse in degrees.
*
* @name Phaser.Curves.Ellipse#startAngle
* @type {number}
* @since 3.0.0
*/
startAngle: {
get: function ()
{
return RadToDeg(this._startAngle);
},
set: function (value)
{
this._startAngle = DegToRad(value);
}
},
/**
* The end angle of the ellipse in degrees.
*
* @name Phaser.Curves.Ellipse#endAngle
* @type {number}
* @since 3.0.0
*/
endAngle: {
get: function ()
{
return RadToDeg(this._endAngle);
},
set: function (value)
{
this._endAngle = DegToRad(value);
}
},
/**
* `true` if the ellipse rotation is clockwise or `false` if anti-clockwise.
*
* @name Phaser.Curves.Ellipse#clockwise
* @type {boolean}
* @since 3.0.0
*/
clockwise: {
get: function ()
{
return this._clockwise;
},
set: function (value)
{
this._clockwise = value;
}
},
/**
* The rotation of the ellipse, relative to the center, in degrees.
*
* @name Phaser.Curves.Ellipse#angle
* @type {number}
* @since 3.14.0
*/
angle: {
get: function ()
{
return RadToDeg(this._rotation);
},
set: function (value)
{
this._rotation = DegToRad(value);
}
},
/**
* The rotation of the ellipse, relative to the center, in radians.
*
* @name Phaser.Curves.Ellipse#rotation
* @type {number}
* @since 3.0.0
*/
rotation: {
get: function ()
{
return this._rotation;
},
set: function (value)
{
this._rotation = value;
}
},
/**
* JSON serialization of the curve.
*
* @method Phaser.Curves.Ellipse#toJSON
* @since 3.0.0
*
* @return {Phaser.Types.Curves.JSONEllipseCurve} The JSON object containing this curve data.
*/
toJSON: function ()
{
return {
type: this.type,
x: this.p0.x,
y: this.p0.y,
xRadius: this._xRadius,
yRadius: this._yRadius,
startAngle: RadToDeg(this._startAngle),
endAngle: RadToDeg(this._endAngle),
clockwise: this._clockwise,
rotation: RadToDeg(this._rotation)
};
}
});
/**
* Creates a curve from the provided Ellipse Curve Configuration object.
*
* @function Phaser.Curves.Ellipse.fromJSON
* @since 3.0.0
*
* @param {Phaser.Types.Curves.JSONEllipseCurve} data - The JSON object containing this curve data.
*
* @return {Phaser.Curves.Ellipse} The ellipse curve constructed from the configuration object.
*/
EllipseCurve.fromJSON = function (data)
{
return new EllipseCurve(data);
};
module.exports = EllipseCurve;