I have a sprite which I need to move along a curve between two points in 2D space. Speed must be consistent all the way. No physics involved. How can I achieve this?
The object is sun sprite.
Game Development Stack Exchange is a question and answer site for professional and independent game developers. It only takes a minute to sign up.
Sign up to join this communityI have a sprite which I need to move along a curve between two points in 2D space. Speed must be consistent all the way. No physics involved. How can I achieve this?
The object is sun sprite.
You can use Bezier Curves.
Given 2 given points, you have to define one third point yourself that controls where the curve is made. In your example you can create the point between your two given points, plus some height.
// Assuming point[0] and point[2] are your starting point and destination
// and all points are Vector3
point[1] = point[0] +(point[2] -point[0])/2 +Vector3.up *5.0f; // Play with 5.0 to change the curve
Then to compute the curve in a script for an object to travel to it, do this:
float count = 0.0f;
void Update() {
if (count < 1.0f) {
count += 1.0f *Time.deltaTime;
Vector3 m1 = Vector3.Lerp( point[0], point[1], count );
Vector3 m2 = Vector3.Lerp( point[1], point[2], count );
myObject.position = Vector3.Lerp(m1, m2, count);
}
}
Basically, to compute a Quadratic Bezier Curve (one with three points) you have to find the interpolated points of it's two lines, construct a line with those two points (The green line in the gif), and interpolate again to find a final point.
As you can see, if you increase the Y value on your second point, the curve will be bigger.
Edit:
If you want to create moving objects like a sun and a moon, create 3 Vector3
points: starting point (where the sun begins travelling) an ending point (where the sun ends up) and a control point (that controls the curve). The control point should be located above the mountains, but the exact value depends on what kind of curve you are looking for.
Now substitute these points with the above example:
point[0] = startingPoint;
point[1] = controlPoint;
point[2] = endingPoint;
I assume that once the sun (or moon) reaches the ending point, they can just disappear from the scene, and re-appear on the next day on the starting point, so it's location until then is irrelevant.
Myself, I'd use a circular arc for this - that way it's easy to get consistent speed.
IEnumerator FollowArc(
Transform mover,
Vector2 start,
Vector2 end,
float radius, // Set this to negative if you want to flip the arc.
float duration) {
Vector2 difference = end - start;
float span = difference.magnitude;
// Override the radius if it's too small to bridge the points.
float absRadius = Mathf.Abs(radius);
if(span > 2f * absRadius)
radius = absRadius = span/2f;
Vector2 perpendicular = new Vector2(difference.y, -difference.x)/span;
perpendicular *= Mathf.Sign(radius) * Mathf.Sqrt(radius*radius - span*span/4f);
Vector2 center = start + difference/2f + perpendicular;
Vector2 toStart = start - center;
float startAngle = Mathf.Atan2(toStart.y, toStart.x);
Vector2 toEnd = end - center;
float endAngle = Mathf.Atan2(toEnd.y, toEnd.x);
// Choose the smaller of two angles separating the start & end
float travel = (endAngle - startAngle + 5f * Mathf.PI) % (2f * Mathf.PI) - Mathf.PI;
float progress = 0f;
do {
float angle = startAngle + progress * travel;
mover.position = center + new Vector2(Mathf.Cos(angle), Mathf.Sin(angle)) * absRadius;
progress += Time.deltaTime/duration;
yield return null;
} while (progresss < 1f);
mover.position = end;
}
Now you can start the object moving with:
StartCoroutine(FollowArc(sunSprite, sunrisePoint, sunsetPoint, radius, daylightDuration));
Mathf.Sign()
is not a trig function (note the "g" - even if it's pronounced the same as "sine"/Mathf.Sin()
, it's a different function) - it returns +1 or -1 depending on the sign of the argument, giving us the \$\pm\$ part of the formula above.
\$\endgroup\$