Oyundaki aktörler kendilerini çizmekten sorumlu mu olmalı?


41

Oyun geliştirme konusunda çok yeniyim, ancak programlamada değil.

JavaScript canvaselemanını kullanarak Pong tipi bir oyunla tekrar oynuyorum .

PaddleAşağıdaki özelliklere sahip bir nesne yarattım ...

  • width
  • height
  • x
  • y
  • colour

Ayrıca Pong... gibi özelliklere sahip bir nesne var

  • width
  • height
  • backgroundColour
  • draw().

draw()Yöntem şu anda sıfırlıyor canvasve bir soru geldi nereye olmasıdır.

Meli Paddlenesne var draw()onun çizim yöntemi sorumlu veya gerektiği draw()ait Pongnesne onun aktörleri çizim sorumlu (Ben yanlış mıyım Doğru terim olduğunu varsayalım, düzelt lütfen).

Ben için avantaj yaratacaktır düşündüm Paddleben iki nesne örneğini olarak, kendisini çizmek için Playerve Enemy. O olmasaydı Pong's draw(), iki kez benzer kod yazmak gerekiyordu.

Buradaki en iyi uygulama nedir?

Teşekkürler.


Yanıtlar:


49

Oyuncuların kendilerini çekmesi iki ana sebepten dolayı iyi bir tasarım değildir:

1) tek bir sorumluluk ilkesini ihlal ediyor , çünkü bu oyuncuların muhtemelen kodları koymadan önce yapacak başka bir işi var.

2) uzatmayı zorlaştırır; Her oyuncu türü kendi çizimini uyguluyorsa ve genel olarak çizim biçiminizi değiştirmeniz gerekiyorsa , çok fazla kod değiştirmeniz gerekebilir. Mirasın aşırı kullanılmasından kaçınmak, bunu bir dereceye kadar hafifletebilir, ancak tamamen ortadan kaldırabilir.

Oluşturucunuzun çizimle ilgilenmesi daha iyidir. Ne de olsa, işveren olmanın anlamı bu. İşleyicinin çizim yöntemi, bir şeyi işlemek için ihtiyacınız olan her şeyi içeren bir "işleme açıklaması" nesnesini almalıdır. (Muhtemelen paylaşılan) geometri verilerine, örneğe özgü dönüşümlere veya color, et cetera gibi malzeme özelliklerine referanslar. Daha sonra bunu çizer ve tanımlamanın ne olması gerektiğini umursamaz.

Aktörleriniz daha sonra kendilerini kendi oluşturdukları bir render tanımını tutabilirler. Oyuncular tipik olarak mantıksal işlem türleri olduğu için, durum değişikliklerini istenen şekilde oluşturma tanımına itebilirler - örneğin, bir oyuncu hasar aldığında oluşturma tanımının rengini bunu belirtmek için kırmızıya ayarlayabilir.

Daha sonra, her görünür aktörü yineleyebilir, render açıklamalarını renderleyiciye girebilir ve kendi işini yapmasına izin verebilirsiniz (temel olarak; bunu daha da genelleştirebilirsiniz).


14
"Oluşturucu çizim kodu" için +1, programcılara yarardan çok zarar veren tek sorumluluk ilkesi için -1 . Doğru bir fikri var (endişelerin ayrılması) , ancak belirtildiği gibi ("her sınıfın tek bir sorumluluğu olmalı ve / veya değişmesi için tek bir sebep olmalı") sadece yanlıştır .
BlueRaja - Danny Pflughoeft

2
1 için -1), BlueRaja'nın işaret ettiği gibi, bu ilke idealisttir, ancak pratik değildir. -1 için -1) çünkü uzantıyı önemli ölçüde zorlaştırmaz. Tüm oluşturma motorunuzu değiştirmeniz gerekiyorsa, oyuncu kodunuzda sahip olduğunuz miktardan daha fazla kodunuz olacak. Ben çok tercih ediyorum actor.draw(renderer,x,y)daha renderer.draw(actor.getAttribs(),x,y).
corsiKa

1
İyi cevap! Eh, "Tek sorumluluk ilkesini ihlal etmeyeceksin" benim dekalogumun içinde değil, fakat dikkate almak için hala iyi bir ilke
FxIII

@glowcoder Konu bu değil, {renderer.draw (mesh, attribs, transform); olarak tanımlanan actor.draw () öğesini koruyabilirsiniz. }. OpenGL'de, struct RenderDetail { glVAO* vao; int shader; int texture; Matrix4f* transform; }işleyicim için az çok bakım yaparım. Bu şekilde, işveren verinin ne temsil ettiği umrunda değil, sadece işliyor. Bu bilgilere dayanarak, genel GPU çağrılarını azaltmak için beraberlik çağrılarının sırasını sıralayıp sıralamayacağınıza da karar verebilirim.
deceleratedcaviar

16

Ziyaretçi Desen burada yararlı olabilir.

Yapabileceğiniz şey, her bir nesneyi nasıl çizeceğinizi bilen bir Renderer arayüzüne ve her oyuncu için hangi (özel) render yönteminin çağrılacağını belirleyen bir “kendiniz çiz” yöntemine sahip olmasıdır.

interface Renderer {
    void drawPaddle(Player owner, Rectangle position);
    // Note: the Renderer chooses the Color based on which player the paddle belongs to

    // Also drawBackground, drawBall etc.
}

interface Actor {
    void draw(Renderer renderer);
}

class Paddle implements Actor {
    void draw(Renderer renderer) {
        renderer.drawPaddle(this.owner, this.getBounds());
    }
}

Bu yolla başka bir grafik kütüphanesine veya çerçeveye taşımak hala çok kolay (bir oyunu Swing / Java2D'den LWJGL'ye taşıdım ve Graphics2Detrafa geçmek yerine bu modeli kullandığım için çok mutlu oldum ).

Başka bir avantaj daha var: Oluşturucu, herhangi bir oyuncu kodundan ayrı olarak test edilebilir.


2

Örneğinizde, Pong nesnelerinin draw () uygulamasını yapmasını ve kendilerini oluşturmasını istersiniz.

Bu büyüklükteki bir projede önemli bir kazanç farketmemenize rağmen, genellikle oyun mantığını ve görsel temsillerini (görselleştirme) ayırmak değerli bir etkinliktir.

Bununla, oyun nesnelerinizin güncellenmesi mümkün olacak () 'd, ancak nasıl oluşturulduklarına dair hiçbir fikirleri yok, sadece simülasyonla ilgileniyorlar.

Sonra, bir Pong nesnesine referansı olan bir PongRenderer () sınıfına sahip olacaksınız ve daha sonra Pong () sınıfını oluşturmak görevini üstlenecek, bu, Kürekleri oluşturmayı veya onunla ilgilenmek için bir PaddleRenderer sınıfına sahip olmayı içerebilir.

Bu durumda endişelerin ayrılması, sınıflarınızın daha az şişirilebileceği anlamına gelen oldukça doğal bir sorundur ve işlerin nasıl yapıldığını değiştirmek daha kolaydır, artık simülasyonunuzun yaptığı hiyerarşiyi takip etmek zorunda kalmaz.


-1

Pong'Draw ()' da yapacak olsanız, kodu kopyalamanıza gerek kalmayacaktı - basitçe Paddleher kürekleriniz için 'draw () işlevini çağırın . Yani Pongçekilişinizde ()

humanPaddle.draw();
compPaddle.draw();

-1

Her nesne, oyun güncelleme kodu ya da çizim kodu tarafından çağrılması gereken kendi çizim fonksiyonunu içermelidir. Sevmek

class X
{
  public void Draw( )
  {
     // Do something 
  } 
}

class Y
{
  public void Draw( )
   { // Do Something 
   } 
}

class Game
{
  X objX;
  Y objY;

  @Override
  public void OnDraw( )
  {
      objX.Draw( );
      objY.Draw( ); 
  } 
}

Bu bir kod değil, sadece çizim nesnelerinin nasıl yapılması gerektiğini göstermek için.


2
Bu "Çizim nasıl yapılmalı" değil, yapmanın tek yoludur. Önceki cevaplarda da belirtildiği gibi, bu yöntemin bazı kusurları ve az yararları varken, diğer desenler önemli fayda ve esnekliklere sahiptir.
Troyseph

Minnettarım ama sahnedeki çeşitli oyuncuların çizim yöntemlerinden basit bir örnek verileceğinden, bu şekilde bahsettim.
user43609
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.