Reputation: 10721
Well, I know this has been asked already and I also happen to know the easiest way to do so.
Now my question is more about your advice on if there is a better way.
I want my method to be called only once when the component is enabled or created. See I can create a component but keep it disabled, then when I enable it for the first time, I want the Init method to be called. The component is contained into an "attached" object.
So I have the Component with
internal bool _runOnce;
then I have the MainObject
List<Component> _listComp = new List<Component>();
void Update(){
foreach(Component c in _listComp){
if(!c.enable)continue;
if(c._runOnce){
c.Init();
c._runOnce = false;
}
c.Update();
}
}
My main concern is that the check for _runOnce will happen every frame for every component on each object. I know it is just a boolean check and is worth nothing but I am just asking if anyone would know a pattern for this purpose that is better than this.
Thanks
Upvotes: 2
Views: 4953
Reputation: 13367
You could also make a list of only the components thats are enabled....
List<Component> _listEnabled = _listComp.Where(item => (item.enable == true));
foreach(Component c in _listEnabled ){
if(c._runOnce){
c.Init(); // if at all possible, _runOnce should be set to false
c._runOnce = false; // IN THE OBJECT, after calling Init();
}
c.Update();
}
Upvotes: 2
Reputation: 3133
My main concern is that the check for _runOnce will happen every frame for every component on each object.
From that I assume that you call Update
very frequently. My concerns would be for the Update
method of the components which is very likely to be much more expensive than a boolean check. This is called micro-optimization: You put a lot of effort into something that isn't a problem at all.
However, I would suggest to encapsulate initialization. Your MainObject
does not need to know anything about it. _runOnce
should be a private member of the component and enable
should be a property (btw: _runOnce
should be initialized to true somewhere). Each time your component is enabled you can check for _runOnce
and call the initialization if needed:
public class MyComponent
{
private bool _isInitialized; // I think this is a better name than _runOnce
private bool _enable;
public bool Enable
{
get
{
return _enable;
}
set
{
if (_enable == value)
{
return;
}
if (value == true && !_isInitialized)
{
Init();
}
_enable = value;
}
}
private void Init()
{
// initialization logic here ...
_isInitialized = true;
}
}
Another idea would be to defer initialization to the Update
method. This is basically what you already have but in an object oriented design:
public void Update()
{
if (_enable && !_isInitialized)
{
Init();
}
// update logic here ...
}
Upvotes: 1
Reputation: 7375
I would question whether Update()
is the appropriate lifecycle design to Init()
your dynamic components.
It seems that it would make more sense to have a method notionally called GameObject.ActivateComponent(AbstractComponent C)
call C.Init()
, and AbstractComponent::Init
call OnInit
, which is what the components override and implement. AbstractComponent::Init
would make the _runonce check and early-return. It's a method call, but it makes the code more abstract, and has the option to be extended to have a OnReinitialize
code path later if you need to provide hooks for 'this is the second or later time I was init'd'. (Say, a statistics reset option...)
It definitely seems wrong for Update()
to be probing an implementation detail like "runonce" to find out about the initialization state of Component
.
List<Component> _listComp = new List<Component>();
void Update(){
foreach(Component c in _listComp){
c.Update();
}
}
AbstractComponent
public bool Enable { get;set;}
private bool _initialized = false;
void Update(){
if (!Enable) return;
Init();
OnUpdate();
}
protected virtual void OnUpdate()
{
// filled in by user script
}
private void Init()
{
if (_initialized) return;
OnInit();
_initialized = true;
}
protected virtual void OnInit()
{
// filled in by user script
}
Upvotes: 1
Reputation: 8783
What about just a regular constructor for Component?
public Component()
{
Init();
}
Upvotes: 0