c# - 我如何检测有多少游戏对象具有某种 Material ?

标签 c# unity3d

所以我目前正在使用 C# 统一开发一款益智游戏。我确定玩家是否获胜的方式是一堆游戏对象是否具有相同的 Material 。如何确定有多少游戏对象附加了某种 Material ?

最佳答案

这段代码应该能帮到你。

当您调用此方法传递要检查的 Material 时,它会返回当前在场景中使用相同 Material 的游戏对象的数量。

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

}

[编辑]我看到你分享的代码示例,用于更改 Material 。

改为尝试:

if (col.GetComponent<MeshRenderer> ())
    col.GetComponent<MeshRenderer> ().sharedMaterial = mat;

这是因为在访问之前检查 GameObject 是否有该组件,即使您的解决方案可能不需要它,它也可以防止某些“空异常引用”的发生。 此外,使用 .sharedMaterial 是一个比使用 .material 更安全的选择,因为它创建了一个新的 Material 实例(我从@fredrik 的回答中更正了最后一个肯定-widerberg 因为我错了)。 最后一个技巧,如果你不知道,获取 Renderer 组件,允许你访问所有 Renderer 类型(例如 MeshRenderer, SkinnedMeshRenderer,...)。

希望对您有所帮助!

迭戈

关于c# - 我如何检测有多少游戏对象具有某种 Material ?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/50661586/

相关文章:

c# - 动态切换状态机 Unity C#

c# - Unity-如何检查主相机是否看到对象

c# - 我们可以在 .NET 中安全地执行核心关联吗?

C# DllIimport 非托管 C 代码应用程序 (exe) 文件抛出 AccessViolationException

c# - 将物体隐藏在看不见的墙后面

audio - Unity3D从粒子播放声音

c# - Vector3.Set 和 Rigidbody2D.velocity.Set 和功能无法正常工作

c# - 仅当从网络驱动器进行编译时,编译问题[“Root activity type is invalid”]

c# - 带整数表达式的 switch case

c# - sql server 数据库同步