Search Unity

  1. Welcome to the Unity Forums! Please take the time to read our Code of Conduct to familiarize yourself with the forum rules and how to post constructively.
  2. Dismiss Notice

Resolved LaserBeam Reflection (RaycastHit2D)was not working like expected and didnt reflect correctly

Discussion in '2D' started by ShiiikK, Aug 16, 2023.

  1. ShiiikK

    ShiiikK

    Joined:
    Jun 27, 2022
    Posts:
    2
    I'm trying to simulate the laser reflection, this partially works,
    however it doesn't work across the entire collider.
    But only in places.

    I've attached four images that effectively illustrate the problem I'm encountering.
    And a image from the settings of my LineRenderer.


    The laser hits exactly at a certain point of the collider, but not at all other points.
    I'm confused by this inconsistency.

    Interestingly, I've also implemented a GrapplingLogic function that I use to pre-emptively check if a hookshot collides with anything at a given distance.
    This RaycastHit2D works perfectly.

    So now I'm at a loss as to what could be the issue.


    Here my GrabblingSystem which is working
    (just for demonstrating)
    Code (CSharp):
    1.  Vector3 GetCollisionPoint(Vector3 directionToCursor)
    2.     {
    3.         Vector3 startPosition = player.position;
    4.  
    5.         RaycastHit2D hit = Physics2D.Raycast(startPosition, directionToCursor.normalized, hookRange, LayerMask.GetMask("Ground"));
    6.  
    7.         if (hit.collider != null)
    8.         {
    9.             return hit.point;
    10.         }
    11.  
    12.         return Vector3.zero;
    13.     }
    Here my Laser Reflection Code
    (where i need help)
    Code (CSharp):
    1.  IEnumerator ReflectLaser()
    2.     {
    3.         Vector3 raycastOrigin = laserBeam.transform.position;
    4.         Vector3 raycastDirection = laserBeam.transform.right;
    5.         laserBeam.positionCount = 1;
    6.         laserBeam.SetPosition(0, raycastOrigin);
    7.  
    8.         float remainLength = defaultLength;
    9.         int groundLayerMask = LayerMask.GetMask("Ground");
    10.  
    11.         for (int i = 0; i < numOfReflections; i++)
    12.         {
    13.             RaycastHit2D hit = Physics2D.Raycast(raycastOrigin, raycastDirection, remainLength, groundLayerMask);
    14.  
    15.             if (hit.collider != null)
    16.             {
    17.                 laserBeam.positionCount += 1;
    18.                 laserBeam.SetPosition(laserBeam.positionCount - 1, hit.point);
    19.                 remainLength -= Vector2.Distance(raycastOrigin, hit.point);
    20.                 raycastOrigin = hit.point;
    21.                 raycastDirection = Vector2.Reflect(raycastDirection, hit.normal);
    22.             }
    23.             else
    24.             {
    25.                 laserBeam.positionCount += 1;
    26.                 laserBeam.SetPosition(laserBeam.positionCount - 1, raycastOrigin + (raycastDirection * remainLength));
    27.                 break; // No more reflections if no collision is detected.
    28.             }
    29.         }
    30.         yield return new WaitForSeconds(laserSpeed);
    31.         laserBeam.SetPosition(0, raycastOrigin);
    32.         laserBeam.SetPosition(1, raycastOrigin);
    33.         laserBeam.SetPosition(2, raycastOrigin);
    34.     }
    fixed by using:
    Code (CSharp):
    1. raycastOrigin = hit.collider.ClosestPoint(raycastDirection);
    Instead of:
    Code (CSharp):
    1. raycastOrigin = hit.point;
     

    Attached Files:

    Last edited: Aug 16, 2023
  2. MelvMay

    MelvMay

    Unity Technologies

    Joined:
    May 24, 2013
    Posts:
    10,468
    You'll need to provide more information by debugging it i.e. not just saying...
    Really not sure what this means nor what the images are trying to show.

    If you continue raycasting from a point that is already intersecting a collider, why don't you expect it to hit that point again? Note that tiny changes in floating-point might make this slightly inconsistent. For this kind of thing, you should, in the very least, start casting slightly away from the last hit point in the direction of the reflection.

    Note that this only happens if you are globally allowing queries to start inside colliders: https://docs.unity3d.com/ScriptReference/Physics2D-queriesStartInColliders.html
     
  3. ShiiikK

    ShiiikK

    Joined:
    Jun 27, 2022
    Posts:
    2
    I accidentally fixed it by using:
    Code (CSharp):
    1. raycastOrigin = hit.collider.ClosestPoint(raycastDirection);
    Instead of:
    Code (CSharp):
    1. raycastOrigin = hit.point;
    now it uses the closestPoint and it is reflecting correctly.



    Regarding your question:

    The image showed one working reflection and one that didn't work. Normally reflections should always occur and always come out at the same angle as they came in, but I believe my previous version allowed the same collider for the reflection direction and so in some cases actually used it instead of bouncing off it.
    Anyway, it works as expected and I thank you for your answer and help.
     
    MelvMay likes this.
  4. MelvMay

    MelvMay

    Unity Technologies

    Joined:
    May 24, 2013
    Posts:
    10,468
    Just note that this is relatively expensive compared to just backing away slightly by a fixed distance i.e.
    Code (CSharp):
    1. // Assume direction is a normalised Vector2 here.
    2. raycastOrigin = hit.point + raycastDirection * someTinyOffset;
    Also, be aware that normalising a 3D Vector for distance/direction is prone to error unless you have zero in the Z. You should always first reduce it to using and passing a Vector2 to be safe; it's the source of hard to find bugs.