Skip to main content
2 of 2
Cleanup
DMGregory
  • 136.3k
  • 22
  • 247
  • 373

Recursive function for LineRenderer with reflections causes Stack Overflow Error

I'm developing a 2D top down shooter game. I'm building the grenade functionality. The idea is that while you're holding the grenade button, it remains in your hand, and then when you release the button it throws the grenade. When the grenade is in your hand, I'm using a line renderer to show the trajectory of where the grenade will be thrown and bounce off walls.

I have a recursive function that uses linecasts to detect where the grenade will bounce and reflect the line as if it was bouncing off the wall. It's working as expected but it's somehow still giving a Stack Overflow Error. If I point the LineRenderer at a wall and put a breakpoint on the first line of the recursive function ThrowLineRaycast() it's only being called twice, and _lineRendererPoints.Count = 3.

void Update() {
    if (_isHeld && _throwable.ReleaseType == "Throw") {
        DrawThrowLine();
    }
}

private void DrawThrowLine() {
    _lineRendererPoints = new() { _rigidbody.position };
    ThrowLineRaycast(_rigidbody.position, transform.up, 0, _throwDistance);
    _lineRenderer.positionCount = _lineRendererPoints.Count;
    _lineRenderer.SetPositions(_lineRendererPoints.ToArray());
}

private void ThrowLineRaycast(Vector3 startPos, Vector3 direction, float distanceTraveled, float distanceRemaining, int hitNum = 0) {
    Vector3 endPos = startPos + (direction * distanceRemaining);
    LayerMask mask = LayerMask.GetMask("Walls", "WindowsAndCover");
    RaycastHit2D[] allHits = Physics2D.LinecastAll(startPos, endPos, mask);
    if (hitNum > allHits.Length - 1) {
        _lineRendererPoints.Add(endPos);
    } else {

        RaycastHit2D hit = allHits[hitNum];
        Vector3 hitPos = hit.point;
        Vector3 newDirection = Vector3.Reflect(direction, hit.normal);
        float totalDistanceToHit = distanceTraveled + hit.distance;
        float distanceRemainingAfterHit = distanceRemaining - hit.distance;

        if (hit.transform.gameObject.layer == LayerMask.NameToLayer("Walls")) {
            _lineRendererPoints.Add(hitPos);
            ThrowLineRaycast(hitPos, newDirection, totalDistanceToHit, distanceRemainingAfterHit, 0);
        } else if (hit.transform.gameObject.layer == LayerMask.NameToLayer("WindowsAndCover")) {
            if (GetThrowHeightFromLength(distanceTraveled, distanceTraveled + distanceRemaining) < _coverHeight) {
                _lineRendererPoints.Add(hitPos);
                ThrowLineRaycast(hitPos, newDirection, totalDistanceToHit, distanceRemainingAfterHit, 0);
            } else {
                ThrowLineRaycast(startPos, direction, distanceTraveled, distanceRemaining, hitNum + 1);
            }
        }
    }
}

private float GetThrowHeightFromLength(float distanceTraveled, float throwDistance) {
    return 3f;
}

Note: Ignore the WallsAndCover and throw height part. That hasn't been fully implemented yet, but the idea is that if the grenade is in the air and has a height greater than the height of the cover (something you can shoot over) it will ignore that hit. this is why I need the LinecastAll and hitNum, but that part of the code isn't even being hit yet.