- Home /
Instantiate and initialize script
This is actually a continuation from another question I've made before and I'm sorry I couldn't find this in the documentation. I believe this must be there somewhere. What I did found was some other answers on similar subject (coincidentally, a lot of them from SisterKy), but I couldn't abstract them to work in this instance.
I have a script, called GroundCheck.js (can be seen on the other question).
Then I have other scripts calling it.
To each script in which I want to use it, I always use the exact same lines in the function Start to initialize its value, after declaring / instantiating it on global. Simplifying it here:
var groundCheck : GroundCheck = null;
function Start () { if (groundCheck == null) // This is in case the groundCheck isn't choosen within Inspector, as it should groundCheck = GetComponentInChildren(GroundCheck); if (groundCheck == null) // This is in case there is no Component in Children, just to avoid warning messages for debugging purposes groundCheck = gameObject.AddComponent(GroundCheck); }
Note this will have different results for running in different objects, and that's just the way this initialization should work. It's just a safe-back and automated way to associate an object to the variable.
I'm hoping to be able to write this initialization just in one place (probably within GroundCheck.js I suppose) rather than writing it repeated in every script where it's being instantiated like I'm doing now.
Hopefully using some kind of "OnConstruction" over GroundCheck.js or something to be able to declare it along the lines of:
var groundCheck = new GroundCheck();
Can something like this be done?
Why does every object in the hierarchy need a GroundCheck component with the same default values as its children? Where do you set the default values for GroundCheck?
The GroundCheck script/class actually have just a "isGrounded" boolean value that's set on runtime for each object. But the groundCheck instance is set to each specific component for each specific object. Some children objects (or maybe even one or none) inside the verifying script should have a GroundCheck attached. I'm just trying to automate the script and make it self contained.
Do you use this component together with another component? then you could either add that value to that component or let the depending component require the groundcheck component.
Answer by runevision · Mar 03, 2010 at 09:24 AM
Okay, so we're talking about the 4 lines of code you currently have in your Start method of (I assume) multiple different scripts, and the problem is that you have to repeat those 4 lines of code in many different scripts, like in say ScriptA and ScriptB. Is that correctly understood?
You can't have the initialization of ScriptA and ScriptB being done by GroundCheck unless GroundCheck knows about ScriptA and ScriptB. In order for GroundCheck to be able to handle ScriptA and ScriptB using the same code, ScriptA and ScriptB need to either inherit from a common class (like GroundCheckUser) or implement an interface (like IGroundCheckUser).
You could then make GroundCheck search for components that is of the type of that class or interface, and perform the necessary initialization on those components.
If you go for making a common parent class, you could also have the initialization inside that class.
Another method which does not require interfaces or parent classes is to make a function that performs the initialization, so you can cut your 4 lines down to one line (the function call). This function could for example be a static function in GroundCheck.
I think you got the question right now. I thought the script was already a class in itself, from the documentation. How would you employ that "common parent class" idea? I've tried static function, but it doesn't allow me to use non-static methods such as GetComponentInChildren. But that did gave me an idea...
Yes, ScriptA and ScriptB are classes by themselves, but they're TWO DIFFERENT classes, and you want the initialization in a single spot as far as I understand. As for the static method, you can use GetComponentsInChildren if you pass a variable to the static function with the object that GetComponentsInChildren should be called on.
@Rune, try using @ next time so I can get notified. StackExchange freaking limitations... Unless the comment is under my question / reply of course. Anyway, the "great" idea I had was using static and passing the parameters to the function. It looks awful and bloated, but it works and it does reduce a lot of lines. Next step would be reducing the parameters, but I have no idea how and don't care enough to go that far for now. This will be marked as answered thanks to the Watson effect. ;)
Answer by runevision · Mar 02, 2010 at 10:42 AM
Like spree mentioned, if you use have another script component that uses this GroundCheck component, you could let the depending component require the GroundCheck component using RequireComponent. This way, whenever you add a script component that uses the isGrounded variable in GroundCheck, the GroundCheck script component will automatically be added.
I was actually already using RequireComponent. $$anonymous$$aybe I did not make myself very clear on the question. I'll try to edit it.
Answer by cregox · Mar 09, 2010 at 09:46 PM
Thanks to Rune's answer I got to this solution, for GroundCheck.js. This is it at its full:
#pragma strict
@System.NonSerialized var isGrounded : boolean = false;
function OnTriggerStay () {isGrounded = true;} function OnTriggerExit () {isGrounded = false;}
function OnCollisionStay () {isGrounded = true;} function OnCollisionExit () {isGrounded = false;}
static function start (groundCheck : GroundCheck , getComponentInChildren : System.Object , transformFind : Transform , gameObject : GameObject ) : GroundCheck { if (groundCheck == null) // This is in case the groundCheck isn't choosen within Inspector, as it should groundCheck = getComponentInChildren;//GetComponentInChildren(GroundCheck); if (groundCheck == null) { if (transformFind != null) groundCheck = transformFind.GetComponent(GroundCheck); } if (groundCheck == null) // This is in case there is no Component in Children, just to avoid warning messages for debugging purposes groundCheck = gameObject.AddComponent(GroundCheck); return groundCheck; }
With that I don't get the line the way I wanted, but at least I get to do the initialization on Script A, B, C, etc, in just one (big bloated) line and the instantiation:
var groundCheck : GroundCheck;
function Start () { groundCheck = GroundCheck.start(groundCheck, GetComponentInChildren(GroundCheck), transform.Find("GroundCheckCollider"), gameObject); }