Alternatif fleksibel untuk banyak kelas polimorfik kecil (untuk digunakan sebagai properti atau pesan atau acara) C ++


9

Ada dua kelas dalam gim saya yang benar-benar bermanfaat, tetapi perlahan-lahan menjadi menyakitkan. Pesan dan Properti (properti pada dasarnya adalah komponen).

Keduanya berasal dari kelas dasar dan berisi id statis sehingga sistem hanya dapat memperhatikan yang mereka inginkan. Ini bekerja dengan sangat baik ... kecuali ...

Saya terus-menerus membuat jenis pesan baru dan tipe properti saat saya memperluas permainan saya. Setiap kali saya perlu menulis 2 file (hpp dan cpp) dan satu ton boilerplate untuk mendapatkan dasarnya sebuah classID dan satu atau dua tipe data standar atau sebuah pointer.

Itu mulai membuat bermain-main dan menguji ide-ide baru menjadi tugas nyata. Saya berharap ketika saya ingin membuat pesan atau tipe properti baru, saya ingin bisa mengetikkan sesuatu seperti

ShootableProperty:  int gunType, float shotspeed;

ItemCollectedMessage:  int itemType;

alih-alih membuat file header dan cpp, menulis konstruktor, termasuk kelas induk, dll.

Ada sekitar 20 - 40 baris (termasuk termasuk penjaga, dan semuanya) hanya untuk melakukan apa yang secara logis 1 atau 2 baris dalam pikiran saya.

Apakah ada pola pemrograman untuk mengatasi ini?

Bagaimana dengan scripting (yang saya tidak tahu) ... apakah ada cara untuk mendefinisikan sekelompok kelas yang hampir sama?


Inilah yang persis seperti satu kelas:

// Velocity.h

#ifndef VELOCITY_H_
#define VELOCITY_H_

#include "Properties.h"

#include <SFML/System/Vector2.hpp>

namespace LaB
{
namespace P
{

class Velocity: public LaB::Property
{
public:
    static const PropertyID id;

    Velocity(float vx = 0.0, float vy = 0.0)
    : velocity(vx,vy) {}
    Velocity(sf::Vector2f v) : velocity(v) {};

    sf::Vector2f velocity;
};

} /* namespace P */
} /* namespace LaB */
#endif /* LaB::P_VELOCITY_H_ */



// Velocity.cpp

#include "Properties/Velocity.h"

namespace LaB
{
namespace P
{

const PropertyID Velocity::id = Property::registerID();

} /* namespace P */
} /* namespace LaB */

Semua itu hanya untuk Vector 2D dan ID yang mengatakan mengharapkan vektor 2D. (Memang, beberapa properti memiliki elemen yang lebih rumit, tetapi ide yang sama)


3
Lihatlah ini, mungkin bisa membantu Anda. gameprogrammingpatterns.com/type-object.html

1
Semua ini terlihat seperti templat mungkin membantu, hanya saja tidak dengan inisialisasi statis. Dalam hal ini tentu bisa menjadi jauh lebih mudah, tetapi sulit untuk mengatakan tanpa informasi lebih lanjut tentang apa yang ingin Anda lakukan dengan ID tersebut dan mengapa Anda menggunakan warisan sama sekali. Menggunakan warisan publik tetapi tidak ada fungsi virtual jelas merupakan bau kode ... Ini bukan polimorfisme!
ltjax

Sudahkah Anda menemukan perpustakaan pihak ke-3 yang mengimplementasikannya?
Boris

Jawaban:


1

C ++ sangat kuat, tapi itu verbose . Jika yang Anda inginkan adalah banyak kelas polimorfik kecil yang semuanya berbeda, maka ya, akan membutuhkan banyak kode sumber untuk menyatakan dan mendefinisikan. Tidak ada yang bisa dilakukan tentang itu, sungguh.

Sekarang, seperti yang dikatakan ltjax, apa yang Anda lakukan di sini bukan polimorfisme , setidaknya untuk kode yang Anda berikan. Saya tidak bisa melihat antarmuka umum yang akan menyembunyikan implementasi spesifik sub-kelas. Kecuali mungkin untuk ID kelas, tetapi ini sebenarnya berlebihan dengan ID kelas nyata: itu namanya. Ini tampaknya hanya sekelompok kelas yang berisi beberapa data, tidak ada yang benar-benar rumit.

Tetapi ini tidak menyelesaikan masalah Anda: Anda ingin membuat banyak pesan dan properti dengan jumlah kode paling sedikit. Lebih sedikit kode berarti lebih sedikit bug sehingga ini adalah keputusan yang bijaksana. Sayangnya untuk Anda tidak ada solusi tunggal. Sulit untuk mengatakan apa yang paling sesuai dengan kebutuhan Anda tanpa tahu persis apa yang ingin Anda lakukan dengan pesan dan properti itu . Jadi izinkan saya memaparkan opsi Anda:

  1. Gunakan templat C ++ . Template adalah cara yang bagus untuk membiarkan kompiler "menulis kode" untuk Anda. Ini menjadi lebih dan menonjol di dunia C ++, karena bahasa berevolusi untuk mendukung mereka dengan lebih baik (mis. Anda sekarang dapat menggunakan sejumlah variabel parameter templat ). Ada seluruh disiplin ilmu yang didedikasikan untuk pembuatan kode secara otomatis melalui templat: templat metaprogram . Masalahnya adalah: itu sulit. Jangan berharap non-programmer dapat menambahkan properti baru sendiri jika Anda berencana untuk menggunakan teknik seperti itu.

  2. Gunakan macro C biasa-lama . Itu sekolah tua, mudah disalahgunakan, dan rawan kesalahan. Mereka juga sangat sederhana untuk dibuat. Macro hanyalah copy-paste yang dimuliakan yang dilakukan oleh preprocessor, jadi mereka sebenarnya cukup cocok untuk membuat banyak hal yang hampir sama dengan sedikit variasi. Tetapi jangan berharap programmer lain menyukai Anda karena menggunakannya, karena macro sering digunakan untuk menyembunyikan kekurangan dalam keseluruhan desain program. Namun, terkadang itu membantu.

  3. Pilihan lain adalah menggunakan alat eksternal untuk menghasilkan kode untuk Anda. Sudah disebutkan dalam jawaban sebelumnya jadi saya tidak akan memperluas itu.

  4. Ada bahasa lain yang kurang verbose dan akan memungkinkan Anda untuk membuat kelas dengan lebih mudah. Jadi jika Anda sudah memiliki binding skrip (atau Anda berencana memilikinya), mendefinisikan kelas-kelas dalam skrip mungkin menjadi pilihan. Mengaksesnya dari C ++ akan cukup rumit, dan Anda akan kehilangan sebagian besar manfaat dari penciptaan kelas yang disederhanakan. Jadi ini mungkin bisa dilakukan hanya Anda berencana melakukan sebagian besar logika gim Anda dalam bahasa lain.

  5. Akhirnya yang tak kalah pentingnya, Anda harus mempertimbangkan menggunakan desain berbasis data . Anda bisa mendefinisikan "kelas-kelas" dalam file teks sederhana menggunakan tata letak yang mirip dengan yang Anda usulkan sendiri. Anda harus membuat format khusus dan parser untuk itu, atau menggunakan salah satu dari beberapa opsi yang sudah tersedia (.ini, XML, JSON dan yang lainnya). Kemudian di sisi C ++, Anda harus membuat sistem yang mendukung koleksi berbagai jenis objek. Ini hampir setara dengan pendekatan skrip (dan mungkin membutuhkan lebih banyak pekerjaan), kecuali Anda akan dapat menyesuaikannya lebih tepat dengan kebutuhan Anda. Dan jika Anda membuatnya cukup sederhana, non-programmer mungkin dapat membuat hal-hal baru sendiri.


0

Bagaimana dengan alat pembuatan kode untuk membantu Anda?

misalnya, Anda bisa mendefinisikan jenis pesan dan anggota dalam file teks kecil dan memiliki alat kode gen menguraikannya dan menulis semua file C ++ boilerplate sebagai langkah pra-bangun.

Ada solusi yang sudah ada seperti ANTLR atau LEX / YACC, dan tidak akan sulit untuk roll sendiri tergantung pada kompleksitas properti dan pesan Anda.


Hanya sebuah alternatif untuk pendekatan LEX / YACC, ketika saya harus menghasilkan file yang sangat mirip dengan hanya modifikasi kecil, saya menggunakan skrip python sederhana dan kecil dan file template kode C ++ yang berisi tag. Skrip python mencari tag-tag ini dalam template yang menggantinya dengan token yang representatif dari elemen yang sedang dibuat.
pemenang

0

Saya menyarankan Anda untuk meneliti tentang Protokol Buffer Google ( http://code.google.com/p/protobuf/ ). Mereka adalah cara yang sangat pintar untuk menangani pesan umum. Anda hanya perlu menentukan properti dalam pola struct-llike dan pembuat kode melakukan semua pekerjaan menghasilkan kelas untuk Anda (Java, C ++ atau C #). Semua kelas yang dihasilkan memiliki parser teks dan biner, yang membuatnya baik untuk inisialisasi dan serialisasi pesan berbasis teks.


Pusat perpesanan saya adalah inti dari program saya - tahukah Anda jika buffer protokol menimbulkan overhead besar?
Bryan

Saya tidak berpikir mereka mengeluarkan biaya besar, karena API hanya kelas Builder untuk setiap pesan dan kelas untuk pesan itu sendiri. Google menggunakannya untuk inti dari infrastruktur mereka. Misalnya Entitas Mesin Google App semua dikonversi ke buffer protokol sebelum bertahan. Jika Anda ragu, saya menyarankan Anda untuk menerapkan uji perbandingan antara implementasi Anda saat ini dan buffer protokol. Jika menurut Anda overhead tersebut dapat diterima, gunakanlah.
dsilva.vinicius
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.