- Home /
Need help setting correct Y height for laser beam with 50 elements
K so I have a laser set up in my game which is using a Line Renderer which shoots up to 50 individual particles or "Elements" to create the visual laser effect. This allows the laser to kind of pulsate due to a "noise" variable causing the x and z positions to change positions slightly along the path.
Everything is working well except one thing. I'm not sure how to go about setting the Y height properly since each of the 50 elements need to have a custom y height. Currently the ray just keeps the same y-height as how it starts which works fine for some enemies but shoots over the head of others so I have to make the enemy colliders taller and it just looks unnatural when the laser isn't hitting their body.
I've tried some solutions but have been unable to get it work correctly so far. This kind of math is not my strong point and with the individual element system I'm not sure if it's even possible with my current system but I was hoping someone might have some answers and advice for me.
Example of the laser code which sets the offset positions (x, y, z) for each of the 50 elements. Not all 50 elements will be used if the laser hits a target before it's max range.
void RenderLaser()
{
//length = 50
for(int i = 0; i<length; i++)
{
//offset is a vector position for each of the 50 elements
//player will be facing the target with other controls
offSet.x = myTransform.position.x + i*myTransform.forward.x + Random.Range(-noise,noise);
offSet.z = i*myTransform.forward.z + Random.Range(-noise,noise) + myTransform.position.z;
//here is the problem I need to set the Y height correctly
//currently using
offSet.y = myTransform.position.y;
position[i] = offSet;
lineRenderer.SetPosition(i, position[i]);
}
So I have access to the gameObject that the laser is hitting, so I would think that I should be able to somehow set the y positions correctly based on what % of distance they are from the player to the enemy?
Right now I had it set up so RenderLaser() is called every Update() perhaps fixedUpdate() would be better for these calculations, not sure if it should matter it is a visual effect so Update should work?
I've tried a bunch of stuff trying to set the y height based on the start of laser position from the player and the enemy transform position, but like I said math is not my strong point and the unique elements are kinda throwing me off.
Examples of how I've tried to set y height:
//the laser destination position
laserTargetVector = damageHit.collider.gameObject.transform.position;
//distance from laser start to finish
float distanceToEnemy = Vector3.Distance (myTransform.position, laserTargetVector);
//attempt to get the y height change to calculate slope
float newOffSetYCalculation = myTransform.position.y - laserTargetVector.y;
//I would think I should be able to solve with just the 3 pieces of info above but I'm not quite getting it seems like
//Here's another example of something I've tried I think this is the closest solution I've had
//but there's so many comments from all the things I've tried
//things getting really messy to keep track of
float slopeRatio = (myTransform.position.y - laserTargetVector.y)/(myTransform.position.x - laserTargetVector.x);
offSet.y = myTransform.position.y - (slopeRatio*i);
I think those are some decent examples of what I'm trying to do. I just feel like I'm a bit out of my league mathematically here. It seems like I should be able to use the slope ratio in relation to my offset.y position to do this. The trouble seems to be that I'm not sure how to determine the y position for each of the 50 elements accurately. I need to determine the % of distance each y particle is from the player to enemy to determine height.
I'm not sure if this is possible with the element system since I'm not sure if they are always spaced out consistent distances since this is called from Update, and since it's not always 50 elements if the laser doesn't go the full length it makes things even more complicated.
I'm thinking maybe I need to get the distance of every y particle before setting the height, so set the x and z position first then get that position to calculate y height?
I dunno this is very complicated for me hopefully someone can help!
Essentially I just want the unique particles to follow the exact path a normal line renderer would be from the player's hand to the enemies body. I know how to do this but not with the 50 element line renderer thing I'm trying to work with.
Answer by mattmanj17 · Oct 23, 2013 at 01:22 AM
You could calculate the positions like this.
1.Calculate the "ideal" line between the source of the lazer and its target (target.position-transform.position).
2.For the " i'th " point in the line, assign it the position i*(ideal/50). At this point the line renderer is just a straight line from the source to the target.
3.Add a random "noise" vector to each point.
An example script using this method below:
using UnityEngine;
using System.Collections;
public class laserScript : MonoBehaviour {
public Transform target;
public float noise =5f;
private LineRenderer laser;
void Awake(){
laser=GetComponent<LineRenderer>();
}
void Update(){
render_line();
}
void render_line(){
for(int i=0;i<50;i++){
laser.SetPosition(i,calculateIthPosition(i));
}
}
Vector3 calculateIthPosition(int i){
Vector3 ideal=(target.position-transform.position);
Vector3 ithIdeal = i*(ideal/50);
return transform.position+(ithIdeal+noiseVector());
//I was getting some weird results with just "ithIdeal+noiseVector()",
//but i think that was because I had
//"use world space" on in the line renderer
}
Vector3 noiseVector(){
return (Random.onUnitSphere*noise);
}
}
and here is a picture of the code working
is this the sort of effect you were going for?
P.S. Your idea is very clever. I would have never thought to use a line renderer like that.
Thank you so much for this solution that seems to make a lot of sense and nice example! Looks like you already got it working!
I wish I could take credit for idea to use the line renderer like this, I agree it's a really cool application! I got the idea though from a poster on these forums, if I remember correctly he was basically just posting a really nice laser script example and said people were free to use it in their own projects!
I just found the post gotta give credit where it's due:
http://forum.unity3d.com/threads/122500-Laser-Beam-Script-in-C
$$anonymous$$ I was able to implement this solution with just some $$anonymous$$or tweaks for my system!
$$anonymous$$ost importantly I had to replace:
Vector3 ithIdeal = i*(ideal/50);
with:
Vector3 ithIdeal = i*(ideal/length);
And I think since your guys answers were so good I'll include some more of the code that helps get the length, I didn't realize it was so important to the solution probably should have included that in my first post.
So in the function RenderLaser() there is an immediate function call that deter$$anonymous$$es the length.
maxLengthReal = 51;
void RenderLaser()
{
UpdateLength();
//remaining RenderLaser() code
)
//this code is a little excessive and seems to work even if I remove certain lines...
//might be useful to others though and is required for my system to work
void UpdateLength()
{
RaycastHit[] hit;
hit = Physics.RaycastAll(startLaserCollisionTransform.position, startLaserCollisionTransform.forward, maxLengthReal, ignoreLaserBeam$$anonymous$$ask & enemyRigidBody$$anonymous$$ask & ignorePlayer$$anonymous$$ask);
int i = 0;
while(i < hit.Length)
{
//*** SEE$$anonymous$$S TO WOR$$anonymous$$ FINE WITHOUT THIS LIN$$anonymous$$..
length = (int)$$anonymous$$athf.Round(hit[i].distance) +2;
position = new Vector3[length];
lineRenderer.SetVertexCount(length);
//*** SEE$$anonymous$$S TO WOR$$anonymous$$ FINE WITHOUT THIS LIN$$anonymous$$..
lineRenderer.SetPosition(1, new Vector3(0,0, 100));
i++;
// this return makes laser not go through multiple objects
return;
}
if (Player$$anonymous$$oveScript.playerLaserBeamBool == true)
{
length = (int)maxLength;
position = new Vector3[length];
lineRenderer.SetVertexCount(length);
}
}
I also added one bool condition to deter$$anonymous$$e whether to call the function:
lineRenderer.SetPosition(i,calculateIthPosition(i));
Based on what the laser hits it either calls that function or executes the code I had before to shoot straight.
The system appears to be working perfectly now! So happy thanks for all the help guys!
Answer by robertbu · Oct 23, 2013 at 01:31 AM
I have to agree with @mattmanj17. Your idea is clever. Here is my take at a solution. Before you attempt to integrate it into your app, test it in a clean scene to make sure it is what you are going for:
Create a game object near the camera for your fire point.
Add a LineRenderer component to the game object. Set the material and width as appropriate.
Add this script.
Put an object in the scene to act as a target.
Initialize the 'target' of the script in the inspector by dragging and dropping the target game object from hierarchy onto the 'target' variable.
Hit play. Move the target around in the inspector.
using UnityEngine; using System.Collections; public class Laser : MonoBehaviour { public int length = 50; public float noise = 0.1f; public Transform target; private LineRenderer lineRenderer; void Start () { lineRenderer = GetComponent<LineRenderer>(); lineRenderer.SetVertexCount (length+1); } void Update() { RenderLaser(transform.position, target.position); } void RenderLaser(Vector3 startPos, Vector3 endPos) { Vector3 targetVector = endPos - startPos; float lineLength = targetVector.magnitude; targetVector = targetVector.normalized * lineLength / length; Vector3 ortho = Vector3.Cross (targetVector, Vector3.up).normalized; Vector3 ongoing = startPos; lineRenderer.SetPosition(0, startPos); for(int i = 1; i <= length; i++) { ongoing += targetVector; Vector3 offset = Quaternion.AngleAxis(Random.Range(0.0f, 360.0f), targetVector) * (ortho * Random.Range (0.0f, noise)); lineRenderer.SetPosition(i, ongoing + offset); } } }
Thanks! That sounds like an excellent way to debug this to make sure everything is working in all scenarios!
I'll let you guys know if I get this working in near future, going to try this very soon!
Your answer
Follow this Question
Related Questions
Bouncing Laser Beam 1 Answer
Perspective top down laser. 1 Answer
How to block a LineRenderer with a shield from a moving origin point 0 Answers
why can't Line Renderer catch movement of camera? 0 Answers
how to know when list is empty? 3 Answers