Advertisement
  1. Code
  2. Coding Fundamentals
  3. Game Development

Isometric Depth Sorting untuk Platform Bergerak

Scroll to top

() translation by (you can also view the original English article)

Final product imageFinal product imageFinal product image
What You'll Be Creating

Depth sorting atau mengurutkan kedalaman bisa dijelaskan secara sederhana sebagai cara untuk menentukan elemen mana yang lebih dekat ke kamera dan mana yang lebih jauh, sehingga menentukan urutan elemen-elemen tersebut agar bisa menggambarkan kedalaman yang benar pada scene.

Dalam tutorial ini kita akan menggali lebih jauh tentang depth sorting untuk level isometric sembari kita menambahkan platform bergerak. Ini bukan tutorial pemula untuk teori isometric dan bukan tentang kode. Fokusnya adalah untuk memahami logika dan teori dibandingkan membedah kode. Alat yang kita gunakan untuk tutorial ini adalah Unity, sehingga depth sorting adalah mengubah sortingOrder dari sprite yang terlibat. Pada framework yang berbeda, mungkin hal ini berhubungan dengan mengubah urutan z atau urutan menggambar objek ke layar.

Untuk memulai dengan teori isometric, lihatlah seri tutorial berikut. Kode dan struktur scene mengikuti tutorial isometric saya sebelumnya. Kembalilah ke artikel tersebut jika kamu merasa tutorial ini sulit diikuti karena saya akan fokus pada logika pada tutorial ini.

1. Level Tanpa Gerakan

Jika level isometric kamu tidak memiliki elemen bergerak atau hanya ada beberapa karakter melewati level tersebut, depth sortingnya sederhana. Dalam kasus tersebut, karakter yang mengisi petak isometric akan lebih kecil dari petak tersebut dan karakter bisa mengikuti urutan gambar/kedalaman dengan tile yang mereka tempati.

Kita menyebut level seperti itu sebagai level statik. Ada beberapa cara menggambar level agar kedalaman yang tepat bisa disampaikan. Biasanya, data level berupa array dua dimensi di mana baris dan kolom mewakili baris dan kolom dalam level.

Pertimbangkan level isometric berikut dengan hanya dua baris dan tujuh kolom.

Isometric level with 2 rows and numbered z orderIsometric level with 2 rows and numbered z orderIsometric level with 2 rows and numbered z order

Nomor pada petak menunjukkan sortingOrder atau kedalaman atau z order, dengan kata lain, urutan mereka perlu digambar. Dengan cara ini, kita menggambar semua kolom di baris pertama, mulai dari kolom dengan sortingOrder 1.

Setelah semua kolom baris pertama digambar, kolom terdekat dengan kamera memiliki sortingOrder 7, dan kita lanjut ke baris berikutnya. Setiap elemen di baris kedua memiliki sortingOrder lebih tinggi daripada elemen manapun pada baris pertama.

Ini adalah bagimana petak perlu diatur untuk menggambarkan kedalaman yang tepat karena gambar dengan sortingOrder yang lebih tinggi akan menimpa gambar dengan sortingOrder yang lebih rendah.

Untuk kodenya, kita hanya mengiterasi baris dan kolom pada array level dan memberi nilai sortingOrder secara berurutan dan meningkat. Hal ini akan tetap benar walau kita menukar baris dan kolom, seperti yang kita lihat pada gambar di bawah.

Isometric level with 2 columns and numbered z orderIsometric level with 2 columns and numbered z orderIsometric level with 2 columns and numbered z order

Di sini kita menggambar kolom lengkap sebelum bergerak ke baris berikutnya. Efek kedalaman tetap terlihat benar. Jadi logika untuk level statis adalah untuk menggambar baris atau kolom dengan lengkap lalu melanjutkan ke bagian berikutnya sambil memberi nilai sortingOrder yang membesar secara berurutan.

Menambahkan Ketinggian

Jika kita mempertimbangkan level sebagai sebuah level, kita sedang menggambar lantai dasar. Jika kita perlu menambahkan lantai baru, kita perlu menggambar lantai dasar terlebih dahulu dan mengikuti metode yang sama untuk lantai berikutnya.

Untuk kedalaman yang benar, kita menunggu sampai baris lengkap selesai baru melanjutkan ke baris berikutnya, dan begitu pula kita menunggu sampai semua baris selesai sebelum kita pindah ke lantai berikutnya. Jadi untuk level dengan hanya satu baris dan dua lantai, akan terlihat seperti gambar di bawah.

Isometric level with 2 floors and numbered z orderIsometric level with 2 floors and numbered z orderIsometric level with 2 floors and numbered z order

Pada dasarnya, semua petak di lantai yang lebih tinggi akan memiliki sortingOrder yang lebih tinggi dari semua petak di lantai lebih rendah. Untuk kode menambahkan lantai, kita hanya perlu menambah nilai y dari koordinat petak di layar, tergantung lantai berapa petak tersebut berada.

1
float floorHeight=tileSize/2.2f;
2
float currentFloorHeight=floorHeight*floorLevel;
3
//

4
tmpPos=GetScreenPointFromLevelIndices(i,j);
5
tmpPos.y+=currentFloorHeight;
6
tile.transform.position=tmpPos;

Nilai floorHeight menunjukkan ketinggian dari gambar blok isometric, dan floorLevel menunjukkan lantai mana petak tersebut berada.

2. Petak yang Bergerak pada Sumbu X

Mengurutkan kedalaman pada level isometrik statis tidak rumit. Sekarang kita tentukan untuk mengikuti metoda baris pertama, di mana kita memberi nilai sortingOrder pada baris pertama sampai selesai baru lanjut ke yang berikutnya. Kita anggap petak atau platform bergerak kita yang pertama bergerak pada satu sumbu, sumbu x.

Saat saya bilang gerakan pada sumbu X, kamu perlu menyadari bahwa kita membicarakan tentang koordinat kartesian dan bukan sistem koordinat isometrik. Kita bayangkan level dengan hanya lantai dasar dan tiga baris dan tujuh kolom. Kita bayangkan juga baris kedua hanya memiliki satu petak, yang merupakan petak bergerak kita. Level tersebut akan terlihat seperti gambar di bawah.

level with 3 rows and single tile moving in x axislevel with 3 rows and single tile moving in x axislevel with 3 rows and single tile moving in x axis

Perak yang gelap adalah petak bergerak kita, dan sortingOrder yang dimilikinya adalah 8 karena baris pertama memiliki 7 petak. Jika petak bergerak pada sumbu x kartesian, maka petak tersebut akan bergerak diantara dua baris. Pada setiap posisi yang ditempatinya sepanjang jalur, semua petak pada baris 1 akan memiliki sortingOrder yang lebih kecil.

Begitu pula, semua petak pada baris dua akan memiliki sortingOrder lebih tinggi, tidak peduli posisi petak gelap pada jalur yang dimaksud. Karena kita mengikuti aturan baris terlebih dahulu dalam memberi sortingOrder, kita tidak perlu melakukan apapun untuk gerakan pada sumbu x. Itu cukup mudah.

3. Petak yang Bergerak pada Sumbu Y

Masalah mulai muncul saat kita mempertimbangkan sumbu Y. Kita bayangkan level sebuah level di mana petak gelap kita bergerak pada celah persegi, seperti gambar di bawah. Kamu bisa melihat scene yang sama pada file sumber Unity pada scene MovingSortingProblem.

showing depth issues while moving in y axisshowing depth issues while moving in y axisshowing depth issues while moving in y axis

Menggunakan pendekatan 'baris terlebih dahulu', kita bisa memberikan sortingOrder untuk petak yang bergerak berdasarkan baris yang ditempatinya. Saat berada diantara dua baris, petak tersebut akan mendapat sortingOrder berdasarkan baris sebelumnya. Dalam kasus tersebut, petak tidak bisa mengikuti sortingOrder berurutan dalam baris yang akan didatangi. Ini akan merusak pendekatan sorting kita.

Sorting dalam Blok

Untuk memecahkan masalah ini, kita perlu membagi level kita menjari beberapa blok berbeda, salah satunya adalah blok yang bermasalah, yang merusak visual pada pendekatan pertama, dan blok lain yang bisa mengikuti pendekatan 'baris terlebih dahulu' tanpa gangguan. Lihat gambar berikut agar lebih jelas.

level divided into blocks of which one is the problem blocklevel divided into blocks of which one is the problem blocklevel divided into blocks of which one is the problem block

Blok petak 2x2 pada area berwarna biru adalah blok yang bermasalah. Semua blok lain bisa mengikuti pendekatan 'baris terlebih dahulu'. Tolong jangan bingung karena gambar ditampilkan dengan benar menggunakan pendekatan blok yang akan kita buat. Blok biru berisi dua kolom petak diantara jalur petak gelap bergerak, dan petak di sebelah kirinya.

Untuk memecahkan masalah kedalaman untuk blok problem itu, kita bisa menggunakan pendekatan 'kolom lebih dahulu' hanya untuk blok ini. Jadi untuk blok hijau, pink, dan kuning, kita menggunakan 'baris lebih dahulu', dan untuk blok biru, kita gunakan pendekatan 'kolom lebih dahulu'.

Perhatikan bahwa kita tetap harus menentukan sortingOrder berurutan. Pertama untuk blok hijau, lalu blok pink ke kiri, lalu blok biru, lalu blok pink ke kanan, dan akhirnya blok kuning. Kita merusak urutan hanya untuk berpindah menjadi pendekatan 'kolom lebih dahulu' saat berada di blok biru.

Selain itu, kita juga bisa mempertimbangkan blok 2x2 di kanan kolom petak yang bergerak. (Yang menarik, kamu tidak perlu mengubah pendekatan karena membagi area menjadi blok sudah memecahkan masalah kita dalam kasus ini.) Solusi ini bisa dilihat pada scene BlockSort.

depth issues solved using blocksdepth issues solved using blocksdepth issues solved using blocks

Hal tersebut dibuat menjadi kode di bawah ini.

1
private void DepthSort(){
2
    Vector2 movingTilePos=GetLevelIndicesFromScreenPoint(movingGO.transform.position);
3
    int blockColStart=(int)movingTilePos.y;
4
  int blockRowStart=(int)movingTilePos.x;
5
	int depth=1;
6
		
7
	//sort rows before block

8
	for (int i = 0; i < blockRowStart; i++) {
9
		for (int j = 0; j < cols; j++) {
10
			depth=AssignDepth(i,j,depth);
11
		}
12
	}
13
	//sort columns in same row before the block

14
	for (int i = blockRowStart; i < blockRowStart+2; i++) {
15
		for (int j = 0; j < blockColStart; j++) {
16
			depth=AssignDepth(i,j,depth);
17
		}
18
	}
19
	//sort block

20
	for (int i = blockRowStart; i < blockRowStart+2; i++) {
21
		for (int j = blockColStart; j < blockColStart+2; j++) {
22
			if(movingTilePos.x==i&&movingTilePos.y==j){
23
				SpriteRenderer sr=movingGO.GetComponent<SpriteRenderer>();
24
				sr.sortingOrder=depth;//assign new depth

25
				depth++;//increment depth

26
			}else{
27
				depth=AssignDepth(i,j,depth);
28
			}
29
		}
30
	}
31
	//sort columns in same row after the block

32
	for (int i = blockRowStart; i < blockRowStart+2; i++) {
33
		for (int j = blockColStart+2; j < cols; j++) {
34
			depth=AssignDepth(i,j,depth);
35
		}
36
	}
37
	//sort rows after block

38
	for (int i = blockRowStart+2; i < rows; i++) {
39
		for (int j = 0; j < cols; j++) {
40
			depth=AssignDepth(i,j,depth);
41
		}
42
	}
43
}

4. Petak Bergerak pada Sumbu Z

Gerakan pada sumbu Z adalah gerakan palsu pada sebuah level isometric. Hal ini hanyalah gerakan pada sumbu Y layar. Untuk level isometric dengan hanya satu lantai, tidak ada yang perlu dilakukan untuk menambahkan gerakan pada sumbu Z jika kamu sudah menerapkan metode block sorting di atas. Kamu bisa melihat prakteknya pada scene SingleLayerWave, di mana saya menambahkan gerakan wave pada sumbu Z bersama gerakan yang sudah ada.

Gerakan Sumbu Z pada Level dengan Banyak Lantai

Menambahkan lantai tambahan pada level menyangkut menambahkan posisi koordinat Y pada layar seperti yang sudah disebutkan sebelumnya. Jika petak tidak bergerak pada sumbu Z maka tidak ada hal lain yang perlu dilakukan untuk depth sorting. Kita bisa melakukan block sort pada lantai dasar yang memiliki gerakan lalu melakukan sorting 'baris lebih dahulu' pada setiap lantai berikutnya. Kamu bisa melihat prakteknya pada Unity scene BlockSortWithHeight.

level with multiple floors and lateral motionlevel with multiple floors and lateral motionlevel with multiple floors and lateral motion

Masalah kedalaman yang mirip muncul saat petak bergerak antar lantai. Hal ini hanya dapat mengikuti urutan dalam satu lantai dengan pendekatan kita, dan akan merusak depth sorting di lantai lain. Kita perlu mengembangkan atau memodifikasi block sorting menjadi tiga dimensi untuk menangani masalah kedalaman dengan beberapa lantai.

Masalah ini pada dasarnya hanya melibatkan dua lantai di mana sebuah petak bergerak. Untuk lantai lainnya, kita bisa mengikuti pendekatan sorting kita saat ini. Kebutuhan khusus hanya berlaku untuk dua lantai ini, dan kita bisa menentukan lantai bawah dengan cara berikut, di mana tileZOffset adalah jumlah gerakan pada sumbu Z untuk petak bergerak yang bersangkutan.

1
float whichFloor=(tileZOffset/floorHeight);
2
float lower=Mathf.Floor(whichFloor);

Ini artinya lower dan lower+1 adalah lantai yang membutuhkan pendekatan spesial. Triknya adalah untuk menentukan sortingOrder untuk kedua lantai ini bersamaan, seperti yang ditampilkan pada kode di bawah. Hal ini memperbaiki urutan agar masalah kedalaman bisa diperbaiki.

1
if(floor==lower){
2
    // we need to sort lower floor and the floor just above it together in one go

3
	depth=(floor*(rows*cols))+1;
4
	int nextFloor=floor+1;
5
	if(nextFloor>=totalFloors)nextFloor=floor;
6
	//sort rows before block

7
	for (int i = 0; i < blockRowStart; i++) {
8
		for (int j = 0; j < cols; j++) {
9
			depth=AssignDepth(i,j,depth,floor);
10
			depth=AssignDepth(i,j,depth,nextFloor);
11
		}
12
	}
13
	//sort columns in same row before the block

14
	for (int i = blockRowStart; i < blockRowStart+2; i++) {
15
		for (int j = 0; j < blockColStart; j++) {
16
			depth=AssignDepth(i,j,depth,floor);
17
			depth=AssignDepth(i,j,depth,nextFloor);
18
		}
19
	}
20
	//sort block

21
				
22
	for (int i = blockRowStart; i < blockRowStart+2; i++) {
23
		for (int j = blockColStart; j < blockColStart+2; j++) {
24
			if(movingTilePos.x==i&&movingTilePos.y==j){
25
		    	SpriteRenderer sr=movingGO.GetComponent<SpriteRenderer>();
26
				sr.sortingOrder=depth;//assign new depth

27
				depth++;//increment depth

28
			}else{
29
				depth=AssignDepth(i,j,depth,floor);
30
				depth=AssignDepth(i,j,depth,nextFloor);
31
			}
32
		}
33
	}
34
				
35
	//sort columns in same row after the block

36
	for (int i = blockRowStart; i < blockRowStart+2; i++) {
37
		for (int j = blockColStart+2; j < cols; j++) {
38
			depth=AssignDepth(i,j,depth,floor);
39
			depth=AssignDepth(i,j,depth,nextFloor);
40
		}
41
	}
42
	//sort rows after block

43
	for (int i = blockRowStart+2; i < rows; i++) {
44
		for (int j = 0; j < cols; j++) {
45
			depth=AssignDepth(i,j,depth,floor);
46
			depth=AssignDepth(i,j,depth,nextFloor);
47
		}
48
	}
49
}

Pada dasarnya, kita menganggap dua lantai sebagai satu lantai dan melakukan block sort pada satu lantai tersebut. Lihatlan kodenya beraksi pada scene BlockSortWithHeightMovement. Dengan pendekatan ini, petak kita sekarang bebas bergerak pada dua sumbu apapun tanpa merusak kedalaman scene, seperti yang ditampilkan di bawah.

level with tile moving along all 3 axeslevel with tile moving along all 3 axeslevel with tile moving along all 3 axes

Kesimpulan

Tujuan dari tutorial ini adalah menjelaskan logika pendekatan depth sorting, dan saya harap kamu sudah cukup memahaminya. Terlihat jelas bahwa kita baru mempertimbangkan level sederhana dengan hanya satu petak bergerak.

Tidak ada bidang miring pula, karena akan membuat tutorial ini jauh lebih panjang. Tapi setelah kamu memahami logika sorting, kamu bisa mengembangkan logika bidang miring dua dimensi untuk tampilan isometric.

Unity memiliki perekonomian yang aktif. Ada banyak produk yang bisa membantu kamu membangun projekmu. Platform Unity juga adalah pilihan yang tepat untuk melatih kemampuan kamu. Apapun kebutuhan kamu, kamu bisa lihat apa yang tersedia di Envato Market.

Advertisement
Did you find this post useful?
Want a weekly email summary?
Subscribe below and we’ll send you a weekly email summary of all new Code tutorials. Never miss out on learning about the next big thing.
Advertisement
Looking for something to help kick start your next project?
Envato Market has a range of items for sale to help get you started.