Catatan : tutorial ini ditujukan untuk pengguna mahir dan berpengalaman, dan tidak mencakup topik seperti menambahkan komponen, membuat skrip GameObject baru, dan sintaksis C #. Jika Anda perlu meningkatkan keterampilan Unity Anda, lihat tutorial Memulai Penggunaan dengan Unity dan Pengantar Script Unity kami .
Di bagian 
pertama tutorial, kami belajar cara membuat kait kucing dengan mekanisme melilitkan tali di sekeliling rintangan. Namun, kami ingin lebih: tali dapat membungkus benda di tingkat, tetapi tidak lepas ketika Anda kembali.
Mulai bekerja
Buka proyek jadi dari bagian pertama di Unity atau unduh 
draf untuk bagian tutorial ini, lalu buka 
2DGrapplingHook-Part2-Starter . Seperti pada bagian pertama, kita akan menggunakan versi Unity 2017.1 atau lebih tinggi.
Buka adegan 
Game di editor dari folder proyek 
Scenes .
Luncurkan adegan Game dan coba kaitkan kait kucing di atas batu di atas karakter, lalu ayun untuk membuat tali membungkus sepasang tepi batu.
Ketika Anda kembali, Anda akan melihat bahwa titik-titik batu tempat tali yang digunakan untuk berbalik tidak terlepas lagi.
Pikirkan tentang titik di mana tali harus dibuka. Untuk menyederhanakan tugas, lebih baik menggunakan kasing saat tali membungkus ujung-ujungnya.
Jika siput, menempel pada batu di atas kepalanya, berayun ke kanan, maka tali akan bengkok setelah ambang batas di mana ia melintasi titik sudut 180 derajat dengan tepi yang saat siput terpasang. Pada gambar di bawah, ini ditunjukkan oleh titik hijau yang disorot.
Ketika siput itu berayun kembali ke arah lain, tali itu harus kembali terlepas pada titik yang sama (disorot dengan warna merah pada gambar di atas):
Logika tidak terputus-putus
Untuk menghitung momen ketika Anda perlu melepas tali pada titik-titik yang dibungkus sebelumnya, kita perlu pengetahuan tentang geometri. Secara khusus, kami akan menggunakan perbandingan sudut untuk menentukan kapan tali harus dilepas dari tepi.
Tugas ini mungkin tampak sedikit mengintimidasi. Matematika dapat menginspirasi horor dan keputusasaan bahkan dalam yang paling berani.
Untungnya, Unity memiliki beberapa fungsi penolong matematika yang hebat yang dapat membuat hidup kita sedikit lebih mudah.
Buka skrip 
RopeSystem di IDE dan buat metode baru yang disebut 
HandleRopeUnwrap() .
 private void HandleRopeUnwrap() { } 
Buka 
Update() dan tambahkan pada akhirnya panggilan ke metode baru kami.
 HandleRopeUnwrap(); 
Sementara 
HandleRopeUnwrap() tidak melakukan apa-apa, tetapi sekarang kita dapat memproses logika yang terkait dengan seluruh proses melepaskan dari tepi.
Seperti yang Anda ingat dari bagian pertama tutorial, kami menyimpan posisi pembungkus tali dalam koleksi yang disebut 
ropePositions , yang merupakan koleksi 
List<Vector2> . Setiap kali tali melilit ujung, kami menjaga posisi titik bungkus ini dalam koleksi ini.
Untuk membuat proses lebih efisien, kami tidak akan menjalankan logika apa pun di 
HandleRopeUnwrap() jika jumlah posisi yang disimpan dalam koleksi sama dengan atau kurang dari 1.
Dengan kata lain, ketika siput telah terhubung ke titik awal dan tali belum melilit ujungnya, jumlah 
ropePositions adalah 1, dan kami tidak akan mengikuti logika pemrosesan yang tidak diputar.
Tambahkan 
return sederhana ini ke bagian atas 
HandleRopeUnwrap() untuk menghemat siklus CPU yang berharga, karena metode ini dipanggil dari 
Update() berkali-kali per detik.
 if (ropePositions.Count <= 1) { return; } 
Menambahkan Variabel Baru
Di bawah pengujian baru ini, kami akan menambahkan beberapa dimensi dan referensi ke berbagai sudut yang diperlukan untuk menerapkan dasar dari logika yang tidak terputar. Tambahkan kode berikut ke 
HandleRopeUnwrap() :
 
Ada banyak variabel di sini, jadi saya akan menjelaskan masing-masing, serta menambahkan ilustrasi yang nyaman yang akan membantu untuk memahami tujuan mereka.
- anchorIndexadalah indeks dalam koleksi- ropePositionsdi dua posisi dari akhir koleksi. Kita dapat menganggapnya sebagai titik di dua posisi pada tali dari posisi siput. Pada gambar di bawah ini, ini adalah titik pertama pengait kait ke permukaan. Saat mengisi koleksi- ropePositionstitik pembungkus baru, titik ini akan selalu tetap menjadi titik pembungkus pada jarak dua posisi dari siput.
- hingeIndexadalah indeks koleksi yang menyimpan titik engsel saat ini; dengan kata lain, posisi tali saat ini sedang membungkus titik terdekat dengan ujung tali dari siput. Itu selalu pada jarak satu posisi dari siput, itulah sebabnya kami menggunakan- ropePositions.Count - 1.
- anchorPositiondihitung dengan merujuk tempat- ropePositionskoleksi- ropePositionsdan merupakan nilai Vector2 sederhana dari posisi itu.
- hingePositiondihitung dengan merujuk tempat- hingeIndexdalam koleksi- ropePositionsdan merupakan nilai Vector2 sederhana dari posisi itu.
- hingeDiradalah vektor yang diarahkan dari- anchorPositionke- hingePosition. Ini digunakan dalam variabel berikut untuk mendapatkan sudut.
- hingeAngle- fungsi pembantu yang berguna- Vector2.Angle()digunakan di sini untuk menghitung sudut antara- anchorPositiondan titik engsel.
- playerDiradalah vektor yang diarahkan dari- anchorPositionke posisi siput saat ini (playerPosition)
- Kemudian, menggunakan sudut antara titik jangkar dan pemain (siput), playerAngledihitung.

Semua variabel ini dihitung menggunakan posisi yang disimpan sebagai nilai Vector2 dalam koleksi 
ropePositions dan membandingkan posisi ini dengan posisi lain atau posisi pemain saat ini (slug).
Dua variabel penting yang digunakan untuk perbandingan adalah 
hingeAngle dan 
playerAngle .
Nilai yang disimpan dalam 
hingeAngle harus tetap statis karena selalu sudut yang konstan antara titik di dua "lipatan tali" dari siput dan "lipatan tali" saat ini yang paling dekat dengan siput yang tidak bergerak sampai tali tidak terpilin atau setelah dilipat titik tikungan baru akan ditambahkan.
Saat siput 
playerAngle berubah. Dengan membandingkan sudut ini dengan 
hingeAngle , dan juga memeriksa apakah siput di sebelah kiri atau kanan sudut ini, kita dapat menentukan apakah titik lipat saat ini yang paling dekat dengan siput harus dilepaskan.
Di bagian pertama tutorial ini, kami menyimpan posisi lipatan dalam kamus yang disebut 
wrapPointsLookup . Setiap kali kami menyimpan titik tekuk, kami menambahkannya ke kamus dengan posisi sebagai kunci dan dengan 0 sebagai nilainya. Namun, nilai 0 ini agak misterius, bukan?
Kami akan menggunakan nilai ini untuk menyimpan posisi siput relatif terhadap sudutnya dengan titik engsel (titik lipat saat ini paling dekat dengan siput).
Jika Anda menetapkan nilai 
-1 , maka sudut siput ( 
playerAngle ) kurang dari sudut engsel ( 
hingeAngle ), dan dengan nilai 
1, sudut 
playerAngle lebih besar daripada 
hingeAngle .
Karena fakta bahwa kita menyimpan nilai-nilai dalam kamus, setiap kali kita membandingkan 
playerAngle dengan 
hingeAngle , kita dapat memahami apakah siput baru saja melewati batas yang setelah itu tali harus dilepas.
Ini dapat dijelaskan secara berbeda: jika sudut siput baru saja diperiksa dan lebih kecil dari sudut engsel, tetapi terakhir kali disimpan dalam kamus titik lengkung itu ditandai dengan nilai yang menunjukkan bahwa itu berada di sisi lain sudut ini, maka titik tersebut harus dihapus !
Tali pemisah
Lihatlah screenshot di bawah ini dengan catatan. Siput kami menempel di batu, bergoyang ke atas, melilitkan tali di tepi batu pada saat naik.
Anda mungkin memperhatikan bahwa pada posisi ayunan paling atas, di mana siputnya buram, titik lipatan terdekat saat ini (ditandai dengan titik putih) akan disimpan dalam kamus 
wrapPointsLookup dengan nilai 
1 .
Dalam perjalanan turun, ketika 
playerAngle menjadi lebih kecil daripada 
hingeAngle (dua garis hijau putus-putus), seperti yang ditunjukkan oleh panah biru, pemeriksaan dilakukan, dan jika nilai terakhir (saat ini) dari titik bengkok adalah 
1 , maka titik bengkok harus dihapus.
Sekarang mari kita terapkan logika ini dalam kode. Tetapi sebelum kita mulai, mari kita buat metode kosong yang akan kita gunakan untuk bersantai. Karena ini, setelah membuat logika, itu tidak akan menyebabkan kesalahan.
Tambahkan metode 
UnwrapRopePosition(anchorIndex, hingeIndex) baru 
UnwrapRopePosition(anchorIndex, hingeIndex) dengan memasukkan baris berikut:
 private void UnwrapRopePosition(int anchorIndex, int hingeIndex) { } 
Setelah melakukan ini, kembali ke 
HandleRopeUnwrap() . Di bawah variabel yang baru ditambahkan, tambahkan logika berikut, yang akan menangani dua kasus: 
playerAngle kurang dari 
hingeAngle dan 
playerAngle lebih dari 
hingeAngle :
 if (playerAngle < hingeAngle) {  
Kode ini harus sesuai dengan penjelasan logika yang dijelaskan di atas untuk kasus pertama (ketika 
playerAngle < 
hingeAngle ), tetapi juga menangani kasus kedua (ketika 
playerAngle > 
hingeAngle ).
- Jika titik lipat saat ini yang paling dekat dengan siput memiliki nilai 1 pada titik di mana playerAngle<hingeAngle, maka kami menghapus titik ini dan melakukan pengembalian sehingga sisa metode tidak dieksekusi.
- Jika tidak, jika titik bengkok tidak ditandai terakhir dengan nilai 1 , tetapi playerAnglekurang darihingeAngle, maka -1 ditugaskan.
- Jika titik lipat saat ini yang paling dekat dengan siput adalah -1 pada titik di mana playerAngle>hingeAngle, kemudian hapus titik dan kembali.
- Jika tidak, kami menetapkan entri dalam kamus titik lengkung pada posisi engsel ke 1 .
Kode ini memastikan bahwa kamus 
wrapPointsLookup selalu diperbarui, memastikan bahwa nilai titik tekuk saat ini (paling dekat dengan siput) cocok dengan sudut siput saat ini relatif terhadap titik tekuk.
Jangan lupa bahwa nilainya -1 ketika sudut slug kurang dari sudut engsel (relatif ke titik referensi), dan 1 ketika sudut slug lebih besar dari sudut engsel.
Sekarang kita akan 
UnwrapRopePosition() dalam skrip 
RopeSystem dengan kode yang akan langsung terlibat dalam pelepasan, memindahkan posisi referensi dan menetapkan nilai jarak baru ke nilai jarak tali DistanceJoint2D. Tambahkan baris berikut ke disk metode yang dibuat sebelumnya:
   
- Indeks titik jangkar saat ini (posisi kedua tali dari siput) menjadi posisi baru dari engsel, dan posisi lama dari engsel dilepas (yang sebelumnya paling dekat dengan siput dan yang sekarang kita "lepaskan"). Variabel newAnchorPositiondiberikan nilaianchorIndexdalam daftar posisi tali. Kemudian akan digunakan untuk memposisikan posisi yang diperbarui dari titik jangkar.
- Tali-sambungan RigidBody2D (dimana tali DistanceJoint2D terpasang) mengubah posisinya ke posisi baru dari titik jangkar. Hal ini memastikan gerakan siput terus menerus yang lancar pada tali ketika terhubung ke DistanceJoint2D, dan koneksi ini harus memungkinkannya untuk terus berayun relatif terhadap posisi baru, yang menjadi referensi - dengan kata lain, relatif ke titik berikutnya turun tali dari posisinya.
- Maka Anda perlu memperbarui nilai jarak distanceJoint2D untuk memperhitungkan perubahan tajam dalam jarak dari siput ke titik referensi baru. Jika ini belum dilakukan, pemeriksaan cepat dari flag distanceSetdilakukan, dan jarak diberikan nilai jarak yang dihitung antara siput dan posisi baru dari titik jangkar.
Simpan skrip dan kembali ke editor. Mulai permainan lagi dan perhatikan bagaimana tali terlepas dari tepi ketika siput melewati nilai ambang batas dari setiap titik tikungan!
Meskipun logikanya sudah siap, kami akan menambahkan beberapa kode pembantu ke 
HandleRopeUnwrap() tepat sebelum membandingkan 
playerAngle dengan 
hingeAngle ( 
if (playerAngle < hingeAngle) ).
 if (!wrapPointsLookup.ContainsKey(hingePosition)) { Debug.LogError("We were not tracking hingePosition (" + hingePosition + ") in the look up dictionary."); return; } 
Sebenarnya, ini seharusnya tidak terjadi, karena kami mendefinisikan ulang dan melepaskan kait kucing ketika membungkus sekitar satu tulang rusuk dua kali, tetapi jika ini masih terjadi, kita dapat dengan mudah keluar dari metode ini dengan 
return sederhana dan pesan kesalahan di konsol.
Selain itu, berkat ini, kami akan lebih mudah menangani kasus pembatas seperti itu; Selain itu, kami mendapatkan pesan kesalahan kami sendiri jika terjadi sesuatu yang tidak perlu.
Ke mana harus pergi selanjutnya?
Berikut ini 
tautan ke proyek yang sudah selesai pada bagian kedua dan terakhir dari tutorial ini.
Selamat telah menyelesaikan seri tutorial ini! Ketika datang untuk membandingkan sudut dan posisi, semuanya menjadi sangat rumit, tetapi kami selamat dari ini dan sekarang kami memiliki sistem kait-kucing dan tali yang indah yang dapat berakhir pada objek dalam permainan.
Tahukah Anda bahwa tim pengembangan Persatuan kami telah menulis buku? Jika tidak, lihat 
Unity Games By Tutorials . Game ini akan mengajarkan Anda cara membuat empat game yang sudah jadi dari awal:
- Penembak dua tongkat
- Penembak orang pertama
- Game menara pertahanan (dengan dukungan VR!)
- Platformer 2D
Setelah membaca buku ini, Anda akan belajar cara membuat game sendiri untuk Windows, macOS, iOS, dan platform lainnya!
Buku ini ditujukan untuk pemula dan mereka yang ingin meningkatkan keterampilan Persatuan mereka ke tingkat profesional. Untuk menguasai buku ini, Anda harus memiliki pengalaman pemrograman (dalam bahasa apa pun).