- Home /
Getter / Setter and Variable Scope Question?
I'm trying to write two classes, a Weapon class and a Bullet test. The weapon class should initialize the bullet to fit the parameters of the weapon (i.e. speed and such) and then fire the bullet. The problem is when I try to set the parameters for the bullet from the weapon it seems to have no effect on it. My Bullet class looks like this (with some unnecessary stuff cut out):
public class Bullet : MonoBehaviour {
private float speed = 10.0F; // The speed of the bullet
public float Speed {
get { return this.speed; }
set { this.speed = value; }
}
}
And the weapon class looks like this:
public class Weapon: MonoBehaviour {
private Bullet bullet;
public void Fire() {
Instantiate(this.bullet, this.transform.position, this.transform.rotation);
}
public void Start() {
this.bullet.Speed = 20.0F;
}
}
The problem is when the bullet comes out of the gun, its speed variable is set to 10, even though it should have been set to 20 by the Weapon class. The really weird thing which confuses me is that if I make the speed variable in the Bullet class public then the Bullet comes out with a speed of 20. I really do not understand why this is happening. I have a set method in the bullet class, so why does it matter if the variable itself is public if the setter method is? This is really confusing me, I almost feel like something is wrong with my compiler because I have never had this type of error happen. Any help is greatly appreciated!!!
Answer by Masterio · Feb 16, 2016 at 08:15 PM
You are setting the speed for the prefab not for the instantioned game object! You shouldn't init the variables in start in this case , you can do it directly after instantiate:
public class Weapon: MonoBehaviour
{
private Bullet bullet;
public void Fire()
{
// get hendler to the spawned bullet
GameObject bulletHandler = (GameObject) Instantiate(bullet, transform.position, transform.rotation);
if(bulletHandler != null)
{
// get Bullet script from the bullet game object
Bullet b = bulletHandler.GetComponent<Bullet>();
if(b != null)
b.Speed = 20f;
}
}
}
Right. However the problem is not that he adjusts the value of the prefab, but that this adjustment is not serialized and therefore has no effect when the object is instantiated. private variables are not serialized by default while public variables are.
If you mark the backing field with the "SerializeField" attribute it should also work.
[SerializeField]
private float speed = 10.0F;
@$$anonymous$$asterio:
Your code has an error and an unnecessary GetComponent call. The prefab is of type "Bullet" so the instantiated reference is also of type "Bullet". So the cast to "GameObject" will fail.
All you need to do is:
private Bullet bullet;
public void Fire()
{
Bullet b = (Bullet) Instantiate(bullet, transform.position, transform.rotation);
b.Speed = 20f;
}
Thank you very much for your response! The first time I wrote the Bullet and Weapon classes, I actually did it this way, by setting the speed of the bullet after initializing it. I thought that I could ins$$anonymous$$d do that in the Start menu so that the game doesn't have to initialize every bullet's speed but it makes sense that you cannot set the variables for prefabs. Thanks again!
No, it is possible to set variables in prefabs, although it's usually a strange approach and has some sideeffects. The problem is, that your variable isn't serialized since it's private. That's why it works when you make your variable public. Public variables are serialized by Unity.
If you make your variable serializable (by either making it public or by using [SerializeField]) you can set the variable before you instantiate the prefab and the instantiated object will copy that value.
However when you change the speed in the prefab you should keep in $$anonymous$$d:
Testing in the editor will permanently change the variable in the prefab asset stored in the project. Once the game is build such changes won't be permanent. They will be reverted when you restart the game.
If two or more weapons reference the same prefab you can't set the speed in Start since the weapon that got initialized last will actually have precedence as each weapon will override the same variable. It's usually simpler to create seperate prefabs for each bullet variant and set the speed in the inspector on the prefab itself. Hardcoded values are never a good approach.
Another way would be to add a "CreateBullet" method to the Bullet class which might look like this:
public Bullet CreateBullet(Transform aSpawnpoint, float aSpeed)
{
Bullet bullet = (Bullet)Instantiate(this, aSpawnpoint.position, aSpawnpoint.rotation);
bullet.Speed = aSpeed;
return bullet;
}
So inside your weapon you can do:
public void Fire() {
bullet.CreateBullet(transform, 20f);
}
So the method inside the prefab simply creates a copy of itself at the provided spawn point with the given speed. Yes, you can call methods on script which are on prefabs. Just keep in $$anonymous$$d that prefab objects are not in the scene but they are real objects in memory.
Your answer
![](https://koobas.hobune.stream/wayback/20220612064337im_/https://answers.unity.com/themes/thub/images/avi.jpg)
Follow this Question
Related Questions
Multiple Cars not working 1 Answer
Distribute terrain in zones 3 Answers
Getters/Setters with C# Array 1 Answer
Update Variables from script to script? 1 Answer
Get and Set difference 2 Answers