Desain peta utuh vs. desain susunan ubin

11

Saya sedang mengerjakan RPG 2D, yang akan menampilkan peta penjara bawah tanah / kota biasa (pra-dibuat).

Saya menggunakan ubin, yang kemudian saya gabungkan untuk membuat peta. Rencana awal saya adalah merakit ubin menggunakan Photoshop, atau program grafis lainnya, untuk memiliki satu gambar lebih besar yang kemudian dapat saya gunakan sebagai peta.

Namun, saya telah membaca di beberapa tempat orang berbicara tentang bagaimana mereka menggunakan array untuk membangun peta mereka di mesin (jadi Anda memberikan array x ubin ke mesin Anda, dan itu mengumpulkan mereka sebagai peta). Saya dapat memahami bagaimana ini dilakukan, tetapi tampaknya jauh lebih rumit untuk diterapkan, dan saya tidak dapat melihat manfaat yang jelas.

Apa metode yang paling umum, dan apa kelebihan / kekurangan masing-masing?

Cristol.GdM
sumber
1
Masalah utamanya adalah memori. Tekstur yang memenuhi layar 1080p sekali adalah sekitar 60mb. Jadi gambar menggunakan int per pixel, ubin menggunakan int per (pixel / (tilesize * tilesize)). Jadi jika ubin 32,32 Anda dapat mewakili peta 1024 kali lebih besar dengan menggunakan ubin vs piksel. Juga waktu bertukar tekstur akan menyakitkan mendorong banyak memori di sekitar dll ...
ClassicThunder

Jawaban:

19

Pertama, izinkan saya mengatakan bahwa RPG 2D dekat dan sangat saya sukai dan bekerja dengan mesin MORPG DX7 VB6 lama (jangan tertawa, itu 8 tahun yang lalu, sekarang :-)) adalah hal pertama yang membuat saya tertarik pada pengembangan game . Baru-baru ini, saya mulai mengubah gim yang saya garap di salah satu mesin itu untuk menggunakan XNA.

Yang mengatakan, rekomendasi saya adalah bahwa Anda menggunakan struktur berbasis ubin dengan layering untuk peta Anda. Dengan API grafik apa pun yang Anda gunakan, Anda akan memiliki batasan ukuran tekstur yang dapat Anda muat. Belum lagi batas memori tekstur kartu grafis. Jadi, mengingat ini, jika Anda ingin memaksimalkan ukuran peta Anda sementara tidak hanya meminimalkan jumlah dan ukuran tekstur yang Anda muat ke dalam memori, tetapi juga mengurangi ukuran aset Anda pada hard drive pengguna DAN waktu muat, Anda pasti akan ingin pergi dengan ubin.

Sejauh implementasi berjalan, saya telah masuk ke detail tentang bagaimana saya menanganinya pada beberapa pertanyaan di sini di GameDev.SE dan di blog saya (keduanya terhubung di bawah), dan bukan itu yang Anda tanyakan jadi saya hanya akan masuk ke dasar-dasar di sini. Saya juga akan mencatat fitur ubin yang menjadikannya bermanfaat daripada memuat beberapa gambar besar yang telah dibuat sebelumnya. Jika ada yang tidak jelas, beri tahu saya.

  1. Hal pertama yang perlu Anda lakukan adalah membuat tilesheet. Ini hanya gambar besar yang berisi semua ubin Anda selaras dalam kotak. Ini (dan mungkin yang ekstra tergantung pada jumlah ubin) akan menjadi satu-satunya hal yang perlu Anda muat. Hanya 1 gambar! Anda bisa memuat 1 per peta atau satu dengan setiap ubin di dalam game; organisasi apa pun yang bekerja untuk Anda.
  2. Selanjutnya, Anda perlu memahami bagaimana Anda dapat mengambil "lembar" itu dan menerjemahkan setiap ubin menjadi angka. Ini cukup mudah dengan beberapa matematika sederhana. Perhatikan bahwa pembagian di sini adalah pembagian bilangan bulat , sehingga tempat desimal dijatuhkan (atau dibulatkan ke bawah, jika Anda mau). Bagaimana mengkonversi sel menjadi koordinat dan kembali.
  3. OK, sekarang setelah Anda memecah tilesheet menjadi serangkaian sel (angka), Anda dapat mengambil angka-angka itu dan memasukkannya ke dalam wadah apa pun yang Anda suka. Demi kesederhanaan, Anda bisa menggunakan array 2D.

    int[,] mapTiles = new int[100,100]; //Map is 100x100 tiles without much overhead
  4. Selanjutnya, Anda ingin menggambar mereka. Salah satu cara Anda dapat membuat BANYAK ini lebih efisien (tergantung pada ukuran peta) adalah menghitung hanya sel-sel yang sedang dilihat kamera dan memutarnya. Anda dapat melakukan ini dengan mengambil koordinat larik ubin peta dari sudut kiri atas ( tl) dan brsudut kanan bawah ( ). Kemudian loop dari tl.X to br.Xdan, dalam loop bersarang, dari tl.Y to br.Yuntuk menggambar mereka. Contoh kode di bawah ini:

    for (int x = tl.X; x <= br.X;x++) {
        for (int y = tl.Y; y <= br.Y;y++) {
            //Assuming tileset setup from image
            Vector2 tilesetCoordinate = new Vector2((mapTiles[x,y] % 8) * 32,(mapTiles[x,y] / 8) * 32);
            //Draw 32x32 tile using tilesetCoordinate as the source x,y
        }
    }
    
  5. Jackpot! Itulah dasar-dasar dari mesin genteng. Anda dapat melihat bahwa memiliki peta 1000x1000 dengan biaya overhead yang tidak banyak. Juga, jika Anda memiliki kurang dari 255 ubin, Anda bisa menggunakan array byte yang mengurangi memori sebesar 3 byte per sel. Jika byte terlalu kecil, ushort mungkin cukup untuk kebutuhan Anda.

Catatan: Saya mengabaikan konsep koordinat dunia (yang menjadi dasar posisi kamera Anda) karena itu, saya pikir, berada di luar cakupan jawaban ini. Anda dapat membaca tentang itu di sini di GameDev.SE.

Sumber Daya Mesin Ubin Saya
Catatan: Semua ini ditargetkan pada XNA, tetapi cukup banyak berlaku untuk apa pun - Anda hanya perlu mengubah panggilan undian.

  • Jawaban saya untuk pertanyaan ini menguraikan bagaimana saya menangani sel-sel peta dan layering dalam permainan saya. (Lihat tautan ketiga.)
  • Jawaban saya untuk pertanyaan ini menjelaskan bagaimana saya menyimpan data dalam format biner.
  • Ini adalah posting blog pertama (baik, secara teknis kedua, tetapi pertama "teknis") tentang pengembangan game yang sedang saya kerjakan. Seluruh seri berisi informasi tentang hal-hal seperti pixel shaders, pencahayaan, perilaku ubin, gerakan dan semua hal yang menyenangkan. Saya benar-benar memperbarui posting untuk memasukkan konten jawaban saya ke tautan pertama yang saya posting di atas, jadi Anda mungkin ingin membacanya (saya mungkin telah menambahkan beberapa hal). Jika Anda memiliki pertanyaan, Anda dapat memberikan komentar di sana atau di sini dan saya akan dengan senang hati membantu.

Sumber Daya Mesin Ubin Lainnya

  • Tutorial mesin ubin dari situs ini memberi saya dasar yang saya gunakan untuk membuat peta saya.
  • Saya belum benar - benar menonton tutorial video ini karena saya belum punya waktu, tetapi mungkin bermanfaat. :) Mereka mungkin sudah ketinggalan zaman, jika Anda menggunakan XNA.
  • Situs ini memiliki beberapa tutorial yang (saya pikir) didasarkan pada video di atas. Mungkin perlu dicoba.
Richard Marskell - Drackir
sumber
Waow, itu info dua kali lebih banyak daripada yang saya tanyakan, dan cukup banyak menjawab semua pertanyaan yang tidak saya tanyakan, bagus, terima kasih :)
Cristol.GdM
@Mikalichov - Senang saya bisa membantu! :)
Richard Marskell - Drackir
Biasanya dengan array 2D Anda ingin menggunakan dimensi pertama sebagai Y Anda dan berikutnya sebagai X Anda. Dalam memori array akan berurutan 0,0-i kemudian 1,0-i. Jika Anda melakukan loop bersarang dengan X pertama ayam, Anda benar-benar melompat bolak-balik dalam memori bukannya mengikuti jalur membaca berurutan. Selalu untuk (y) lalu untuk (x).
Brett W
@ BrettW - Poin yang valid. Terima kasih. Itu membuat saya bertanya-tanya bagaimana array 2D disimpan dalam. Net (Urutan utama baris. Mempelajari sesuatu yang baru hari ini! :-)). Namun, setelah memperbarui kode saya, saya menyadari bahwa itu persis sama dengan apa yang Anda gambarkan, hanya dengan variabel yang diaktifkan. Perbedaannya adalah dalam urutan apa ubin bisa ditarik. Kode contoh saya saat ini menarik dari atas ke bawah, dari kiri ke kanan sedangkan apa yang Anda gambarkan akan menggambar kiri-ke-kanan, atas-ke-bawah. Jadi, demi kesederhanaan, saya memutuskan untuk mengembalikannya ke aslinya. :-)
Richard Marskell - Drackir
6

Baik sistem berbasis ubin dan model statis / sistem tekstur dapat digunakan untuk mewakili dunia dan masing-masing memiliki kekuatan yang berbeda. Apakah yang satu lebih baik daripada yang lain bermuara pada bagaimana Anda menggunakan potongan-potongan itu, dan apa yang paling cocok untuk keahlian dan kebutuhan Anda.

Itu dikatakan kedua sistem dapat digunakan secara terpisah, atau juga bersama-sama.

Sistem berbasis ubin standar memiliki kekuatan berikut:

  • Array 2D ubin sederhana
  • Setiap ubin memiliki satu bahan
    • Bahan ini dapat berupa tekstur tunggal, berganda, atau dicampur dari ubin di sekitarnya
    • Dapat menggunakan kembali tekstur untuk semua ubin jenis itu, mengurangi pembuatan dan pengerjaan ulang aset
  • Setiap ubin bisa lumayan atau tidak (collision detection)
  • Mudah membuat dan mengidentifikasi bagian-bagian peta
    • Posisi karakter dan posisi peta adalah koordinat absolut
    • Mudah untuk mengulang ubin yang relevan untuk wilayah layar

Kerugian dari ubin adalah Anda harus membuat sistem untuk membangun data berbasis ubin ini. Anda bisa membuat gambar yang menggunakan setiap piksel sebagai ubin, sehingga menciptakan array 2D Anda dari tekstur. Anda juga dapat membuat format berpemilik. Menggunakan bitflag, Anda dapat menyimpan sejumlah besar data per ubin dalam ruang yang cukup kecil.

Alasan utama kebanyakan orang membuat ubin adalah karena memungkinkan mereka untuk membuat aset kecil dan menggunakannya kembali. Ini memungkinkan Anda membuat gambar yang jauh lebih besar akan potongan yang lebih kecil. Ini mengurangi pengerjaan ulang karena Anda tidak mengubah seluruh peta dunia untuk membuat perubahan kecil. Misalnya jika Anda ingin mengubah naungan semua rumput. Dalam gambar besar Anda harus mengecat ulang semua rumput. Dalam sistem ubin, Anda cukup memperbarui ubin rumput.

Secara menyeluruh Anda akan menemukan diri Anda melakukan lebih sedikit pengerjaan ulang dengan sistem berbasis ubin daripada peta grafis besar. Anda mungkin akhirnya menggunakan sistem berbasis ubin untuk tabrakan bahkan jika Anda tidak menggunakannya untuk peta dasar Anda. Hanya karena Anda menggunakan ubin secara internal tidak berarti Anda tidak dapat menggunakan model untuk mewakili objek lingkungan yang mungkin menggunakan lebih dari 1 ubin untuk ruang mereka.

Anda perlu memberikan lebih spesifik tentang lingkungan / mesin / bahasa Anda untuk memberikan contoh kode.

Brett W
sumber
Terima kasih! Saya sedang bekerja di bawah C #, dan saya akan mencari versi Final Fantasy 6 yang serupa (tapi kurang berbakat) (atau pada dasarnya kebanyakan SNES RPG Square), jadi ubin lantai DAN ubin struktur (yaitu rumah). Kekhawatiran terbesar saya adalah bahwa saya tidak melihat cara membangun array 2D tanpa menghabiskan berjam-jam memeriksa "ada sudut rumput di sana, lalu tiga lurus horisontal, lalu sudut rumah, lalu ..", dengan banyak kemungkinan kesalahan di sepanjang cara.
Cristol.GdM
Sepertinya Richard telah Anda bahas dalam hal kode spesifik. Saya pribadi akan menggunakan enum jenis huruf dan menggunakan bitflag untuk mengidentifikasi nilai ubin. Ini memungkinkan Anda untuk menyimpan 32+ nilai dalam integer rata-rata. Anda juga dapat menyimpan beberapa bendera per ubin. Jadi Anda bisa mengatakan Grass = true, Wall = true, Collision = true, dll. Tanpa variabel yang terpisah. Kemudian Anda cukup menetapkan "tema" yang menentukan tilesheet untuk grafik untuk wilayah peta tertentu.
Brett W
3

Menggambar peta: Ubin mudah di mesin, karena dengan demikian peta dapat direpresentasikan sebagai array indeks ubin raksasa. Kode undian hanyalah loop bersarang:

for i from min_x to max_x:
    for j from min_y to max_y:
        Draw(Tiles[i][j], getPosition(i,j))

Untuk peta besar, satu gambar bitmap besar untuk seluruh peta bisa memakan banyak ruang dalam memori, dan bisa lebih besar dari apa yang didukung kartu grafis untuk ukuran gambar tunggal. Tetapi Anda tidak akan memiliki masalah dengan ubin karena Anda hanya mengalokasikan memori grafis satu kali untuk setiap ubin (atau satu total, secara optimal, jika semuanya ada di satu lembar)

Juga mudah untuk menggunakan kembali informasi petak untuk mis. Tabrakan. misalnya, untuk mendapatkan petak medan di sudut kiri atas sprite karakter:

let x,y = character.position
let i,j = getTileIndex(x,y) // <- getTileIndex is the opposite function of getPosition
let tile = Tiles[i][j]

Misalkan Anda perlu memeriksa tabrakan terhadap batu / pohon dll. Anda bisa mendapatkan ubin di posisi (posisi karakter + ukuran karakter sprite + arah saat ini) dan periksa apakah itu ditandai walkable atau tidak walkable.

Jimmy
sumber