Help with reflecting in 2D

I’ve been trying to create a little lasers and mirrors with the goal being get a laser past obstacles to a receiver and have been trying to get the reflecting down.
To help I put a line gizmo to help me visualize things so i can just slap on a line renderer once I iron it out.
I’ve been trying to do it recursively and i’m sure i’m close but i’m struggling to figure it out.
Here is what i got:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class MyLaser3 : MonoBehaviour
{
    public int maxReflectionCount = 5;
    public float maxStepDistance = 200;

    private void OnDrawGizmos()
    {
        drawPredictedReflection(this.transform.position, this.transform.up, maxReflectionCount);
    }

    void drawPredictedReflection(Vector2 position, Vector2 direction, int reflectionsRemaining)
    {
        if (reflectionsRemaining <= 0)
        {
            return;
        }

        Vector2 startingPos = position;

        RaycastHit2D hit2D = Physics2D.Raycast(startingPos, this.transform.up, maxStepDistance);

        if (hit2D) //if we hit somthing reflect, else just keep going
        {
            direction = Vector2.Reflect(direction, hit2D.normal);
            position = hit2D.point;
            Debug.Log(direction);
        }
        else
        {
            position += direction * maxStepDistance;
        }

        Gizmos.color = Color.yellow;
        Gizmos.DrawLine(startingPos, position);

        drawPredictedReflection(position, direction, reflectionsRemaining - 1);


    }
}

Let me know your thoughts/improvements or if i’m way off and to try a different way.

Your math looks and ended up being fine. One issue you might’ve bumped into was your use of:

position = hit2D.point;

for assigning the next ray source. This seems fine and it’s right geometrically, but you end up with weird behavior from firing a new ray from the surface of a collider that it’s also allowed to strike. You’ll get a weird floating point situation where sometimes it will hit it and sometimes it won’t.

In your case, you’d expect that you won’t. To adjust for that, I added a portion of the next ray’s direction to its starting position. This fixed the clipping issue and got the expected behavior:

151131-reflect.gif

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class RayReflect : MonoBehaviour
{
    public int maxReflectionCount = 5;
    public float maxStepDistance = 200;

    void OnDrawGizmos()
    {
        if (!Application.isPlaying)
            return;

        var source = this.transform.position;
        var xyPlane = new Plane(Vector3.forward, source);

        var cameraRay = Camera.main.ScreenPointToRay(Input.mousePosition);

        if (xyPlane.Raycast(Camera.main.ScreenPointToRay(Input.mousePosition), out float enter))
        {
            var worldCursor = cameraRay.GetPoint(enter);
            var direction = (worldCursor - source).normalized;

            this.DrawPredictedReflection(source, direction, this.maxReflectionCount);
        }
    }

    void DrawPredictedReflection (Vector2 position, Vector2 direction, int reflectionsRemaining)
    {
        var gizmoHue = (reflectionsRemaining / (this.maxReflectionCount + 1f);
        Gizmos.color = Color.HSVToRGB(gizmoHue, 1, 1);

        RaycastHit2D hit2D = Physics2D.Raycast (position, direction, maxStepDistance);

        if (hit2D && hit2D.collider) //if we hit somthing reflect, else just keep going
        {
            Gizmos.DrawLine (position, hit2D.point);
            Gizmos.DrawWireSphere(hit2D.point, 0.25f);

            direction = Vector2.Reflect (direction, hit2D.normal);
            position = hit2D.point + direction * 0.01f;
        }
        else
        {
            Gizmos.DrawLine (position, position + direction * maxStepDistance);
            position += direction * maxStepDistance;
        }

        Gizmos.color = Color.white;

        if (reflectionsRemaining > 0)
            DrawPredictedReflection (position, direction, --reflectionsRemaining);
    }
}