Yorumlarda, cevabımın eski cevabının özetini yayınladım:
Kullanımı DrawableGameComponent
sizi 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 Update
Oyunun 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)
tag
Parametresi 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; }
}
DrawableGameComponent
Yukarı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ığı, DrawableGameComponent
rotadan 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 Update
sipariş 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ı Services
popü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 DrawableGameComponent
bu 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 DrawableGameComponent
ve "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 DrawOrder
ve 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 gameTime
veya daha fazla parametreye (veya UpdateContext
iç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. DrawableGameComponent
Kodumu 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
.)