How to load scripts, materials on GameObject in ru

2019-09-14 20:14发布

问题:

I'm new to Unity3d and in JS scripting and I need help to symplify a scene and code in the app I'm developing Here is the concept of my scene:

There is a Camera, that sees through layer masking, three planes. Also there is a material that acts as a swapping texture, and a script that runs this swapping respectively on each plane. In order to run this script, I use a GUI with a scroll list buttons, so when button1 is pressed, camera sees only plane1 and the script1 runs the texture material1 on this plane. The same happens on the other 2 planes by pressing the corresponding buttons. You can get a view of this concept in the attached image 1:

What I need your help for, is to simplify this scene by keeping only one plane for the camera to be seen, and attaching the respective scripts (1, 2, 3 etc), material as texture (1, 2, 3 etc) on this same plane when the player touches the corresponding GUI buttons, in runtime. Need to mention though that the GUI buttons are on a script named "GUI" attached to an empty GameObject and the script and materials I need to a dynamically attach, are on a GameObject named "Animator" as a child to a Camera. You can get a view of this concept in the attached image 2.

I believe this functionality can be achieved by using e.g. "gameObject.AddComponent ("myScript")" , but as I'm a noob, I cannot make it happen. Furthermore, I do not know how to apply the different material on this plane in runtime. So I need some help and a coding example maybe, as I find it difficult to follow only tips without seeing an example.

Thank you all for your time reading this post, hope someone be kind enough to help me on this matter.

Edit 1

Well, in order to make it more comprehensive for anyone willing help, and for me be helped afterwards by their answers, I'm posting screenshots of Hierarchy and Inspector, plus a code snippet of Unity project.

In image 3, view of Hierarchy, I'm showing that, script "ShowAnimation" is on gameObject "Animation_Buttons_Controller". Through this script, I want to access e.g. gameObject child "Animator2inScene2" in parent gameObject "AnimationCamera".

In image 4, view of Inspector, I'm showing the material element "Texture_Animator2_Material", and the script "ScriptTextureAnimator2" that should be added on this gameObject only in runtime.

Following is the code snippet in script "ShowAnimation.js" that has to access gameObject child "Animator2inScene2" and add material element "Texture_Animator2_Material" and the script "ScriptTextureAnimator2" on this gameObject child:

if (GUI.Button (Rect (2,2,100,20), "PlayAnimation2")) 
            {
            var addScriptOnPlane2 : GameObject[] = GameObject.FindGameObjectsWithTag("Animator");     
            //for(var addTextureScript2 : GameObject in addScriptOnPlane2)

if(addScriptOnPlane2)
            { 

            // Adds the script named ScriptTextureAnimator2 to the game object child "Animator2inScene2"
            gameObject.AddComponent("ScriptTextureAnimator2");

            // Adds the script named Texture_Animator2_Material to the game object child "Animator2inScene2"
            var addMaterial : Material;

            addMaterial = Resources.Load("Materials/Materials/Texture_Animator2_Material",typeof(Material)) as Material;

}
}

Problem is that on play, I get no function on gui button and the following error in console:

" NullReferenceException: Object reference not set to an instance of an object ScriptTextureAnimator2.FixedUpdate ()"

I know, I've missed something vital for compilation, but what may that be? Please take a look and post a recommendation on my codding. Thank you.

回答1:

I really appreciate you for making pictures out of this question, thus making it more enjoyable to read :)

To change your script at runtime, you need to destroy the old script and add the new one:

Destroy the old script:

Destroy(plane.GetComponent(TestScript)); // get component of type TestScript

Add the new script:

plane.AddComponent(TestScript); // add component of type TestScript

To change material at runtime:

Prepare global variables for your material and assign it with the materials from the inspector:

var material1 : Material;
var material2 : Material;
var material3 : Material;

Then you can just change your material to the material of your choice like this:

plane.renderer.material = material1; // change plane material to material1

Seeing your example, these scripts will be put inside the GUI Button.
So you'll need to make a public game object variable inside GUI button scripts so that you can assign your plane to it.
Notice that in the code above I always write plane as the base class, that is what I meant about the public game object in the GUI button.

Just declare the plane game object variable like this:

var plane : GameObject;

And assign it your plane object at the inspector.

Hope this helps!

EDIT 1:
That error is possibly caused by misplacement of your code snippet.
Have you placed your function to OnGUI()?
I have modified your code to match your needs:

function OnGUI () {
    if (GUI.Button (Rect (2,2,100,20), "PlayAnimation2")){
        var addScriptOnPlane2 : GameObject[] = GameObject.FindGameObjectsWithTag("Animator");     

        for(var addTextureScript2 : GameObject in addScriptOnPlane2)
        { 
            // Adds the script named ScriptTextureAnimator2 to the game object child "Animator2inScene2"
            addTextureScript2.AddComponent("ScriptTextureAnimator2");

            // Adds the script named Texture_Animator2_Material to the game object child "Animator2inScene2"
            var addMaterial : Material;

            addMaterial = GameObject.Instantiate(Resources.Load("Materials/Materials/Texture_Animator2_Material",typeof(Material))) as Material;

            addTextureScript2.renderer.material = addMaterial;
        }
    }
}

Note that to add the script and material to the gameobject you want, you must specify the variable of that gameobject if you want to do it from other gameobject.

gameObject.AddComponent("ScriptTextureAnimator2"); 
// gameObject = this.gameObject = Animation_Buttons_Controller gameobject
// change it to addTextureScript2.AddComponent("ScriptTextureAnimator2"); 

I have also assign the material which you haven't done before.
Please note that Resources.Load will search for directory Resources in Assets, so make sure you put your material in there.



回答2:

Adding scripts.

TestScript newScript = gameObject.AddComponent<TestScript>();

Newest versions of Unity allows to multiple instances of the script on the same game object.

Adding materials.

Create "Resources" folder in your project and create a new material "TestMaterial" in this folder. You can load this material in runtime using Resources routine:

Material testMaterial = Resources.Load( 
   "TestMaterial", 
   typeof(Material) 
) as Material;

You may add subfolders "Materials" to your "Resources" and place TestMaterian in to this subfolder:

Material testMaterial = Resources.Load( 
   "Materials/TestMaterial", 
   typeof(Material) 
) as Material;

Note that this loaded material is a shared material. I.e. if you change it in runtime the changes will be saved in project. You still may place this material on to any renderer but you must use sharedMaterial property:

this.renderer.sharedMaterial = testMaterial;

If you want to avoid changing shared material in runtime you must create an instance:

Material testMaterialInstance = GameObject.Instantiate( Resources.Load(
   "Materials/TestMaterial", 
   typeof(Material) 
) as Material ) as Material;

Now you can safely change this material and you can place in on to renderer using material property:

this.renderer.material = testMaterialInstance;