- Home /
How could you access a script of varying name?
I thought this would be easy, but it's turning out to be a multi-hour stumbler. I'm basically trying to define a variable that points to a script of varying names.
Suppose I have 10 cubes. Every cube has a script attached (mainCubeScript.js). This script contains all the functions common to each cube. Now, every cube also has one unique secondary script attached (cubeAScript.js, or cubeBScript.js, or cubeCScript.js etc.), all similar scripts with variations to give each cube unique behaviors providing different flavors of functions needed in mainCube. Every one of those scripts has identical function names, with varying code within. Now, what I really want, is for gameCubeScript to talk to the one secondary script attached which varies in name.
My challenge is to reference functions and variables in the scripts using a single handle. So the code in mainCubeScript.js might be:
private var hCube : cubeAScript;// this line is my problem (I think)
var iCube : int = 1;// setting this in the inspector on each cube allows mainCube to know which script is attached.
Start()
{
switch(iCube)
{
case 1: hCube = GetComponent("cubeAScript"); break;
case 2: hCube = GetComponent("cubeBScript"); break;
case 3: hCube = GetComponent("cubeCScript"); break;
(etc.)
}
// now we can use the functions inside the chosen script in other functions:
print(hCube.showID());
hCube.doInitialMove();//etc.
}
The typical examples in the documentation (var hCube = GameObject.Find("cubeAScript");) only work because the variable hCube is dynamically typed, but hence it has no script-wide scope. I have to prototype the variable hCube before using it because many functions in mainCube will need to access it. The problem is therefore that Unity then forces me to specify a variable type, which must be a specific script name. My challenge is that pesky prototype line: "var hCube : cubeAScript;" which prevents hCube from ever being linked to anything but cubeAScript.
It has been recommended in other variations of this question that I use "var hCube : MonoBehavior;" but then I get the errors "showID() is not a member of MonoBehaviour". It's been recommended also that I could make cube?Script subclasses of a master class, but then I get problems with some of the class functions and subclass functions getting ignored (different topic). Let's keep the focus of this question narrow: is there any way to prototype the variable hCube so that I can assign it by variable to different scripts as shown in the code above? Let's also assume that we simply need to structure the scripts this way without exploring why. All help welcome. Thanks!
Answer by Maarten · May 20, 2011 at 08:35 AM
You can create an Interface containing the function defenitions of your cube classes, so for example:
public interface ICube
{
public string GetId();
public void Rotate();
}
public class ACube : ICube()
{
//You have to implement your methods in this class
public string GetId()
{
return "";
}
public void Rotate()
{
}
}
Then you can retrieve your object by the following code:
ICube hcube = (ICube)GetComponent("cubeAScript");
And now on you can call every method that is defined in this interface.
Thanks $$anonymous$$aarten, switching everything to classes is a possibility, but I'm having all kinds of problems with functions no longer being taken into account when I do so. A problem for another thread perhaps. At the moment, the scripts are too long and elaborate and completely stable, but not when I switch them to classes. If only there was a simple "var hCube : Script" type I could simply use that means, this variable will take any type of script, that would make my current situation much easier. Thank you for your recommendation, I will probably use that next time.
If the cubes have a lot in common, subclassing is probably better (common stuff in Cube, tweaks in ACube, BCube.) But, an interface does the same thing, just with more cut&paste. If you think you want to learn what inheritance and subclasses are really all about, this is almost a perfect project to go back to later and try it.
I agree. I believe now that the ultimate solution is to build a project like this using genuine classes and subclasses, as there seems to be no way to point to a script of variable name. I'm using Switch statements as a workaround this time, but classes on the next project! Thanks!
Answer by demize2010 · May 20, 2011 at 08:34 AM
That sounds like quite a pesky problem... how about declaring your variable in line? I'm not sure if Unity will spit back that the variable has already been defined... but you could try something along these lines:
var iCube : int = 1;// setting this in the inspector on each cube allows mainCube to know which script is attached.
Start()
{
switch(iCube)
{
case 1: private var hCube : cubeAScript = GetComponent("cubeAScript"); break;
case 2: private var hCube : cubeBScript = GetComponent("cubeBScript"); break;
case 3: private var hCube : cubeCScript = GetComponent("cubeCScript"); break;
(etc.)
}
// now we can use the functions inside the chosen script in other functions:
print(hCube.showID());
hCube.doInitialMove();//etc.
}
Alternatively, have you thought about putting these scripts into a single cubeScript? If you have shared functions with just small changes to behaviour it may be less of a headache all round?
This is a noble attempt, demize2010, but Unity wholeheartedly rejects the multiple definitions of hCube which is unfortunately the center of the problem. Also, by defining it here, the scope of hCube would be local to Start() and I need it available throughout all other functions here, so it has to be prototyped before all functions before it gets assigned. Your other recommendation, merging these scripts into one and using lots of "switch" statements is at the forefront of my plan at the moment, unless a simple solution emerges. Thanks for the prompt feedback.
Darn, I figured it might throw a wobler... sorry I couldn't help more man.
Answer by Eric5h5 · May 20, 2011 at 03:20 PM
You should probably just use SendMessage instead.
I thought of that, but there are too many intricate interactions back and forth, it works simpler if only I can get references to each other. The secondary scripts can all talk to the main script because they know it by name, but the main script just can't talk to one of many secondary scripts unless I use a switch statement with many cases. Thanks!
Answer by Bravini · May 20, 2011 at 03:39 PM
you can name the scripts the same name as your cubes and then GetComponent(cube.name) or use a variable to differentiate the cubes and use GetComponent("CubeScript" + var).
Those are workarounds, for your case, I really suggest you make one script with all the variations and use a switch, or if you're using C# make an interface.
As Erich5h5 stated, you can simply solve it using a Sendmessage ot acces the method in whatever the script is named too, although it is slower than using getcomponent. http://answers.unity3d.com/questions/16061/whats-the-difference-between-sendmessage-and-getco.html
Indeed. I have now added many Switch statements that select from one of many script pointers at the key points. Less than ideal. The difficulty with the recommendation you list in the first line is that I have to assign the return value from GetComponent to something (say a variable named hCube), and that variable has to be defined to be of a particular type (var hCube : cubeAscript), and the only possibility for a type seems to be a specific script name which prevents it from being assignable to different scripts at run time.
Answer by EOrbiter · May 20, 2011 at 09:46 PM
This is my present solution, in mainCubeScript:
var iCube : int;// assign in inspector, different on each cube
var hCubeA : cubeAScript;
var hCubeB : cubeBScript;
var hCubeC : cubeCScript; // etc.
function Awake()
{
hCubeA = GetComponent(cubeAScript);
hCubeB = GetComponent(cubeBScript);
hCubeC = GetComponent(cubeCScript); // etc.
}
// throughout the functions of the rest of the script:
function spawnCube()
{
// complex common code
switch(iCube)
{
hCubeA.spawnCube(x, y, z);// unique spawn visual for cube A
hCubeB.spawnCube(x, y, z);// etc.
hCubeC.spawnCube(x, y, z);
}
}
Each cube then gets assigned mainCubeScript and one of the cube?Scripts. Unity doesn't generate any errors about the missing scripts (9 of 10 of the references are null) because they are not used at run time.
I added switch statements in the main script only. The reason I have kept the secondary scripts separate is that I'm not really working with cubes, but rather creatures of moderate complexity. Each secondary script links to many specific objects (creature parts) and manipulates them uniquely (widely different anatomies), yet all creatures share some common behaviors such as going to a place. Now in retrospect, I should've created classes, but alas, perhaps this exercise helps others contemplating this approach.