Saya ingin menyingkirkan pola desain make-everything-static-dan-global, tapi bagaimana caranya?


11

Saya membuat crawler bawah tanah kecil di ruang angkasa, dan saya ingin mendengar beberapa saran tentang cara membuat backend dari mesin lebih bagus. Pada dasarnya, saat ini semuanya didasarkan pada omong kosong manajer:

  • BackgroundManager: memiliki AddBackground(image, parallax)metode untuk membuat efek latar belakang keren.
  • ConfigManager: membaca / membuat file konfigurasi dan juga menyimpan data yang dibaca dari file konfigurasi tersebut.
  • DrawManager: memiliki Draw(sprite)metode untuk menggambar barang ke layar, dan hal-hal seperti SetView(view), GetView()dll.
  • EntityManager: memegang semua entitas yang aktif dan memiliki metode untuk menambah, menghapus, dan menemukan entitas.
  • DungeonManager (sebenarnya disebut GridManager, tapi ini untuk kesederhanaan): memiliki metode seperti GenerateDungeon(), PlaceEnemies(), PlaceFinish()dll

Sekarang saya bahkan tidak setengah jalan mendaftar semua manajer saya, jadi saya pikir ini harus berubah. Permainan saya juga didasarkan pada Layar, yang membuatnya lebih menyebalkan karena saya tidak perlu setengah dari hal-hal yang dikelola manajer saya, misalnya, menu utama (saya tidak perlu fisika / entitas / ruang bawah tanah di menu utama saya !)

Sekarang saya berpikir untuk membuat manajer tidak statis, dan memberikan ScreenMainGame saya contoh dari semua manajer khusus game. Tapi itu membuat memanggil / membuat segala sesuatu yang berhubungan dengan manajer berantakan besar ... misalnya, jika saya ingin menggambar ruang bawah tanah saya dari tempat yang tidak ada ScreenMainGame.Draw(), saya harus melakukan ini ...

((ScreenMainGame)ScreenManager.CurrentScreen).GridManager.Draw()

Itu sangat jelek.

Jadi, sesama pengembang game, apakah ada di antara Anda yang punya ide bagaimana mengatasi kekacauan ini? Saya akan dihargai!


Saya tidak yakin bagaimana cara membantu Anda, tetapi saya akan merekomendasikan membaca buku yang bagus tentang pola desain. Saya telah membaca Pola Desain Kepala Pertama dan sangat mudah dimengerti. Contohnya ada di Jawa, tapi saya pikir itu cukup dekat dengan C # untuk membantu Anda. Maaf jika saran saya terlalu pemula.
Amplify91

Apa yang Anda gunakan untuk berinteraksi dengan kartu grafis? XNA? SlimDX?
BlueRaja - Danny Pflughoeft

@ BlueRaja: Saya menggunakan SFML.NET.
Dlaor

Dalam hal ini, Anda cukup menggunakan metode normal untuk mengatasi masalah ini di C #: Lihat tautan terakhir saya di bawah ini, serta Apa itu injeksi ketergantungan?
BlueRaja - Danny Pflughoeft

Jawaban:


10

Bagaimana dengan mesin berbasis komponen ?

Anda akan memiliki kelas utama bernama Engine, yang akan menyimpan daftar GameScreens, yang akan memiliki daftar Components.

Mesin ini memiliki Updatedan Drawmetode dan kedua panggilan GameScreen's Updatedan Drawmetode, yang sendiri pergi melalui setiap komponen dan panggilan Updatedan Draw.

Disajikan seperti itu, saya setuju bahwa itu terdengar seperti desain yang buruk dan berulang-ulang. Tapi percayalah, kode saya menjadi lebih bersih dengan menggunakan pendekatan berbasis komponen daripada dengan semua kelas manajer lama saya .

Jauh lebih mudah untuk mempertahankan kode seperti itu juga, karena Anda hanya akan melalui hierarki kelas besar dan tidak harus mencari BackgroundManagersemua latar belakang yang berbeda. Anda hanya memiliki ScrollingBackground, ParallaxBackground, StaticBackground, dll, yang semua berasal dari Backgroundkelas.

Anda akhirnya akan membangun mesin yang cukup solid yang dapat Anda gunakan kembali atas semua proyek Anda dengan banyak komponen yang sering digunakan dan metode penolong (misalnya FrameRateDisplayersebagai utilitas debugging, Spritekelas sebagai sprite dasar dengan tekstur dan metode ekstensi untuk vektor dan generasi nomor acak).

Anda tidak akan lagi memiliki BackgroundManagerkelas, tetapi Backgroundkelas yang akan mengelola sendiri.

Saat gim Anda mulai, yang harus Anda lakukan hanyalah ini pada dasarnya:

// when declaring variables:
Engine engine;

// when initializing:
engine = new Engine();
engine.Initialize();
engine.LoadContent();
engine.AddGameScreen(new MainMenuScreen());

// when updating:
engine.Update();

// when drawing:
engine.Draw();

Dan itu saja untuk kode permulaan gim Anda.

Kemudian, untuk layar menu utama:

class MainMenuScreen : MenuScreen // where MenuScreen derives from the GameScreen class
{
    const int ENEMY_COUNT = 10;

    StaticBackground background;
    Player player;
    List<Enemy> enemies;

    public override void Initialize()
    {
        background = new StaticBackground();
        player = new Player();
        enemies = new List<Enemy>();

        base.AddComponent(background); // defined within the GameScreen class
        base.AddComponent(player);
        for (int i = 0; i < ENEMY_COUNT; ++i)
        {
            Enemy newEnemy = new Enemy();
            enemies.Add(newEnemy);
            base.AddComponent(newEnemy);
        }
    }
}

Anda mendapatkan ide umum.

Anda juga akan menyimpan referensi di Enginedalam semua GameScreenkelas Anda , untuk dapat menambahkan layar baru bahkan di dalam GameScreenkelas (misalnya ketika pengguna mengklik tombol StartGame saat berada di dalam Anda MainMenuScreen, Anda dapat beralih ke GameplayScreen).

Hal yang sama berlaku untuk Componentkelas: harus memegang referensi dari induknya GameScreen, untuk memiliki akses ke Enginekelas dan induknya GameScreenuntuk menambahkan komponen baru (misalnya Anda dapat membuat kelas terkait HUD DrawableButtonyang disebut memegang DrawableTextkomponen dan StaticBackgroundkomponen).

Anda bahkan dapat menerapkan pola desain lain setelah itu, seperti "pola desain layanan" (tidak yakin tentang nama persisnya) tempat Anda dapat menyimpan berbagai layanan bermanfaat di dalam Enginekelas Anda (Anda cukup menyimpan daftar IServicedan membiarkan kelas lain menambahkan layanan sendiri ). misalnya saya akan menyimpan Camera2Dkomponen di atas semua proyek saya sebagai layanan untuk menerapkan transformasi ketika menggambar komponen lain. Ini menghindari harus meneruskannya sebagai parameter di mana pun.

Kesimpulannya, mungkin ada desain lain yang lebih baik untuk sebuah mesin, tetapi saya menemukan mesin yang diusulkan oleh tautan ini sangat elegan, sangat mudah dirawat, dan dapat digunakan kembali. Saya pribadi akan merekomendasikan setidaknya mencobanya.


1
XNA mendukung semua ini di luar kotak via GameComponentdan layanan. Tidak perlu Enginekelas yang terpisah .
BlueRaja - Danny Pflughoeft

+1 untuk jawaban ini. Juga, apakah masuk akal untuk meletakkan gambar di utas terpisah dari utas pembaruan game?
f20k

1
@BlueRaja - DannyPflughoeft: Memang, tetapi saya berasumsi XNA tidak digunakan, jadi saya menjelaskan sedikit tentang cara melakukannya.
Jesse Emond

@ f20k: Ya, hampir seperti XNA melakukannya. Saya tidak tahu bagaimana ini diterapkan. = / Pasti ada artikel di internet tentang cara melakukannya. :)
Jesse Emond

Ya, saya tidak menggunakan XNA tapi ini sepertinya alternatif yang bagus untuk apa yang saya lakukan. Saat ini saya sedang membaca buku "Pola Desain Kepala Pertama" untuk melihat apakah ada alternatif lain. Bersulang!
Dlaor


-3

Hanya karena mereka statis atau global tidak berarti mereka harus selalu dimuat / diinisialisasi. Gunakan pola Singleton dan biarkan manajer dibebaskan dan dimuat kembali sesuai permintaan.


4
Singleton hanyalah fasad untuk masalah mendasar yang coba dipecahkan OP di sini.
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.