Help creating function for changing vars in another script

Hello. I’ve been hunting around the forums for this, but haven’t had any luck. I’m sure there has got to be a straight forward way to do this, but I can’t find it. I have a “Weapon” script which has to regularly change variables in a “Projectile” script. The script is repetitive, and the only real thing that changes are the variables I need to access. I’m tired of constantly having to use getcomponent and was looking to streamline my increasingly bulky code. What I would like is to be able to create a function in my “Weapon” script which I can feed in the variable name in my “Projectile” script and change it. Any advice on how to pull this off would be appreciated. Sample code of how I imagine it functioning below.

//Weapon Script
void Update()
{
    ChangeProjectileVar(damage, explosion);
}

void ChangeProjectileVar(Projectile float, Projectile bool)
{
    float = 4;
    bool = true;
}

Like all inter-script interaction, all you need is:

  • Script A needs a reference to script B, which you will populate in the editor:
// inside of ScriptA:
public ScriptB myBScript;
  • Script B needs to have something public that script A can change:
// variable / field inside of ScriptB:
public int myFooInteger;

// function inside of ScriptB:
public void DoStuff( string reason)
{
}
  • Script A can then change it directly using the reference to B:
// here is ScriptA accessing something in ScriptB
myBScript.myFooInteger = 1;
myBScript.DoStuff( "Please");

This is basically The Reference Unity Pattern™ for inter-script reference. Live it, learn it, love it… tons of code operates with this fundamental pattern.

5 Likes

I don’t know what you are trying to do. Since you mention projectile, it’s something short lived I’m guessing, which means to get a reference to it’s script, you’ll need to use GetComponent at least once, even if you assign whatever GetComponent returns to a variable.

MyFancyScript foundScript = targetProjectile.GetComponent<MyFancyScript>();

foundScript.DoSomethingIn();

For example the above only requires GetComponent once. If it’s a persistent item, then you could create a public variable and drag and drop that item into it.

1 Like

Got it. Thanks for the feedback. I’m with you so far. I’ve taken this…

        if (isLaser3 == true)
        {
            projectile.GetComponent<Projectile>().isLaser3 = true;
            projectile.GetComponent<Projectile>().projectilePrefab3 = laserPrefab;
        }

and turned it into this…

    public Projectile projectileScript;

        WeaponType(isLaser3, projectileScript.isLaser3, projectileScript.projectilePrefab3, laserPrefab);


    void WeaponType(bool weapon, bool projectileWeapon, GameObject projectilePrefab, GameObject prefab)
    {
        if (weapon == true)
        {
            projectileWeapon = true;
            projectilePrefab = prefab;
        }
    }

but for some reason the variable aren’t being passed to the “Projectile” script now. No errors being thrown in the code. Any ideas to what I’m doing wrong?

I think I understand what you’re saying. Unfortunately the Projectile script is attached to a prefab that get’s instantiated, and prefabs won’t hang on to public variables like that. It’s why I’m having to pass the variables into the project script in the first place. Thanks for the feedback though.

I thought about it more and think I better understand what you were getting at. I tried putting the WeaponType method in the Projectile script, and calling it from the Weapon script, but it had the same effect as what I posted above. No errors, but the variables are not getting passed for some reason.

I understand it’s instantiated, which is why you can just use GetComponent once when you instantiate the object and assign the returned value, which is exactly what I said about projectiles. You can store references at a different time.

I’m not seeing enough of your code to understand what isn’t correct. In your WeaponType call, you are passing values to a method and then changing some of those values, but I think you’re misunderstanding how methods and variables work. Possibly some confusion on value types vs ref types as well.

Can you better explain what you are trying to do?

1 Like

Sorry I’m not making much sense. Due to the shear volume of code in this script, I’m trying not to post the whole thing because I don’t think it would be very helpful. I’ll try better to explain what I’m going for.

The Weapon script holds variables that I need to pass to the Projectile script upon instantiation. Due to all the variables, this is generating a lot of redundant code. Example…

    void Augment1()
    {
        if (isRifle1 == true)
        {
            projectile.GetComponent<Projectile>().isRifle1 = true;
            projectile.GetComponent<Projectile>().projectilePrefab1 = riflePrefab;
        }
        if (isGrenadeLauncher1 == true)
        {
            projectile.GetComponent<Projectile>().isGrenadeLauncher1 = true;
            projectile.GetComponent<Projectile>().projectilePrefab1 = grenadeLauncherPrefab;
        }
        if (isLandmine1 == true)
        {
            projectile.GetComponent<Projectile>().isLandmine1 = true;
            projectile.GetComponent<Projectile>().projectilePrefab1 = landminePrefab;
        }
        if (isRadialSpread1 == true)
        {
            projectile.GetComponent<Projectile>().isRadialSpread1 = true;
            projectile.GetComponent<Projectile>().projectilePrefab1 = radialSpreadPrefab;
        }
        if (isSpread1 == true)
        {
            projectile.GetComponent<Projectile>().isSpread1 = true;
            projectile.GetComponent<Projectile>().projectilePrefab1 = spreadPrefab;
        }
        if (isLaser1 == true)
        {
            projectile.GetComponent<Projectile>().isLaser1 = true;
            projectile.GetComponent<Projectile>().projectilePrefab1 = laserPrefab;
        }
    }

I’d like to create a method which allows me to pair this down, but for some reason, my attempts so far do not seem to update the variables in the projectile script. Thoughts?

PS: Also it’s probably worth mentioning that only one of the cases in the script above can be true at a time.

Admirable, definitely get away from patterns like the above.

I like the Factory Pattern when used in MonoBehavior land in order to ensure everything makes it over to the new object. Here is how I would do a projectile script:

Factory Pattern in lieu of AddComponent (for timing and dependency correctness):

https://pastebin.com/euGb7t3k

Ultimately all that augmentation choice stuff should probably live in its own AugmentationManager, which accepts a generically-augmentable item and something that says what augmentations you want, then takes care of it all. That way in the future if you go full Borderlands and have augmentable-everything, there is only one central place to do it all.

2 Likes

Whoa, ok. Gonna have to chew on this for a while. Obviously, lots of good info, just doesn’t all make sense to me at first blush. I’ll report back when I’ve had some time with it. Thanks for the reply.

1 Like

Here’s a simple question I could use some help with. Why does this…

public Projectile projectileScript;

projectileScript.isRifle1 = true;

not equal this…

            projectile.GetComponent<Projectile>().isRifle1 = true;
public Projectile projectileScript;

projectileScript.isRifle1 = true;
public GameObject projectile;
projectile.GetComponent<Projectile>().isRifle1 = true;

These are exactly the same assuming the component in the first code block is attached to the gameobject in the second block. They will both target the same instance for the Projectile script.

1 Like

Huh, weird. For whatever reason I’m not having any luck passing variables into the Projectile script with the first case.

Edit: I see what I’m missing. The code is not attached to the referenced object as you said.

1 Like

Yeah, super easy to do… I do it all the time. Put the script on this object and THINK I’m talking about that object but I’m actually not… it’s definitely a thing.

My best defense is what you see in my avatar: call your dog / cat / houseplant over and explain to them where everything is located. “The player controller is located on the player GameObject… oh no wait… it’s over on the main GameManager! Okay, that’s it, good boy, here’s a treat for you.” WOOF

4 Likes

Haha, yeah I’ve got some dogs that are good for that.

Inside ScriptA you also need GetComponent<>(); to reference it’s instance, like:

 //If the script is in the same GameObject
myBScript = gameObject.GetComponent<ScriptB>();

or

 //If the script is in a different GameObject
myBScript = GameObject.Find("AnotherGameObjectName").GetComponent<ScriptB>();