Haruskah objek dalam game 2D membuat itu sendiri?


16

Saya membuat game street-fighter 2D yang tidak berbasis ubin. Biasanya orang merekomendasikan bahwa entitas diberikan kepada penyaji yang membuat mereka, bukan membuat mereka sendiri, tetapi tampaknya kebalikannya lebih baik,

Mengapa yang satu lebih baik dari yang lain?

Terima kasih


Menurut Anda mengapa kebalikannya lebih baik?

1
@ Martin karena objek akan mengisyaratkan bitmap mana yang harus digunakan, jadi mengapa tidak melakukan object-> render ();
jmasterx

Jawaban:


11

Beberapa pertimbangan:

  • seperti yang Anda sebutkan, setiap sprite harus "memberi petunjuk" tentang bitmap mana yang akan digunakan, tetapi jika entitas harus membuat sendiri. Apa 'petunjuk' itu? Jika ini adalah referensi untuk bitmap, sprite sheet, dll ... yang berbeda untuk setiap sprite, maka Anda mungkin berakhir menggunakan lebih banyak memori daripada yang diperlukan, atau mengalami kesulitan mengelola memori itu. Keuntungan dari renderer terpisah adalah Anda hanya memiliki satu kelas yang bertanggung jawab atas manajemen aset apa pun. Yang mengatakan, dalam game pertempuran seperti SF2, Anda mungkin hanya memiliki dua sprite;)

  • seperti disebutkan di tempat lain, setiap kali Anda ingin mengubah API grafis Anda, Anda harus mengubah kode untuk semua sprite Anda.

  • rendering jarang dilakukan tanpa referensi ke beberapa konteks grafis. Jadi ada variabel global yang mewakili konsep ini, atau setiap sprite memiliki antarmuka dengan render (GraphicalContext ctx). Ini mencampur API grafis dan logika permainan Anda (yang sebagian orang akan anggap tidak menarik), dan dapat menyebabkan masalah kompilasi.

  • Saya pribadi menemukan bahwa memisahkan rendering dari entitas individu adalah langkah pertama yang menarik dalam arah melihat permainan Anda sebagai sistem yang tidak perlu grafis sama sekali. Yang saya maksudkan adalah bahwa ketika Anda melakukan rendering, Anda menyadari banyak gameplay terjadi di "dunia non-grafis" di mana koordinat entitas, status internal mereka, dll ... adalah yang penting. Ini membuka pintu untuk pengujian otomatis, lebih banyak sistem yang dipisahkan, dll ...

Secara keseluruhan, saya cenderung memilih sistem di mana rendering dilakukan oleh kelas yang terpisah. Itu tidak berarti sprite Anda tidak dapat memiliki beberapa atribut yang "berhubungan secara grafis" (nama animasi, bingkai animasi, tinggi x lebar, id sprite dll ...), jika itu membuat renderer lebih mudah untuk ditulis atau lebih efisien.

Dan saya tidak tahu apakah itu akan berlaku untuk 3D (di mana gagasan tentang jerat, dan variabel koordinat yang akan Anda gunakan mungkin akan dikaitkan dengan API 3D Anda; sedangkan x, y, h, w cukup independen dari setiap 2D API).

Semoga ini bisa membantu.


11

Anda ingin sistem rendering mengendalikan apa yang ditarik saat. Jika sebaliknya sprite mengendalikan rendering Anda kehilangan banyak keuntungan efisiensi dan fleksibilitas. Saya berpendapat bahwa memiliki sistem render dalam kontrol menghasilkan kode yang lebih bersih.

Beberapa keuntungan dari rendering terpusat:

  • z-booking:
    Jika objek game itu sendiri yang bertanggung jawab untuk rendering Anda harus memastikan Anda memanggilnya dalam urutan yang benar. Kalau tidak, objek latar belakang dapat digambar di atas objek latar depan.
    Dengan sistem render dalam kontrol, ia dapat memilih untuk menyortir semua objek render, mendeteksi overloaps pada waktu render dan hanya me-rendernya, atau hanya tidak memesan semuanya bersama-sama. Intinya adalah bahwa keputusan dapat dibuat dengan mudah sekarang.
  • batching:
    Keuntungan nyata lainnya yang memungkinkan sistem render untuk mengendalikan adalah batching. Di sini sekali lagi sistem render memiliki opsi untuk batch sprite membuat pembagian menjadi tekstur. Ini dapat menggunakan pengirisan segitiga untuk membuat semuanya dengan satu panggilan. Mungkin bisa men-cache beberapa perhitungan render. Atau bisa saja membuat setiap sprite pada gilirannya dengan tidak ada barang mewah itu. (Catatan: dimungkinkan batch ketika setiap objek membuat sendiri, tetapi masalahnya kurang efisien dan lebih kompleks).

Cara saya menerapkan ini di gim saya agar objek gim mendaftarkan sprite yang mereka inginkan digambar dengan sistem render. Ketika objek tidak lagi ingin objek yang ditarik itu membatalkan registrasi sprite, atau menandainya tidak aktif.

Semua itu dikatakan. Jika lebih mudah untuk membuat objek gim Anda membuat dirinya dengan segala cara melakukannya dengan cara itu. Jauh lebih penting untuk membuat kemajuan dan mendapatkan sesuatu / apa pun yang diambil daripada memiliki arsitektur yang sempurna.


Tentang z-pemesanan jika objek menggambar sendiri tidak dapat sistem memutuskan tentang perintah untuk memanggil metode menggambar mereka? Maksud saya terpusat vs non terpusat tampaknya tidak membuat perbedaan tentang pemesanan z.
GorillaApe

3

Penafian: pertanyaan Anda tidak memberikan banyak detail jadi saya merespons dengan prinsip umum. Maafkan saya jika saya salah mengerti penggunaan Anda atau 'render'.

Saya biasanya menggunakan objek eksternal untuk membuat berbagai aktor dalam adegan sebagai cara merangkum properti tingkat adegan dan metode di luar 'objek aktor' individu. Objek dalam adegan hanya boleh berisi metode dan properti internal; mereka seharusnya hanya tahu tentang diri mereka sendiri dan apa yang mereka lakukan. Agaknya, mereka akan dipengaruhi oleh objek lain dalam game serta input pengguna. Ini akan mempengaruhi bagaimana / apakah mereka ditampilkan di layar. 'Objek sutradara' dapat, misalnya, menerjemahkan penekanan tombol 'w' untuk melompat, lalu memberi tahu objek aktor .jump (). Logika tingkat sutradara semacam itu juga dapat memberi tahu aktor untuk masuk atau keluar dari adegan sepenuhnya.

Cheers, David


Tetapi dalam pengertian itu tidak bisa sutradara hanya mengatakan acton-> setVisible (false); ?
jmasterx

Bahkan dalam kasus setVisible (false), itu adalah entitas eksternal yang melakukan rendering dengan memeriksa variabel aktor yang terlihat dan menjadikannya hanya jika itu benar.
Nav

Hanya membuat aktor tidak terlihat tidak menghapusnya dari tempat kejadian. Itu juga harus berhenti berpartisipasi dalam tabrakan dll.
finnw

3

Bagaimana jika suatu hari Anda ingin memport game Anda ke resolusi yang berbeda (yaitu iPhone dan teman-teman). Dengan demikian, properti global tentang rendering perubahan, bagaimana Anda dengan mudah memperbarui kode Anda?


3

Apa yang saya gunakan adalah desain berbasis pengamat. Ketika saya membuat sebuah instance dari kelas yang ingin saya render, maka sebuah pointer ke dalamnya disimpan di kelas Renderer pusat. Saat Anda menelepon RenderFrame(), maka renderer sudah memiliki semua objek yang ada yang perlu di-render dan diakses propertinya untuk melakukannya. Kelas-kelas itu sendiri tidak tahu bahwa mereka akan diberikan sama sekali. API ini bagus dan bersih dan mudah digunakan.


1
+1 Menarik. Saya telah menggunakan pendekatan ini untuk suara saat menggunakan Pola Pengunjung untuk grafik. Saya pikir ini lebih masuk akal untuk suara karena sementara grafik dan AI berjalan pada jam yang sama, mixer audio berjalan pada yang lain sehingga model acara lebih mudah. Juga tidak kritis jika suatu peristiwa pergerakan (yang menyebabkan pan / reverb saluran audio berubah) terlambat beberapa milidetik tetapi sangat penting jika sprite digambar dalam kondisi yang salah.
finnw

2

Secara umum selalu tentang betapa mudahnya memelihara dan memperluas kode Anda. Besok Anda mengetahui bahwa Anda tidak suka API grafik yang Anda gunakan saat ini, dan ingin beralih. Apakah Anda sekarang harus melalui semua kelas objek Anda dan mengubah segalanya, atau apakah Anda masih perlu mengubah kode Anda di satu titik pusat proyek?

Itu tergantung pada apa objek Anda benar-benar lakukan ketika Anda memanggil render (). Selama mereka hanya membungkus panggilan metode di sekitar mesin grafis Anda, itu baik-baik saja, karena logika <-> perbedaan grafis masih akan diberikan.

Misalnya, jika metode render () Anda pada dasarnya adalah metode kenyamanan dan terlihat seperti ini:

void MyClass::render(const Graphics &g)
{
    g.draw(this);
}

atau

void MyClass::render()
{
   mySprite->render();
}

atau

void MyClass::render()
{
    mySprite->UseShader(thatshader);
    mySprite->render();
}

atau dekat dengan itu, saya tidak berpikir itu masalah sama sekali.

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.