Reputation: 11317
I have a List of GameObjects and I want to compare each gameobject to the List gameobjects and if they are not the same then to add it as result. The name can be the same but enough if one parameter like position or rotation is not the same then add the gameobject as result.
using System.Collections;
using System.Collections.Generic;
using System.Reflection;
using UnityEditor;
using UnityEngine;
namespace AutocompleteSearchField
{
public class DatabaseSearch : EditorWindow
{
[MenuItem("Window/Autocomplete Searchbar/Database Search")]
static void Init()
{
GetWindow<DatabaseSearch>("DataBse Search").Show();
}
[SerializeField]
AutocompleteSearchField autocompleteSearchField;
private static SearchableEditorWindow hierarchy { get; set; }
private static List<GameObject> allobj = new List<GameObject>();
void OnEnable()
{
if (autocompleteSearchField == null) autocompleteSearchField = new AutocompleteSearchField();
autocompleteSearchField.onInputChanged = OnInputChanged;
autocompleteSearchField.onConfirm = OnConfirm;
}
void OnGUI()
{
GUILayout.Label("Search Hierarchy", EditorStyles.boldLabel);
autocompleteSearchField.OnGUI();
}
void OnInputChanged(string searchString)
{
autocompleteSearchField.ClearResults();
if (!string.IsNullOrEmpty(searchString))
{
allobj = new List<GameObject>();
allobj.AddRange(UnityEngine.SceneManagement.SceneManager.GetActiveScene().GetRootGameObjects());
foreach (GameObject obj in allobj)
{
if (HasAllComponents(obj, typeof(MeshRenderer), typeof(BoxCollider))
&& CompareTransformsData(obj) == false)
{
autocompleteSearchField.AddResult(obj.ToString());
}
}
}
}
void OnConfirm(string result)
{
var obj = AssetDatabase.LoadMainAssetAtPath(autocompleteSearchField.searchString);
Selection.activeObject = obj;
EditorGUIUtility.PingObject(obj);
}
public static bool HasAllComponents(GameObject gameObject, params System.Type[] types)
{
for (int i = 0; i < types.Length; i++)
{
if (gameObject.GetComponent(types[i]) == null)
return false;
}
return true;
}
public static bool CompareTransformsData(GameObject objToCompare)
{
List<GameObject> results = allobj;
bool identical = true;
foreach(GameObject obj in results)
{
if (GameObject.ReferenceEquals(obj, objToCompare))
{
return identical;
}
}
return identical;
}
public const int FILTERMODE_ALL = 0;
public const int FILTERMODE_NAME = 1;
public const int FILTERMODE_TYPE = 2;
public static void SetSearchFilter(string filter, int filterMode)
{
SearchableEditorWindow[] windows = (SearchableEditorWindow[])Resources.FindObjectsOfTypeAll(typeof(SearchableEditorWindow));
foreach (SearchableEditorWindow window in windows)
{
if (window.GetType().ToString() == "UnityEditor.SceneHierarchyWindow")
{
hierarchy = window;
break;
}
}
if (hierarchy == null)
return;
MethodInfo setSearchType = typeof(SearchableEditorWindow).GetMethod("SetSearchFilter", BindingFlags.NonPublic | BindingFlags.Instance);
object[] parameters = new object[] { filter, filterMode, false };
setSearchType.Invoke(hierarchy, parameters);
}
}
}
But it keep adding all the gameobjects even if identical.
Upvotes: 1
Views: 4203
Reputation: 1588
You are not getting desired result because of the comparers. You should not compare floating point values/Vectors/Quaternions using "==". As they are based on floats & many a times they wont be accurate enough. Even the cloned objects will have float values 1.000001 or 0.999999.
The better option would be for vectors use "Vector3.distance" or "Vector3.Equals" and for Quternions you can use "Quaternion.Angle" or Quaternion.Equals to check the corresponding result.
ie obj.transform.position.Equals(objToCompare.transform.position)
& obj.transform.quaternion.Equals(objToCompare.transform.quaternion)
. This should return the proper results but there is a chance that the results might not come up same
if that happens you can use
ie Vector3.Distance(obj.transform.position, objToCompare.transform.position) < "Margin of difference"
.
Quaternion.Angle(transform.rotation, rotation)<"Margin of difference"
You can specify your own value like for margin of difference you would allow.
Note: If you want less CPU intensive solution, you should use
(obj.transform.position - objToCompare.transform.position).sqrMagnitude
which is faster than .Distance because .Distance has to compute a square root, which is really slow.
Here are some links to follow up: Vector3 Compare Quaternion Compare
Update:
public static bool CompareTransformsData(GameObject objToCompare)
{
List<GameObject> results = allobj;
foreach (GameObject obj in results)
{
//Method 1 using Equal
if( obj.transform.position.Equals(objToCompare.transform.position) &&
obj.transform.rotation.Equals(objToCompare.transform.rotation))//Do confirm here if the vectors & quaternions are able to use equal comparer & result is satisfactory to your needs
{
return true;
}
//Method 2 using sqrmagnitude & Quaternion.angle
//Use this one if you need more acurate result and control on objects
//modify the 0.1f paramters for more accuracy and filtering
if ((obj.transform.position - objToCompare.transform.position).sqrMagnitude < 0.1f &&
Quaternion.Angle(obj.transform.rotation, objToCompare.transform.rotation) < 0.1f)//Do confirm here if the vectors & quaternions are able to use equal comparer & result is satisfactory to your needs
{
return true;
}
}
return false;
}
Use either one of them but don't use both.
Upvotes: 2