-
Notifications
You must be signed in to change notification settings - Fork 22
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[Api] Add FindFirstObjectByType #61
Comments
And maybe these as well, also from Nicogo public static class Extensions
{
public static T GetInMeOrParents<T>(this Entity entity) where T : EntityComponent
{
while (entity != null)
{
var res = entity.Get<T>();
if (res != null)
return res;
entity = entity.GetParent();
}
return null;
}
public static T GetInMeOrChilds<T>(this Entity entity) where T : EntityComponent
{
var res = entity.Get<T>();
if (res != null)
return res;
var childrens = entity.GetChildren();
foreach (var child in childrens)
{
res = child.GetInMeOrChilds<T>();
if (res != null)
return res;
}
return null;
}
public static T GetInParents<T>(this Entity entity) where T : EntityComponent
{
entity = entity.GetParent();
while (entity != null)
{
var res = entity.Get<T>();
if (res != null)
return res;
entity = entity.GetParent();
}
return null;
}
public static T GetInChilds<T>(this Entity entity) where T : EntityComponent
{
var childrens = entity.GetChildren();
foreach (var child in childrens)
{
var res = child.GetInMeOrChilds<T>();
if (res != null)
return res;
}
return null;
}
} |
public static T FindFirstObjectByType<T>(this Entity entity) where T : EntityComponent
{
foreach (var childEntity in entity.Scene.Entities)
{
var component = GetInMeOrChilds<T>(childEntity);
if (component != null)
{
return component;
}
}
return null;
} Here is a little bit better version, also, we should add a note that it search only in the current Scene (don't know about child scene, it need testing) and also that it should not be used each frames |
Ok. Thanks, Yep, we can add all those remarks/comments. |
And a way better code from Kryptos : That method is recursive, which can cause issues (e.g. StackOverflowException) if entities are deeply nested. Better use an iterative approach such as:
// Note: this performs a depth-first iteration
// For a breadth-first iteration, replace Stack<T> with Queue<IEnumerable<T>>
public static IEnumerable<Entity> GetDescendants(this Entity entity)
{
yield return entity; // If you want to return self; otherwise, comment this line
// Create our own stack as to not use the runtime call stack
var stack = new Stack<Entity>();
foreach (var child in entity.GetChildren())
{
stack.Push(child);
while (stack.Count > 0)
{
var descendant = stack.Pop();
yield return descendant;
foreach (var x in descendant.GetChildren()) stack.Push(x);
}
}
}
public static IEnumerable<T> GetComponentsInDescendants<T>(this Entity entity) where T : EntityComponent
{
foreach (var descendant in entity.GetDescendants())
{
if (descendant.Get<T>() is T component)
yield return component;
}
}
public static T FindFirstObjectByType<T>(this Entity entity) where T : EntityComponent
{
return entity.GetComponentsInDescendants<T>().FirstOrDefault();
} |
Ok, here is a full rewrite; it probably just need a PR. /// <summary>
/// Provides extension methods for working with Entity hierarchies and components.
/// </summary>
public static class EntityExtensions
{
/// <summary>
/// Returns all the descendants of the current Entity using a stack and yield return.
/// </summary>
/// <param name="entity">The current Entity.</param>
/// <param name="includeMyself">Include the current Entity in the result.</param>
/// <returns>An IEnumerable of descendant Entities.</returns>
public static IEnumerable<Entity> GetDescendants(this Entity entity, bool includeMyself = false)
{
if (includeMyself)
yield return entity;
var stack = new Stack<Entity>();
foreach (var child in entity.GetChildren())
{
stack.Push(child);
while (stack.Count > 0)
{
var descendant = stack.Pop();
yield return descendant;
foreach (var x in descendant.GetChildren()) stack.Push(x);
}
}
}
/// <summary>
/// Returns all the parents of the current Entity using yield return.
/// </summary>
/// <param name="entity">The current Entity.</param>
/// <param name="includeMyself">Include the current Entity in the result.</param>
/// <returns>An IEnumerable of parent Entities.</returns>
public static IEnumerable<Entity> GetParents(this Entity entity, bool includeMyself = false)
{
if (includeMyself)
yield return entity;
var parent = entity.GetParent();
while (parent != null)
{
yield return parent;
parent = entity.GetParent();
}
}
/// <summary>
/// Returns all the components of type 'T' in the descendants of the entity.
/// </summary>
/// <typeparam name="T">The type of EntityComponent to search for.</typeparam>
/// <param name="entity">The current Entity.</param>
/// <param name="includeMyself">Include the current Entity in the search.</param>
/// <returns>An IEnumerable of components of type 'T' in the descendants of the entity.</returns>
public static IEnumerable<T> GetComponentsInDescendants<T>(this Entity entity, bool includeMyself = false) where T : EntityComponent
{
foreach (var descendant in entity.GetDescendants(includeMyself))
{
if (descendant.Get<T>() is T component)
yield return component;
}
}
/// <summary>
/// Returns all the components of type 'T' in the parents of the entity.
/// </summary>
/// <typeparam name="T">The type of EntityComponent to search for.</typeparam>
/// <param name="entity">The current Entity.</param>
/// <param name="includeMyself">Include the current Entity in the search.</param>
/// <returns>An IEnumerable of components of type 'T' in the parents of the entity.</returns>
public static IEnumerable<T> GetComponentsInParents<T>(this Entity entity, bool includeMyself = false) where T : EntityComponent
{
foreach (var parent in entity.GetParents(includeMyself))
{
if (parent.Get<T>() is T component)
yield return component;
}
}
/// <summary>
/// Returns the first component of type 'T' found in any entity in the scene.
/// </summary>
/// <typeparam name="T">The type of EntityComponent to search for.</typeparam>
/// <param name="entity">The current Entity.</param>
/// <returns>The first component of type 'T' found in the scene, or null if none is found.</returns>
public static T GetFirstComponentInScene<T>(this Entity entity) where T : EntityComponent
{
foreach (var childEntity in entity.Scene.Entities)
{
var components = childEntity.GetComponentsInDescendants<T>(true);
if (components.FirstOrDefault() is T component)
return component;
}
return null;
}
/// <summary>
/// Calls GetFirstComponentInScene, providing a Unity-like "wrapper."
/// </summary>
/// <typeparam name="T">The type of EntityComponent to search for.</typeparam>
/// <param name="entity">The current Entity.</param>
/// <returns>The first component of type 'T' found in the scene, or null if none is found.</returns>
public static T FindFirstObjectByType<T>(this Entity entity) where T : EntityComponent
{
return entity.GetFirstComponentInScene<T>();
}
/// <summary>
/// Note: These methods may perform deep traversal of the Entity hierarchy, which can be resource-intensive. Consider using them judiciously and avoid frequent use in performance-critical scenarios (e.g., in an Update method called every frame).
/// </summary>
} |
Warning, there is a little typo : public static IEnumerable<Entity> GetParents(this Entity entity, bool includeMyself = false)
{
if (includeMyself)
yield return entity;
var parent = entity.GetParent();
while (parent != null)
{
yield return parent;
parent = entity.GetParent();
}
}
Should be
public static IEnumerable<Entity> GetParents(this Entity entity, bool includeMyself = false)
{
if (includeMyself)
yield return entity;
var parent = entity.GetParent();
while (parent != null)
{
yield return parent;
parent = parent.GetParent(); //Here
}
}``` |
From Nicogo in Discord:
https://discord.com/channels/500285081265635328/500292370923913222/1171202793193877534
The text was updated successfully, but these errors were encountered: