Membuat Sistem Barang Kuat


12

Tujuan saya adalah untuk membuat sistem item modular / generik mungkin yang dapat menangani hal-hal seperti:

  • Barang yang Dapat Diupgrade (+6 Katana)
  • Stat Modifiers (+15 dexterity)
  • Item Modifiers (% X kemungkinan untuk melakukan kerusakan Y, kesempatan untuk membekukan)
  • Item yang Dapat Diisi Ulang (Staf ajaib dengan 30 penggunaan)
  • Set Items (Equip 4 piece of X set untuk mengaktifkan fitur Y)
  • Kelangkaan (umum, unik, legendaris)
  • Disenchantable (pecah menjadi beberapa bahan kerajinan)
  • Craftable (bisa dibuat dengan bahan tertentu)
  • Konsumsi (daya serangan 5 menit% X, sembuhkan +15 hp)

* Saya dapat menyelesaikan fitur-fitur yang berani dalam pengaturan berikut.

Sekarang saya mencoba menambahkan banyak opsi kepada kami untuk mencerminkan apa yang ada dalam pikiran saya. Saya tidak berencana untuk menambahkan semua fitur ini yang diperlukan, tetapi saya ingin dapat mengimplementasikannya sesuai keinginan saya. Ini juga harus kompatibel dengan sistem inventaris dan serialisasi data.

Saya berencana untuk tidak menggunakan warisan sama sekali tetapi pendekatan entitas-komponen / data didorong. Awalnya saya memikirkan sebuah sistem yang memiliki:

  • BaseStat: kelas generik yang menyimpan statistik saat bepergian (dapat digunakan untuk item dan statistik karakter juga)
  • Item: kelas yang menyimpan data seperti daftar, nama, jenis barang dan hal-hal yang terkait dengan ui, actionName, deskripsi, dll.
  • IWeapon: antarmuka untuk senjata. Setiap senjata akan memiliki kelasnya sendiri dengan IWeapon diimplementasikan. Ini akan memiliki Attack dan referensi ke statistik karakter. Ketika senjata dilengkapi, datanya (Item class 'stat) akan disuntikkan ke dalam stat karakter (apa pun BaseStat yang dimilikinya, itu akan ditambahkan ke kelas karakter sebagai bonus Stat) Jadi misalnya, kami ingin menghasilkan pedang (berpikir untuk menghasilkan kelas item dengan json) sehingga pedang akan menambah 5 serangan ke statistik karakter. Jadi kita memiliki BaseStat sebagai ("Serangan", 5) (kita juga bisa menggunakan enum). Stat ini akan ditambahkan ke stat "Serangan" karakter sebagai BonusStat (yang akan menjadi kelas yang berbeda) setelah melengkapi itu. Jadi kelas bernama Sword mengimplementasikan IWeapon akan dibuat saat ituKelas Barang dibuat. Jadi kita bisa menyuntikkan statistik karakter ke pedang ini dan ketika menyerang, ia dapat mengambil statistik Serangan total dari statistik karakter dan menimbulkan kerusakan dalam metode Serangan.
  • BonusStat: adalah cara menambahkan statistik sebagai bonus tanpa menyentuh BaseStat.
  • Dapat dikonsumsi: Logika yang sama dengan IWeapon. Menambahkan stat langsung cukup mudah (+15 hp) tapi saya tidak yakin tentang menambahkan senjata sementara dengan pengaturan ini (% x untuk menyerang selama 5 menit).
  • IUpgradeable: Ini dapat diimplementasikan dengan pengaturan ini. Saya berpikir UpgradeLevel sebagai stat dasar, yang ditingkatkan setelah meningkatkan senjata. Ketika ditingkatkan, kita dapat menghitung ulang BaseStat senjata untuk mencocokkan tingkat Upgrade nya.

Sampai titik ini, saya dapat melihat bahwa sistem itu cukup baik. Tetapi untuk fitur lain, saya pikir kita perlu sesuatu yang lain, karena misalnya saya tidak dapat mengimplementasikan fitur Craftable ke ini karena BaseStat saya tidak akan dapat menangani fitur ini dan ini adalah di mana saya terjebak. Saya bisa menambahkan semua bahan sebagai Stat tetapi itu tidak masuk akal.

Agar mudah bagi Anda untuk berkontribusi ini, berikut adalah beberapa pertanyaan yang dapat Anda bantu:

  • Haruskah saya melanjutkan pengaturan ini untuk mengimplementasikan fitur lain? Apakah mungkin tanpa warisan?
  • Apakah ada cara yang dapat Anda pikirkan, untuk mengimplementasikan semua fitur ini tanpa warisan?
  • Tentang Item Modifiers, bagaimana seseorang bisa mencapai itu? Karena sifatnya yang sangat generik.
  • Apa yang bisa dilakukan untuk mempermudah proses membangun arsitektur semacam ini, rekomendasi apa saja?
  • Apakah ada sumber yang bisa saya gali yang terkait dengan masalah ini?
  • Saya benar-benar mencoba untuk menghindari warisan, tetapi apakah Anda pikir ini akan diselesaikan / dicapai dengan warisan dengan mudah sambil menjaganya agar tetap dipertahankan?

Jangan ragu untuk menjawab hanya satu pertanyaan karena saya menyimpan pertanyaan yang sangat luas sehingga saya bisa mendapatkan pengetahuan dari berbagai aspek / orang.


EDIT


Mengikuti jawaban @ jjimenezg93, saya membuat sistem yang sangat mendasar dalam C # untuk pengujian, itu berhasil! Lihat apakah Anda dapat menambahkan apa pun ke dalamnya:

public interface IItem
{
    List<IAttribute> Components { get; set; }

    void ReceiveMessage<T>(T message);
}

public interface IAttribute
{
    IItem source { get; set; }
    void ReceiveMessage<T>(T message);
}

Sejauh ini, IItem dan IAttribute adalah antarmuka dasar. Tidak perlu (yang dapat saya pikirkan) untuk memiliki antarmuka dasar / atribut untuk pesan, jadi kami akan langsung membuat kelas pesan uji. Sekarang untuk kelas tes:


public class TestItem : IItem
{
    private List<IAttribute> _components = new List<IAttribute>();
    public List<IAttribute> Components
    {
        get
        {
            return _components;
        }

        set
        {
            _components = value;
        }
    }

    public void ReceiveMessage<T>(T message)
    {
        foreach (IAttribute attribute in Components)
        {
            attribute.ReceiveMessage(message);
        }
    }
}

public class TestAttribute : IAttribute
{
    string _infoRequiredFromMessage;

    public TestAttribute(IItem source)
    {
        _source = source;
    }

    private IItem _source;
    public IItem source
    {
        get
        {
            return _source;
        }

        set
        {
            _source = value;
        }
    }

    public void ReceiveMessage<T>(T message)
    {
        TestMessage convertedMessage = message as TestMessage;
        if (convertedMessage != null)
        {
            convertedMessage.Execute();
            _infoRequiredFromMessage = convertedMessage._particularInformationThatNeedsToBePassed;
            Debug.Log("Message passed : " + _infoRequiredFromMessage);

        }
    }
} 

public class TestMessage
{
    private string _messageString;
    private int _messageInt;
    public string _particularInformationThatNeedsToBePassed;
    public TestMessage(string messageString, int messageInt, string particularInformationThatNeedsToBePassed)
    {
        _messageString = messageString;
        _messageInt = messageInt;
        _particularInformationThatNeedsToBePassed = particularInformationThatNeedsToBePassed;
    }
    //messages should not have methods, so this is here for fun and testing.
    public void Execute()
    {
        Debug.Log("Desired Execution Method: \nThis is test message : " + _messageString + "\nThis is test int : " + _messageInt);
    }
} 

Ini adalah pengaturan yang diperlukan. Sekarang kita dapat menggunakan sistem (Berikut adalah untuk Persatuan).

public class TestManager : MonoBehaviour
{

    // Use this for initialization
    void Start()
    {
        TestItem testItem = new TestItem();
        TestAttribute testAttribute = new TestAttribute(testItem);
        testItem.Components.Add(testAttribute);
        TestMessage testMessage = new TestMessage("my test message", 1, "VERYIMPORTANTINFO");
        testItem.ReceiveMessage(testMessage);
    }

}

Lampirkan skrip TestManager ini ke komponen dalam adegan dan Anda dapat melihat di debug bahwa pesan berhasil diteruskan.


Untuk menjelaskan hal-hal: Setiap item dalam game akan menerapkan antarmuka IItem dan setiap Atribut (nama tidak boleh membingungkan Anda, itu berarti fitur / sistem item. Seperti yang Dapat Diperbaharui, atau disenchantable) akan menerapkan IAttribute. Kemudian kita memiliki metode untuk memproses pesan (mengapa kita membutuhkan pesan akan dijelaskan dalam contoh lebih lanjut). Jadi dalam konteksnya, Anda dapat melampirkan atribut ke suatu item dan membiarkan sisanya melakukan untuk Anda. Yang sangat fleksibel, karena Anda dapat menambah / menghapus atribut dengan mudah. Jadi contoh-pseudo akan Disenchantable. Kami akan memiliki kelas yang disebut Disenchantable (IAttribute) dan dalam metode Disenchant, ia akan meminta:

  • Daftar bahan-bahan (ketika item dibubarkan, item apa yang harus diberikan kepada pemain) catatan: IItem harus diperluas untuk memiliki ItemType, ItemID dll.
  • int resultModifier (jika Anda menerapkan semacam boost fitur disenchant, Anda dapat melewatkan int di sini untuk meningkatkan bahan yang diterima saat disenchanted)
  • int failureChance (jika proses disenchant memiliki peluang kegagalan)

dll.

Informasi ini akan disediakan oleh kelas yang disebut DisenchantManager, ia akan menerima item dan membentuk pesan ini sesuai dengan item (bahan dari item ketika disenchanted) dan perkembangan pemain (resultModifier and failureChance). Untuk meneruskan pesan ini, kami akan membuat kelas DisenchantMessage, yang akan bertindak sebagai badan untuk pesan ini. Jadi DisenchantManager akan mengisi DisenchantMessage dan mengirimkannya ke item. Item akan menerima pesan dan meneruskannya ke semua Attribut yang dilampirkan. Karena metode ReceiveMessage kelas Disenchantable akan mencari DisenchantMessage, hanya atribut Disenchantable yang akan menerima pesan ini dan menindaklanjutinya. Semoga ini mengosongkan hal-hal seperti yang terjadi pada saya :).


1
Anda mungkin menemukan beberapa inspirasi yang berguna dalam sistem pengubah yang digunakan dalam For Honor
DMGregory

@DMGregory Hai! Terima kasih untuk tautannya. Meskipun kelihatannya sangat banyak akal, sayangnya saya perlu bicara untuk memahami konsepnya. Dan saya mencoba mencari tahu pembicaraan yang sebenarnya, yang sayangnya konten khusus anggota GDCVault ($ 495 selama setahun adalah gila!). (Anda dapat menemukan ceramah di sini jika Anda memiliki keanggotaan GDCVault -, -
Vandarthul

Bagaimana, tepatnya, konsep "BaseStat" Anda menghalangi senjata yang bisa dirakit?
Attackfarm

Itu tidak benar-benar menghalangi tetapi tidak benar-benar cocok dengan konteks dalam pikiran saya. Adalah mungkin untuk menambahkan "Kayu", 2 dan "Besi", 5 sebagai BaseStat ke resep kerajinan, yang akan menghasilkan pedang. Saya pikir mengubah nama BaseStat ke BaseAttribute akan berfungsi lebih baik dalam konteks ini. Tapi tetap saja, sistem tidak akan dapat melayani tujuan itu. Pikirkan tentang barang habis pakai dengan daya serangan 5 menit -% 50. Bagaimana saya akan lulus sebagai BaseStat? "Perc_AttackPower", 50 ini harus diselesaikan sebagai "jika itu Perc, perlakukan bilangan bulat sebagai persentase" dan melewatkan info menit. O harap Anda mengerti maksud saya.
Vandarthul

@Attackfarm pada pemikiran kedua, konsep "BaseStat" ini dapat diperluas dengan memiliki daftar int bukan hanya satu int. jadi, untuk buff yang dapat dikonsumsi, saya dapat menyediakan "Attack", 50, 5, 1 dan IConsumable akan mencari 3 bilangan bulat, 1. - nilai, 2. - menit, 3. - apakah itu persentase atau tidak. Tapi rasanya tidak baik ketika sistem lain masuk dan dipaksa untuk menjelaskan sendiri hanya di int.
Vandarthul

Jawaban:


6

Saya pikir Anda dapat mencapai apa yang Anda inginkan dalam hal skalabilitas dan pemeliharaan dengan menggunakan Sistem Entitas-Komponen dengan warisan dasar dan sistem pesan. Tentu saja, ingatlah bahwa sistem ini adalah yang paling modular / dapat disesuaikan / terukur yang dapat saya pikirkan, tetapi mungkin akan berkinerja lebih buruk daripada solusi Anda saat ini.

Saya akan jelaskan lebih lanjut:

Pertama-tama, Anda membuat antarmuka IItemdan antarmuka IComponent. Barang apa pun yang ingin Anda simpan harus diwarisi IItem, dan komponen apa pun yang ingin Anda pengaruhi harus diwariskan IComponent.

IItemakan memiliki berbagai komponen dan metode untuk penanganan IMessage. Metode penanganan ini hanya mengirim pesan yang diterima ke semua komponen yang tersimpan. Kemudian, komponen yang tertarik pada pesan yang diberikan akan bertindak sesuai, dan yang lain akan mengabaikannya.

Satu pesan, misalnya, adalah tipe kerusakan, dan menginformasikan kedua penyerang dan menyerang, sehingga Anda tahu berapa banyak Anda memukul dan mungkin mengisi bilah kemarahan Anda berdasarkan kerusakan itu. Atau AI musuh dapat memutuskan untuk berlari jika menyerang Anda dan membuat kerusakan kurang dari 2HP. Ini adalah contoh bodoh tetapi menggunakan sistem yang mirip dengan ini saya sebutkan, Anda tidak perlu melakukan apa pun selain membuat pesan dan penanganan yang tepat untuk menambahkan sebagian besar mekanik semacam ini.

Saya memiliki implementasi untuk ECS dengan pengiriman pesan di sini , tetapi ini digunakan untuk entitas alih-alih item dan menggunakan C ++. Bagaimanapun, saya pikir itu bisa membantu jika Anda melihat component.h, entity.hdan messages.h. Ada banyak hal yang harus diperbaiki tetapi itu berhasil bagi saya dalam pekerjaan universitas yang sederhana itu.

Semoga ini bisa membantu.


Hey @ jjimenezg93, terima kasih atas jawaban Anda. Jadi untuk menguraikan contoh sederhana dari apa yang telah Anda jelaskan: Kami menginginkan pedang yaitu: - [Komponen] Disenchantable - Pengubah Stat [Komponen] - [Komponen] yang dapat diupgrade. Saya memiliki daftar tindakan yang berisi semua hal seperti: - DISENCHANT - MODIFY_STAT - UPGRADE Setiap kali item menerima pesan ini, memeriksa semua komponennya dan mengirimkan pesan ini, setiap komponen akan tahu apa yang harus dilakukan dengan pesan yang diberikan. Secara teori, ini tampak luar biasa! Saya tidak memeriksa contoh Anda, tetapi saya akan, terima kasih banyak!
Vandarthul

@ Vandarthul Ya, itulah ide dasarnya. Dengan cara ini, item tidak akan tahu apa-apa tentang komponennya sehingga tidak ada sambungan sama sekali, dan pada saat yang sama, item akan memiliki semua fungsionalitas yang Anda inginkan, yang juga dapat dibagi di antara berbagai jenis item. Saya harap ini sesuai dengan kebutuhan Anda!
jjimenezg93
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.