Make Instantiate create objects in scope scene
Closes #376
Don't know your API vision, let it be a prototype.
There is another option via SceneManager.MoveGameObjectToScene(), but it executes Awake/Start on the random scene, and is harder to pass to the plain C# part of the VContainer (object ApplicationOrigin already used in project to pass from Unity-C#-Unity layer).
The latest updates on your projects. Learn more about Vercel for Git ↗︎
| Name | Status | Preview | Updated |
|---|---|---|---|
| vcontainer | ✅ Ready (Inspect) | Visit Preview | Oct 26, 2022 at 3:30AM (UTC) |
Thanks for the PR. I am positive about this feature, but a little hesitant about adding IObjectResolver.ApplicationOrigin. I will think about it and If I can't come up with any other good ideas, I would like to merge them. Thanks.
Agree with you.
There are few issues about object creation, maybe we need deprecate these extension methods and give a more powerful solution?
For example:
public interface IObjectCreator
{
//empty game object in the scope scene
GameObject InstantiateEmpty(string name); //or CreateGameObject()
//like current extension methods
T Instantiate<T>(T prefab) where T : Object;
T Instantiate<T>(T prefab, Vector3 position, Quaternion rotation) where T : Object;
T Instantiate<T>(T prefab, Vector3 position, Quaternion rotation, Transform parent) where T : Object;
T Instantiate<T>(T prefab, Transform parent, bool worldPositionStays = false) where T : Object;
//A few places inside VContainer will use it (NewGameObjectResolver/Creation, PrefabCreation, don't remember correct names)
//Sometimes it's impossible to resolve GameObject: precache or hold the reference in the upper scope, but resolve it current scope
//It can be used for the optimization: do not traversal GameObject with a big structure
T InstantiateNoInject<T>(T prefab) where T : Object;
T InstantiateNoInject<T>(T prefab, Vector3 position, Quaternion rotation) where T : Object;
T InstantiateNoInject<T>(T prefab, Vector3 position, Quaternion rotation, Transform parent) where T : Object;
T InstantiateNoInject<T>(T prefab, Transform parent, bool worldPositionStays = false) where T : Object;
//#352 and #304 issues
TObject InstantiateWithParameter<TObject, TArg1>(TObject prefab, TArg1 arg1) where TObject : Object;
TObject InstantiateWithParameter<TObject, TArg1, TArg2>(TObject prefab, TArg1 arg1, TArg2 arg2) where TObject : Object;
TObject InstantiateWithParameter<TObject, TArg1, TArg2, TArg3>(TObject prefab, TArg1 arg1, TArg2 arg2, TArg3 arg3) where TObject : Object;
TObject InstantiateWithParameter<TObject, TArg1, TArg2, TArg3, TArg4>(TObject prefab, TArg1 arg1, TArg2 arg2, TArg3 arg3, TArg4 arg4) where TObject : Object;
//likewise:
T InstantiateWithParameter<T,...>(T prefab, Vector3 position, Quaternion rotation) where T : Object;
T InstantiateWithParameter<T,...>(T prefab, Vector3 position, Quaternion rotation, Transform parent) where T : Object;
T InstantiateWithParameter<T,...>(T prefab, Transform parent, bool worldPositionStays = false) where T : Object;
//mb plain C# methods?
T Create<T>();
T CreateNoInject<T>(); //for the unification
T CreateWithParameter<T, TArg>();
}
Few notes about code:
component.transform.parent = nullgives a warning for the UI:
Parent of RectTransform is being set with parent property.
Consider using the SetParent method instead, with the worldPositionStays argument set to false.
This will retain local orientation and scale rather than world orientation and scale, which can prevent common UI scaling issues.
- We should use overloaded version of the method:
component.transform.SetParent(null, worldPositionStays: true/false);
There are few issues about object creation, maybe we need deprecate these extension methods and give a more powerful solution?
I'm actually not very positive about this. ( In my experience, if DIContainer becomes a helper that dynamically creates objects, people will abuse it. I don't like that very much...
I would suggest that objects that are dynamically generated at runtime should first consider using Factory. You can also control parameters as follows
// before
builder.RegisterFactory<Param1, FooComponent>(container =>
{
var dependency = container.Resolve<Dependency>();
return param1 =>
{
var instance = container.Instanciate()
instance.Configure(param1);
return instance;
};
}, Lifetime.Scoped);
I think this is sufficient, however it is also somewhat poor. According to your suggestion, this could also be written much shorter.
// maybe after
builder.RegisterFactory<Param1, FooComponent>(container =>
{
return param1 => container.InstantiateWithParameter<FooComponent>(param1);
}, ...);
Not bad, but I am cautious as to whether this is necessary. Either way, I thought it was a separate issue from this issue.
IObjectResolver.ApplicationOrigin
How about keeping ApplicationOrigin only used by ContainerBuilder?
Why not have the RegisterComponent* method family all reference a scene and have the ComponentRegistrationBuilder always reference a scene? I think this issue could be solved.
I have decided to adopt this PR. Because I recently had an experience debugging scopes. And I came to think that linking Containers and GameObjects would help.