所以我目前正在使用c#进行团结拼图游戏。我决定玩家是否获胜的方式是,如果一堆游戏对象拥有相同的材料。如何确定有多少游戏对象附加某种材料?
答案 0 :(得分:2)
此代码可以为您提供帮助。
当您调用此方法传递要检查的材质时,它会返回使用相同材质的当前在场景中处于活动状态的游戏对象的数量。
//-----------------------------------------------------------------------------
// 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”中打开edito中的窗口。
//---------------------
//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之前检查GameObject是否具有该组件,即使您的解决方案可能不需要它,也可以防止发生某些“Null Exception引用”。
此外,使用.sharedMaterial
是一个更安全的选项,使用.material
,因为它创建了一个新的材料实例(我从@ fredrik-wideberg的答案中纠正了这个最后的确认,因为我不正确)。
如果您不知道,最后一个提示是获取Renderer
组件,则可以访问所有呈现器类型(例如MeshRenderer
,SkinnedMeshRenderer
,...)。< / p>
我希望我有所帮助!
迭
答案 1 :(得分: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时,请务必使用sharedMaterial而不是材质,因为分配材质会创建材质的新实例。