Yorumlarda, cevabımın eski cevabının özetini yayınladım:
Kullanımı DrawableGameComponentsizi tek bir yöntem imzaları kümesine ve belirli bir tutulan veri modeline kilitler. Bunlar genellikle başlangıçta yanlış bir seçimdir ve kilitleme, kodun geleceğinin gelişimini önemli ölçüde engellemektedir.
Burada, mevcut projemden bazı kodlar göndererek bunun neden böyle olduğunu açıklamaya çalışacağım.
Oyun dünyasının durumunu koruyan kök nesnenin Updateşuna benzeyen bir yöntemi vardır:
void Update(UpdateContext updateContext, MultiInputState currentInput)
Giriş noktaları vardır UpdateOyunun ağda çalışıp çalışmadığına bağlı , . Örneğin, oyun durumunun önceki bir noktaya geri döndürülmesi ve daha sonra yeniden simüle edilmesi mümkündür.
Ayrıca aşağıdakiler gibi bazı güncelleme benzeri yöntemler de vardır:
void PlayerJoin(int playerIndex, string playerName, UpdateContext updateContext)
Oyunun içinde güncellenecek aktörlerin bir listesi var. Ama bu basit bir şey değilUpdate çağrıdan . Fiziği işlemek için önce ve sonra ek geçişler var. Ayrıca, aktörlerin ertelenmesi / ertelenmesi ve aynı zamanda seviye geçişleri için bazı süslü şeyler var.
Oyun durumu dışında, bağımsız bir şekilde yönetilmesi gereken bir UI sistemi var. Ancak, kullanıcı arayüzündeki bazı ekranların bir ağ bağlamında da çalışabilmesi gerekir.
Çizim için, oyunun doğası gereği, bu yöntemlerden girdi alan özel bir sıralama ve toplama sistemi vardır:
virtual void RegisterToDraw(SortedDrawList sortedDrawList, Definitions definitions)
virtual void RegisterShadow(ShadowCasterList shadowCasterList, Definitions definitions)
Ve sonra ne çizileceğini anladıktan sonra, otomatik olarak çağırır:
virtual void Draw(DrawContext drawContext, int tag)
tagParametresi bazı aktörler diğer aktörlerin tutunmaya çünkü gereklidir - ve ihtiyaç böylece bekletilen aktör üstünde ve altında hem çizmek edebilmek için. Sıralama sistemi bunun doğru sırada olmasını sağlar.
Çizilecek menü sistemi de var. Ve oyunun etrafında, kullanıcı arayüzü, HUD etrafında çizmek için hiyerarşik bir sistem.
Şimdi bu gereksinimleri aşağıdakilerle karşılaştırın DrawableGameComponent:
public class DrawableGameComponent
{
public virtual void Update(GameTime gameTime);
public virtual void Draw(GameTime gameTime);
public int UpdateOrder { get; set; }
public int DrawOrder { get; set; }
}
DrawableGameComponentYukarıda tarif ettiğim sistemi kullanan bir sistemden ulaşmanın makul bir yolu yoktur . (Ve bunlar mütevazı karmaşıklıkta bile bir oyun için olağandışı şartlar değildir).
Ayrıca, bu gereksinimlerin projenin başlangıcında basitçe ortaya çıkmadığına dikkat etmek önemlidir. Aylarca süren geliştirme çalışmaları ile gelişti.
Genelde insanların yaptığı, DrawableGameComponentrotadan aşağıya inerlerse, saldırıların üzerine inşa etmeye başlarlar:
Yöntem eklemek yerine, kendi temel türlerine biraz aşağı inme yapıyorlar (neden bunu doğrudan kullanmıyorsunuz?).
Sıralama ve çağırma kodunu değiştirmek yerine Draw/ çağırmak yerine, hareket halindeki Updatesipariş numaralarını değiştirmek için çok yavaş şeyler yaparlar.
Ve hepsinden kötüsü: Yöntemlere parametre eklemek yerine, yığın olmayan bellek konumlarında "" parametreleri "geçmeye başlarlar (bunun kullanımı Servicespopülerdir). Bu sarsılmış, hataya açık, yavaş, kırılgan, nadiren iş parçacığı güvenlidir ve ağ eklerseniz, harici araçlar yaparsanız vb. Sorun yaşar.
Ayrıca kodun kullanımını daha da zorlaştırır , çünkü bağımlılıklarınız artık API sınırında yayınlanmak yerine "bileşen" içinde gizlidir.
Ya da bunların neredeyse ne kadar çılgınca olduğunu görüyorlar ve DrawableGameComponentbu sorunların üstesinden gelmek için "yönetici" ler yapmaya başlıyorlar . Bunun dışında hala "yönetici" sınırlarında bu problemleri var.
Muhtemelen bu "yöneticiler" kolayca istenen sıraya göre bir dizi yöntem çağrısı ile değiştirilebilir. Başka bir şey fazla karmaşık.
Tabii ki, bir kez bu saldırıları kullanmaya başladığınızda, sağladığınızdan daha fazlasına ihtiyacınız olduğunu fark ettiğinizde bu saldırıları geri almak gerçek bir iş gerektirir DrawableGameComponent. " Kilitli " oldun . Baştan çıkarıcı olmak çoğu zaman kesmek zorunda kalmaya devam etmektir - pratikte sizi yavaşlatacak ve nispeten basit olanlarla yapabileceğiniz oyun türlerini sınırlayacaktır.
Birçok insan bu noktaya ulaşıyor ve içgüdüsel bir tepki gösteriyor - muhtemelen kullanıyorlar DrawableGameComponentve "yanlış" olmayı kabul etmek istemiyorlar. Bu yüzden en azından "çalışmasını" mümkün kıldığı gerçeğine dayanıyorlar .
Tabii ki "çalışmak" için yapılabilir ! Bizler programcıyız - olağandışı sınırlamalarla işleri yürütmek pratikte bizim işimiz Ancak bu kısıtlama gerekli, faydalı veya rasyonel değildir ...
Özellikle korkutucu olan şey, bu konunun tarafına atılmasının şaşırtıcı derecede önemsiz olmasıdır. Burada, size kodu bile vereceğim:
public class Actor
{
public virtual void Update(GameTime gameTime);
public virtual void Draw(GameTime gameTime);
}
List<Actor> actors = new List<Actor>();
foreach(var actor in actors)
actor.Update(gameTime);
foreach(var actor in actors)
actor.Draw(gameTime);
(It sade göre sıralama eklemek DrawOrderve UpdateOrder. Basit bir yolu iki listeleri ve kullanımını sağlamaktır List<T>.Sort(). Ayrıca sap için Önemsiz Load/ ' UnloadContent.)
O kod aslında neyin önemli değildir olduğunu . Önemli olan, önemsiz bir şekilde değiştirebilmem .
Farklı bir zamanlama sistemine ihtiyacım olduğunu gameTimeveya daha fazla parametreye (veya UpdateContextiçinde yaklaşık 15 şey olan bir nesnenin tümüne ihtiyacım olduğunu) veya çizim için tamamen farklı bir işlem sırasına ihtiyacım olduğunu veya bazı ekstra yöntemlere ihtiyacım olduğunu fark ettiğimde farklı güncelleme geçişleri için, devam edip bunu yapabilirim .
Ve hemen yapabilirim. DrawableGameComponentKodumu seçmem konusunda endişelenmeme gerek yok . Daha da kötüsü: Böyle bir ihtiyaç ortaya çıktığında daha da zorlaşacak bir şekilde hackleyin.
Kullanmanın iyi bir seçim olduğu tek bir senaryo var DrawableGameComponent: ve eğer tam anlamıyla XNA için sürükle ve bırak-bileşen-tarzı ara katman yazılımı yapıyor ve yayınlıyorsanız . Asıl amacı buydu. Hangisini ekleyeceğim - kimse yapmıyor!
(Benzer şekilde, yalnızca içinServices özel içerik türleri yaparken kullanımı gerçekten mantıklı geliyorContentManager .)