Hello Community,
Today I want to share with you my script for bouncing raycast lasers.WEBDEMO I am doing this for two main reasons:
I want feedback to make this evolve and become better.
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:
#pragma strict
@script RequireComponent(LineRenderer)
var dist : int; //max distance for beam to travel.
var lr : LineRenderer;
var winTag : String; // i was using for minigame, if laser touches this tag , win
var reftag :String; //tag it can reflect off.
var limit : int = 100; // max reflections
private var verti :int = 1; //segment handler don't touch.
private var iactive :boolean;
private var currot : Vector3;
private var curpos : Vector3;
function Start () {
}
function Update () {
lr.enabled = Input.GetKey(KeyCode.Space);
if (Input.GetKey(KeyCode.Space)||Input.GetKeyUp(KeyCode.Space)){
DrawLaser();
}
}
function DrawLaser()
{
verti = 1;
iactive = true;
currot = transform.forward;
curpos = transform.position;
lr.SetVertexCount(1);
lr.SetPosition(0,transform.position);
while(iactive)
{
verti ++;
var hit : RaycastHit;
lr.SetVertexCount(verti);
if (Physics.Raycast(curpos,currot,hit,dist))
{
//verti++;
curpos=hit.point;
currot = Vector3.Reflect(currot,hit.normal);
lr.SetPosition(verti-1,hit.point);
if (hit.transform.gameObject.tag != reftag){
iactive = false;
}
}
else
{
//verti++;
iactive = false;
lr.SetPosition(verti-1,curpos+100*currot);
}
if (verti >limit)
{
iactive = false;
}
}
}
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)
void DrawLaser () {
/*
public int laserDistance = 100; //max raycasting distance
public int laserLimit = 10; //the laser can be reflected this many times
public LineRenderer laserRenderer; //the line renderer
*/
int laserReflected = 1; //How many times it got reflected
int vertexCounter = 1; //How many line segments are there
bool loopActive = true; //Is the reflecting loop active?
Vector2 laserDirection = transform.up; //direction of the next laser
Vector2 lastLaserPosition = transform.position; //origin of the next laser
laserRenderer.SetVertexCount(1);
laserRenderer.SetPosition(0, transform.position);
while (loopActive) {
RaycastHit2D hit = Physics2D.Raycast(lastLaserPosition, laserDirection, laserDistance);
if (hit) {
laserReflected++;
vertexCounter += 3;
laserRenderer.SetVertexCount (vertexCounter);
laserRenderer.SetPosition (vertexCounter-3, Vector3.MoveTowards(hit.point, lastLaserPosition, 0.01f));
laserRenderer.SetPosition(vertexCounter-2, hit.point);
laserRenderer.SetPosition(vertexCounter-1, hit.point);
lastLaserPosition = hit.point;
laserDirection = Vector3.Reflect(laserDirection, hit.normal);
} else {
laserReflected++;
vertexCounter++;
laserRenderer.SetVertexCount (vertexCounter);
laserRenderer.SetPosition (vertexCounter - 1, lastLaserPosition + (laserDirection.normalized * laserDistance));
loopActive = false;
}
if (laserReflected > laserLimit)
loopActive = false;
}
}
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.
[RequireComponent(typeof(LineRenderer))]
public class BouncingLaser : MonoBehaviour
{
public int laserDistance;
public LineRenderer mLineRenderer;
public string bounceTag;
public int maxBounce;
private float timer = 0;
// Use this for initialization
void Start ()
{
}
// Update is called once per frame
void Update ()
{
if (Input.GetKeyDown ("space") && !mLineRenderer.enabled) {
timer = 0;
StartCoroutine ("FireMahLazer");
}
}
IEnumerator FireMahLazer ()
{
//Debug.Log("Running");
mLineRenderer.enabled = true;
int laserReflected = 1; //How many times it got reflected
int vertexCounter = 1; //How many line segments are there
bool loopActive = true; //Is the reflecting loop active?
Vector3 laserDirection = transform.forward; //direction of the next laser
Vector3 lastLaserPosition = transform.localPosition; //origin of the next laser
mLineRenderer.SetVertexCount (1);
mLineRenderer.SetPosition (0, transform.position);
RaycastHit hit;
while (loopActive) {
if (Physics.Raycast (lastLaserPosition, laserDirection, out hit, laserDistance) && hit.transform.gameObject.tag == bounceTag) {
Debug.Log ("Bounce");
laserReflected++;
vertexCounter += 3;
mLineRenderer.SetVertexCount (vertexCounter);
mLineRenderer.SetPosition (vertexCounter - 3, Vector3.MoveTowards (hit.point, lastLaserPosition, 0.01f));
mLineRenderer.SetPosition (vertexCounter - 2, hit.point);
mLineRenderer.SetPosition (vertexCounter - 1, hit.point);
mLineRenderer.SetWidth (.1f, .1f);
lastLaserPosition = hit.point;
laserDirection = Vector3.Reflect (laserDirection, hit.normal);
} else {
Debug.Log ("No Bounce");
laserReflected++;
vertexCounter++;
mLineRenderer.SetVertexCount (vertexCounter);
Vector3 lastPos = lastLaserPosition + (laserDirection.normalized * laserDistance);
Debug.Log ("InitialPos " + lastLaserPosition + " Last Pos" + lastPos);
mLineRenderer.SetPosition (vertexCounter - 1, lastLaserPosition + (laserDirection.normalized * laserDistance));
loopActive = false;
}
if (laserReflected > maxBounce)
loopActive = false;
}
if(Input.GetKey("space") && timer < 2)
{
yield return new WaitForEndOfFrame();
timer+=Time.deltaTime;
StartCoroutine("FireMahLazer");
}
else{
yield return null;
mLineRenderer.enabled = false;
}
}
}
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.
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.
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).
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.
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:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Laser : MonoBehaviour
{
public int maxReflectionCount = 5;
public int maxSplitCount = 5;
public float maxStepDistance = 100;
private void OnDrawGizmos()
{
if (!Application.isPlaying)
{
return;
}
DrawPredictedReflection(this.transform.position, this.transform.up, maxReflectionCount, maxSplitCount);
}
void DrawPredictedReflection(Vector2 position, Vector2 direction, int reflectionsRemaining, int splitsRemaining)
{
var gizmoHue = (reflectionsRemaining / (this.maxReflectionCount + 1f));
Gizmos.color = Color.HSVToRGB(gizmoHue, 1, 1);
RaycastHit2D hit2D = Physics2D.Raycast(position, direction, maxStepDistance);
if (hit2D) //did we hit somthing?
{
Gizmos.DrawLine(position, hit2D.point);
Gizmos.DrawWireSphere(hit2D.point, 0.25f);
if (hit2D.transform.gameObject.tag == "Receiver")
{
Debug.Log("Receiver hit");
}
if (hit2D.transform.gameObject.tag == "Mirror") //mirror hit. set new pos where hit. reflect angle and make that new direction
{
Debug.Log("Mirror Hit");
direction = Vector2.Reflect(direction, hit2D.normal);
position = hit2D.point + direction * 0.01f;
if (reflectionsRemaining > 0)
DrawPredictedReflection(position, direction, --reflectionsRemaining, splitsRemaining);
}
if (hit2D.transform.gameObject.tag == "Splitter") //reflect and go ahead
{
Debug.Log("Splitter hit");
if (splitsRemaining > 0)//go ahead
{
Debug.Log("Splitting");
Vector2 splitPosition = new Vector2();
Vector2 findOppBegin = hit2D.point + direction * 1f;
RaycastHit2D[] findOppHit = Physics2D.RaycastAll(findOppBegin, -direction);
for ( int i = 0; i <= findOppHit.Length; i++) //findOppHit[i].transform.gameObject != hit2D.transform.gameObject
{
if (findOppHit[i].transform.gameObject == hit2D.transform.gameObject)
{
splitPosition = findOppHit[i].point + direction * 0.01f;
break;
}
}
DrawPredictedReflection(splitPosition, direction, reflectionsRemaining, --splitsRemaining);
}
direction = Vector2.Reflect(direction, hit2D.normal);
position = hit2D.point + direction * 0.01f;
if (reflectionsRemaining > 0)//reflect too
{
DrawPredictedReflection(position, direction, --reflectionsRemaining, splitsRemaining);
}
}
}
}
}
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: