Xenko equivalent of Unity "Object.FindObjectOfType"?


#1

Hello, i’m used to use FindObjectOfType in Unity to use variables from others scripts instances, but i can’t find an equivalent on xenko, is there an equivalent function on Xenko ? if not what are the possible ways to create a function with the same feature ?


#2

Hello :slight_smile:

I don’t remember the exact way to access them, but there is basically something looking like
Scene.Instance.ListOfObjectInTheScene. From that, since you access the list of object, you can just iterate through them and so a if(object is MyType) and if it is add it to an array or list that you return upon completion.

I’m sorry I don’t remember the name of the list to access it tho.
If you take a look at how to add objects to the scene, you’ll find it! :slight_smile:


#3

I do not believe there is a built in method to like this. And I don’t really recommend it anyways. Even Unity docs say don’t use those find object methods. There are better options. But if you really want to use a method similar it would not be hard to write one and use it. i.e. create an extension method like:

public static T FindComponent<T>(this IEnumerable<Entity> entities, bool includeDisabled = false) where T : EntityComponent
{
    if (entities == null)
        throw new ArgumentNullException(nameof(entities));

    //breadth first
    var queue = new Queue<Entity>(entities);

    while (queue.Count > 0)
    {
        var current = queue.Dequeue();


        var component = current.Get<T>();

        var isEnabled = ((component as ActivableEntityComponent)?.Enabled).GetValueOrDefault(true);
        if (component != null && (isEnabled || includeDisabled))
        {
            return component;
        }

        var children = current.Transform.Children;

        for (int i = 0; i < children.Count; i++)
        {
            queue.Enqueue(children[i].Entity);
        }
    }

    return null;
}

Then use it like:

SceneSystem.SceneInstance.RootScene.Entities.FindComponent<CameraComponent>();

#4

What would be a better option in this case ?
if there is a better way to do it, i’m curious


#5

Well it depends entirely on what you are trying to do. But if you are implementing somethings that there is only one of then you could use the singleton pattern. Though some consider that an anti-pattern. You could also use evens though I don’t really like have static ones or those either. Something I have been toying with is using is the built in ServiceRegistry. An example:

public interface IFooSystem
{
    void Bar(Vector3 wordLocation, string name);
}

public class FooSystem : StartupScript, IFooSystem
{
    public override void Start()
    {
        //Do initililization.


        //Register service
        Game.Services.AddService<IFooSystem>(this);
    }

    public override void Cancel()
    {
        //Unregister
        Game.Services.RemoveService<IFooSystem>();

        // clean up
    }


    public void Bar(Vector3 wordLocation, string name)
    {
        //do something
    }

}



public class SomeOtherScript : SyncScript
{
    public override void Update()
    {
        var fooSystem = Game.Services.GetService<IFooSystem>();

        if (fooSystem != null)
        {
            fooSystem.Bar(Entity.Transform.Position, "Something");
        }
    }
}

And to make sure the service is registered before other scripts run set it to a higher priority like -1000 on the FooSystem script you add to an entity.


#6

It’s true that this way to proceed looks really interesting
thanks a lot for this information
since i want to correctly optimize my game it will be useful


#7

You are welcome. Always glad too help.


#8

Hi,

It seems you can access entities in the scene including child scene with SceneSystem.SceneInstance.

var component = SceneSystem.SceneInstance.First(e => e.Any(c => c is T)).Get<T>();


#9

Yeah looks like @EternalTamago is correct so you could simplify my helper method to:

public static T FindComponent<T>(this EntityManager entityManager) where T : EntityComponent
{
   if (entityManager == null)
       throw new ArgumentNullException(nameof(entityManager));

   return entityManager.SelectMany(e => e.Components).OfType<T>().FirstOrDefault();
 
}

The EntityManager “collection” seems to be a flattened out hash-set of entities.


#10

Might be better off writing an extension method for SceneInstance. I had a look at the code for SceneInstance and EntityManager and I can’t see what flattens out the hierarchy. They both have events. Maybe something handling those events or a EntityProcessor or something else does the flattening.


#11

i’ve never used the “=>” operator in c# so it’s a bit difficult for me to understand this code


#12

If you have ever heard about lambda functions, this is what it is. (If I can remember correctly the names)

Basically you can declare an anonymous function by doing () => {} in C#.
In the case of a delegate, in the case of LINQ functions for example, you can also write it, let’s say in the case of the Find function:
ListVar.Find(element => element.var == true)

With ListVar being a list for example in this case, the Find Function will iterate through all the elements and check for a predicate. if this predicate is true, then it will return this element. :slight_smile:

.NetPerls Predicate

The link above may give you a small idea about what it is and how it works. I’ll encourage you to look at it more it depth to understand the concepts behind it! :slight_smile:


#13

Thanks for the explaination