我该如何检测有多少个游戏对象使用了特定的材质?

7

我目前正在使用C#在Unity中开发一个益智游戏。我判断玩家是否获胜的方法是看一堆游戏对象是否具有相同的材质。如何确定有多少个游戏对象附有特定的材质?


你是指特定的纹理吗?还是特定的材质对象?如何更改材质?能展示一些代码吗 :) 或许使用计数器来代表玩家拥有的方块,并在每次移动后更新会更容易一些? - Fredrik Widerberg
@FredrikWiderberg 这是一个材质对象。这里是附加材料的代码,现在我只需要确定有多少个对象拥有该材料。 - Posterum
2个回答

4

以下是关于IT技术的翻译内容:

这段代码应该会对你有所帮助。

当你调用此方法并传入想要检查的材质时,它将返回当前在场景中使用相同材质的游戏物体数量。

    //-----------------------------------------------------------------------------
    // getObjsWithMat
    //-----------------------------------------------------------------------------
    public static int getObjsWithMat (Material mat) {
        Material m_DefaultMat = mat;
        int m_c = 0;

        GameObject[] AllObjs = Object.FindObjectsOfType<GameObject> ();
        foreach (GameObject Obj in AllObjs) {
            if (Obj.activeInHierarchy) {
                if (Obj.GetComponent <Renderer> ()) {
                    foreach (Material Mat in Obj.GetComponent <Renderer> ().sharedMaterials) {
                        if (Mat == m_DefaultMat)
                            m_c++;
                    }
                }
            }
        }

        return m_c;
    }

这是我在编辑器中实现并测试的代码。 既然我已经做好了,而我不需要它,我想它可能会在某个时候帮助到别人,所以在这里分享一下。 您需要将其复制到一个脚本中,最好叫做“GetStatsWindow.cs”,并且该脚本必须放在名为“Editor”的文件夹中。 您可以从菜单“Window/Find Objects with Material”中打开窗口。

//---------------------
//FrankGames production
//---------------------

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEditor;

public class GetStatsWindow : EditorWindow {

    private static Material m_DefaultMat = null;
    private static int m_c = -1;
    private static int m_c2 = 0;

    private static bool m_DisplayResult = false;
    private static Vector2 m_RectPos = Vector2.zero;

    private static GameObject[] m_ObjsFound = new GameObject[0];

    private static bool m_Working = false;

    //-----------------------------------------------------------------------------
    // ShowWindow
    //-----------------------------------------------------------------------------
    [MenuItem ("Window/Find Objects with Material")]
    public static void ShowWindow () {
        EditorWindow.GetWindow (typeof (GetStatsWindow));
    }

    //-----------------------------------------------------------------------------
    // OnGUI
    //-----------------------------------------------------------------------------
    void OnGUI () {
        EditorGUILayout.BeginVertical ();

        EditorGUILayout.HelpBox ("First, select a material in the 'Material to find' Input field.\nThan press the 'Find' Button.\nAfter some calculations (it could take some time, depending on your Hardware and the amount of objects and Materials that it has to check.", MessageType.Info);

        if (m_Working)
            EditorGUI.BeginDisabledGroup (true);

        m_DefaultMat = EditorGUILayout.ObjectField ("Material to find", m_DefaultMat, typeof (Material), true) as Material;

        if (m_DefaultMat == null && !m_Working)
            EditorGUI.BeginDisabledGroup (true);

        if (GUILayout.Button ("Find Objects")) {
            getObjWithMat ();
        }

        if (m_DefaultMat == null && !m_Working)
            EditorGUI.EndDisabledGroup ();

        if (m_Working)
            EditorGUILayout.LabelField ("Calculating...");

        if (m_c != -1) {
            if (GUILayout.Button ("Clear result") && EditorUtility.DisplayDialog ("Are you sure?", "Do you really want to clear the result of your search?", "Continue", "Cancel")) {
                m_DefaultMat = null;
                m_c = -1;
                m_c2 = 0;
                m_DisplayResult = false;
                m_RectPos = Vector2.zero;
                m_ObjsFound = new GameObject[0];
                m_Working = false;
            } else {

                EditorGUILayout.LabelField (m_c2 + " Objects have been checked!");
                EditorGUILayout.LabelField (m_c + " Objects with the '" + m_DefaultMat.name + "' Material have been found!");

                m_DisplayResult = EditorGUILayout.Toggle ("Display Results", m_DisplayResult);

                if (m_DisplayResult) {
                    EditorGUILayout.LabelField ("Objects found with '" + m_DefaultMat.name + "':");

                    m_RectPos = EditorGUILayout.BeginScrollView (m_RectPos);
                    EditorGUILayout.BeginVertical ();
                    EditorGUI.BeginDisabledGroup (true);
                    for (int i = 0; i < m_ObjsFound.Length; i++) {
                        EditorGUILayout.ObjectField ("[" + i + "] Object found", m_ObjsFound [i], typeof(GameObject), true);
                    }
                    EditorGUI.EndDisabledGroup ();
                    EditorGUILayout.EndVertical ();
                    EditorGUILayout.EndScrollView ();

                }
            }
        }

        if (m_Working)
            EditorGUI.EndDisabledGroup ();

        EditorGUILayout.EndVertical ();
    }

    //-----------------------------------------------------------------------------
    // getObjWithMat
    //-----------------------------------------------------------------------------
    public static int getObjWithMat (Material mat = null) {
        if (mat != null)
            m_DefaultMat = mat;
        else if (m_DefaultMat == null)
            return -1;

        m_Working = true;

        m_c = 0;
        m_c2 = 0;

        List<GameObject> Objs = new List<GameObject> ();

        GameObject[] AllObjs = Object.FindObjectsOfType<GameObject> ();
        foreach (GameObject Obj in AllObjs) {
            m_c2++;
            bool Found = false;
            if (Obj.activeInHierarchy) {
                if (Obj.GetComponent <Renderer> ()) {
                    foreach (Material Mat in Obj.GetComponent <Renderer> ().sharedMaterials) {
                        if (Mat == m_DefaultMat) {
                            Found = true;
                            m_c++;
                        }
                    }
                }
            }
            if (Found)
                Objs.Add (Obj);
        }

        m_ObjsFound = Objs.ToArray ();
        Objs.Clear ();

        m_Working = false;

        return m_c;
    }

}

[编辑] 我看到了你分享的代码示例,用于更改材料。
尝试使用以下代码:
if (col.GetComponent<MeshRenderer> ())
    col.GetComponent<MeshRenderer> ().sharedMaterial = mat;

这是因为在访问GameObject之前检查它是否具有组件,即使对于您的解决方案可能不必要,也可以防止发生一些“空异常引用”。 另外,使用.sharedMaterial比使用.material更安全,因为它创建材质的新实例(我从@fredrik-widerberg的回答中纠正了这个最后的断言,因为我是错误的)。 最后一个提示是,如果您不知道,获取Renderer组件允许您访问所有渲染器类型(如MeshRendererSkinnedMeshRenderer,...)。
希望对您有所帮助!
Diego

1
假设你有一个游戏对象列表,你可以这样做:
private int CountMaterials(Material material)
{
    int count = 0;
    foreach (var gameObject in gameObjects)
    {
        if (gameObject.GetComponent<MeshRenderer>().sharedMaterial == material)
           count++;
    }
    return count;
}

使用它的方式如下:
if(CountMaterials(mat) > CountMaterials(mat2)) 
{
    Debug.Log("1 Wins");
}
else
{
    Debug.Log("2 Wins");
}

编辑:在分配材质时,请确保使用sharedMaterial而不是material,因为分配material会创建材质的新实例。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接