2013-10-04 81 views
1

嗯,我知道這已被問及,我也碰巧知道這樣做的最簡單的方法。初始方法只調用一次c#

現在我的問題是更多關於你的建議,如果有更好的方法。

我希望我的方法僅在啓用或創建組件時被調用一次。 看到我可以創建一個組件,但保持禁用,然後當我第一次啓用它時,我想要調用Init方法。該組件包含在「附加」對象中。

所以我有

internal bool _runOnce; 

組件,然後我有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(); 
    } 
} 

我主要關心的是,_runOnce檢查會發生每一幀的每個對象上的所有組件。我知道這只是一個布爾檢查,沒有任何價值,但我只是問是否有人會知道一個比這更好的模式。

感謝

+1

忠告:不要將其命名公共類變量與「_」 – Kevin

+0

開始@Kevin我也是想給同樣的建議,但它可能是私有變量和OP可能在'組件'中 –

+0

@SriramSakthivel如果這種情況他爲什麼會把它稱爲Component和MainObject? – Kevin

回答

2

你也可以將僅這就是啓用的組件列表....

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(); 
} 
+0

Linq會不會讓一切變慢?我猜想第一行是在這個方法中,所以它意味着我爲每個對象聽到Linq的每一幀,這聽起來不是一個好主意。如果你打算在課堂外進行,那麼它會錯過所有尚未創建的組件。或者我錯過了什麼? – Everts

+0

Linq將創建僅啓用了「Components」的第二個列表。把它們作爲循環的一部分是沒有意義的,如果你只是「繼續」,甚至不需要更新它們。 –

+0

我只是害怕,如果我有數百個物體,可能會傷害速度。我仍然會嘗試一下,看看它給了什麼。我認爲這適合速度不是太大問題的程序,我正在處理一個遊戲,所以它可能不適合。 – Everts

0

什麼有關組件只是一個普通的構造函數?

public Component() 
{ 
    Init(); 
} 
+0

因爲可以創建一個組件,但仍處於禁用狀態。這樣它會調用創建方法。看到它是爲了一個遊戲對象,所以你可能會將所有類型的組件附加到GO上,但也許其中一些組件正在等待並且不活動。 – Everts

+0

那麼你可以添加在構造函數中啓用的檢查...但我很困惑。組件是否可以啓動禁用,然後啓用?那麼是什麼觸發了對init的調用? – Derek

+0

是的,Component可以作爲設置附加到GameObject,但保持不活動狀態直到某些事件被喚醒。那就是當初始化應該被調用並且只有那時。不晚了。 – Everts

1

我會質疑Update()是否是合適的生命週期設計Init()動態組件。

它似乎會更有意義有一個名義上稱爲GameObject.ActivateComponent(AbstractComponent C)通話C.Init()方法,並AbstractComponent::Init呼叫OnInit,這是什麼成分重寫和實現。 AbstractComponent::Init會使_runonce檢查和提前返回。這是一個方法調用,但它使得代碼更加抽象,並且可以選擇擴展到以後有一個OnReinitialize代碼路徑,如果您需要提供「這是我第二次或以後的初始化時間」的鉤子。 (說,統計重置選項...)

Update()肯定似乎是錯誤的探測像「runonce」的實現細節,以瞭解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 
} 
+0

也注意到我稱之爲'AbstractComponent'可能會在你的遊戲模型中被實現爲'Component' –

+0

我正要說,是的。組件可以是用戶創建的腳本從其繼承的抽象類。至於:「,如果你需要爲'這是第二次或更晚的時候'初始化''提供鉤子,那麼以後可以選擇擴展爲具有OnReinitialize代碼路徑'」不會有任何第二次初始化。這就是這一點,只在開始時調用一次,而不再一次。 – Everts

+0

你現在說...(我的遊戲編程很久以前,但...) –

1

My main concern is that the check for _runOnce will happen every frame for every component on each object.

,從我以爲你叫Update非常頻繁。我擔心的是組件的Update方法很可能比布爾檢查貴得多。這就是所謂的微型優化:你付出了很多努力,根本不是問題。

但是,我會建議封裝初始化。您的MainObject不需要知道任何關於它的信息。_runOnce應該是組件的私有成員,並且enable應該是屬性(btw:_runOnce應該在某處初始化爲true)。您的每一個組件已啓用如果需要,您可以檢查_runOnce並調用初始化時間:

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; 
    } 
} 

另一個想法是推遲初始化的方法Update。這基本上就是你已經擁有但在面向對象的設計:

public void Update() 
{ 
    if (_enable && !_isInitialized) 
    { 
     Init(); 
    } 

    // update logic here ... 
} 
+0

我意識到你的答案並未解決問題。我使用了屬性模式,並在稍後設置激活時解決了問題,但如果組件是從創建開始就是主動的,那麼我回到初始設置。或者我必須從組件ctor調用這個不合適的調用... – Everts

+0

@fafase:如果組件在創建時處於活動狀態,則該屬性的值將仍然設置爲true。只要使用該屬性(而不是後臺字段)設置它,初始化將被調用。 – pescolino