Search Unity

Accessing a variable of a script that is assigned at runtime?

Discussion in 'Scripting' started by gevarre, Dec 30, 2016.

  1. gevarre

    gevarre

    Joined:
    Jan 19, 2009
    Posts:
    132
    Hi, so I've got a situation where I have several object that each have a unique script on them. The scripts can't be combined because they are different in function. Also on each object are other scripts that are the same, but they have to access the unique scripts. Because of this, I have to assign that unique script at runtime, like this:

    Code (CSharp):
    1. public Component uniqueScript;
    2. private string uniqueScriptName;
    3.  
    4. void Awake()
    5.     {
    6.         uniqueScriptName = gameObject.name + "_Script";
    7.         uniqueScript = gameObject.GetComponent(uniqueScriptName);
    8.     }
    So far, that works fine, and I hope it makes sense. The problem is, now in the other scripts that need to access the variables of that unique script, I get the following error:

    error CS1061: Type `UnityEngine.Component' does not contain a definition for `power' and no extension method `power' of type `UnityEngine.Component' could be found. Are you missing an assembly reference?

    This is still in the editor. I can't even get to the point of runtime because of course I can't assign the scripts until all the errors are cleared.

    So I guess the question is: if I'm assigning one of several scripts to an object at runtime, how do I write the other scripts so they can access variables on that script (after it's assigned) but not cause errors in the editor because it doesn't find that script yet?
     
  2. LaneFox

    LaneFox

    Joined:
    Jun 29, 2011
    Posts:
    7,529
    Well, first of all it looks like your uniqueScriptName will never be the component name which means the GetComponent will always fail.

    Second, what is this component actually supposed to do? If you have these other components already on the object then why cant you just GetComponent them instead of using this proxy script?
     
  3. gevarre

    gevarre

    Joined:
    Jan 19, 2009
    Posts:
    132
    I have a whole bunch of different vehicles. Each one contains a script that handles the ultimate movement, etc, so that one is the same across all of them. Each vehicle handles differently: not just changes to stats, but in how things are calculated. This is why there is a different script on each vehicle. The generic movement script then accesses the resulting output of the individual vehicles' calculation script. This is why the calculation script (the unique one) has to be assigned at runtime. Otherwise I would have to also have a unique version of each movement script, which will very quickly get very untidy.
     
  4. gevarre

    gevarre

    Joined:
    Jan 19, 2009
    Posts:
    132
    To clarify a bit, I've got one series of scripts that we'll call CalculationScript1, CalculationScript2, CalculationScript3, and so on. Each one assigned to a different vehicle.

    I have one other script called MovementScript. It's assigned to all vehicles.
    In MovementScript I'd like to do the following:

    Code (CSharp):
    1. public class MovementScript : MonoBehaviour
    2. {
    3.     public Script calculationScript;
    4.     private float variable1;
    5.  
    6.     void Update()
    7.     {
    8.         variable1 = calculationScript.variable;  
    9.         calculationScript.DoThis();
    10.     }
    11. }
    But of course there is no such thing as a "Script" variable. So I'm trying to find a workaround for it.

    And to back up a bit, I don't actually need to assign this at runtime. That's just what I'd read on different threads. Both scripts will already be on the vehicles, so I'm just searching for a way to assign the first one to the second one without having to rewrite that second script for each and every vehicle just to change that one line with the name of the first script.
     
  5. LaneFox

    LaneFox

    Joined:
    Jun 29, 2011
    Posts:
    7,529
    Why dont you just use Interfaces and do something like

    Code (csharp):
    1.  
    2. public ISpecialVehicle calculationScript;
    3.  
    4. void Start()
    5. {
    6.     calculationScript = GetComponent<ISpecialVehicle>();
    7. }
    8.  
    9. void Update()
    10. {
    11.     calculationScript.DoStuff();
    12. }
    13.  
     
    RavenOfCode likes this.
  6. gevarre

    gevarre

    Joined:
    Jan 19, 2009
    Posts:
    132
    Because each vehicle's calculation script is substantially different and therefore requires a different name.

    So "public ISpecialVehicle" isn't possible. it would have to be "public ISpecialVehicle1", "public ISpecialVehicle2", "public ISpecialVehicle3", and so on. Otherwise Unity throws an error because the name of the variable (ISpecialVehicle) doesn't match the name of the class it's trying to reference (public ISpecialVehicle1, public ISpecialVehicle2, public ISpecialVehicle3, etc).

    Thanks for the help, but I believe at this point that there is no way to do this. I'm just going to have to have a completely unique set of scripts on each vehicle. It's doable, but very messy. I was just searching for a way to tidy things up a bit.


     
  7. RavenOfCode

    RavenOfCode

    Joined:
    Apr 5, 2015
    Posts:
    869
    As @LaneFox said, use Interfaces. The scripts can have any name they want, as long as they have the same methods/variables as the interface.
     
  8. LaneFox

    LaneFox

    Joined:
    Jun 29, 2011
    Posts:
    7,529
    There is, and we're trying to tell you.

    If the unique scripts exist, then you can put an interface on them. If there is an interface, then you are able to communicate through the interface.

    Code (csharp):
    1. public Interface ISpecialVehicle // Here's your magical unique interface.
    2. {
    3.     public int someVariable {get;set;}
    4.     public string someString {get;set;}
    5.     public void UniqueControlMath();
    6. }
    Code (csharp):
    1. public class Vehicle57 : Monobehavior, ISpecialVehicle // Here's some random vehicle with unique stats
    2. {
    3.     public int someVariable {get;set;}
    4.     public string someString {get;set;}
    5.  
    6.     public void UniqueControlMath()
    7.     {
    8.         // Up equals down and multiple someVariable by 10,000!
    9.     }
    10. }
    Set those to whatever you want, they're now totally unique to Vehicle 57.

    Code (csharp):
    1. public class Vehicle83 : Monobehavior, ISpecialVehicle
    2. {
    3.     public int someVariable {get;set;}
    4.     public string someString {get;set;}
    5.  
    6.     public void UniqueControlMath()
    7.     {
    8.         // Left is Up and multiple input by someVariable!
    9.     }
    10. }
    Set those to whatever you want, they're now totally unique to Vehicle 83.

    Code (csharp):
    1.  
    2. // this is the only controller you need for an unlimited number of super-special-unique vehicles. It is vehicle-agnostic.
    3. public class MyTotallyGenericController : Monobehavior
    4. {
    5.     public ISpecialVehicle thingToControl;
    6.  
    7.     public void Start()
    8.     {
    9.         thingToControl = GetComponent<ISpecialVehicle>();
    10.     }
    11.     public void Update()
    12.     {
    13.         // doesn't even care what is in the method, just runs it.
    14.         thingToControl.UniqueControlMath(); // unique to whatever vehicle script its pointed at.
    15.     }
    16. }
     
    Last edited: Dec 31, 2016
  9. gevarre

    gevarre

    Joined:
    Jan 19, 2009
    Posts:
    132
    Oh, thanks. Sorry, I had never known about interfaces before, so I misread the word and didn't understand it. That looks like it should do the tricks.

    Thanks to all for the help :)