| Parameter | Description |
|---|---|
| flags | The hierarchy node flags. |
bool
true if any node has all of the flags set, false otherwise.
Gets whether or not all of the specified flags are set on any hierarchy node.
| Parameter | Description |
|---|---|
| node | The hierarchy node. |
| flags | The hierarchy node flags. |
bool
true if all of the flags are set, false otherwise.
Gets whether or not all of the specified flags are set on the hierarchy node.
The following example adds an action to a context menu that you can use to select the nearest common ancestor of the GameObjects you have selected in the Hierarchy window. The action appears in the Hierarchy Samples submenu of the context menu. The example uses HasFlags to check whether the common ancestor is itself selected, and if so, returns the ancestor's parent instead.
To use this example:
Assets/Editor/SelectCommonAncestor. Scripts in an Editor folder can use the Hierarchy module API without additional setup. If you save the script outside of an Editor folder, you must enable the Hierarchy built-in module in the Package Manager window, which also adds the module to your Player builds.using Unity.Hierarchy; using Unity.Hierarchy.Editor; using UnityEditor; using UnityEngine.UIElements;
namespace Unity.HierarchySamples.Editor { class SelectCommonAncestor { [InitializeOnLoadMethod] static void Initialize() { HierarchyWindow.PopulateContextMenu += OnPopulateContextMenu; }
static void OnPopulateContextMenu(HierarchyWindow window, HierarchyView view, HierarchyViewItem item, DropdownMenu menu) { menu.AppendAction("Hierarchy Samples/Select Common Ancestor", _ => { HierarchyNode commonAncestor = FindCommonAncestor(view);
if (commonAncestor != HierarchyNode.Null && commonAncestor != view.ViewModel.GetRoot()) { view.SetSelection(commonAncestor); view.Frame(commonAncestor); window.UpdateEditorSelection(); } }, _ => view.ViewModel.HasFlagsCount(HierarchyNodeFlags.Selected) < 2 ? DropdownMenuAction.Status.Disabled : DropdownMenuAction.Status.Normal); }
static HierarchyNode FindCommonAncestor(HierarchyView view) { HierarchyViewModel viewModel = view.ViewModel;
// The view is a DFS pre-order flattening, so each subtree occupies a contiguous // index range. Therefore LCA(set) == LCA(min-index node, max-index node) — one // linear scan replaces the previous O(N·D) pairwise fold. int minIndex = int.MaxValue; int maxIndex = int.MinValue; HierarchyNode leftmost = HierarchyNode.Null; HierarchyNode rightmost = HierarchyNode.Null;
foreach (HierarchyNode node in viewModel.EnumerateNodesWithFlags(HierarchyNodeFlags.Selected)) { int index = viewModel.IndexOf(node); if (index < minIndex) { minIndex = index; leftmost = node; } if (index > maxIndex) { maxIndex = index; rightmost = node; } }
if (leftmost == HierarchyNode.Null) return HierarchyNode.Null;
HierarchyNode lca = FindPairwiseLCA(viewModel, leftmost, rightmost);
// A selected node isn't considered its own ancestor, so return its parent instead. if (lca != HierarchyNode.Null && viewModel.HasFlags(lca, HierarchyNodeFlags.Selected)) lca = viewModel.GetParent(lca);
return lca; }
static HierarchyNode FindPairwiseLCA(HierarchyViewModel viewModel, HierarchyNode node1, HierarchyNode node2) { // Move the deeper node up until both nodes are at the same depth, then advance both together in a single loop. while (node1 != node2 && node1 != HierarchyNode.Null && node2 != HierarchyNode.Null) { int depthA = viewModel.GetDepth(node1); int depthB = viewModel.GetDepth(node2); if (depthA >= depthB) { node1 = viewModel.GetParent(node1); } if (depthB >= depthA) { node2 = viewModel.GetParent(node2); } }
return node1; } } }