Dasar Physics Platformer 2D, Bagian 6: Respon Tabrakan Antar Objek
() translation by (you can also view the original English article)
Pada tutorial sebelumnya di seri ini, kita mengimplementasi mekanisme deteksi tabrakan antar objek dalam game. Kali ini, kita akan gunakan mekanisme tersebut untuk membangun sistem respon fisik yang sederhana namun tangguh.
Demo berikut menunjukkan hasil akhir dari tutorial ini. Gunakan WASD untuk menggerakkan karakter. Tombol mouse tengah membuat sebuah platform satu arah, tombol mouse kanan membuat petak solid, dan tombol spasi membuat salinan karakter. Slider mengubah ukuran karakter pemain.
Demo ini dibuat dengan Unity 5.4.0f3, dan source code-nya juga kompatibel dengan Unity versi tersebut.
Respon Tabrakan
Sekarang kita punya semua data tabakan dari tutorial bagian sebelumnya, kita bisa menambahkan respon sederhana untuk objek-objek yang bertabrakan. Tujuan kita adalah untuk membuat objek tidak menembus satu sama lain. Kita ingin objek-objek tersebut bersifat solid dan bertindak sebagai rintangan atau platform untuk objek lain. Untuk itu, kita perlu melakukan satu hal: menggeser objek keluar dari kondisi tumpang tindih jika hal tersebut terjadi.
Menangani Data Tambahan
Kita membutuhkan data tambahan untuk kelas MovingObject
untuk menangani respon tabrakan antar objek. Pertama, kita perlu boolean untuk menandai sebuah objek bersifat kinematik, artinya objek ini tidak bisa didorong oleh objek lain.
Objek-objek ini akan berfungsi dengan baik sebagai platform, dan bisa digunakan sebagai platform yang bergerak. Merekak seharusnya adalah objek yang paling berat, sehingga posisinya tidak akan diubah bagaimapun juga, objek lain akan perlu bergerak menjauh untuk memberi ruang untuk objek-objek tersebut.
1 |
public bool mIsKinematic = false; |
Data lain yang saya butuhkan adalah informasi apakah kita berdiri di atas objek, atau di samping kanan/kiri, dan lain-lain. Sejauh ini kita hanya bisa berinteraksi dengan petak, tapi sekarang kita bisa juga berinteraksi dengan objek lain.
Untuk memberi keseimbangan, kita perlu sekumpulan variabel untuk menjelaskan apakah karakter mendorong sesuatu pada sisi kiri, kanan, atas, atau bawah.
1 |
public bool mPushesRight = false; |
2 |
public bool mPushesLeft = false; |
3 |
public bool mPushesBottom = false; |
4 |
public bool mPushesTop = false; |
5 |
|
6 |
public bool mPushedTop = false; |
7 |
public bool mPushedBottom = false; |
8 |
public bool mPushedRight = false; |
9 |
public bool mPushedLeft = false; |
10 |
|
11 |
public bool mPushesLeftObject = false; |
12 |
public bool mPushesRightObject = false; |
13 |
public bool mPushesBottomObject = false; |
14 |
public bool mPushesTopObject = false; |
15 |
|
16 |
public bool mPushedLeftObject = false; |
17 |
public bool mPushedRightObject = false; |
18 |
public bool mPushedBottomObject = false; |
19 |
public bool mPushedTopObject = false; |
20 |
|
21 |
public bool mPushesRightTile = false; |
22 |
public bool mPushesLeftTile = false; |
23 |
public bool mPushesBottomTile = false; |
24 |
public bool mPushesTopTile = false; |
25 |
|
26 |
public bool mPushedTopTile = false; |
27 |
public bool mPushedBottomTile = false; |
28 |
public bool mPushedRightTile = false; |
29 |
public bool mPushedLeftTile = false; |
Banyak sekali variabel yang dibutuhkan. Pada kondiri produksi, penting untuk membuatnya menjadi flag dan menyimpan satu bilangan bulat dibanding semua boolean ini, tapi agar lebih sederhana, kita akan gunakan kumpulan boolean tersebut.
Seperti yang bisa kamu lihat, kita memiliki data yang cukup detail. Kita tahu apakah karakter sedang mendorong atau sudah mendorong rintangan ke sebuah arah, tapi kita bisa juga mendapatkan informasi apakah kita berada di sebelah petak atau objek.
Bergerak Keluar dari Tumpang Tindih
Ayo buat fungsi UpdatePhysicsResponse
, yang akan menangani respon tabrakan antar objek.
1 |
private void UpdatePhysicsResponse() |
2 |
{
|
3 |
}
|
Pertama, jika sebuah objek ditandai sebagai kinematic, kita langsung keluar dari fungsi. Kita tidak perlu membuat respon karena objek kinematik tidak merespon objek lain, justru sebaliknya, objek lain yang akan merespon objek kinematik.
1 |
if (mIsKinematic) |
2 |
return; |
Sekarang, dengan asumsi kita tidak perlu objek kinematik untuk memiliki data yang benar terkait apakah objek tersebut mendorong objek dari sisi kiri, dan seterusnya. Jika tidak, kita perlu memodifikasinya sedikit, yang akan dibahas pada bagian lain tutorial ini.
Sekarang kita mulai menangani variabel yang baru kita buat.
1 |
mPushedBottomObject = mPushesBottomObject; |
2 |
mPushedRightObject = mPushesRightObject; |
3 |
mPushedLeftObject = mPushesLeftObject; |
4 |
mPushedTopObject = mPushesTopObject; |
5 |
|
6 |
mPushesBottomObject = false; |
7 |
mPushesRightObject = false; |
8 |
mPushesLeftObject = false; |
9 |
mPushesTopObject = false; |
Kita simpan hasil dari frame sebelumnya ke variabel yang sesuai dan sekarang asumsikan kita tidak menyentuh objek lain.
Kita mulai dengan mengiterasi semua data tabrakan.
1 |
for (int i = 0; i < mAllCollidingObjects.Count; ++i) |
2 |
{
|
3 |
var other = mAllCollidingObjects[i].other; |
4 |
var data = mAllCollidingObjects[i]; |
5 |
var overlap = data.overlap; |
6 |
}
|
Pertama, kita tangani kasus di mana objek baru menyentuh satu sama lain, tidak tumpang tindih. Dalam kasus ini, kita tahu kita tidak harus menggeser apapun, hanya mengatur isi variabel.
Seperti yang disebutkan sebelumnya, indikator objek saling menyentuh adalah kondisi tumpang tindih pada salah satu sumbu bernilai 0. Kita mulai dengan memeriksa sumbu x.
1 |
if (overlap.x == 0.0f) |
2 |
{
|
3 |
}
|
Jika kondisi ini true, kita perlu melihat apakah objek satunya ada di kiri atau kanan AABB kita.
1 |
if (overlap.x == 0.0f) |
2 |
{
|
3 |
if (other.mAABB.center.x > mAABB.center.x) |
4 |
{
|
5 |
}
|
6 |
else
|
7 |
{
|
8 |
}
|
9 |
}
|
Akhirnya, jika objek lain pada sisi kanan, maka atur nilai mPushesRightObject
menjadi true dan atur kecepatan agar tidak lebih besar dari 0, karena objek kita tidak bisa bergerak ke kanan karena jalurnya terhalang.
1 |
if (overlap.x == 0.0f) |
2 |
{
|
3 |
if (other.mAABB.center.x > mAABB.center.x) |
4 |
{
|
5 |
mPushesRightObject = true; |
6 |
mSpeed.x = Mathf.Min(mSpeed.x, 0.0f); |
7 |
}
|
8 |
else
|
9 |
{
|
10 |
}
|
11 |
}
|
Kita akan menangani sisi kiri dengan cara yang sama.
1 |
if (overlap.x == 0.0f) |
2 |
{
|
3 |
if (other.mAABB.center.x > mAABB.center.x) |
4 |
{
|
5 |
mPushesRightObject = true; |
6 |
mSpeed.x = Mathf.Min(mSpeed.x, 0.0f); |
7 |
}
|
8 |
else
|
9 |
{
|
10 |
mPushesLeftObject = true; |
11 |
mSpeed.x = Mathf.Max(mSpeed.x, 0.0f); |
12 |
}
|
13 |
}
|
Akhirnya, kita tahu bahwa sudah tidak perlu melakukan apapun di sini, jadi kita lanjutkan ke loop berikutnya.
1 |
if (overlap.x == 0.0f) |
2 |
{
|
3 |
if (other.mAABB.center.x > mAABB.center.x) |
4 |
{
|
5 |
mPushesRightObject = true; |
6 |
mSpeed.x = Mathf.Min(mSpeed.x, 0.0f); |
7 |
}
|
8 |
else
|
9 |
{
|
10 |
mPushesLeftObject = true; |
11 |
mSpeed.x = Mathf.Max(mSpeed.x, 0.0f); |
12 |
}
|
13 |
continue; |
14 |
}
|
Kita tangani sumbu y dengan cara dengan cara yang sama.
1 |
if (overlap.x == 0.0f) |
2 |
{
|
3 |
if (other.mAABB.center.x > mAABB.center.x) |
4 |
{
|
5 |
mPushesRightObject = true; |
6 |
mSpeed.x = Mathf.Min(mSpeed.x, 0.0f); |
7 |
}
|
8 |
else
|
9 |
{
|
10 |
mPushesLeftObject = true; |
11 |
mSpeed.x = Mathf.Max(mSpeed.x, 0.0f); |
12 |
}
|
13 |
continue; |
14 |
}
|
15 |
else if (overlap.y == 0.0f) |
16 |
{
|
17 |
if (other.mAABB.center.y > mAABB.center.y) |
18 |
{
|
19 |
mPushesTopObject = true; |
20 |
mSpeed.y = Mathf.Min(mSpeed.y, 0.0f); |
21 |
}
|
22 |
else
|
23 |
{
|
24 |
mPushesBottomObject = true; |
25 |
mSpeed.y = Mathf.Max(mSpeed.y, 0.0f); |
26 |
}
|
27 |
continue; |
28 |
}
|
Ini adalah tempat yang baik untuk mengatur variabel untuk objek kinematik jika diperlukan. Kita tidak peduli jika kondisi tumpang tindih bernilai nol atau tidak karena kita tidak akan menggeser objek kinematik. Kita juga mengabaikan pengaturan kecepatan karena kita tidak perlu menghentikan objek kinematik. Kita mengabaikan langkah tersebut untuk demo ini, karena kita tidak akan menggunakan variabel bantuan untuk objek kinematik.
Setelah hal tersebut ditangani, kita bisa memproses objek yang tumpang tindih dengan AABB kita. Sebelumnya, saya akan menjelaskan pendekatan yang saya gunakan untuk membuat respon tabrakan pada demo ini.
Pertama, jika objek tidak bergerak, dan kita menabraknya, objek lain tersebut akan tetap diam. Kita anggap sebagai benda kinematik. Saya menggunakan cara ini karena saya rasa cara ini lebih umum, dan tindakan mendorong bisa ditangani di bagian lain pada update khusus untuk masing-masing objek.



Jika kedua objek bergerak saat tabrakan, kita bagi tumpang tindih antar objek-objek tersebut berdasarkan kecepatannya. Makin cepat mereka bergerak, semakin jauh mereka akan didorong dari area tumpang tindih.
Poin terakhir, mirip dengan pendekatan respon tabrakan dengan tilemap, jika sebuah objek sedang jatuh dan saat bergerak ke bawah dia bergesekan dengan objek lain bahkan hanya satu piksel secara horizontal, objek tersebut tidak akan meluncur dan terus bergerak ke bawah, melainkan akan berdiri pada satu piksel tersebut.



Saya pikir ini adalah cara yang paling mudah diubah, dan mengubahnya nanti tidak akan terlalu sulit jika kamu ingin menangani beberapa respon dengan berbeda.
Kita lanjutkan implementasi dengan menghitung vektor kecepatan absolut untuk kedua objek saat tabrakan. Kita juga perlu jumlah kecepatannya, agar kita tahu persentase jarak objek kita harus digeser dari tumpang tindih.
1 |
Vector2 absSpeed1 = new Vector2(Mathf.Abs(data.pos1.x - data.oldPos1.x), Mathf.Abs(data.pos1.y - data.oldPos1.y)); |
2 |
Vector2 absSpeed2 = new Vector2(Mathf.Abs(data.pos2.x - data.oldPos2.x), Mathf.Abs(data.pos2.y - data.oldPos2.y)); |
3 |
Vector2 speedSum = absSpeed1 + absSpeed2; |
Perhatikan bahwa kita tidak menggunakan kecepatan yang disimpan pada data tabrakan, melainkan selisih antara posisi pada waktu tabrakan dan frame sebelumnya. Ini akan lebih akurat, karena kecepatan mewaliki vektor gerakan sebelum korensi fisik. Posisi perlu diperbaiki misalnya jika objek menabrak petak solid , jadi jika kita ingin mendapat vektor kecepatan yang dikoreksi kita perlu hitung seperti ini.
Sekarang kita mulai hitung rasio kecepatan objek kita. Jika objek lain bersifat kinematik, kita atur rasio kecepatan menjadi 1, untuk memastikan kita bergerak sesuai nilai vektor tumpang tindih, mengikuti aturan bahwa objek kinematik seharusnya tidak digerakkan.
1 |
float speedRatioX, speedRatioY; |
2 |
|
3 |
if (other.mIsKinematic) |
4 |
speedRatioX = speedRatioY = 1.0f; |
5 |
else
|
6 |
{
|
7 |
}
|
Kita mulai dengan kasus aneh di mana kedua objek saling tumpang tindih tapi tidak memiliki kecepatan. Hal ini seharusnya tidak terjadi, tapi jika sebuah objek dibuat dalam kondisi tumpang tindih dengan objek lain, kita ingin kedua objek itu bergerak menjauh. Dalam kasus tersebut, kita ingin menggerakkan mereka sejauh setengah dari vektor tumpang tindih.
1 |
if (other.mIsKinematic) |
2 |
speedRatioX = speedRatioY = 1.0f; |
3 |
else
|
4 |
{
|
5 |
if (speedSum.x == 0.0f && speedSum.y == 0.0f) |
6 |
{
|
7 |
speedRatioX = speedRatioY = 0.5f; |
8 |
}
|
9 |
}
|
Kasus lainnya adalah saat speedSum
pada sumbu x bernilai nol. Dalam kasus ini kitahitung rasio yang sesuai untuk sumbu y, dan atur agar kita bergerak 50% dari tumpang tindih pada sumbu x.
1 |
if (speedSum.x == 0.0f && speedSum.y == 0.0f) |
2 |
{
|
3 |
speedRatioX = speedRatioY = 0.5f; |
4 |
}
|
5 |
else if (speedSum.x == 0.0f) |
6 |
{
|
7 |
speedRatioX = 0.5f; |
8 |
speedRatioY = absSpeed1.y / speedSum.y; |
9 |
}
|
Begitu pula kita tangani kasus di mana speedSum
bernilai nol hanya pada sumbu y, dan pada kasus terakhir kita hitung kedua rasio dengan benar.
1 |
if (other.mIsKinematic) |
2 |
speedRatioX = speedRatioY = 1.0f; |
3 |
else
|
4 |
{
|
5 |
if (speedSum.x == 0.0f && speedSum.y == 0.0f) |
6 |
{
|
7 |
speedRatioX = speedRatioY = 0.5f; |
8 |
}
|
9 |
else if (speedSum.x == 0.0f) |
10 |
{
|
11 |
speedRatioX = 0.5f; |
12 |
speedRatioY = absSpeed1.y / speedSum.y; |
13 |
}
|
14 |
else if (speedSum.y == 0.0f) |
15 |
{
|
16 |
speedRatioX = absSpeed1.x / speedSum.x; |
17 |
speedRatioY = 0.5f; |
18 |
}
|
19 |
else
|
20 |
{
|
21 |
speedRatioX = absSpeed1.x / speedSum.x; |
22 |
speedRatioY = absSpeed1.y / speedSum.y; |
23 |
}
|
24 |
}
|
Setelah menghitung rasio, kita bisa lihat seberapa banyak kita perlu menggeser objek kita.
1 |
float offsetX = overlap.x * speedRatioX; |
2 |
float offsetY = overlap.y * speedRatioY; |
Lalu, sebelum kita tentukan apakah kita perlu menggeser objek keluar dari tabrakan pada sumbu x atau sumbu y, kita hitung arah kejadian tumpang tindih ini. akan ada tiga kemungkinan: apakah kita menabrak objek lain secara horizontal, vertikal, atau diagonal.
Pada kasus pertama, kita ingin bergerak keluar pada sumbu x, pada kasus kedua kita ingin bergerak keluar pada sumbu y, dan pada kasus terakhir, kita ingin keluar dari tumpang tindih di sumbu dengan nilai tumpang tindih terkecil.



Ingatlah bahwa untuk tumpang tindih dengan objek lain, kita perlu AABB untuk tumpang tindih pada sumbu x dan sumbu y. untuk memeriksa apakah kita menabrak objek secara horizontal, kita akan lihat apakah pada frame sebelumnya kita sudah tumpang tindih dengan objek pada sumbu y. Jika demikian, dan kita belum tumpang tindih pada sumbu x, maka tumpang tindih pasti terjadi karena pada frame ini AABB mulai tumpang tindih pada sumbu x, jadi kita simpulkan bahwa kita menabrak objek lain secara horizontal.
Pertama, kita hitung apakah kita tumpang tindih dengan AABB lain di frame sebelumnya.
1 |
bool overlappedLastFrameX = Mathf.Abs(data.oldPos1.x - data.oldPos2.x) < mAABB.HalfSizeX + other.mAABB.HalfSizeX; |
2 |
bool overlappedLastFrameY = Mathf.Abs(data.oldPos1.y - data.oldPos2.y) < mAABB.HalfSizeY + other.mAABB.HalfSizeY; |
Sekarang kita tur ko ndisi untuk bergerak keluar dari kondisi tumpang tindih secara horizontal. Seperti yang dijelaskan sebelumnya, kita perlu tumpang tindih pada sumbu y dan tidak tumpang tindih pada sumbu x di frame sebelumnya.
1 |
if (!overlappedLastFrameX && overlappedLastFrameY) |
2 |
{
|
3 |
}
|
Jika tidak, kita akan bergerak keluar dari tumpang tindih pada sumbu y.
1 |
if (!overlappedLastFrameX && overlappedLastFrameY) |
2 |
{
|
3 |
}
|
4 |
else
|
5 |
{
|
6 |
}
|
Seperti yang disebutkan di atas, kita juga perlu menangani skenario menabrak objek lain secara diagonal. Kita menabrak objek secara diagonal jika AABB tidak tumpang tindih di kedua sumbu pada frame sebelumna, karena kita tahu pada frame saat ini kedua objek tumpang tindih, maka tabrakan terjadi pada kedua sumbu secara bersamaan.
1 |
if ((!overlappedLastFrameX && overlappedLastFrameY) |
2 |
|| (!overlappedLastFrameX && overlappedLastFrameY)) |
3 |
{
|
4 |
}
|
5 |
else
|
6 |
{
|
7 |
}
|
Tapi kita ingin bergerak keluar dari tumpang tindih pada sumbu x hanya jika nilai tumpang tindih pada sumbu x lebih kecil dari tumpang tindih pada sumbu y.
1 |
if ((!overlappedLastFrameX && overlappedLastFrameY) |
2 |
|| (!overlappedLastFrameX && overlappedLastFrameY && Mathf.Abs(overlap.x) <= Mathf.Abs(overlap.y))) |
3 |
{
|
4 |
}
|
5 |
else
|
6 |
{
|
7 |
}
|
Semua kasus sudah ditangani. Sekarang kita perlu bergerak keluar dari kondisi tumpang tindih.
1 |
if ((!overlappedLastFrameX && overlappedLastFrameY) |
2 |
|| (!overlappedLastFrameX && overlappedLastFrameY && Mathf.Abs(overlap.x) <= Mathf.Abs(overlap.y))) |
3 |
{
|
4 |
mPosition.x += offsetX; |
5 |
|
6 |
if (overlap.x < 0.0f) |
7 |
{
|
8 |
mPushesRightObject = true; |
9 |
mSpeed.x = Mathf.Min(mSpeed.x, 0.0f); |
10 |
}
|
11 |
else
|
12 |
{
|
13 |
mPushesLeftObject = true; |
14 |
mSpeed.x = Mathf.Max(mSpeed.x, 0.0f); |
15 |
}
|
16 |
}
|
17 |
else
|
18 |
{
|
19 |
}
|
Seperti yang bisa kamu lihat, kita mengananinya serupa dengan kasus di mana kita hanya menyentuh AABB lain, tapi dengan tambahan bahwa kita menggeser keluar objek kita berdasarkan selisih yang diperhitungkan.
Koreksi posisi vertikal dilakukan dengan cara yang sama.
1 |
if ((!overlappedLastFrameX && overlappedLastFrameY) |
2 |
|| (!overlappedLastFrameX && !overlappedLastFrameY && Mathf.Abs(overlap.x) <= Mathf.Abs(overlap.y))) |
3 |
{
|
4 |
mPosition.x += offsetX; |
5 |
|
6 |
if (overlap.x < 0.0f) |
7 |
{
|
8 |
mPushesRightObject = true; |
9 |
mSpeed.x = Mathf.Min(mSpeed.x, 0.0f); |
10 |
}
|
11 |
else
|
12 |
{
|
13 |
mPushesLeftObject = true; |
14 |
mSpeed.x = Mathf.Max(mSpeed.x, 0.0f); |
15 |
}
|
16 |
}
|
17 |
else
|
18 |
{
|
19 |
mPosition.y += offsetY; |
20 |
|
21 |
if (overlap.y < 0.0f) |
22 |
{
|
23 |
mPushesTopObject = true; |
24 |
mSpeed.y = Mathf.Min(mSpeed.y, 0.0f); |
25 |
}
|
26 |
else
|
27 |
{
|
28 |
mPushesBottomObject = true; |
29 |
mSpeed.y = Mathf.Max(mSpeed.y, 0.0f); |
30 |
}
|
31 |
}
|
Sedikit lagi selesai, hanya satu hal lagi yang perlu ditangani. Bayangkan sekenario kita mendarat pada dua objek secara bersamaan. Kita memiliki dua data tabrakan yang hampir sama persis. Saat kita mengiterasi semua tabrakan, kita memperbaiki posisi tabrakan objek pertama, menggeser sedikit ke atas.
Lalu kita tangani tabrakan untuk objek kedua. Nilai tumpang tindih yang disimpan di waktu tabrakan bukan data paling baru, karena kita sudah bergerak dari posisi awal, dan jika kita menangani tabrakan kedua seperti kita menangani tabrakan pertana, kita akan bergerak lagi ke atas, membuat objek kita bergerak dua kali lebih jauh dari seharusnya.



Untuk memperbaiki masalah ini, kita akan catat seberapa jauh kita mengkoreksi posisi objek. Kita buat vektor offsetSum
tepat sebelum kita mengiterasi semua tabrakan.
1 |
Vector2 offsetSum = Vector2.zero; |
Sekarang, kita pastikan menjumlahkan semua selisih/offset yang kita terapkan pada objek ke dalam vektor ini.
1 |
if ((!overlappedLastFrameX && overlappedLastFrameY) |
2 |
|| (!overlappedLastFrameX && !overlappedLastFrameY && Mathf.Abs(overlap.x) <= Mathf.Abs(overlap.y))) |
3 |
{
|
4 |
mPosition.x += offsetX; |
5 |
offsetSum.x += offsetX; |
6 |
|
7 |
if (overlap.x < 0.0f) |
8 |
{
|
9 |
mPushesRightObject = true; |
10 |
mSpeed.x = Mathf.Min(mSpeed.x, 0.0f); |
11 |
}
|
12 |
else
|
13 |
{
|
14 |
mPushesLeftObject = true; |
15 |
mSpeed.x = Mathf.Max(mSpeed.x, 0.0f); |
16 |
}
|
17 |
}
|
18 |
else
|
19 |
{
|
20 |
mPosition.y += offsetY; |
21 |
offsetSum.y += offsetY; |
22 |
|
23 |
if (overlap.y < 0.0f) |
24 |
{
|
25 |
mPushesTopObject = true; |
26 |
mSpeed.y = Mathf.Min(mSpeed.y, 0.0f); |
27 |
}
|
28 |
else
|
29 |
{
|
30 |
mPushesBottomObject = true; |
31 |
mSpeed.y = Mathf.Max(mSpeed.y, 0.0f); |
32 |
}
|
33 |
}
|
Dan akhirnya, kita kurangi nilai tumpang tindih setiap tabrakan berikutnya sesuai total vektor koreksi yang sudah kita lakukan sejauh ini.
1 |
var overlap = data.overlap - offsetSum; |
Sekarang jika kita mendarat pada dua objek dengan tinggi yang sama di waktu yang sama, tabrakan pertama akan diproses dengan benar, dan tabrakan kedua akan dikurangi menjadi nol, yang tidak akan meggerakkan objek kita.



Setelah fungsi kita siap, kita pastikan untuk menggunakan fungsi tersebut. Tempat yang baik untuk memanggil fungsi ini adalah setelah pemanggilan fungsi CheckCollisions
. Hal ini memerlukan kita untuk membagi fungsi UpdatePhysics
menjadi dua bagian. Mari buat bagian kedua tersebut sekarang, pada kelas MovingObject
.
1 |
public void UpdatePhysicsP2() |
2 |
{
|
3 |
UpdatePhysicsResponse(); |
4 |
|
5 |
mPushesBottom = mPushesBottomTile || mPushesBottomObject; |
6 |
mPushesRight = mPushesRightTile || mPushesRightObject; |
7 |
mPushesLeft = mPushesLeftTile || mPushesLeftObject; |
8 |
mPushesTop = mPushesTopTile || mPushesTopObject; |
9 |
}
|
Pada bagian kedua ini kita panggil fungsi UpdatePhysicsResponse
yang sudah kita buat dan atur variabel mendorong ke kiri, kanan, bawah, dan atas. Setelah ini kita tinggal menerapkan perubahan posisi objek.
1 |
public void UpdatePhysicsP2() |
2 |
{
|
3 |
UpdatePhysicsResponse(); |
4 |
|
5 |
mPushesBottom = mPushesBottomTile || mPushesBottomObject; |
6 |
mPushesRight = mPushesRightTile || mPushesRightObject; |
7 |
mPushesLeft = mPushesLeftTile || mPushesLeftObject; |
8 |
mPushesTop = mPushesTopTile || mPushesTopObject; |
9 |
|
10 |
//update the aabb
|
11 |
mAABB.center = mPosition; |
12 |
|
13 |
//apply the changes to the transform
|
14 |
transform.position = new Vector3(Mathf.Round(mPosition.x), Mathf.Round(mPosition.y), mSpriteDepth); |
15 |
transform.localScale = new Vector3(ScaleX, ScaleY, 1.0f); |
16 |
}
|
Sekarang, pada update loop utama, kita panggil bagian kedua dari update physics setelah pemanggilan CheckCollisions
.
1 |
void FixedUpdate() |
2 |
{
|
3 |
for (int i = 0; i < mObjects.Count; ++i) |
4 |
{
|
5 |
switch (mObjects[i].mType) |
6 |
{
|
7 |
case ObjectType.Player: |
8 |
case ObjectType.NPC: |
9 |
((Character)mObjects[i]).CustomUpdate(); |
10 |
mMap.UpdateAreas(mObjects[i]); |
11 |
mObjects[i].mAllCollidingObjects.Clear(); |
12 |
break; |
13 |
}
|
14 |
}
|
15 |
|
16 |
mMap.CheckCollisions(); |
17 |
|
18 |
for (int i = 0; i < mObjects.Count; ++i) |
19 |
mObjects[i].UpdatePhysicsP2(); |
20 |
}
|
Selesai! Sekarankg objek-objek kita tidak akan saling tumpang tindih. Tentu saja, dalam pengaturan game kita perlu menambahkan beberapa hal seperti pengelompokkan tabrakan, dan lain-lain, agar tidak harus mendeteksi atau merespon tabrakan ke semua objek, tapi hal-hal ini tergantung dengan bagaimana kamu ingin mengatur gameplay dalam game kamu, jadi tidak akan kita bahas lebih lanjut.
Ringkasan
Satu bagian dari seri tutorial dasar physics platformer 2D sudah selesai. Kita menggunakan mekanisme deteksi tabrakan dari bagian sebelumnya untuk membuat respon fisik sederhana antar objek.
Dengan kode ini kita bisa membuat objek standar seperti platform yang bergerak, blok yang bisa didorong, rintangan khusus, dan banyak lai jenis objek yang tidak bisa menjadi bagian dari tilemap, tapi perlu manjadi bagian dari level. Ada satu lagi fitur populer yang belum kita implemen, yaitu bidang miring.
Semoga di bagian berikutnya kita akan mulai mengembangkan tilemap agar bisa mendukung bidang miring, yang akan melengkapi fitur dasar untuk game platformer 2D, dan akan menjadi akhir dari seri tutorial ini.
Tentu saja akan ada ruang untuk perkembangan, jadi jika kamu punya pertanyaan atau tips untuk melakukan sesuatu lebih baik, atau memiliki komentar terhadap tutorial ini, jangan sungkan untuk menggunakan bagian komentar untuk memberi tahu saya!