Search Unity

[FREE]bouncing laser script!

Discussion in 'Assets and Asset Store' started by Maurice_B, Dec 22, 2014.

?

Opinion

  1. 1 C**p

    3.3%
  2. 2

    0 vote(s)
    0.0%
  3. 3 erm

    1.7%
  4. 4

    0 vote(s)
    0.0%
  5. 5 OK

    16.7%
  6. 6

    1.7%
  7. 7Good

    10.0%
  8. 8

    8.3%
  9. 9

    6.7%
  10. 10 Amazing

    51.7%
  1. Maurice_B

    Maurice_B

    Joined:
    Jan 10, 2014
    Posts:
    14
    Hello Community,
    Today I want to share with you my script for bouncing raycast lasers.WEBDEMO I am doing this for two main reasons:

    1. I want feedback to make this evolve and become better.
    2. I love free stuff but I feel I have taken too much with out contributing some back
    Enjoy and please help this improve through comments.
    JS:
    Code (JavaScript):
    1. #pragma strict
    2. @script RequireComponent(LineRenderer)
    3. var dist : int; //max distance for beam to travel.
    4. var lr : LineRenderer;
    5. var winTag : String; // i was using for minigame, if laser touches this tag , win
    6. var reftag :String; //tag it can reflect off.
    7. var limit : int = 100; // max reflections
    8. private var verti  :int = 1; //segment handler don't touch.
    9. private var iactive :boolean;
    10. private var currot : Vector3;
    11. private var curpos : Vector3;
    12. function Start () {
    13.  
    14.  
    15. }
    16.  
    17. function Update () {
    18.  
    19.     lr.enabled = Input.GetKey(KeyCode.Space);
    20.     if (Input.GetKey(KeyCode.Space)||Input.GetKeyUp(KeyCode.Space)){
    21.         DrawLaser();
    22.     }
    23. }
    24. function DrawLaser()
    25. {
    26.     verti = 1;
    27.     iactive = true;
    28.     currot = transform.forward;
    29.     curpos = transform.position;
    30.     lr.SetVertexCount(1);
    31.     lr.SetPosition(0,transform.position);
    32.  
    33.     while(iactive)
    34.     {
    35.         verti ++;
    36.         var hit : RaycastHit;
    37.         lr.SetVertexCount(verti);
    38.         if (Physics.Raycast(curpos,currot,hit,dist))
    39.         {
    40.             //verti++;
    41.             curpos=hit.point;
    42.             currot = Vector3.Reflect(currot,hit.normal);
    43.             lr.SetPosition(verti-1,hit.point);
    44.             if (hit.transform.gameObject.tag != reftag){
    45.                 iactive = false;
    46.             }
    47.         }
    48.         else
    49.         {
    50.             //verti++;
    51.             iactive = false;
    52.             lr.SetPosition(verti-1,curpos+100*currot);
    53.        
    54.         }
    55.         if (verti >limit)
    56.         {
    57.         iactive = false;
    58.         }
    59.    
    60.    
    61.     }
    62.  
    63.  
    64.  
    65. }
     
    Last edited: Feb 2, 2015
  2. jay911144

    jay911144

    Joined:
    Jan 30, 2015
    Posts:
    2
    Good script, but I can't figure out how to get it working with multiplayer. If anyone has any idea why, please let me know!
     
  3. Maurice_B

    Maurice_B

    Joined:
    Jan 10, 2014
    Posts:
    14
    How do you mean.
     
  4. carking1996

    carking1996

    Joined:
    Jun 15, 2010
    Posts:
    2,609
    Your web player is broken it seem, doesn't load. Make sure both files are in the folder.
     
  5. jay911144

    jay911144

    Joined:
    Jan 30, 2015
    Posts:
    2
    It shows up for the client, but not for anyone else connected
     
  6. Trigary

    Trigary

    Joined:
    Jan 5, 2016
    Posts:
    1
    Thanks for the script, after some digging I could fix the line renderer problem, it works great now. If anyone is wondering, here's the script: (thanks to you and Patrick234)

    Code (CSharp):
    1. void DrawLaser () {
    2.         /*
    3.         public int laserDistance = 100; //max raycasting distance
    4.         public int laserLimit = 10; //the laser can be reflected this many times
    5.         public LineRenderer laserRenderer; //the line renderer
    6.         */
    7.  
    8.         int laserReflected = 1; //How many times it got reflected
    9.         int vertexCounter = 1; //How many line segments are there
    10.         bool loopActive = true; //Is the reflecting loop active?
    11.         Vector2 laserDirection = transform.up; //direction of the next laser
    12.         Vector2 lastLaserPosition = transform.position; //origin of the next laser
    13.  
    14.         laserRenderer.SetVertexCount(1);
    15.         laserRenderer.SetPosition(0, transform.position);
    16.  
    17.         while (loopActive) {
    18.             RaycastHit2D hit = Physics2D.Raycast(lastLaserPosition, laserDirection, laserDistance);
    19.  
    20.             if (hit) {
    21.                 laserReflected++;
    22.                 vertexCounter += 3;
    23.                 laserRenderer.SetVertexCount (vertexCounter);
    24.                 laserRenderer.SetPosition (vertexCounter-3, Vector3.MoveTowards(hit.point, lastLaserPosition, 0.01f));
    25.                 laserRenderer.SetPosition(vertexCounter-2, hit.point);
    26.                 laserRenderer.SetPosition(vertexCounter-1, hit.point);
    27.                 lastLaserPosition = hit.point;
    28.                 laserDirection = Vector3.Reflect(laserDirection, hit.normal);
    29.             } else {
    30.                 laserReflected++;
    31.                 vertexCounter++;
    32.                 laserRenderer.SetVertexCount (vertexCounter);
    33.                 laserRenderer.SetPosition (vertexCounter - 1, lastLaserPosition + (laserDirection.normalized * laserDistance));
    34.  
    35.                 loopActive = false;
    36.             }
    37.             if (laserReflected > laserLimit)
    38.                 loopActive = false;
    39.         }
    40.     }
     
  7. Maurice_B

    Maurice_B

    Joined:
    Jan 10, 2014
    Posts:
    14
    Im glad you like it!
     
  8. asdfasdfasdfas-dgrdtuert

    asdfasdfasdfas-dgrdtuert

    Joined:
    Mar 25, 2015
    Posts:
    1
    Little bit too late but i took your .js and transform it into c# and it had a little problem with raycasthit = physics.raycast because it was missing the out hit parameter.

    Code (CSharp):
    1.  
    2.  
    3. [RequireComponent(typeof(LineRenderer))]
    4. public class BouncingLaser : MonoBehaviour
    5. {
    6.  
    7.     public int laserDistance;
    8.     public LineRenderer mLineRenderer;
    9.     public string bounceTag;
    10.     public int maxBounce;
    11.     private float timer = 0;
    12.    
    13.     // Use this for initialization
    14.     void Start ()
    15.     {
    16.        
    17.     }
    18.    
    19.     // Update is called once per frame
    20.     void Update ()
    21.     {
    22.         if (Input.GetKeyDown ("space") && !mLineRenderer.enabled) {
    23.             timer = 0;
    24.             StartCoroutine ("FireMahLazer");  
    25.         }
    26.     }
    27.    
    28.     IEnumerator FireMahLazer ()
    29.     {
    30.         //Debug.Log("Running");
    31.         mLineRenderer.enabled = true;
    32.         int laserReflected = 1; //How many times it got reflected
    33.         int vertexCounter = 1; //How many line segments are there
    34.         bool loopActive = true; //Is the reflecting loop active?
    35.        
    36.         Vector3 laserDirection = transform.forward; //direction of the next laser
    37.         Vector3 lastLaserPosition = transform.localPosition; //origin of the next laser
    38.    
    39.         mLineRenderer.SetVertexCount (1);
    40.         mLineRenderer.SetPosition (0, transform.position);
    41.         RaycastHit hit;
    42.  
    43.         while (loopActive) {
    44.  
    45.             if (Physics.Raycast (lastLaserPosition, laserDirection, out hit, laserDistance) && hit.transform.gameObject.tag == bounceTag) {
    46.                
    47.                     Debug.Log ("Bounce");
    48.                     laserReflected++;
    49.                     vertexCounter += 3;
    50.                     mLineRenderer.SetVertexCount (vertexCounter);
    51.                     mLineRenderer.SetPosition (vertexCounter - 3, Vector3.MoveTowards (hit.point, lastLaserPosition, 0.01f));
    52.                     mLineRenderer.SetPosition (vertexCounter - 2, hit.point);
    53.                     mLineRenderer.SetPosition (vertexCounter - 1, hit.point);
    54.                     mLineRenderer.SetWidth (.1f, .1f);
    55.                     lastLaserPosition = hit.point;
    56.                     laserDirection = Vector3.Reflect (laserDirection, hit.normal);
    57.                 } else {
    58.            
    59.                     Debug.Log ("No Bounce");
    60.                     laserReflected++;
    61.                     vertexCounter++;
    62.                     mLineRenderer.SetVertexCount (vertexCounter);
    63.                     Vector3 lastPos = lastLaserPosition + (laserDirection.normalized * laserDistance);
    64.                     Debug.Log ("InitialPos " + lastLaserPosition + " Last Pos" + lastPos);
    65.                     mLineRenderer.SetPosition (vertexCounter - 1, lastLaserPosition + (laserDirection.normalized * laserDistance));
    66.  
    67.                     loopActive = false;
    68.                 }
    69.             if (laserReflected > maxBounce)
    70.                 loopActive = false;
    71.         }
    72.        
    73.         if(Input.GetKey("space") && timer < 2)
    74.         {
    75.             yield return new WaitForEndOfFrame();
    76.             timer+=Time.deltaTime;
    77.             StartCoroutine("FireMahLazer");
    78.         }
    79.         else{
    80.             yield return null;
    81.             mLineRenderer.enabled = false;
    82.         }
    83.     }
    84. }
    85.  
    86.  
    87.  
    Anyway your code was pretty good and it works fine.
    Thanks for sharing the knowledge!

    EDIT: The script now works on a 3D space, and it can keep detecting collision for 2 seconds then it shuts itself off.
     
    Last edited: Mar 16, 2016
  9. lharoon

    lharoon

    Joined:
    Mar 31, 2016
    Posts:
    5
    Can I be a bother and ask for an example scene to see the script in action (& how objects might be set up)? I can't get the original poster's web demo to work.
     
    isa_martin likes this.
  10. Curaxu

    Curaxu

    Joined:
    Apr 28, 2016
    Posts:
    1
    hey, im trying to implement this in a 2d environment, but i cant seem to get the laser to move in the right direction, any tips? :/
     
  11. RobNewton

    RobNewton

    Joined:
    Sep 29, 2014
    Posts:
    1
    Thanks everyone for the great script. In the spirit of returning the favor for the next one to come along and find this, here is my contribution:

    I've added beam splitters. They bounce as you'd expect but also pass through acting just like a real beam splitter. The way it works is at the hit point we reflect then instantiate another copy of the laser with the attached script. This new laser is aligned with the inbound path. That new beam continues to raycast and bounce or split since it's just running another copy of the same script.

    I also wanted to be able to move objects in realtime and have the laser react accordingly, so I changed the looping mechanism and added an update frequency so you can tune it based on the number of bounces/splits expected (if it's bogging down).







    Code (CSharp):
    1.  
    2. using UnityEngine;
    3. using System.Collections;
    4. using System.Collections.Generic;
    5.  
    6. [RequireComponent(typeof(LineRenderer))]
    7. public class BouncingLaser : MonoBehaviour
    8. {
    9.     public float updateFrequency = 0.1f;
    10.     public int laserDistance;
    11.     public string bounceTag;
    12.     public string splitTag;
    13.     public string spawnedBeamTag;
    14.     public int maxBounce;
    15.     public int maxSplit;
    16.     private float timer = 0;
    17.     private LineRenderer mLineRenderer;
    18.  
    19.     // Use this for initialization
    20.     void Start()
    21.     {
    22.         timer = 0;
    23.         mLineRenderer = gameObject.GetComponent<LineRenderer>();
    24.         StartCoroutine(RedrawLaser());
    25.     }
    26.  
    27.     // Update is called once per frame
    28.     void Update()
    29.     {
    30.         if (gameObject.tag != spawnedBeamTag)
    31.         {
    32.             if (timer >= updateFrequency)
    33.             {
    34.                 timer = 0;
    35.                 //Debug.Log("Redrawing laser");
    36.                 foreach (GameObject laserSplit in GameObject.FindGameObjectsWithTag(spawnedBeamTag))
    37.                     Destroy(laserSplit);
    38.  
    39.                 StartCoroutine(RedrawLaser());
    40.             }
    41.             timer += Time.deltaTime;
    42.         }
    43.     }
    44.  
    45.     IEnumerator RedrawLaser()
    46.     {
    47.         //Debug.Log("Running");
    48.         int laserSplit = 1; //How many times it got split
    49.         int laserReflected = 1; //How many times it got reflected
    50.         int vertexCounter = 1; //How many line segments are there
    51.         bool loopActive = true; //Is the reflecting loop active?
    52.  
    53.         Vector3 laserDirection = transform.forward; //direction of the next laser
    54.         Vector3 lastLaserPosition = transform.localPosition; //origin of the next laser
    55.  
    56.         mLineRenderer.SetVertexCount(1);
    57.         mLineRenderer.SetPosition(0, transform.position);
    58.         RaycastHit hit;
    59.  
    60.         while (loopActive)
    61.         {
    62.             //Debug.Log("Physics.Raycast(" + lastLaserPosition + ", " + laserDirection + ", out hit , " + laserDistance + ")");
    63.             if (Physics.Raycast(lastLaserPosition, laserDirection, out hit, laserDistance) && ((hit.transform.gameObject.tag == bounceTag) || (hit.transform.gameObject.tag == splitTag)))
    64.             {
    65.                 //Debug.Log("Bounce");
    66.                 laserReflected++;
    67.                 vertexCounter += 3;
    68.                 mLineRenderer.SetVertexCount(vertexCounter);
    69.                 mLineRenderer.SetPosition(vertexCounter - 3, Vector3.MoveTowards(hit.point, lastLaserPosition, 0.01f));
    70.                 mLineRenderer.SetPosition(vertexCounter - 2, hit.point);
    71.                 mLineRenderer.SetPosition(vertexCounter - 1, hit.point);
    72.                 mLineRenderer.SetWidth(.01f, .01f);
    73.                 lastLaserPosition = hit.point;
    74.                 Vector3 prevDirection = laserDirection;
    75.                 laserDirection = Vector3.Reflect(laserDirection, hit.normal);
    76.                
    77.                 if (hit.transform.gameObject.tag == splitTag)
    78.                 {
    79.                     //Debug.Log("Split");
    80.                     if (laserSplit >= maxSplit)
    81.                     {
    82.                         Debug.Log("Max split reached.");
    83.                     }
    84.                     else
    85.                     {
    86.                         //Debug.Log("Splitting...");
    87.                         laserSplit++;
    88.                         Object go = Instantiate(gameObject, hit.point, Quaternion.LookRotation(prevDirection));
    89.                         go.name = spawnedBeamTag;
    90.                         ((GameObject)go).tag = spawnedBeamTag;
    91.                     }
    92.                 }
    93.             }
    94.             else
    95.             {
    96.                 //Debug.Log("No Bounce");
    97.                 laserReflected++;
    98.                 vertexCounter++;
    99.                 mLineRenderer.SetVertexCount(vertexCounter);
    100.                 Vector3 lastPos = lastLaserPosition + (laserDirection.normalized * laserDistance);
    101.                 //Debug.Log("InitialPos " + lastLaserPosition + " Last Pos" + lastPos);
    102.                 mLineRenderer.SetPosition(vertexCounter - 1, lastLaserPosition + (laserDirection.normalized * laserDistance));
    103.  
    104.                 loopActive = false;
    105.             }
    106.             if (laserReflected > maxBounce)
    107.                 loopActive = false;
    108.         }
    109.        
    110.         yield return new WaitForEndOfFrame();
    111.     }
    112. }
    113.  
     
    Last edited: Aug 23, 2016
  12. mdsrayyan

    mdsrayyan

    Joined:
    Apr 2, 2015
    Posts:
    1
    Thanks alot for the post guys, It was really helpful. Just to add @RobNewton , If you wanna update player dynamically with gameObject.

    Code (CSharp):
    1. // Use this for initialization
    2.     void Start()
    3.     {
    4.         timer = 0;
    5.     }
    6.  
    7.     // Update is called once per frame
    8.     void Update()
    9.     {
    10.         if (gameObject.tag != spawnedBeamTag) {
    11.             if (timer >= updateFrequency) {
    12.                 timer = 0;
    13.                 //Debug.Log("Redrawing laser");
    14.                 foreach (GameObject laserSplit in GameObject.FindGameObjectsWithTag(spawnedBeamTag))
    15.                     Destroy (laserSplit);
    16.  
    17.                 StartCoroutine (RedrawLaser ());
    18.             }
    19.             timer += Time.deltaTime;
    20.         } else {
    21.             mLineRenderer = gameObject.GetComponent<LineRenderer>();
    22.             StartCoroutine(RedrawLaser());
    23.         }
    24.     }
     
  13. Vasir_

    Vasir_

    Joined:
    Jan 5, 2013
    Posts:
    13
    Sorry to bump a old thread, but using Mdsraayan's version:

    Script works perfectly! I wanted it for a 2d game so I replaced the raycast with a 2draycast and all the vector3s to vector2s. Now, when I rotate the mirror as the game is played, the bouncing laser (not the part from the projector) kind of flickers in and out of existence. I am happy to post my code, but I was wondering if anyone already converted this to 2d?

    Would post a screenshot, but screenshot wouldn't show the flickering. I'd need a video and I don't think I have any screen capture software at the moment.
     
  14. isa_martin

    isa_martin

    Joined:
    Oct 10, 2017
    Posts:
    1
    Hey Vasir_,

    Well, I fixed the problem of the ray's flickering.
    The problem actually is that the laser collide with the mirror that reflected it, it get stuck inside the mirror basically.
    So just add some points in the last laser position like this:

    lastLaserPosition = hit.point + (laserDirection*10);

    I hope this is useful.

    :po_O:rolleyes::D:);):cool::(:confused::eek::mad::oops:
     
    jiteshmule07 likes this.
  15. The3DPrintist

    The3DPrintist

    Joined:
    Feb 13, 2016
    Posts:
    1
    I cant get this script to split the laser more than three times, does anyone know why?
     
  16. jingray

    jingray

    Joined:
    Feb 6, 2015
    Posts:
    53
    sometime not working for some angle. no reflection in 2D.
    may be lastLaserPosition fail.
     
  17. LevyEBerg

    LevyEBerg

    Joined:
    Oct 9, 2018
    Posts:
    1
    Nice! but the only thing wrong is when a split hit's it's it self it creates in infinite loop that crashes unity.
     
  18. faizan_raza93

    faizan_raza93

    Joined:
    Dec 21, 2018
    Posts:
    9
    yes I am having a same issue .Did you solved it ?
     
  19. Major_Lag

    Major_Lag

    Joined:
    Sep 12, 2019
    Posts:
    1
    Wanted to share my own 2d version. let me know any optimizations you may find:

    Code (CSharp):
    1. using System.Collections;
    2. using System.Collections.Generic;
    3. using UnityEngine;
    4.  
    5. public class Laser : MonoBehaviour
    6. {
    7.     public int maxReflectionCount = 5;
    8.     public int maxSplitCount = 5;
    9.     public float maxStepDistance = 100;
    10.  
    11.     private void OnDrawGizmos()
    12.     {
    13.         if (!Application.isPlaying)
    14.         {
    15.             return;
    16.         }
    17.         DrawPredictedReflection(this.transform.position, this.transform.up, maxReflectionCount, maxSplitCount);
    18.     }
    19.  
    20.     void DrawPredictedReflection(Vector2 position, Vector2 direction, int reflectionsRemaining, int splitsRemaining)
    21.     {
    22.         var gizmoHue = (reflectionsRemaining / (this.maxReflectionCount + 1f));
    23.         Gizmos.color = Color.HSVToRGB(gizmoHue, 1, 1);
    24.         RaycastHit2D hit2D = Physics2D.Raycast(position, direction, maxStepDistance);
    25.  
    26.         if (hit2D) //did we hit somthing?
    27.         {
    28.             Gizmos.DrawLine(position, hit2D.point);
    29.             Gizmos.DrawWireSphere(hit2D.point, 0.25f);
    30.  
    31.             if (hit2D.transform.gameObject.tag == "Receiver")
    32.             {
    33.                 Debug.Log("Receiver hit");
    34.             }
    35.             if (hit2D.transform.gameObject.tag == "Mirror") //mirror hit. set new pos where hit. reflect angle and make that new direction
    36.             {
    37.                 Debug.Log("Mirror Hit");
    38.                 direction = Vector2.Reflect(direction, hit2D.normal);
    39.                 position = hit2D.point + direction * 0.01f;
    40.  
    41.                 if (reflectionsRemaining > 0)
    42.                     DrawPredictedReflection(position, direction, --reflectionsRemaining, splitsRemaining);
    43.             }
    44.             if (hit2D.transform.gameObject.tag == "Splitter") //reflect and go ahead
    45.             {
    46.  
    47.                 Debug.Log("Splitter hit");
    48.                 if (splitsRemaining > 0)//go ahead
    49.                 {
    50.                     Debug.Log("Splitting");
    51.                     Vector2 splitPosition = new Vector2();
    52.                     Vector2 findOppBegin = hit2D.point + direction * 1f;
    53.                     RaycastHit2D[] findOppHit = Physics2D.RaycastAll(findOppBegin, -direction);
    54.                     for ( int i = 0;  i <= findOppHit.Length; i++) //findOppHit[i].transform.gameObject != hit2D.transform.gameObject
    55.                     {
    56.                         if (findOppHit[i].transform.gameObject == hit2D.transform.gameObject)
    57.                         {
    58.                             splitPosition = findOppHit[i].point + direction * 0.01f;
    59.                             break;
    60.                         }
    61.                     }
    62.  
    63.                     DrawPredictedReflection(splitPosition, direction, reflectionsRemaining, --splitsRemaining);
    64.                 }
    65.                
    66.            
    67.                 direction = Vector2.Reflect(direction, hit2D.normal);
    68.                 position = hit2D.point + direction * 0.01f;
    69.                 if (reflectionsRemaining > 0)//reflect too
    70.                 {
    71.                     DrawPredictedReflection(position, direction, --reflectionsRemaining, splitsRemaining);
    72.                 }
    73.             }
    74.         }
    75.     }
    76. }
     
    Last edited: Jan 19, 2020
  20. DanielDouglas

    DanielDouglas

    Joined:
    Mar 21, 2020
    Posts:
    4
    PLEASE HELP ME!
    my goal is create a line from point A to point B, in point B (hit.point) i need to create a new line (or colorize a section in the same line) from point B to point C, but maintein de line before A-B. the new line need to give the color from material hit. like image:

     
  21. Sa1vad0r

    Sa1vad0r

    Joined:
    Oct 26, 2023
    Posts:
    1

    First time uploading here. Your code didn't seem to work very well for me so I updated a few things to fit in my project. This code updates the positionCount so that the amount of mirrors that the laser is going to hit doesn't become a problem. It stops whenever it hits a wall and is constantly updated every frame. I am pretty new so I had to look up a bunch of LineRenderer tutorials. For the LineRenderer to work well and not spit errors, put the amount of positions to one, the code will change the necessary amount when needed. Also thanks everyone that posted codes it really helped and feel free to point out any errors.