Bagaimana cara menangani gambar besar yang sewenang-wenang dalam game 2D?

13

Pertanyaan

Ketika Anda memiliki gim 2D yang menggunakan gambar sangat besar (lebih besar dari yang dapat didukung oleh perangkat keras Anda), apa yang Anda lakukan? Mungkin ada beberapa solusi menarik untuk masalah ini yang tidak pernah terjadi pada saya sebelumnya.

Saya pada dasarnya mengerjakan sejenis pembuat game petualangan grafis. Target audiens saya adalah orang-orang dengan sedikit pengalaman pengembangan game (dan pemrograman). Jika Anda bekerja dengan aplikasi seperti itu, tidakkah Anda lebih suka untuk itu menangani masalah secara internal daripada meminta Anda untuk "pergi membagi gambar Anda"?

Konteks

Sudah diketahui bahwa kartu grafis memaksakan serangkaian batasan pada ukuran tekstur yang dapat mereka gunakan. Misalnya, ketika bekerja dengan XNA, Anda dibatasi untuk ukuran tekstur maksimum 2048 atau 4096 piksel tergantung pada profil yang Anda pilih.

Biasanya ini tidak menimbulkan banyak masalah dalam game 2D karena kebanyakan dari mereka memiliki level yang dapat dibangun dari potongan individual yang lebih kecil (mis. Ubin atau sprite yang diubah).

Tapi pikirkan beberapa game petualangan grafis point'n'click klasik (mis. Monkey Island). Kamar-kamar dalam permainan petualangan grafis biasanya dirancang secara keseluruhan, dengan sedikit atau tanpa bagian yang dapat diulang, sama seperti pelukis yang bekerja pada lanskap. Atau mungkin gim seperti Final Fantasy 7 yang menggunakan latar belakang besar yang telah dirender.

Beberapa kamar ini bisa menjadi cukup besar, sering mencakup tiga atau lebih layar lebar. Sekarang jika kita mempertimbangkan latar belakang ini dalam konteks game definisi tinggi modern, mereka akan dengan mudah melebihi ukuran tekstur maksimum yang didukung.

Sekarang, solusi yang jelas untuk ini adalah untuk membagi latar belakang menjadi bagian-bagian yang lebih kecil yang sesuai dengan persyaratan dan menarik mereka berdampingan. Tetapi apakah Anda (atau artis Anda) harus menjadi orang yang membelah semua tekstur Anda?

Jika Anda bekerja dengan API tingkat tinggi, bukankah sebaiknya dipersiapkan untuk menghadapi situasi ini dan melakukan pemisahan dan pemasangan tekstur secara internal (baik sebagai pra-proses seperti Pipa Konten XNA atau saat runtime)?

Edit

Inilah yang saya pikirkan, dari sudut pandang implementasi XNA.

Mesin 2D saya hanya membutuhkan sebagian kecil fungsi Texture2D. Saya benar-benar dapat mengurangi ke antarmuka ini:

public interface ITexture
{
    int Height { get; }
    int Width { get; }
    void Draw(SpriteBatch spriteBatch, Vector2 position, Rectangle? source, Color  color, float rotation, Vector2 origin, Vector2 scale, SpriteEffects effects, float layerDepth);
}

Satu-satunya metode eksternal yang saya gunakan yang bergantung pada Texture2D adalah SpriteBatch.Draw () sehingga saya bisa membuat jembatan di antara mereka dengan menambahkan metode ekstensi:

    public static void Draw(this SpriteBatch spriteBatch, ITexture texture, Vector2 position, Rectangle? sourceRectangle, Color color, float rotation, Vector2 origin, Vector2 scale, SpriteEffects effects, float layerDepth)
    {
        texture.Draw(spriteBatch, position, sourceRectangle, color, rotation, origin, scale, effects, layerDepth);
    }

Ini akan memungkinkan saya untuk menggunakan ITexture secara bergantian setiap kali saya menggunakan Texture2D sebelumnya.

Lalu saya bisa membuat dua implementasi berbeda dari ITexture misalnya RegularTexture dan LargeTexture, di mana RegularTexture hanya akan membungkus Texture2D biasa.

Di sisi lain, LargeTexture akan menyimpan daftar masing-masing Texture2D yang sesuai dengan salah satu potongan gambar penuh. Bagian yang paling penting adalah memanggil Draw () pada LargeTexture harus dapat menerapkan semua transformasi dan menggambar semua bagian seolah-olah mereka hanya satu gambar yang berdekatan.

Akhirnya, untuk membuat seluruh proses transparan, saya akan membuat kelas pemuat tekstur terpadu yang akan bertindak sebagai Metode Pabrik. Itu akan mengambil jalur tekstur sebagai parameter dan mengembalikan ITexture yang akan menjadi RegularTexture atau LargeTexture tergantung pada ukuran gambar yang melebihi batas atau tidak. Tetapi pengguna tidak perlu tahu yang mana itu.

Sedikit berlebihan atau apakah itu terdengar oke?

David Gouveia
sumber
1
Jika Anda ingin memecah gambar, perpanjang Pipeline Konten untuk melakukannya secara terprogram. Tidak semua fungsi ada untuk mencakup setiap skenario dan pada titik tertentu Anda harus mengembangkannya sendiri. Membagi suara secara pribadi seperti solusi paling sederhana, karena Anda kemudian dapat menangani gambar seperti ubin peta, yang memiliki banyak sumber daya.
DMan
Melakukannya di saluran konten adalah pendekatan yang paling masuk akal. Tetapi dalam kasus saya, saya perlu memuat gambar saya saat runtime dan saya sudah berhasil membuat solusi runtime (itulah sebabnya saya menanyakan pertanyaan ini kemarin). Tetapi keindahan yang sebenarnya datang dari mengambil "peta ubin" ini dan membuatnya berperilaku seperti tekstur normal. Yaitu Anda masih bisa meneruskannya ke spritebatch untuk menggambar, dan Anda masih bisa menentukan posisi, rotasi, skala, src / dest segi empat, dll. Saya hampir setengah jalan sekarang :)
David Gouveia
Tapi sejujurnya, saya sudah pada titik di mana saya bertanya-tanya apakah semua yang benar-benar layak atau jika saya hanya harus menunjukkan peringatan kepada pengguna mengatakan kepadanya bahwa ukuran gambar maksimum yang didukung adalah 2048x2048 dan dilakukan dengan itu.
David Gouveia
Terserah Anda soal desain. Jika Anda menyelesaikan proyek dan Anda tidak dapat menggulir di antara kamar-kamar itu akan lebih baik daripada editor yang tidak selesai yang memungkinkan Anda untuk menggulir tekstur besar: D
Aleks
Menyembunyikannya di API terdengar seperti cara yang bagus untuk membuat kehidupan penulis game lebih mudah. Saya mungkin akan mengimplementasikannya di kelas Polygon (sprite) dan Texture, dan bukan khusus-kasus gambar yang lebih kecil, tetapi hanya membuat mereka ubin yang 1x1. Jadi kelas tekstur adalah grup tekstur yang menggambarkan semua ubin & berapa banyak baris / kolom. Kelas Polygon kemudian melihat info ini untuk memisahkan dirinya dan menggambar setiap ubin dengan tekstur yang sesuai. Dengan begitu, itu adalah kelas yang sama. Poin bonus jika kelas sprite Anda hanya menggambar ubin yang terlihat, dan grup tekstur tidak memuat tekstur sampai diperlukan.
uliwitness

Jawaban:

5

Saya pikir Anda berada di jalur yang benar. Anda harus membagi gambar menjadi potongan-potongan kecil. Karena Anda membuat pembuat game, Anda tidak dapat menggunakan pipa Konten XNA. Kecuali jika pembuat Anda lebih seperti Mesin yang masih akan meminta pengembang untuk menggunakan Visual Studio. Jadi, Anda perlu membangun rutinitas Anda sendiri yang akan melakukan pemisahan. Anda bahkan harus mempertimbangkan streaming potongan-potongan sedikit sebelum menjadi visizble sehingga Anda masih tidak membatasi berapa banyak memori video yang harus dimiliki pemain.

Ada beberapa trik yang bisa Anda lakukan khusus untuk game petualangan. Saya membayangkan seperti semua game petualangan klasik, Anda akan memiliki beberapa lapisan tekstur ini sehingga ... karakter Anda dapat berjalan di belakang pohon atau bangunan ...

Jika Anda ingin lapisan ini memiliki efek paralaxing maka ketika Anda membelah ubin Anda cukup lewati semua tembus sekali. Di sini Anda perlu memikirkan ukuran ubin. Ubin yang lebih kecil akan menambah mengatur overhead dan menarik panggilan, tetapi akan lebih sedikit data di mana ubin yang lebih besar akan lebih ramah GPU tetapi akan memiliki banyak transparansi.

Jika Anda tidak memiliki efek paralaxing maka alih-alih menutupi seluruh adegan dengan 2-4 gambar raksasa yang memiliki kedalaman 32 bit Anda dapat membuat hanya satu kedalaman 32 bit. Dan Anda dapat memiliki lapisan stensil atau kedalaman yang hanya akan 8 bit per piksel.

Saya tahu ini terdengar sulit untuk mengelola aset oleh pengembang non-game tetapi sebenarnya tidak harus begitu. Misalnya jika Anda memiliki jalan dengan 3 pohon dan pemain berjalan di belakang 2 pohon dan di depan pohon ketiga dan latar belakang lainnya ... Buat tata letak adegan seperti yang Anda inginkan di editor dan kemudian di membangun langkah dari pembuat gim Anda, Anda dapat memanggang gambar raksasa ini (ubin kecil dari gambar besar).

Tentang bagaimana game klasik melakukannya. Saya tidak yakin mereka mungkin melakukan trik yang sama, tetapi Anda harus ingat bahwa pada saat layar berukuran 320x240 gim-gamenya memiliki 16 warna yang ketika menggunakan tekstur palattelized memungkinkan Anda untuk menyandikan 2 piksel dalam byte tunggal. Tapi ini bukan cara kerja arsitektur saat ini: D

Semoga berhasil

Aleks
sumber
Terima kasih, Banyak ide yang sangat menarik di sini! Saya sebenarnya telah melihat teknik lapisan stensil yang digunakan sebelumnya di Adventure Game Studio. Sedangkan untuk aplikasi saya, saya melakukan hal-hal yang sedikit berbeda. Kamar tidak harus memiliki satu gambar latar belakang. Sebagai gantinya ada palet gambar yang diimpor pengguna, dan layer latar / latar depan. Pengguna bebas untuk menarik dan melepaskan potongan ke dalam ruangan untuk membuatnya. Jadi jika dia mau, dia bisa menyusunnya dari potongan-potongan kecil juga tanpa harus membuat objek game non-interaktif. Tidak ada paralaks, karena hanya ada dua lapisan itu.
David Gouveia
Dan saya telah melihat file data untuk Monkey Island Edisi Khusus (remake HQ). Setiap latar belakang dibagi menjadi 1024x1024 bagian (bahkan jika sebagian besar gambar dibiarkan tidak digunakan). Pokoknya, periksa edit saya untuk apa yang ingin membuat seluruh proses transparan.
David Gouveia
Saya mungkin akan memilih sesuatu yang lebih masuk akal seperti 256x256. Dengan cara ini saya tidak akan menyia-nyiakan sumber daya dan jika kemudian memutuskan untuk menerapkan streaming itu akan memuat potongan yang lebih masuk akal. Mungkin saya tidak menjelaskannya dengan cukup baik, tetapi saya menyarankan agar Anda bisa memanggang semua objek permainan statis kecil ini menjadi tekstur besar. Yang akan Anda simpan adalah, jika Anda memiliki tekstur latar belakang yang besar, semua piksel ditutupi oleh objek statis di atas.
Aleks
Begitu, jadi gabungkan semua objek statis ke latar belakang, lalu bagi dan buat atlas tekstur. Saya juga bisa memanggang semuanya menjadi atlas tekstur mengikuti alur pemikiran itu. Itu ide yang bagus juga. Tetapi saya akan membiarkannya nanti, karena saat ini saya tidak memiliki langkah "membangun", yaitu editor dan klien game berjalan di atas mesin yang sama dan format data yang sama.
David Gouveia
Saya suka pendekatan stensil tetapi jika saya membuat editor game petualangan saya mungkin tidak akan menggunakannya ... Mungkin karena jika saya membangun alat seperti itu saya akan ditujukan untuk pengembang game. Baik itu pro dan kontra. Misalnya, Anda dapat menggunakan gambar lain tempat bit dapat menentukan pemicu per piksel atau jika Anda memiliki animasi air, Anda dapat dengan mudah menempelkannya. Catatan: Satu saran aneh yang tidak terkait melihat ke dalam diagram UML State / Activity untuk skrip Anda.
Aleks
2

Potong mereka sehingga mereka tidak lagi besar, seperti yang Anda katakan. Tidak ada sihir. Game-game 2D lama itu melakukannya atau ditampilkan dalam perangkat lunak, dalam hal ini tidak ada batasan perangkat keras di luar ukuran RAM. Yang perlu dicatat adalah bahwa banyak dari game 2D tersebut benar-benar tidak memiliki latar belakang yang besar, mereka hanya menggulirnya secara perlahan sehingga mereka merasa besar.

Apa yang ingin Anda lakukan dalam pembuat game petualangan grafis adalah pra-proses gambar-gambar besar selama beberapa jenis "membangun" atau "mengintegrasikan" langkah sebelum permainan dikemas untuk dijalankan.

Jika Anda ingin menggunakan API dan pustaka yang sudah ada alih-alih menulis sendiri, saya sarankan Anda mengonversi gambar-gambar besar itu menjadi ubin selama "build" dan menggunakan mesin ubin 2D, yang jumlahnya banyak.

Jika Anda ingin menggunakan teknik 3D Anda sendiri, Anda mungkin masih ingin membagi menjadi ubin dan menggunakan 2D API yang terkenal dan dirancang dengan baik untuk menulis perpustakaan 3D Anda sendiri untuk itu, dengan cara ini Anda dijamin setidaknya mulai dengan desain API yang baik dan desain yang lebih sedikit diperlukan pada bagian Anda.

Patrick Hughes
sumber
Melakukannya pada waktu build akan ideal ... Tapi editor saya juga menggunakan XNA untuk rendering, bukan hanya mesinnya. Itu berarti bahwa sekali pengguna mengimpor gambar dan menyeretnya ke dalam ruangan, XNA seharusnya sudah dapat membuatnya. Jadi dillema besar saya adalah apakah akan melakukan pemisahan dalam memori saat memuat konten, atau pada disk saat mengimpor konten. Juga, secara fisik membagi gambar menjadi beberapa file akan berarti bahwa saya akan membutuhkan cara untuk menyimpan ini secara berbeda, sedangkan melakukannya dalam memori saat runtime tidak akan memerlukan perubahan apa pun pada file data gim.
David Gouveia
1

Jika Anda terbiasa dengan bagaimana tampilan quadtree dalam praktik visual, saya telah menggunakan metode yang memotong detail gambar besar menjadi gambar yang lebih kecil, relatif mirip dengan apa yang terlihat seperti bukti / visualisasi quadtree. Namun saya dibuat sedemikian rupa untuk memotong area khusus yang dapat dikodekan atau dikompres berbeda berdasarkan warna. Anda dapat menggunakan metode ini dan melakukan apa yang saya jelaskan, karena ini juga berguna.

Pada saat dijalankan, memotongnya akan membutuhkan lebih banyak memori untuk sementara dan menyebabkan waktu muat menjadi melambat. Saya akan mengatakan itu tergantung pada apakah Anda lebih peduli tentang penyimpanan fisik atau waktu buka game yang dibuat dengan editor Anda.

Load / Run Time: Cara saya melakukan pemuatan hanya memotongnya menjadi potongan-potongan berukuran proporsional. Akun untuk satu piksel pada bagian paling kanan jika jumlah piksel aneh, tidak ada yang suka gambar mereka dipotong, terutama pengguna yang tidak berpengalaman yang mungkin tidak tahu bahwa itu tidak sepenuhnya terserah mereka. Buatlah mereka setengah lebar ATAU setengah tinggi (atau 3rds, 4d apa pun) alasan untuk tidak menjadi kotak atau 4 bagian (2 baris 2 kolom) adalah karena itu akan membuat memori ubin lebih kecil karena Anda tidak akan khawatir tentang x dan y pada saat yang sama (dan tergantung pada berapa banyak gambar yang besar, itu bisa sangat penting)

Sebelum Tangan / Secara Otomatis: Dalam hal ini saya menyukai gagasan memberikan pengguna pilihan untuk menyimpannya dalam satu gambar atau menyimpannya sebagai bagian yang terpisah (satu gambar harus default). Menyimpan gambar sebagai .gif akan bekerja dengan baik. Gambar akan berada dalam satu file, dan alih-alih setiap frame menjadi animasi, gambar akan lebih seperti arsip terkompresi dari semua gambar yang sama (yang pada dasarnya adalah apa .gif sebenarnya). Ini akan memungkinkan kemudahan transportasi file fisik, kemudahan memuat:

  1. Ini satu file
  2. Semua file memiliki format yang hampir identik
  3. Anda dapat dengan mudah memilih kapan DAN jika ingin memotongnya menjadi masing-masing tekstur
  4. Mungkin lebih mudah untuk mengakses masing-masing gambar jika sudah dalam satu gif dimuat. Karena tidak akan memerlukan banyak kekacauan file gambar dalam memori

Oh dan jika Anda menggunakan metode .gif, Anda harus mengubah ekstensi file ke sesuatu yang lain (.gif -> .kittens) demi mengurangi kebingungan ketika .gif Anda menjiwai seperti file yang rusak. (jangan khawatir tentang legalitas itu, .gif adalah format terbuka)

Joshua Hedges
sumber
Halo dan terima kasih atas komentar Anda! Maaf jika saya salah paham tetapi bukankah apa yang Anda tulis terutama berkaitan dengan kompresi dan penyimpanan? Dalam hal ini yang saya benar-benar khawatirkan adalah pengguna aplikasi saya dapat mengimpor gambar apa pun , dan mesin (dalam XNA) yang mampu memuat dan menampilkan gambar apa pun saat runtime . Saya telah berhasil menyelesaikannya hanya dengan menggunakan GDI untuk membaca bagian gambar yang berbeda menjadi Tekstur XNA yang terpisah, dan membungkusnya dalam kelas yang berperilaku seperti tekstur biasa (yaitu mendukung gambar dan transformasi secara keseluruhan).
David Gouveia
Tetapi karena penasaran, dapatkah Anda menjelaskan lebih lanjut tentang kriteria apa yang Anda gunakan untuk memilih area gambar mana yang masuk ke setiap bagian?
David Gouveia
Beberapa di antaranya mungkin berada di atas kepala Anda jika Anda kurang berpengalaman dalam penanganan gambar. Tapi pada dasarnya, saya menggambarkan memotong gambar menjadi segmen-segmen. Dan ya, titik .gif menjelaskan penyimpanan dan pemuatan, tetapi itu dimaksudkan sebagai metode bagi Anda untuk memotong gambar, dan kemudian menyimpannya di komputer bagaimana itu. Jika Anda menyimpannya sebagai gif, saya mengatakan bahwa Anda dapat memotongnya menjadi gambar individu, dan kemudian menyimpannya sebagai animasi gif, dengan setiap potongan gambar disimpan sebagai bingkai animasi terpisah. Ini bekerja dengan baik dan saya bahkan menambahkan fitur lain yang mungkin bisa membantu.
Joshua Hedges
Sistem quadtree seperti yang saya jelaskan sepenuhnya dinyatakan sebagai referensi, karena dari situlah saya mendapat ide. Meskipun alih-alih memadatkan pertanyaan yang mungkin dapat digunakan untuk pembaca yang mungkin memiliki masalah serupa, kami harus menggunakan pesan pribadi jika Anda ingin tahu lebih banyak.
Joshua Hedges
Roger, saya mendapat bagian tentang menggunakan bingkai GIF sebagai arsip sejenis. Tapi saya juga bertanya-tanya, bukankah GIF merupakan format yang diindeks dengan palet warna terbatas? Bisakah saya menyimpan seluruh gambar RGBA 32bpp di setiap frame? Dan saya membayangkan proses memuatnya berakhir lebih rumit, karena XNA tidak mendukung hal ini.
David Gouveia
0

Ini akan terdengar jelas, tetapi, mengapa tidak membagi kamar Anda menjadi potongan-potongan kecil? Pilih ukuran sewenang-wenang yang tidak akan membenturkan kepala ke kartu grafis apa pun (seperti 1024x1024, atau mungkin lebih besar) dan pisahkan kamar Anda menjadi beberapa bagian.

Saya tahu ini menghindari masalah, dan jujur, ini adalah masalah yang sangat menarik untuk dipecahkan. Bagaimanapun, ini semacam solusi sepele, yang mungkin bisa digunakan untuk Anda.

ashes999
sumber
Saya pikir saya mungkin telah menyebutkan alasan di suatu tempat di utas ini, tetapi karena saya tidak yakin saya akan mengulanginya. Pada dasarnya karena ini bukan game melainkan pembuat game untuk masyarakat umum (pikirkan sesuatu pada lingkup yang sama dengan pembuat RPG), jadi alih-alih memaksakan batasan ukuran tekstur ketika pengguna mengimpor aset mereka sendiri, mungkin lebih baik untuk menangani pemisahan dan penjahitan secara otomatis di belakang layar tanpa pernah mengganggu mereka dengan detail teknis dari batasan ukuran tekstur.
David Gouveia
Oke, itu masuk akal. Maaf, kurasa aku melewatkan itu.
ashes999