Saya akan sedikit tidak setuju dengan semua orang dan mengatakan bahwa pendekatan relasional masuk akal di sini. Yang menarik di sini adalah item dapat memiliki banyak peran. Masalah utama adalah bahwa pemetaan antara tata letak relasional ini dan tata letak OO dalam kode tidak akan terasa "alami", tapi saya pikir di sisi database banyak peran dapat diekspresikan dengan bersih (tanpa pengkodean atau redundansi yang aneh, hanya bergabung) .
Hal pertama yang harus diputuskan adalah berapa banyak data spesifik item dan berapa banyak dibagi oleh semua item dari jenis tertentu.
Inilah yang akan saya lakukan jika semua data spesifik untuk item:
// ITEMS table: attributes common to all items
item_id | name | owner | location | sprite_id | ...
1 | Light Saber | 14 (Tchalvek) | 381 (Tchalvek house) | 5663 | ...
// WEAPONS table: attributes for items that are weapons
item_id | damage | damage_type | durability | ...
1 | 5 | sharp | 13 | ...
// LIGHTING table: attributes for items that serve as lights
item_id | radius | brightness | duration | ...
1 | 3 meters | 50 | 8 hours | ...
Dalam desain ini, setiap item ada di tabel Item, bersama dengan atribut yang dimiliki semua (atau sebagian besar) item. Setiap peran tambahan yang dapat dimainkan item adalah tabel terpisah.
Jika Anda ingin menggunakannya sebagai senjata, Anda akan mencarinya di tabel Senjata. Jika itu ada, maka itu dapat digunakan sebagai senjata. Jika tidak ada di sana, maka itu tidak dapat digunakan sebagai senjata. Keberadaan catatan memberi tahu Anda apakah itu senjata. Dan jika itu ada di sana, semua atribut spesifik senjata disimpan di sana. Karena atribut tersebut disimpan secara langsung alih-alih dalam bentuk yang disandikan, Anda dapat melakukan kueri / filter dengannya. (Misalnya, untuk halaman metrik game Anda, Anda mungkin ingin mengagregasi pemain berdasarkan jenis kerusakan senjata, dan Anda dapat melakukannya dengan beberapa gabungan dan grup-by damage_type.)
Item dapat memiliki beberapa peran, dan ada di lebih dari satu tabel peran-spesifik (dalam contoh ini, baik senjata maupun pencahayaan).
Jika itu hanya boolean seperti "apakah ini bisa dipegang", saya akan memasukkannya ke dalam tabel Item. Mungkin layak untuk di-cache "apakah ini senjata" dll di sana sehingga Anda tidak perlu melakukan pencarian pada Senjata dan tabel peran lainnya. Namun, itu menambah redundansi sehingga Anda harus berhati-hati untuk tetap menyinkronkannya.
Rekomendasi Ari untuk memiliki tabel tambahan per jenis juga dapat digunakan dengan pendekatan ini jika beberapa data tidak akan bervariasi per item. Misalnya, jika kerusakan senjata tidak bervariasi per item, tetapi perannya masih bervariasi per item, Anda dapat memasukkan faktor atribut senjata bersama ke dalam tabel:
// WEAPONS table: attributes for items that are weapons
item_id | durability | weapon_type
1 | 13 | light_saber
// WEAPONTYPES table: attributes for classes of weapons
weapon_type_id | damage | damage_type
light_saber | 5 | energy
Pendekatan lain adalah jika peran yang dimainkan oleh item tidak bervariasi berdasarkan item, tetapi hanya berdasarkan jenis item. Dalam hal ini Anda akan meletakkan item_type ke dalam tabel Items, dan dapat menyimpan properti seperti "apakah itu senjata" dan "apakah itu dapat ditampung" dan "apakah itu cahaya" di tabel ItemTypes? Dalam contoh ini saya juga membuat nama item tidak berbeda per item:
// ITEMS table: attributes per item
item_id | item_type | owner | location
1 | light_saber | 14 (Tchalvek) | 381 (Tchalvek house)
// ITEMTYPES table: attributes shared by all items of a type
item_type | name | sprite_id | is_holdable | is_weapon | is_light
light_saber | Light Saber | 5663 | true | true | true
// WEAPONTYPES table: attributes for item types that are also weapons
item_type | damage | damage_type
light_saber | 5 | energy
Kemungkinan itemtypes dan weaponontypes tidak berubah selama permainan, jadi Anda bisa memuat tabel-tabel itu ke dalam memori satu kali, dan mencari atribut-atribut itu di tabel hash alih-alih dengan penggabungan basis data.
Sayangnya, situasi seperti ini adalah tempat database relasional (seperti SQL) gagal, dan database non-relasional (seperti MongoDB ) unggul. Yang sedang berkata, bukan tidak mungkin untuk memodelkan data dalam database relasional, dan karena sepertinya basis kode Anda sudah bergantung pada SQL, berikut adalah model yang akan saya gunakan:
Alih-alih membuat item dan menggunakan tabel, buat tabel dan tabel referensi "[item] _type" untuk setiap jenis item.
Berikut ini beberapa contoh:
Solusi ini memberi Anda banyak fleksibilitas jangka panjang dan skalabilitas, mengurangi (jika tidak menghilangkan) ruang yang terbuang, dan mendokumentasikan diri sendiri (tidak seperti "item_use_data"). Ini melibatkan sedikit pengaturan di sisi pengembang, tetapi, menurut saya, ini adalah solusi paling elegan yang tersedia untuk situasi di mana Anda perlu menggunakan database relasional untuk menyimpan data Anda. Secara umum, database non-relasional jauh lebih baik untuk pengembangan game, karena mereka lebih fleksibel dalam cara mereka memodelkan data, sementara menjadi lebih berkinerja daripada database berbasis SQL - menjadikannya pilihan "win-win".
Sunting 1: Memperbaiki kesalahan dengan bidang potion_type_id
Sunting 2: Menambahkan lebih detail pada basis data non-relasional vs relasional untuk memberikan perspektif tambahan
sumber
Pertama, buang pendekatan pewarisan berorientasi objek dan pergi dengan sistem berbasis komponen .
Setelah Anda selesai melakukannya, tata letak SQL tiba-tiba menjadi jauh lebih mudah. Anda memiliki satu tabel untuk setiap jenis komponen dengan nomor ID bersama. Jika Anda ingin item # 17, Anda mencari "item ID 17" di setiap tabel. Setiap tabel yang memiliki kunci akan ditambahkan komponennya.
Tabel Item Anda berisi semua data yang diperlukan untuk item secara umum (nama, harga jual, berat, ukuran, apa pun yang dibagikan di antara semua item.) Tabel Senjata Anda berisi semua data yang sesuai untuk senjata, tabel Ramuan Anda berisi semua data yang sesuai untuk ramuan, tabel Armor Anda berisi semua data yang sesuai untuk baju besi. Ingin penutup dada, itu entri di Item dan entri di Armor. Ingin pedang yang bisa Anda minum, Anda hanya memasukkan entri di setiap meja, dan bam, Anda sudah selesai.
Ingatlah bahwa pola yang sama ini tidak terlalu spesifik untuk barang tertentu - Anda dapat menggunakan ini untuk makhluk, zona, apa pun yang Anda inginkan. Ini sangat serbaguna.
sumber
Menggunakan SQL adalah kesalahan besar Anda. Sama sekali TIDAK cocok untuk menyimpan data desain game statis.
Jika Anda tidak dapat menjauh dari SQL, saya akan mempertimbangkan menyimpan item dalam serial dari. Yaitu
Tentu saja, itu jelek dan membuang semua "kebaikan" SQL keluar jendela, tetapi apakah Anda benar - benar membutuhkannya ? Kemungkinan besar, Anda membaca semua data item Anda di permulaan permainan, dan tidak pernah
SELECT
dengan hal lain selain ituitem_id
.sumber
Bergantung pada berapa banyak sifat yang mungkin Anda perlukan, Anda bisa menggunakan bitmask sederhana untuk objek dengan bit berbeda sesuai dengan ciri berbeda:
Kemudian Anda dapat melakukan tes bit sederhana untuk melihat apakah suatu objek dapat digunakan untuk fungsi tertentu.
Jadi "botol kaca" mungkin memiliki nilai 101111 yang berarti dapat dipegang, dapat digunakan sebagai senjata, mudah pecah, Anda dapat membuangnya dan dapat berisi cairan.
Editor apa pun yang Anda buat untuk item kemudian dapat memiliki satu set kotak centang sederhana untuk mengaktifkan / menonaktifkan sifat pada suatu objek.
sumber
Di proyek kami, kami memiliki item_attributes untuk "data ekstra" berbeda yang mungkin dimiliki suatu item. Ditata kira-kira seperti ini:
Kemudian kita memiliki tabel atribut yang terlihat seperti ini:
Ari Patrick benar, akhirnya db relasional tidak dibuat untuk ini. Kelemahannya adalah kami memiliki beberapa prosedur yang cukup rumit untuk menghasilkan item baru (dilakukan melalui alat eksternal - yang saya sangat rekomendasikan, Jangan coba dan secara manual menambahkan ini, Anda hanya akan membingungkan diri Anda sendiri)
Opsi lain yang Anda miliki adalah menggunakan bahasa skrip untuk membuat templat item, maka Anda dapat dengan mudah menguraikan yang ada dan menggunakannya untuk membuat item baru. Anda tentu saja masih harus menyimpan data item dalam database tetapi pada saat itu Anda tidak perlu khawatir tentang spesifik membuat item baru, Anda dapat cukup banyak hanya menyalin dan file skrip lama, mengubah beberapa informasi dan Anda baik untuk pergi.
Sejujurnya, jika kita melakukan kembali bagaimana kita membuat item statis baru kita mungkin akan pergi untuk pendekatan yang lebih sederhana menggunakan templat item skrip.
sumber
Ini adalah hubungan banyak-ke-banyak Anda yang khas, tidak ada yang terlalu esoteris untuk basis data relasional yang mampu. Anda memiliki banyak sifat untuk satu objek, dan satu sifat apa pun dapat digunakan oleh satu atau lebih tipe objek yang berbeda. Model tiga relasi (tabel), dengan satu menjadi hubungan asosiasi, dan Anda selesai. Pengindeksan yang tepat akan memastikan Anda membaca data dengan cepat.
Lapisan ORM dalam kode Anda dan Anda harus memiliki sedikit masalah bolak-balik antara DB dan middleware. Banyak ORM yang dapat membuat sendiri kelas secara otomatis, sehingga menjadi lebih "tidak terlihat".
Adapun untuk database NoSQL, tidak ada alasan Anda tidak dapat melakukannya dengan itu. Saat ini sedang populer untuk mendukung teknologi itu dalam perdagangan kain dan blog, tetapi mereka datang dengan banyak masalah sendiri: platform yang relatif belum matang, bagus untuk bacaan sederhana yang jarang berubah (seperti satu-ke-banyak twit dalam profil) tetapi buruk untuk pembacaan atau pembaruan dinamis yang rumit, rantai alat pendukung yang buruk, data yang berlebihan dan masalah integritas yang menyertainya, dll. Namun, mereka menawarkan daya tarik skalabilitas yang lebih baik karena mereka menghindari berbagai tingkat kemampuan transaksional dan overhead-nya, dan model distribusi / replikasi yang lebih mudah .
Hobgoblin biasa dari database relasional vs database NoSQL adalah kinerja. RDMBS yang berbeda memiliki tingkat overhead yang berbeda yang terlibat yang membuatnya kurang disukai untuk penskalaan ke tingkat Facebook atau Twitter. Namun, sangat tidak mungkin Anda akan menghadapi masalah tersebut. Bahkan kemudian, sistem server berbasis SSD yang sederhana dapat membuat perdebatan kinerja menjadi tidak berguna.
Mari kita perjelas: kebanyakan basis data NoSQL adalah tabel hash yang terdistribusi secara fundamental, dan akan membatasi Anda dengan cara yang sama dengan tabel hash dalam kode Anda, yaitu. tidak semua data cocok dengan model itu. Model Relasional jauh lebih kuat untuk memodelkan hubungan antar data. (Faktor perancu adalah bahwa sebagian besar RDBMSes adalah sistem warisan yang tidak disetel dengan baik untuk tuntutan 0,0001% dari web yang populer, yaitu Facebook dkk.)
sumber
Di sinilah saya menemukan lebih banyak pemetaan ATAU modern yang benar-benar berguna, seperti Entity Framework 4 dan fitur pertama kode- nya (CTP) . Anda cukup menulis kelas dan hubungan mereka dalam kode reguler dan bahkan tanpa harus menghiasnya atau menjalankan alat apa pun secara manual, EF akan menghasilkan backing store dalam format SQL untuk Anda, dengan tabel tautan yang diperlukan dan semua ... benar-benar melepaskan kreativitas. ^^
sumber
Inilah yang sekarang saya pertimbangkan:
Karena setiap "sifat" pada dasarnya memerlukan perubahan dalam kode, jadi saya telah memutuskan untuk tetap mempertahankan sifat (dan data default apa pun yang diperlukan) dalam kode itu sendiri (setidaknya untuk saat ini).
Misalnya
$traits = array('holdable'=>1, 'weapon'=>1, 'sword'=>array('min_dam'=>1, 'max_dam'=>500));
Kemudian item mendapatkan bidang "trait_data" dalam database yang akan menggunakan
json_encode()
fungsi untuk disimpan dalam format JSON.Plan adalah bahwa item akan mewarisi semua statistik default dari sifat induknya, dan hanya akan memiliki sifat over-ride yang menentukan perbedaan dari apa yang ditetapkan sebagai sifat bawaan.
Kelemahan dari bidang sifat adalah bahwa sementara saya bisa mengedit bagian json dengan tangan ... ... itu tidak akan benar-benar mudah atau aman untuk melakukannya dengan data yang ada di database.
sumber
Ini agak hacky, dan saya tidak menjamin itu desain DB yang bagus; kelas DB saya beberapa waktu yang lalu, dan mereka tidak datang dengan cepat ke pikiran. Tetapi jika item dijamin memiliki, katakanlah, kurang dari 10 item, Anda bisa memberikan setiap item bidang atribut1, dan bidang atribut2, dan seterusnya hingga atribut10. Ini akan menghilangkan kebutuhan Anda untuk tabel atribut item banyak-ke-banyak, dengan biaya membatasi jumlah atribut.
Melihat kembali itu, saya cukup yakin itu adalah desain yang mengerikan, tetapi itu berarti Anda dapat tetap dengan database relasional yang nyaman dan tidak harus pergi ke wilayah yang belum dipetakan. Terserah Anda untuk memutuskan apakah pertukaran itu sepadan.
sumber
Nevermind memberikan jawaban yang baik, tapi saya ingin tahu, apakah Anda bahkan membutuhkan database untuk ini? Menyimpan semua data dalam file biasa dan memuatnya ke dalam program saat peluncuran sepertinya cara paling cerdas untuk melakukan ini.
Sunting:
Benar, dalam lingkungan yang didorong oleh permintaan kewarganegaraan, Anda sebaiknya menyimpan data dalam basis data. Tulis data Anda dalam file dan tulis sepotong kode untuk mengubahnya menjadi database dengan tipe Nevermind yang disarankan.
Bergantian jika jumlah objek tidak terlalu besar menyatakan lot secara harfiah dalam file kode mungkin metode tercepat.
sumber