0
\$\begingroup\$

I have some units shooting arrows, right now they move in a straight line to the target. I want them to move like a real arrow, i.e using a parabola curve. However I don't want to use physics.

The math I need to do seems to be beyond me, I've tried to convert 2d solution I found online and other semi-similar solution with no luck.

My current straight movement:

private void Update()
{
    var nextPos = Vector3.MoveTowards(transform.position, target, speed * Time.deltaTime);
    transform.LookAt(nextPos, transform.forward);
    transform.position = nextPos;

    if (Vector3.Distance(nextPos, target) < .1f)
        Arrived();
}

An example of a 2d version I tried to replicate: Here.

\$\endgroup\$
  • \$\begingroup\$ You can use Quadratic Bezier curves to add a parabolic path to your projectiles. They are really easy to understand. You can find a really good tutorial here. The tutorial also provides the link to all the source code in the description. \$\endgroup\$ – BunnyDhaliwal Jun 14 '20 at 12:09
2
\$\begingroup\$
public float speed;
public Vector3 target;
public float arcHeight;

Vector3 _startPosition;
float _stepScale;
float _progress;

void Start() {
    _startPosition = transform.position;

    float distance = Vector3.Distance(_startPosition, target);

    // This is one divided by the total flight duration, to help convert it to 0-1 progress.
    _stepScale = speed / distance;
}

void Update() {
    // Increment our progress from 0 at the start, to 1 when we arrive.
    _progress = Mathf.Min(_progress + Time.deltaTime * _stepSize, 1.0f);

    // Turn this 0-1 value into a parabola that goes from 0 to 1, then back to 0.
    float parabola = 1.0f - 4.0f * (_progress - 0.5f) * (_progress - 0.5f);

    // Travel in a straight line from our start position to the target.        
    Vector3 nextPos = Vector3.Lerp(_startPosition, target, progress);

    // Then add a vertical arc in excess of this.
    nextPos.y += parabola * arcHeight;

    // Continue as before.
    transform.LookAt(nextPos, transform.forward);
    transform.position = nextPos;

    // I presume you disable/destroy the arrow in Arrived so it doesn't keep arriving.
    if(progress == 1.0f)
        Arrived();
}
\$\endgroup\$
  • 1
    \$\begingroup\$ Works perfectly, thank you, learned a lot from the comments! \$\endgroup\$ – Majs Jun 14 '20 at 14:31
  • \$\begingroup\$ For anyone coming back here in the future, in order to alter the arc height depending on distance (longer distance = higher arc) I simply add arcHeight = arcHeight * distance; where arcHeight has a value between 0 and 1. \$\endgroup\$ – Majs Jun 14 '20 at 15:10

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.