Bagaimana saya bisa dengan bersih dan elegan menangani data dan ketergantungan antar kelas


12

Saya sedang mengerjakan game topdown 2d di SFML 2, dan perlu menemukan cara yang elegan di mana semuanya akan bekerja dan cocok bersama.

Izinkan saya menjelaskan. Saya memiliki sejumlah kelas yang mewarisi dari basis abstrak yang menyediakan metode menggambar dan metode pembaruan untuk semua kelas.

Dalam lingkaran permainan, saya memanggil pembaruan dan menggambar di setiap kelas, saya membayangkan ini adalah pendekatan yang cukup umum. Saya memiliki kelas untuk ubin, tabrakan, pemain dan manajer sumber daya yang berisi semua ubin / gambar / tekstur. Karena cara input bekerja di SFML, saya memutuskan untuk meminta setiap kelas menangani input (jika perlu) dalam panggilan pembaruannya.

Sampai sekarang saya telah melewati dependensi sesuai kebutuhan, misalnya, di kelas pemain ketika tombol gerakan ditekan, saya memanggil metode pada kelas tabrakan untuk memeriksa apakah posisi pemain ingin pindah akan menjadi tabrakan, dan hanya memindahkan pemain jika tidak ada tabrakan.

Ini berfungsi dengan baik untuk sebagian besar, tapi saya percaya itu bisa dilakukan dengan lebih baik, saya hanya tidak yakin bagaimana caranya.

Saya sekarang memiliki hal-hal yang lebih kompleks yang perlu saya terapkan, misalnya: seorang pemain dapat berjalan ke suatu objek di tanah, tekan tombol untuk mengambilnya / menjarahnya dan kemudian akan muncul di inventaris. Ini berarti bahwa beberapa hal perlu terjadi:

  • Periksa apakah pemain berada dalam jangkauan item yang dapat dijarah pada penekanan tombol, jika tidak, jangan lanjutkan.
  • Temukan item.
  • Perbarui tekstur sprite pada item dari tekstur default menjadi tekstur "dijarah".
  • Perbarui tumbukan untuk item: mungkin telah berubah bentuk atau telah dihapus sepenuhnya.
  • Persediaan perlu diperbarui dengan item yang ditambahkan.

Bagaimana cara saya membuat semuanya berkomunikasi? Dengan sistem saya saat ini, saya akan berakhir dengan kelas saya keluar dari ruang lingkup, dan metode panggilan satu sama lain di semua tempat. Saya bisa mengikat semua kelas dalam satu manajer besar dan memberikan masing-masing referensi ke kelas manajer orangtua, tetapi ini tampaknya hanya sedikit lebih baik.

Setiap bantuan / saran akan sangat dihargai! Jika ada sesuatu yang tidak jelas, saya senang untuk memperluas hal-hal.


1
Anda mungkin ingin mempertimbangkan komposisi di sini, daripada warisan. Lihatlah contoh-contoh komposisi dan mungkin memberi Anda beberapa ide. Ungkapan pimpl mungkin membantu menyelesaikan masalah juga.
OriginalDaemon

5
Salah satu artikel kanon tentang komposisi: Berevolusi Hierarki Anda
doppelgreener

Tampaknya terlalu terlokalisasi. Coba Ulasan Kode SE?
Anko

Jawaban:


5

Tidak yakin apakah komposisi akan menyelesaikan semua masalah. Mungkin sebagian bisa membantu. Tetapi jika apa yang Anda inginkan adalah memisahkan kelas saya akan melihat lebih banyak peristiwa didorong logika. Dengan cara ini misalnya Anda akan memiliki fungsi OnLoot yang perlu memiliki posisi pemain dan info tentang loot yang tersedia untuk menemukan yang paling dekat. Kemudian fungsi mengirimkan acara ke item yang dijarah. Item yang dijarah dalam siklus proses acara menangani peristiwa ini sehingga barang hanya perlu tahu cara memperbarui dirinya. Fungsi OnLoot juga dapat memperbarui inventaris pemain atau item itu sendiri dapat mengirimkan pembaruanInventory / * event OnLootSucess * dan pemain / inventaris akan menanganinya dalam siklus proses prosesnya sendiri.

Pro: Anda telah memisahkan beberapa kelas Anda

Cons: menambahkan kelas acara, mungkin overhead kode yang tidak dibutuhkan.

Berikut adalah salah satu cara yang mungkin tentang bagaimana tampilannya:

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

Ini hanyalah salah satu cara yang mungkin. Mungkin Anda tidak membutuhkan banyak acara. Dan saya yakin Anda bisa mengetahui data Anda dengan lebih baik, ini hanya satu dari banyak cara.

Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.