I have written a function named getPointOnEllipse
that allows you to move your sprites pixel-by-pixel in an elliptical path. The function determines the coordinates of a particular point in the elliptical path, given the coordinates of the center of the ellipse, the lengths of the semi-major axis and the semi-minor axis, and finally the offset of the point into the elliptical path, all in pixels.
Note: To be honest, unfortunately, the getPointOnEllipse
function skips (does not detect) a few of the points in the elliptical path. As a result, the arc distance is not exactly uniform. Sometimes it is one pixel, and sometimes two pixels, but not three or more! In spite of the fault, changes in speed will be really "faint", and IMO, your sprites will move pretty smoothly.
Below is the getPointOnEllipse
function, along with another function named getEllipsePerimeter
, which is used to determine an ellipse's perimeter through Euler's formula. The code is written in JScript.
function getEllipsePerimeter(rx, ry)
{
with (Math)
{
// You'll need to floor the return value to obtain the ellipse perimeter in pixels.
return PI * sqrt(2 * (rx * rx + ry * ry));
}
}
function getPointOnEllipse(cx, cy, rx, ry, d)
{
with (Math)
{
// Note: theta expresses an angle in radians!
var theta = d * sqrt(2 / (rx * rx + ry * ry));
//var theta = 2 * PI * d / getEllipsePerimeter(rx, ry);
return {x:floor(cx + cos(theta) * rx),
y:floor(cy - sin(theta) * ry)};
}
}
The following figure illustrates the parameters of this function:

cx
- the x-coordinate of the center of the ellipse
cy
- the y-coordinate of the center of the ellipse
rx
- the length of semi-major axis
ry
- the length of semi-minor axis
d
- the offset of the point into the elliptical path (i.e. the arc length from the vertex to the point)
The unit of all parameters is pixel.
The function returns an object containing the x- and y-coordinate of the point of interest, which is represented by a purple ball in the figure.
d
is the most important parameter of the getPointOnEllipse
function. You should call this function multiple times. In the first call, set d
to 0, and then place the sprite at the point returned, which causes the sprite to be positioned on the vertex. Then wait a short period (e.g. 50 milliseconds), and call the function again, setting d
parameter to 1. This time, by placing the sprite at the point returned, it moves 1 pixel forward in the ellipse path. Then repeat doing so (wait a short period, call the function with increased d
value, and position the sprite) until the value of d
reaches the perimeter of the ellipse. You can also increase d
value by more than one, so that the sprite moves more pixels forward in each step, resulting in faster movement.
Moreover, you can modify the getEllipsePerimeter function in the code to use a more precise formula (like Ramanujan's formula) for getting ellipse perimeter. But in that case, be sure to modify the getPointOnEllipse
function as well to use the second version of theta
variable (which is commented in the code). Note that the first version of theta
is just a simplified form of the second version for the sake of optimization.