2
0
Fork 0
mirror of https://github.com/photonstorm/phaser synced 2024-12-28 14:03:40 +00:00
phaser/wip/hermite/Hermite.js
2018-01-09 22:12:16 +00:00

366 lines
9.7 KiB
JavaScript

var Point = require('../../geom/Point');
var Class = require('../../utils/Class');
/**
* A data representation of a Hermite Curve (see http://en.wikipedia.org/wiki/Cubic_Hermite_spline)
*
* A Hermite curve has a start and end point and tangent vectors for both of them.
* The curve will always pass through the two control points and the shape of it is controlled
* by the length and direction of the tangent vectors. At the control points the curve will
* be facing exactly in the vector direction.
*
* As these curves change speed (speed = distance between points separated by an equal change in
* 't' value - see Hermite.getPoint) this class attempts to reduce the variation by pre-calculating
* the `accuracy` number of points on the curve. The straight-line distances to these points are stored
* in the private 'points' array, and this information is used by Hermite.findT() to convert a pixel
* distance along the curve into a 'time' value.
*
* Higher `accuracy` values will result in more even movement, but require more memory for the points
* list. 5 works, but 10 seems to be an ideal value for the length of curves found in most games on
* a desktop screen. If you use very long curves (more than 400 pixels) you may need to increase
* this value further.
*
* @param {number} p1x - The x coordinate of the start of the curve.
* @param {number} p1y - The y coordinate of the start of the curve.
* @param {number} p2x - The x coordinate of the end of the curve.
* @param {number} p2y - The y coordinate of the end of the curve.
* @param {number} v1x - The x component of the tangent vector for the start of the curve.
* @param {number} v1y - The y component of the tangent vector for the start of the curve.
* @param {number} v2x - The x component of the tangent vector for the end of the curve.
* @param {number} v2y - The y component of the tangent vector for the end of the curve.
* @param {number} [accuracy=10] The amount of points to pre-calculate on the curve.
*/
var Hermite = new Class({
initialize:
function Hermite (p1x, p1y, p2x, p2y, v1x, v1y, v2x, v2y, accuracy)
{
if (accuracy === undefined) { accuracy = 10; }
/**
* @property {number} _accuracy - The amount of points to pre-calculate on the curve.
* @private
*/
this._accuracy = accuracy;
/**
* @property {number} _p1x - The x coordinate of the start of the curve.
* @private
*/
this._p1x = p1x;
/**
* @property {number} _p1y - The y coordinate of the start of the curve.
* @private
*/
this._p1y = p1y;
/**
* @property {number} _p2x - The x coordinate of the end of the curve.
* @private
*/
this._p2x = p2x;
/**
* @property {number} _p2y - The y coordinate of the end of the curve.
* @private
*/
this._p2y = p2y;
/**
* @property {number} _v1x - The x component of the tangent vector for the start of the curve.
* @private
*/
this._v1x = v1x;
/**
* @property {number} _v1y - The y component of the tangent vector for the start of the curve.
* @private
*/
this._v1y = v1y;
/**
* @property {number} _v2x - The x component of the tangent vector for the end of the curve.
* @private
*/
this._v2x = v2x;
/**
* @property {number} _v2y - The y component of the tangent vector for the end of the curve.
* @private
*/
this._v2y = v2y;
/**
* @property {array} _points - A local array of cached points.
* @private
*/
this._points = [];
/**
* @property {Phaser.Point} _temp1 - A local cached Point object.
* @private
*/
this._temp1 = new Point();
/**
* @property {Phaser.Point} _temp2 - A local cached Point object.
* @private
*/
this._temp2 = new Point();
this.recalculate();
},
/**
* Performs the curve calculations.
*
* This is called automatically if you change any of the curves public properties, such as `Hermite.p1x` or `Hermite.v2y`.
*
* If you adjust any of the internal private values, then call this to update the points.
*
* @method Phaser.Hermite#recalculate
* @return {Phaser.Hermite} This object.
*/
recalculate: function ()
{
this._ax = (2 * this._p1x - 2 * this._p2x + this._v1x + this._v2x);
this._ay = (2 * this._p1y - 2 * this._p2y + this._v1y + this._v2y);
this._bx = (-3 * this._p1x + 3 * this._p2x - 2 * this._v1x - this._v2x);
this._by = (-3 * this._p1y + 3 * this._p2y - 2 * this._v1y - this._v2y);
this.length = this.calculateEvenPoints();
return this;
},
/**
* Calculate a number of points along the curve, based on `Hermite.accuracy`, and stores them in the private `_points` array.
*
* @method Phaser.Hermite#calculateEvenPoints
* @return {number} The total length of the curve approximated as straight line distances between the points.
*/
calculateEvenPoints: function ()
{
var totalLength = 0;
this._temp1.setTo(0, 0); // pnt
this._temp2.setTo(this._p1x, this._p1y); // lastPnt
this._points[0] = 0;
for (var i = 1; i <= this._accuracy; i++)
{
this.getPoint(i / this._accuracy, this._temp1);
totalLength += this._temp1.distance(this._temp2);
this._points[i] = totalLength;
this._temp2.copyFrom(this._temp1);
}
return totalLength;
},
/**
* @name Phaser.Hermite#accuracy
* @property {number} accuracy - The amount of points to pre-calculate on the curve.
*/
accuracy: {
get: function ()
{
return this._accuracy;
},
set: function (value)
{
if (value !== this._accuracy)
{
this._accuracy = value;
this.recalculate();
}
}
},
/**
* @name Phaser.Hermite#p1x
* @property {number} p1x - The x coordinate of the start of the curve. Setting this value will recalculate the curve.
*/
p1x: {
get: function ()
{
return this._p1x;
},
set: function (value)
{
if (value !== this._p1x)
{
this._p1x = value;
this.recalculate();
}
}
},
/**
* @name Phaser.Hermite#p1y
* @property {number} p1y - The y coordinate of the start of the curve. Setting this value will recalculate the curve.
*/
p1y: {
get: function ()
{
return this._p1y;
},
set: function (value)
{
if (value !== this._p1y)
{
this._p1y = value;
this.recalculate();
}
}
},
/**
* @name Phaser.Hermite#p2x
* @property {number} p2x - The x coordinate of the end of the curve. Setting this value will recalculate the curve.
*/
p2x: {
get: function ()
{
return this._p2x;
},
set: function (value)
{
if (value !== this._p2x)
{
this._p2x = value;
this.recalculate();
}
}
},
/**
* @name Phaser.Hermite#p2y
* @property {number} p2y - The y coordinate of the end of the curve. Setting this value will recalculate the curve.
*/
p2y: {
get: function ()
{
return this._p2y;
},
set: function (value)
{
if (value !== this._p2y)
{
this._p2y = value;
this.recalculate();
}
}
},
/**
* @name Phaser.Hermite#v1x
* @property {number} v1x - The x component of the tangent vector for the start of the curve. Setting this value will recalculate the curve.
*/
v1x: {
get: function ()
{
return this._v1x;
},
set: function (value)
{
if (value !== this._v1x)
{
this._v1x = value;
this.recalculate();
}
}
},
/**
* @name Phaser.Hermite#v1y
* @property {number} v1y - The y component of the tangent vector for the start of the curve. Setting this value will recalculate the curve.
*/
v1y: {
get: function ()
{
return this._v1y;
},
set: function (value)
{
if (value !== this._v1y)
{
this._v1y = value;
this.recalculate();
}
}
},
/**
* @name Phaser.Hermite#v2x
* @property {number} v2x - The x component of the tangent vector for the end of the curve. Setting this value will recalculate the curve.
*/
v2x: {
get: function ()
{
return this._v2x;
},
set: function (value)
{
if (value !== this._v2x)
{
this._v2x = value;
this.recalculate();
}
}
},
/**
* @name Phaser.Hermite#v2y
* @property {number} v2y - The y component of the tangent vector for the end of the curve. Setting this value will recalculate the curve.
*/
v2y: {
get: function ()
{
return this._v2y;
},
set: function (value)
{
if (value !== this._v2y)
{
this._v2y = value;
this.recalculate();
}
}
}
});
module.exports = Hermite;