【问题标题】:How to load scripts, materials on GameObject in runtime in Unity3d?如何在 Unity3d 运行时在 GameObject 上加载脚本、材质?
【发布时间】:2014-09-13 23:42:41
【问题描述】:

我是 Unity3d 和 JS 脚本的新手,我需要帮助来简化我正在开发的应用程序中的场景和代码这是我的场景的概念:

有一个相机,可以看穿图层蒙版,三个平面。还有一种材质充当交换纹理,以及在每个平面上分别运行此交换的脚本。为了运行这个脚本,我使用了一个带有滚动列表按钮的 GUI,所以当按下 button1 时,相机只能看到 plane1,并且 script1 在这个平面上运行纹理 material1。通过按下相应的按钮,在其他 2 个平面上也会发生同样的情况。您可以在附图 1 中了解这个概念:

我需要你的帮助,是通过只保留一个平面供相机看到,并附加相应的脚本(1、2、3 等)、材质作为纹理(1、2、3)来简化这个场景等)在同一平面上,当玩家在运行时触摸相应的 GUI 按钮时。需要提一下,虽然 GUI 按钮位于一个名为“GUI”的脚本上,该脚本附加到一个空的游戏对象,而我需要动态附加的脚本和材料位于一个名为“动画师”的游戏对象上,作为相机的子对象。您可以在附图 2 中了解这个概念。

我相信这个功能可以通过使用例如来实现。 "gameObject.AddComponent ("myScript")" ,但由于我是菜鸟,我无法实现它。此外,我不知道如何在运行时在这个平面上应用不同的材料。所以我可能需要一些帮助和一个编码示例,因为我发现很难在没有看到示例的情况下仅遵循提示。

感谢大家花时间阅读这篇文章,希望有人能在这件事上帮助我。

编辑 1

好吧,为了让任何愿意帮助的人更全面,并在他们的回答之后帮助我,我发布了 Hierarchy 和 Inspector 的屏幕截图,以及 Unity 项目的代码 sn-p。

在图 3,层次结构视图中,我展示了脚本“ShowAnimation”位于游戏对象“Animation_Buttons_Controller”上。通过这个脚本,我想访问例如父游戏对象“AnimationCamera”中的游戏对象子“Animator2inScene2”。

在图 4 中,Inspector 视图中,我展示了材质元素“Texture_Animator2_Material”和脚本“ScriptTextureAnimator2”,该脚本仅应在运行时添加到此游戏对象上。

以下是脚本“ShowAnimation.js”中的代码 sn-p,它必须访问子游戏对象“Animator2inScene2”并在该子游戏对象上添加材质元素“Texture_Animator2_Material”和脚本“ScriptTextureAnimator2”:

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;

}
}

问题是在播放时,我在 gui 按钮上没有任何功能,并且在控制台中出现以下错误:

" NullReferenceException:对象引用未设置为对象的实例 ScriptTextureAnimator2.FixedUpdate()"

我知道,我错过了一些对编译至关重要的东西,但那可能是什么?请查看并发布关于我的编码的建议。谢谢。

【问题讨论】:

    标签: android unity3d unityscript


    【解决方案1】:

    非常感谢您从这个问题中制作图片,从而使阅读更加愉快:)

    要在运行时更改脚本,您需要销毁旧脚本并添加新脚本:

    销毁旧脚本:

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

    添加新脚本:

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

    在运行时更改材质:

    为您的材质准备全局变量并将其分配给检查器中的材质:

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

    然后您可以将您的材料更改为您选择的材料,如下所示:

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

    看到您的示例,这些脚本将被放入 GUI 按钮中。
    因此,您需要在 GUI 按钮脚本中创建一个公共游戏对象变量,以便您可以将您的飞机分配给它。
    请注意,在上面的代码中,我总是将 plane 写为基类,这就是我在 GUI 按钮中的公共游戏对象的意思。

    只需像这样声明 plane 游戏对象变量:

    var plane : GameObject;
    

    并在检查员处分配您的平面对象。

    希望这会有所帮助!

    编辑 1:
    该错误可能是由于您的代码 sn-p 错位造成的。
    你把你的函数放到OnGUI()了吗?
    我已经修改了您的代码以满足您的需求:

    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;
            }
        }
    }
    

    请注意,要将脚本和材质添加到您想要的游戏对象,如果您想从其他游戏对象执行此操作,则必须指定该游戏对象的变量。

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

    我还分配了您以前没有做过的材料。
    请注意Resources.Load 将在Assets 中搜索目录Resources,因此请确保将您的材料放在那里。

    【讨论】:

    • 您的编辑效果很好,并且在游戏对象子“Animator2inScene2”中添加了“材质”和“脚本”。有一点小事故。我是“ScriptTextureAnimator2”,有一个变量“theGameObject : GameObject”,用于获取在 Inspector 中添加的游戏对象“Animation_Buttons_Controller”。我试图通过在“ScriptTextureAnimator2”中编写以下行来在运行时添加它: function Start(){ myGameObject = GameObject.FindGameObjectWithTag("Player"); myGameObject=this.gameObject; }。我得到了在运行时添加的游戏对象“Animator1inScene2”。为什么?
    • 您的第一行代码是正确的(假设Animation_Buttons_Controller 已被标记为Player)。但是myGameObject 更改为它所在的游戏对象,即Animator2inScene2,因为您将这一行放在了myGameObject=this.gameObject。尝试删除该行,看看是否有效。
    【解决方案2】:

    添加脚本。

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

    最新版本的 Unity 允许在同一个游戏对象上使用多个脚本实例。

    添加材料。

    在您的项目中创建“Resources”文件夹,并在此文件夹中创建一个新材料“TestMaterial”。您可以使用资源例程在运行时加载此材料:

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

    您可以将子文件夹“材料”添加到“资源”中,并将 TestMaterian 放入此子文件夹中:

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

    请注意,此加载的材料是共享材料。 IE。如果您在运行时更改它,更改将保存在项目中。您仍然可以将此材质放在任何渲染器上,但您必须使用 sharedMaterial 属性:

    this.renderer.sharedMaterial = testMaterial;
    

    如果您想避免在运行时更改共享材质,您必须创建一个实例:

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

    现在您可以安全地更改此材质,并且可以使用材质属性将其放入渲染器:

    this.renderer.material = testMaterialInstance;

    【讨论】:

    • 感谢“sxl”和@Jay Kazama 的回答。我已尝试按照 sxl 的建议进行第一次尝试,但仍然可以运行。请查看我的编辑。添加了 Hierarchy 和 Inspector 的视图,以及编码的 sn-ps。
    猜你喜欢
    • 1970-01-01
    • 2021-07-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-06-24
    • 2012-09-15
    • 2020-06-22
    • 1970-01-01
    相关资源
    最近更新 更多