Displaying projected launch trajectory with line renderer

Greetings devs,

I’m working on an Angry Birds called Ninja Eggs and I want to display the projected trajectory the character will follow when launched.

I’m using a line renderer trying to use this formula to calculate the points along the line:
6608263--751894--upload_2020-12-10_9-12-6.png

This works in this simple game using the Love2D game engine:

Here’s a screenshot of the Lua code to do that:

But I’m having difficulty getting it to work in my Unity 2D game:

Here’s how I calculate launch force and apply it to my “ninja egg” when launching him:

    /// <summary>
    /// Adjust launch force based on how far back the egg has been dragged
    /// </summary>
    /// <returns>Launch force adjusted by drag distance</returns>
    public float GetAdjustedLaunchForce()
    {
        var distance = Vector2.Distance(_startPosition, _rigidbody2D.position);
        float forceAdjustment = maxDragDistance - 0.5f;
        float distanceFactor = distance / forceAdjustment;
        float calculatedLaunchForce = distanceFactor * launchForce;
        return calculatedLaunchForce;
    }

    /// <summary>
    /// Get normalized direction egg has been dragged
    /// </summary>
    /// <returns>Normalized drag distance</returns>
    public Vector2 GetDragDirection()
    {
        var currentPosition = _rigidbody2D.position;
        var direction = _startPosition - currentPosition;
        direction.Normalize();
        return direction;
    }

    private void LaunchNinjaEgg()
    {
        Scoreboard.Instance.AddLaunch();
        _launched = true;
        _collided = false;
        _audioSource.PlayOneShot(launchSound);
        _audioSource.PlayOneShot(whooHoo);
        var direction = GetDragDirection();
        _rigidbody2D.isKinematic = false;
        _rigidbody2D.AddForce(direction * GetAdjustedLaunchForce());
        SetNinjaEggColor(Color.white);
        dragEffect.Stop();
        _spriteRenderers[0].sprite = launchSprite;
        puffOfSmoke.transform.position = transform.position + new Vector3(direction.x, direction.y, 0) * 1f;
        puffOfSmoke.SetActive(true);
        puffOfSmoke.GetComponent<Rigidbody2D>()?.AddForce(direction * 50f);
        particleTrails.Play();
        IsDragging = false;
    }

This works perfectly for launching the egg. What I need help with is how to take that calculated launch force and use it to generate the points for the line renderer to accurately show the projected trajectory the egg will follow. Here’s my current code:

    void CalculateProjectedTrajectory()
    {
        // only update line renderer if we dragged the egg to a new position
        if (_lastPosition == _ninjaEgg.transform.position) return;
        _lastPosition = _ninjaEgg.transform.position;

        // normalized direction we are dragging the egg
        Vector3 direction = _ninjaEgg.GetDragDirection();

        // Adjusted velocity to apply to the egg position at each point on the line renderer
        Vector2 velocity = ((direction * _ninjaEgg.GetAdjustedLaunchForce()) / (_mass * _mass));
        Vector2 gravity = Physics2D.gravity;

        // Initialize a list of points and add start position
        List<Vector3> points = new List<Vector3>();
        points.Add(_rigidBody.position);
        int numSegments = 1;

        // do 90 iterations with every 5th position being added to line renderer
        Vector2 position = _lastPosition;
        for (int i = 1; i <= maxIterations; i++)
        {
            position.x = direction.x + i * Time.fixedDeltaTime * velocity.x;
            position.y = direction.y + i * Time.fixedDeltaTime * velocity.y + 0.5f * (i * i + i) * gravity.y * Time.fixedDeltaTime * Time.fixedDeltaTime;
            if (i % _segmentStepModulo == 0)
            {
                points.Add(position);
                ++numSegments;
            }
        }

        // Convert list of points to an array and use it to set line renderer positions
        _lineRenderer.SetPositions(points.ToArray());
    }

Based on the results I’m seeing I believe that the calculated velocity is way too high so it continues ascending through all 90 iterations.

Thanks in advance for any help!!!

-MidniteOil.

I have figured this out. There were 2 issues:

  • The velocity (really acceleration) needed to be adjusted by Time.fixedDeltaTime.
  • I was setting the positions along the line to direction adjusted by the physics calculation. I instead need to set them to be the start position, adjusted by the physics calculation for that iteration.
    void CalculateProjectedTrajectory()
    {
        // only update line renderer if we dragged the egg to a new position
        if (_lastPosition == _ninjaEgg.transform.position) return;
        _lastPosition = _ninjaEgg.transform.position;

        // normalized direction we are dragging the egg
        Vector3 direction = _ninjaEgg.GetDragDirection();

        // Adjusted velocity to apply to the egg position at each point on the line renderer
        var launchForce = _ninjaEgg.GetAdjustedLaunchForce();
        Vector2 velocity = ((direction * launchForce) / _mass) * _launchForceAdjustment;
        Vector2 gravity = Physics2D.gravity;

        // Initialize a list of points and add start position
        List<Vector3> points = new List<Vector3>();
        points.Add(_rigidBody.position);
        int numSegments = 1;

        // do 90 iterations with every 5th position being added to line renderer
        Vector2 position = _lastPosition;
        for (int i = 0; i < maxIterations; i++)
        {
            int n = i + 1;
            position.x = _lastPosition.x + n * Time.fixedDeltaTime * velocity.x;
            position.y = _lastPosition.y + n * Time.fixedDeltaTime * velocity.y + 0.5f * (n * n + n) * gravity.y * Time.fixedDeltaTime * Time.fixedDeltaTime;
            if (i % _segmentStepModulo == 0)
            {
                points.Add(position);
                ++numSegments;
            }
        }

        // Convert list of points to an array and use it to set line renderer positions
        _lineRenderer.SetPositions(points.ToArray());
    }

2 Likes