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. We have updated the language to the Editor Terms based on feedback from our employees and community. Learn more.
    Dismiss Notice

Bug Laser Beam with raycast and line renderer bug. Help needed.

Discussion in 'Scripting' started by fivegrandpint, Sep 18, 2022.

  1. fivegrandpint

    fivegrandpint

    Joined:
    Jan 16, 2020
    Posts:
    16
    I have made a grid of mirrors and designed a laser, made with a raycast and line renderer but am getting some strange behaviour. Mirrors in certain positions do not reflect and the laser passes straight through. All the mirrors are identical and when I destroy the faulty mirror and move a new one to its place, it adopts the unwanted behaviour, even though it was functioning as expected before. Really can't get my head round why this would be happening. My Line renderer has a size of 17 and the max bounces on the laser script is set to 16. Any help much appreciated.

    Behaviour:



    Code:

    Code (CSharp):
    1. using System.Collections;
    2. using System.Collections.Generic;
    3. using UnityEngine;
    4.  
    5. public class LazerGeneration : MonoBehaviour
    6. {
    7.     public int maxBounces = 100;
    8.     private LineRenderer lr;
    9.     [SerializeField]
    10.     private Transform startPoint;
    11.     [SerializeField]
    12.     private bool reflectOnlyMirror;
    13.  
    14.     private void Start()
    15.     {
    16.         //get the line renderer component
    17.         lr = GetComponent<LineRenderer>();
    18.  
    19.         //set position 0 to be start point
    20.         lr.SetPosition(0, startPoint.position);
    21.  
    22.     }
    23.  
    24.     private void Update()
    25.     {
    26.         // cast lazer forward
    27.         CastLazer(transform.position, -transform.forward);
    28.  
    29.     }
    30.  
    31.  
    32.     void CastLazer(Vector3 position, Vector3 direction)
    33.     {
    34.         lr.SetPosition(0, startPoint.position);
    35.  
    36.             for(int i=0; i< maxBounces; i++)
    37.         {
    38.             Ray ray = new Ray(position, direction);
    39.             RaycastHit hit;
    40.  
    41.             if(Physics.Raycast( ray, out hit, 300, 1))
    42.             {
    43.                 position = hit.point;
    44.                 direction = Vector3.Reflect(direction, hit.normal);
    45.                 lr.SetPosition(i + 1, hit.point);
    46.  
    47.                 if(hit.transform.tag != "Mirror" && reflectOnlyMirror)
    48.                 {
    49.                     for(int j = (i+1); j <= maxBounces; j++)
    50.                     {
    51.                         lr.SetPosition(j, hit.point);
    52.                     }
    53.                     break;
    54.                 }  
    55.             }
    56.  
    57.         }
    58.     }
    59. }
     
  2. Kurt-Dekker

    Kurt-Dekker

    Joined:
    Mar 16, 2013
    Posts:
    36,963
    If these are always in a grid and always at 45 degrees, you might want to consider just keeping references to what is in each tile (such as by using a 2D array) and doing the logic yourself rather than raycasting.

    Raycasting will fail to detect if you start within a collider for any reason.

    If you insist on this way, time to start debugging!

    You must find a way to get the information you need in order to reason about what the problem is.

    What is often happening in these cases is one of the following:

    - the code you think is executing is not actually executing at all
    - the code is executing far EARLIER or LATER than you think
    - the code is executing far LESS OFTEN than you think
    - the code is executing far MORE OFTEN than you think
    - the code is executing on another GameObject than you think it is
    - you're getting an error or warning and you haven't noticed it in the console window

    To help gain more insight into your problem, I recommend liberally sprinkling
    Debug.Log()
    statements through your code to display information in realtime.

    Doing this should help you answer these types of questions:

    - is this code even running? which parts are running? how often does it run? what order does it run in?
    - what are the values of the variables involved? Are they initialized? Are the values reasonable?
    - are you meeting ALL the requirements to receive callbacks such as triggers / colliders (review the documentation)

    Knowing this information will help you reason about the behavior you are seeing.

    You can also supply a second argument to Debug.Log() and when you click the message, it will highlight the object in scene, such as
    Debug.Log("Problem!",this);


    If your problem would benefit from in-scene or in-game visualization, Debug.DrawRay() or Debug.DrawLine() can help you visualize things like rays (used in raycasting) or distances.

    You can also call Debug.Break() to pause the Editor when certain interesting pieces of code run, and then study the scene manually, looking for all the parts, where they are, what scripts are on them, etc.

    You can also call GameObject.CreatePrimitive() to emplace debug-marker-ish objects in the scene at runtime.

    You could also just display various important quantities in UI Text elements to watch them change as you play the game.

    If you are running a mobile device you can also view the console output. Google for how on your particular mobile target, such as this answer or iOS: https://forum.unity.com/threads/how-to-capturing-device-logs-on-ios.529920/ or this answer for Android: https://forum.unity.com/threads/how-to-capturing-device-logs-on-android.528680/

    Another useful approach is to temporarily strip out everything besides what is necessary to prove your issue. This can simplify and isolate compounding effects of other items in your scene or prefab.

    Here's an example of putting in a laser-focused Debug.Log() and how that can save you a TON of time wallowing around speculating what might be going wrong:

    https://forum.unity.com/threads/coroutine-missing-hint-and-error.1103197/#post-7100494

    When in doubt, print it out!(tm)

    Note: the
    print()
    function is an alias for Debug.Log() provided by the MonoBehaviour class.
     
  3. fivegrandpint

    fivegrandpint

    Joined:
    Jan 16, 2020
    Posts:
    16
    Thanks for the advice. I'm not actually particularly set on this method and would prefer to do it a less buggy way if possible. I'm just a bit of a newbie programmer so had never thought of doing it another way. I am watching a youtube tutorial just now on how to make a 2D array and create a grid. However, my game is actually in 3d, I was just looking at this grid from directly above in the clip I provided. Will a 2D array still work? Is there any chance you could summarise a bit of guidance on the type of logic that might be required for this? No worries if not of course, I realise that it may be rather involved and this is not your project. I just struggle to think of these types of things as I am a beginner. I am guessing it would be a lot of looping through lists and checking different bools etc.
     
  4. karliss_coldwild

    karliss_coldwild

    Joined:
    Oct 1, 2020
    Posts:
    530
    Does your game actually have any rules or mechanics which depend on third dimension or you are thinking only about the 3d graphics? Think about it this way: a chess game might be using 3d graphics (or even physical 3d objects) but all the rules are still based on fixed 8x8 grid. Anyway whether this approach is suitable is less about 2d vs 3d as it is whether rules of game are based on discrete states in a grid. You can create 3d or even 4d arrays if game demands it, but that won't help if your freely spin the mirrors at any angle other than 45 degree angles showed in your video (even if everything is fully 2D).
     
    Kurt-Dekker likes this.
  5. Kurt-Dekker

    Kurt-Dekker

    Joined:
    Mar 16, 2013
    Posts:
    36,963
    It sounds like you're already thinking about the problem correctly!

    Yeah, it's stuff like looping and looking up and yes that stuff will bend your brain, but it's really just a matter of getting your mind around it, and doing it enough times with simple games to build up your confidence.

    Everything that @karliss_coldwild says above applies, and the "chess is a 2D game in a 3D world" analogy nails it.

    But as we both said, just gazing at your game does not tell us if you envision those 45 degree mirrors being at other non-45-degree angles, which would break the logic of a simple 2D grid and require you to go at odd diagonals, for instance.

    The key is not to get discouraged or delay because of the massive range of choices available. Just move forward.

    Take the above approach as far as you can, while simultaneously looking at other 2D grid game mechanisms, and try to tease apart in your brain WHY each step is done. For instance:

    - you are using raycasting to find a tile some number of tiles to the right

    - a 2D approach might start at the tile you're on, stepping one tile to the right until it finds either what it wants or the edge of the screen or a laser.

    Both are valid ways, but the raycast involves a much larger "surface of function" because it involves the big global physics engine, which could have weird unintended consequences if you change something about physics in the future.

    Just make games, have fun, you're well on your way!!
     
  6. fivegrandpint

    fivegrandpint

    Joined:
    Jan 16, 2020
    Posts:
    16
    Thanks, this makes sense. And indeed what you mean @karliss_coldwild. My game just has 3d graphics and for the mirrors and reflectors everything really only happens in 2d as the angles they go to will only be in the X and Z directions and I won't be reflecting the beams on the Y axis. I found a way around this bug with my current method, when creating the raycast, you cast it from 0.01f from outside the collider and this stops the bug. It seems it must have been getting stuck inside the collider or something, I'm not sure. Still, this doesn't feel very robust even though it works so I think I will still work on something using lists and logic as I feel this will be more reliable and easier to debug and control.

    Thanks for the advice.
     
  7. Kurt-Dekker

    Kurt-Dekker

    Joined:
    Mar 16, 2013
    Posts:
    36,963
    See? You are already thinking ahead. Yes it isn't very robust.

    BUT... you could stick with this technique and do a little bit of extra work and make it happen!

    First is to always use layers / layer masks so you only hit the colliders you're interested in on any given query.

    Second is to use RaycastAll() and get a FULL list of everything the ray passes through.

    Then you can sort that list by distance and start walking through the hits.

    - What did I hit? Myself? Ignore
    - What did I hit? Mirror? Reflect, and stop iterating
    - What did I hit? Goal? Done!

    Then repeat for the next segment of travel.