- Home /
Script for shooting with a LineRender (Laser Weapon)
I am modding Unity Tanks!, a game from a 2015 tutorial. In the game two players control two tanks on one keyboard and have to destroy the opponent by shooting shells at them. I want to add new secondary weapons for the players to use. for simplicity's sake I am going to assign them to dedicated secondary fire buttons.
I first created a WeaponHolder object where to store the weapons. I start working on a Laser Beam (a continuous laser), as a child item of the WeaponHolder. I drew it with a line renderer (I don't think I need to add colliders and rigidbody?). Online I found and attached this script for the laser behaviour.
public class LineLaser : MonoBehaviour
{
private LineRenderer lr;
// Start is called before the first frame update
void Start()
{
lr = GetComponent<LineRenderer>();
}
// Update is called once per frame
void Update()
{
lr.SetPosition(0, transform.position);
RaycastHit hit;
if (Physics.Raycast(transform.position, transform.forward, out hit))
{
if (hit.collider)
{
lr.SetPosition(1, hit.point);
}
}
else lr.SetPosition(1, transform.forward * 5000);
}
}
The way the original game is designed there is one tank prefab that gets cloned in two variants (red and blue) (GameManager.cs does it). the tank holds the shooting script while the shell is a separate prefab that holds a script for the impact explosion and damages count.
I would like to keep the same organisation for my mods, with one minor difference: the laser prefab must exist as a child of the WeaponHolder because the player will pickup a "?" block on the map in the style of Mario Kart, which will randomply pick a powerup weapon in the WeaponHolder.
That said, while the laser hold the script above, the tank should control the shooting (but fails) with the following:
public class WeaponLaser : MonoBehaviour
{
public int m_PlayerNumber = 1;
public Transform firePoint;
public GameObject laserPrefab;
private string SpecialButton;
private LineRenderer lr;
private void Start()
{
SpecialButton = "Special" + m_PlayerNumber;
lr = GetComponent<LineRenderer>();
}
// Update is called once per frame
void Update()
{
if(Input.GetButtonDown(SpecialButton))
{
Shoot();
}
void Shoot()
{
//shooting logic
Instantiate(laserPrefab, firePoint.position, Quaternion.identity);
laserPrefab.GetComponent<LineRenderer>.Invoke();
}
}
}
I know. It's definitely not .Invoke(), but I had to try with something... Help! Firepoint is an empty object on the tank cannon and laserPrefab obvs refers to the laser prefab (but does not follow the behavioural script attached? maybe?).
Little note: m_PlayerNumber refers to the way the game handles cloning and, here specifically, the 2-in-1 input system. This is also giving me problems, but so far I would be content if even one single tank was able to shoot this laser.
If I manage to solve this I will probably come back here to also deal with the laser impact and explosion, but so far please help me fix this one here! :)
Answer by unity_ek98vnTRplGj8Q · Apr 07, 2020 at 08:15 PM
First, a couple notes... make sure your Shoot() method is outside of your Update method, otherwise the compiler will complain. Also for these lines
Instantiate(laserPrefab, firePoint.position, Quaternion.identity);
laserPrefab.GetComponent<LineRenderer>.Invoke();
Instantiate will create a copy of laserPrefab and put it in the world. Using laserPrefab on the following line will use the original (which probably doesn't exist in your scene), not the copy that does exist in your scene. If you want to access the object that Instantiate creates, do something like
GameObject newLaser = Instantiate(blah blah);
newLaser.GetComponent<blah blah>();
So there are a few ways that you can do this, but be careful not to overcomplicate things. You mention that you would like to make the laser a prefab like the bullets that the main weapon shoots. While you can go down this path (I'll help if you shoot me a reply) I strongly recommend against it. There is only one laser per tank, so it would be easiest just to have the laser there all the time, but just have it disabled.
With that in mind I recommend making a gameobject that is your laser weapon (with your WeaponLaser script) and put it as a child of your weapon holder. You can set this weapon as inactive until you pick up the powerup box. Next I would make the laser object as a child of the weapon. It will hold the actual line renderer and the LineLaser script. Then you can modify your WeaponLaser script like so -
public class WeaponLaser : MonoBehaviour {
public int m_PlayerNumber = 1;
public Transform firePoint;
//Set this to the child laser object. This should not be a prefab.
public LineLaser laser;
private string SpecialButton;
private LineRenderer lr;
private void Start () {
SpecialButton = "Special" + m_PlayerNumber;
}
// Update is called once per frame
void Update () {
if (Input.GetButton (SpecialButton)) {
Shoot ();
}
else{
TurnOffLaser();
}
}
void Shoot () {
//Shooting logic
laser.gameObject.SetActive(true);
//Do damage here
//In your LineLaser script you could find the object that the raycast hits (hit.gameObject will give you the gameObject)
//Then you could grab that object here and do damage or whatever you want
}
void TurnOffLaser(){
laser.gameObject.SetActive(false);
}
}
Thanks for your help! I tried to do to this as you suggested.
I got the same hierarchy you suggested:
Also my WeaponLaser script is now:
public class WeaponLaser : $$anonymous$$onoBehaviour
{
public int m_PlayerNumber = 1;
public Transform firePoint;
//I am not sure about this
public Transform laser;
private string SpecialButton;
private void Start()
{
//This is the only way I found to reference children
laser = transform.Find("ActualLaser");
SpecialButton = "Special" + m_PlayerNumber;
}
// Update is called once per frame
void Update()
{
if (Input.GetButton(SpecialButton))
{
Shoot();
}
else
{
TurnOffLaser();
}
}
void Shoot()
{
//Shooting logic
laser.gameObject.SetActive(true);
//Do damage here
//In your LineLaser script you could find the object that the raycast hits (hit.gameObject will give you the gameObject)
//Then you could grab that object here and do damage or whatever you want
}
void TurnOffLaser()
{
laser.gameObject.SetActive(false);
}
}
But as a result only the original laser gets instantiated, it doesn't follow the FirePoint (which is a child of the Tanks) and it doesn't carry over to the other clone tanks (blue and red)
Ah ok almost there. First I would recommend changing this
//I am not sure about this
public Transform laser;
To public LineLaser laser
. This gives you access to the LineLaser script itself on the object (which you will probably need further down the road) and is more efficient than grabbing it later. Ins$$anonymous$$d of using Transform.Find
to grab the reference to it (which works), you can also drag the "ActualLaser" object from the hierarchy into the slot on your component.
As to why your laser is not following your tank, I think there may have been a misunderstanding on my part. I assumed the weaponholder would be a child of the tank as well (and I think you'll find that if you make it a child of your tank then this will work well). However if you had some different purpose in $$anonymous$$d for the weapon holder let me know and I can help you modify this script so that it works as intended...
It works! Thanks!
However I still have to figure out three things:How to lift the point from which the laser is shot (see image below)
How to have the laser shoot only last a couple of seconds after pressing the button
Why pressing the dedicated "SpecialButton" triggers the lasers of all tanks ins$$anonymous$$d of just tank clone 1
The laser now behaves correctly! Thanks so much! Unfortunately I was not able to solve the input configuration issue, but I opened a new question thread for that. You can visit it here if you are curious.
Your answer
Follow this Question
Related Questions
Fire Line Renderer from Camera 0 Answers
Laser Beam using Raycasting & Line Renderer 1 Answer
Draw line from Player to Mouse position 0 Answers
Reload Ammo is not working 1 Answer
My crosshair is moving the opposite of the mouse position. Why? 1 Answer