Halo, Habr! Baru-baru ini kami keluar dengan
permainan kami , yang kami siapkan untuk waktu yang lama dan dalam proses yang telah mengumpulkan banyak topik menarik yang layak untuk dibagikan kepada masyarakat. Topik ini akan menarik tidak hanya untuk iOS dan pengembang seluler lainnya, tetapi juga untuk semua orang yang tertarik pada bagaimana segala macam hal grafis bekerja di bawah tenda, serta semua penggemar strategi 2D, yang saya sendiri telah lakukan selama dekade ketiga.
Hari ini kita akan berbicara tentang nuansa topik penting seperti z-indeks pada permukaan isometrik (ya, tidak semuanya sesederhana kelihatannya bagi beberapa orang bijak). Di dunia 3d, kita, anehnya, memiliki tiga koordinat - x, y, z - yang sepenuhnya menentukan posisi objek di ruang angkasa. Tugas menentukan kedekatan objek dengan kamera juga ada, tetapi sepenuhnya berada di pundak OpenGL. Pengembang hanya beroperasi dengan parameter tingkat tinggi seperti kedalaman buffer-z, yang memengaruhi kinerja, tetapi Anda dapat mempercayai OpenGL sebagai kotak hitam - ia memiliki informasi yang cukup.
Situasi yang sangat berbeda diamati di dunia "pseudo-3D" kami - setiap objek hanya memiliki (x, y) - koordinat dan ukuran sprite. Tugas pertama yang dihadapi seorang programmer saat menulis mesin adalah tugas menentukan objek mana yang harus saling tumpang tindih di depan "kamera" virtual kami.
Sinopsis
Koordinat SpriteKit (di mana (0; 0) adalah pusat dari "dunia" dan Y naik) dalam hal ini kita sama sekali tidak tertarik, karena mereka tidak berarti apa-apa di "dunia" isometrik kami dengan Anda, jadi mari kita melakukan pemesanan - kami memiliki bidang berbentuk berlian seperti Zaman Kerajaan.

Ubin dengan koordinat (0; 0) terletak di sudut kiri belah ketupat, absis X meningkatkan "turun" dan "kanan", yaitu. tumbuh lebih dekat dengan pengamat, Y ditahbiskan meningkat "ke atas" dan "ke kanan", yaitu berkurang saat Anda mendekati pengamat.
Juga, rel harus "di bawah" kereta, asap dari cerobong asap harus "di atas" kereta. Tapi kita tidak akan repot-repot sekarang dengan "lapisan makhluk" - jelas, tidak ada yang mencegah kita membuat sebanyak "irisan" isometrik yang Anda suka, bekerja sesuai dengan aturan yang sama. Kami berasumsi bahwa dalam satu ubin selalu ada satu objek - untuk kejelasan, lebih banyak tidak diperlukan.

Perhatikan dua kereta di atas. Jelas, dari sudut pandang pengamat, mobil-mobil harus ditempatkan "di bawah" kereta, yaitu indeks-z mereka harus lebih kecil. Pada saat yang sama, kereta "atas" harus "tumpang tindih" dengan tetangga, menjadi "lebih jauh". Bisakah kita, hanya memiliki koordinat (x; y), membangun peta indeks-z untuk setiap ubin?
Jelas, ya, menggunakan rumus berikut (pseudocode a la swift):
zIndex = pos.x * field.size.width - pos.y
Dengan demikian, kami menjamin bahwa ketika ordinat tumbuh, benda-benda bergerak menjauh (-pos.y), serta dengan pertumbuhan absis, pendekatan objek (pos.x) dan, yang penting, setiap objek yang memiliki absis, katakanlah 44, akan sengaja “lebih dekat” "Daripada benda apa pun yang memiliki absis 43. Untuk menambahkan" pelapisan "di sini (ingat, rel di bawah kereta, asap di atas pipa), itu sudah cukup untuk menambahkan" ketinggian "konstan lapisan:
zIndex = layerZIndex + pos.x * field.size.width - pos.y
Itu saja, Anda bisa mengakhiri artikel, dan memuji diri sendiri untuk dasar-dasar stereometri yang dipelajari di kelas 10 dan memulai logika permainan. Tidak Kalau saja! Saya akan menulis tentang hal-hal yang jelas! (Yah, sudah jelas, beberapa hari hancur dan ini)
Kami baru saja turun ke bagian yang menyenangkan, bergerak maju.
Perjuangan kinerja
Semua orang, setidaknya sekali, menjalankan proyek uji untuk SpriteKit (atau kelapa, atau mesin lainnya), melihat angka ajaib - fps dan node.

Jelas, fps adalah jumlah frame per detik, node adalah jumlah node, terutama sprite. Namun dalam praktiknya, sebagian besar dari semua fps diatur bukan oleh jumlah node, tetapi oleh parameter lain, yang secara default tidak ditampilkan, tetapi yang juga dapat ditampilkan dengan satu baris - jumlah undian digambar ulang.

Dalam adegan yang sama, seperti yang Anda lihat sekarang, jumlah node adalah sekitar 6000, dan jumlah rendering sekitar 120. Ini adalah pada zoom minimum (kamera sedekat mungkin ke permukaan), 1: 1.
Sekarang, mari kita gerakkan kamera ke jarak maksimum (dalam game kami ini 2,5: 1)

Kami mengubah skala hanya 2,5 kali (dalam contoh, jauh dari semua objek yang diambil), dan jumlah undian meningkat 5-6 kali dengan jumlah node tidak berubah!
Tentu saja, jumlah rendering mempengaruhi fps jauh lebih banyak daripada jumlah abstrak node. SpriteKit tidak menggambar node yang tidak jatuh ke viewport (ke dalam kamera). Satu-satunya pengecualian yang saya temukan sejauh ini adalah penghasil partikel, yang selalu digambar, terlepas dari apakah mereka terlihat atau tidak.
Sekarang mari kita bicara tentang apa arti menggambar "menggambar" ini. Kartu video memiliki semua "lapisan" node, dipandu oleh indeks-z mereka. Dan itu melewati seluruh gambar berulang-ulang, dari yang terendah ke yang tertinggi. Jumlah siklus perenderan seperti itu adalah draw.
Sekarang Anda mengerti bahwa jika Anda menggambar setiap objek kecil (dan kami memiliki peta besar, sekitar 6000 x 3000) dengan indeks-z sendiri, ini akan merusak kinerja ponsel apa pun.
Masalah paling baik dilihat pada versi 5 dan 5 yang lama, tetapi kehadiran iPhone 10 tidak menjamin apa pun - dengan pendekatan yang salah, Anda dapat membuang perangkat keras yang kuat. Dalam permainan kami, salah satu landasannya adalah kejelasan ekstrim. Pada zoom terdekat, sprite satu-satu sesuai dengan retin piksel. Saya harus mengatakan bahwa di sebagian besar permainan ponsel, resolusinya lebih rendah daripada pesanan, sehingga persyaratannya tidak terlalu besar, tetapi kami melakukannya secara kualitatif, seperti untuk diri kami sendiri ...
Jadi, Anda harus pergi ke trik.
- Semua objek yang tidak berinteraksi dengan pemain, dan yang berada pada level yang sama dalam koordinat X, umumnya dapat digabung menjadi satu sprite. Untuk kartu video, lebih mudah untuk menggambar satu sprite besar daripada 10 yang kecil. Oleh karena itu, jalur hutan antara jalan adalah sprite integral yang terdiri dari beberapa pohon. Dan pohon-pohon yang tidak tumpang tindih jalan dan pohon-pohon lain umumnya dijahit ke dalam peta. Di alpha, ngomong-ngomong, ada beberapa bug ketika pohon ek berumur satu abad tumbuh tepat di bawah rel kereta api atau di bawah lampu lalu lintas kereta api, jadi hati-hati menguji game Anda agar tidak menghibur pengguna.
- Objek yang memiliki satu indeks-z digambar sesuai urutan kemunculannya pada kartu video. Yaitu menambahkan objek "jauh" sebelum yang "tutup", mereka akan jatuh dengan benar, tetapi tidak akan menambah jumlah kartu grafis yang dirender.
Semua ini memungkinkan Anda untuk mengurangi jumlah pengundian di kali, memperbaiki fps bahkan di iPhone lama. Saya harus sangat membatasi beberapa efek pada mereka, tetapi Apple belum merilis pembaruan untuk mereka selama satu tahun sekarang - dosa akan mengeluh!
Ketinggian
Nah, semuanya, mesin sudah siap, bisakah Anda memulai sesuatu yang menarik? Seseorang bisa, tetapi masih terlalu dini untuk kita. Lagipula, kereta itu seharusnya dengan indahnya meninggalkan terowongan, dan di sini semuanya tidak sesederhana kelihatannya.

Kereta harus ditempatkan "lebih tinggi" dari dinding terowongan yang "jauh", dan "lebih rendah" dari atap terowongan dan gunung-gunung yang mengikutinya. Betapa indahnya, ketika peta itu multi-level, dengan perubahan ketinggian - sekali lagi, kita tidak melakukan omong kosong tanpa jiwa, tapi apa yang kita sukai!
Tetapi kembali ke detail - untuk ini peta "dipotong" sebagai berikut.

Dinding bagian dalam terowongan dan segala sesuatu di sebelah kiri lebih rendah dan

bagian atas terowongan bersama dengan pegunungan di mana ia mengalir. Di sini, tidak ada generasi prosedural indeks-z yang akan membantu, hanya hardcode Belarusia yang parah.
Habrayuzer yang penuh perhatian memperhatikan dalam cuplikan layar dari permainan bahwa di dekat terowongan, pohon-pohon itu "dipangkas" dengan rapi, memperlihatkan pasir pantai yang masih asli. Kelemahan yang tampaknya ini datang dari ketidakmungkinan mendasar untuk mewujudkan penanaman pohon seperti itu dalam 2D. Kereta, meninggalkan terowongan, harus dengan sengaja "di atas" pohon-pohon yang tumpang tindih, menutupinya dengan sendirinya. Tapi pohon-pohon yang sama ini harus tumpang tindih dengan atap terowongan, di mana kereta harus memanggil! Dan atapnya harus lebih tinggi dari kereta, dan dalam lingkaran, kita memiliki kontradiksi logis ...
Untuk alasan yang sama, karena ketidaksempurnaan mesin grafis, dalam game lama seperti Duke Nukem dan Doom2 tidak ada perbedaan besar dalam ketinggian dan lantai bangunan.
Itu sebabnya pohon tidak tumbuh di dekat terowongan.
Saya harap itu menarik,
mainannya tinggal di sini (gratis untuk bermain) , artikel selanjutnya dalam seri ini akan tentang air 2D realistis yang indah, jangan ketinggalan!
PS By the way, video untuk menarik perhatian dapat
dilihat di youtube dalam kualitas normal.
PPS Game ini sejauh ini hanya tersedia di CIS, Kanada dan Irlandia, jika seseorang ingin melihat dari negara lain, kirim email pribadi dengan appleId - Saya akan menambahkannya ke TestFlight