Sınıflar arasındaki veri ve bağımlılıkları nasıl temiz ve zarif bir şekilde ele alabilirim


12

SFML 2'de 2d yukarıdan aşağıya oyun üzerinde çalışıyorum ve her şeyin birlikte çalışacağı ve uyumlu olacağı zarif bir yol bulmam gerekiyor.

Açıklamama izin ver. Tüm sınıflar için bir beraberlik yöntemi ve bir güncelleme yöntemi sağlayan soyut bir temel miras sınıfları bir dizi var.

Oyun döngüsünde, güncelleme çağırıyorum ve sonra her sınıfa çizim yapıyorum, bunun oldukça yaygın bir yaklaşım olduğunu hayal ediyorum. Fayans, çarpışma, oyuncu ve tüm fayans / görüntüleri / dokuları içeren bir kaynak yöneticisi için sınıfları var. Girişin SFML'de çalışma şekli nedeniyle, her sınıfın güncelleme çağrısında giriş (gerekirse) işlemeye karar verdim.

Şimdiye kadar, örneğin bir hareket tuşuna basıldığında oyuncu sınıfında gerektiğinde bağımlılıkları geçiyorum, oyuncunun gitmek istediği pozisyonun bir çarpışma olup olmadığını kontrol etmek için çarpışma sınıfında bir yöntem çağırıyorum, ve oyuncuyu sadece çarpışma yoksa hareket ettirin.

Bu çoğunlukla işe yarıyor, ama daha iyi yapılabileceğine inanıyorum, nasıl olduğundan emin değilim.

Şimdi uygulamak zorunda olduğum daha karmaşık şeyler var, örneğin: bir oyuncu yerdeki bir nesneye yürüyebilir, onu almak / yağmalamak için bir tuşa basabilir ve daha sonra envanterde görünecektir. Bu, birkaç şeyin olması gerektiği anlamına gelir:

  • Oynatıcının tuşa basıldığında lootable bir öğe aralığında olup olmadığını kontrol edin, aksi takdirde devam etmeyin.
  • Öğeyi bulun.
  • Öğe üzerindeki hareketli grafik dokusunu varsayılan dokusundan "yağmalanan" dokuya güncelleyin.
  • Öğenin çarpışmasını güncelleyin: şekli değişmiş veya tamamen kaldırılmış olabilir.
  • Envanterin eklenen öğeyle güncellenmesi gerekiyor.

Her şeyi nasıl iletişim kurabilirim? Mevcut sistemimle derslerimin kapsamı dışına çıkacağım ve her yerde yöntem çağrısında bulunacağım. Tüm sınıfları büyük bir yöneticiye bağlayabilir ve her birine ana yönetici sınıfına bir referans verebilirim, ancak bu sadece biraz daha iyi görünüyor.

Herhangi bir yardım / tavsiye büyük mutluluk duyacağız! Bir şey net değilse, şeyleri genişletmekten mutluluk duyarım.


1
Burada kalıtım yerine kompozisyonu düşünmek isteyebilirsiniz. Kompozisyon örneklerine bir göz atın ve size bazı fikirler verebilir. Pimpl deyim de işleri halletmeye yardımcı olabilir.
OriginalDaemon

5
Kompozisyon hakkındaki kanon makalelerinden biri: Hiyerarşinizi
Geliştirin

Çok yerel görünüyor. Kod İnceleme SE'yi denemek ister misiniz?
Anko

Yanıtlar:


5

Kompozisyonun tüm sorunları çözüp çözemeyeceğinden emin değilim. Belki kısmen yardımcı olabilir. Ama eğer sınıfları birbirinden ayırmak istiyorsan daha fazla olay güdümlü mantığa bakardım. Bu şekilde, örneğin , en yakını bulmak için oyuncu pozisyonuna ve yağmalarla ilgili bilgiye sahip olması gereken OnLoot işlevine sahip olacaksınız . Ardından işlev, yağmalanan öğeye olay gönderir. Olay işlem döngüsünde yağmalanmış öğe bu olayı işler, böylece öğenin yalnızca kendini nasıl güncelleyeceğini bilmesi gerekir. OnLoot işlevi ayrıca oyuncu envanterini güncelleyebilir veya öğenin kendisi updateInventory / * OnLootSucess * olayı gönderebilir ve oynatıcı / envanter kendi işlem olayları döngüsünde işleyebilir.

Artıları: bazı sınıflarınızı ayırdınız

Eksileri: eklenen olaylar sınıfları, belki gereksiz kod yükü.

Burada bir o görünebilir nasıl mümkün yollarından:

case LOOT_KEY:
   OnLoot(PLayer->getPos(), &inventoryItems);
....

// note onLoot do not needs to know anything about InvItem class (forward decl in enough)
int onLoot(vec3 pos, InvItems& pitems)
{
    InvItem* pitem = findInRange(pos, pitems, LOOT_RANGE);
    if(pitem)
     EventManager::Instance->post( Event::makeLootEvent(pitem));
}
....

// knows only about EventManager
InvItem::processEvents()
{
    while(!events.empty())
    {
        Event* pev = events.pop();
        ...
        case LOOT_EVENT:
            // in case you broadcasted it, but better is to sort all posted/sent events and add them only if they addressed to particular item 
            if(pev->item == this && handleLoot((LootEvent)pev))
            {
                EventManager::Instance->post(Event::makeLootSuccessEvent(this));
            }
    }
}

int handleLoot(LootEvent* plootev)
{
    InvItem* pi = plootev->item;
    if(pi->canLoot())
    {
        updateTexture(pi->icon, LOOTED_ICON_RES);
        return true;
    }
    return false; 
}


...
// knows only LootSuccessEvent and player
Inventory::processEvents()
{
    while(!events.empty())
    {
        Event* pev = events.pop();
        ...
        case LOOT_SUCCESS_EVENT:
             player->GetInventory()->add( ((LootSuccessEvent*)pev)->item );
        ...
}

Bu sadece olası yollardan biridir. Muhtemelen çok fazla etkinliğe ihtiyacınız yok. Ve eminim verilerinizi daha iyi tanıyabilirsiniz, bu birçok yoldan sadece biridir.

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.