4
\$\begingroup\$

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? enter image description here

The object is sun sprite.

enter image description here

\$\endgroup\$
4

2 Answers 2

13
\$\begingroup\$

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.

enter image description here

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.

\$\endgroup\$
6
  • \$\begingroup\$ What if I have two objects for moving. Like sun and moon. And I want them to take turns. What is it with counting then? \$\endgroup\$ Apr 17, 2018 at 10:59
  • \$\begingroup\$ @NikitaDemidenko I edited my answer with a sun and moon example \$\endgroup\$ Apr 17, 2018 at 11:06
  • \$\begingroup\$ It is moving to fast. Just instantly sprite is at the finish point no mater how I tweak count value. \$\endgroup\$ Apr 17, 2018 at 11:45
  • \$\begingroup\$ @NikitaDemidenko Can you post some code? I'm afraid there is nothing I can do, since this method I posted work, unless I see what you did wrong in the code. \$\endgroup\$ Apr 17, 2018 at 11:57
  • \$\begingroup\$ I have created more elaborated question gamedev.stackexchange.com/questions/157646/… I accept your answer here cause I think it is valid, it is just I do something wrong. \$\endgroup\$ Apr 17, 2018 at 12:05
4
\$\begingroup\$

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));
\$\endgroup\$
5
  • \$\begingroup\$ Seems to be a good solution for speed consistency. But does it provide trajectory adjustment? I mean is it only perfectly round or is it adjustable to stretch arcs height but preserve start and finish points coordinates? Sorry if it is obvious in the code. I need a day or two to digest it :) \$\endgroup\$ Apr 17, 2018 at 12:50
  • \$\begingroup\$ This particular version is perfectly round, though you can shape how steep or shallow an arc you want by varying the radius parameter (bigger radii = shallower, straighter arc) \$\endgroup\$
    – DMGregory
    Apr 17, 2018 at 12:59
  • \$\begingroup\$ @DMGregory please take a look at this for me gamedev.stackexchange.com/questions/157685/… \$\endgroup\$ Apr 19, 2018 at 3:34
  • \$\begingroup\$ Can you explain why you multiple the perp by a trig function plus the square root? I don't understand that. \$\endgroup\$
    – WDUK
    Aug 13, 2018 at 2:35
  • \$\begingroup\$ @WDUK I'm seeing this late, but this is just Pythagorean theorem: \$a^2 + b^2 = c^2\$ implies that \$b^2 = c^2 - a^2\$, which in turn gives us \$b = \pm \sqrt{c^2 - a^2}\$. 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\$
    – DMGregory
    Sep 7, 2021 at 16:58

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .