Unlimited WordPress themes, graphics, videos & courses! Unlimited asset downloads! From $16.50/m
Advertisement
  1. Game Development
  2. Unity
Gamedevelopment

Membuat Efek Air 2D Dinamis dalam Kesatuan

by
Difficulty:IntermediateLength:LongLanguages:

Indonesian (Bahasa Indonesia) translation by Dwi Bagus Nurrohman (you can also view the original English article)

Dalam tutorial ini, kita akan mensimulasikan tubuh 2D dinamis air menggunakan fisika sederhana. Kami akan menggunakan campuran penyaji garis, penyaji jala, pemicu, dan partikel untuk menciptakan efek kami. Hasil akhir dilengkapi dengan ombak dan cipratan, siap untuk ditambahkan ke gim berikutnya. Sumber demo Unity (Unity3D) disertakan, tetapi Anda harus bisa mengimplementasikan sesuatu yang serupa menggunakan prinsip yang sama di mesin gim apa pun.


Hasil Akhir

Inilah yang kita akan berakhir dengan. Anda memerlukan plugin browser Unity untuk mencobanya.

Klik untuk membuat objek baru jatuh ke air.

Menyiapkan Manajer Air Kami

Dalam tutorialnya, Michael Hoffman mendemonstrasikan bagaimana kita dapat memodelkan permukaan air dengan deretan pegas.

Kita akan membuat bagian atas air kita menggunakan salah satu penyaji garis Unity, dan menggunakan begitu banyak simpul yang tampak sebagai gelombang kontinu.

Create 2D Dynamic Water Effects in Unity Unity3D

Kita harus melacak posisi, kecepatan dan percepatan setiap node. Untuk melakukan itu, kita akan menggunakan array. Jadi di bagian atas kelas kami, kami akan menambahkan variabel-variabel ini:

LineRenderer akan menyimpan semua node kita dan menguraikan badan air kita. Kami masih membutuhkan air itu sendiri; kami akan membuat ini dengan Meshes. Kita akan membutuhkan objek untuk menahan jerat ini juga.

Kami juga akan membutuhkan colliders sehingga hal-hal dapat berinteraksi dengan air kami:

Dan kami akan menyimpan semua konstanta kami juga

Konstanta ini sama seperti yang dibicarakan Michael, dengan pengecualian z — ini adalah z-offset kami untuk air kami. Kami akan menggunakan -1 untuk ini sehingga akan ditampilkan di depan objek kami. (Anda mungkin ingin mengubah ini tergantung pada apa yang ingin Anda tampilkan di depan dan di belakangnya; Anda harus menggunakan z-koordinat untuk menentukan di mana sprite duduk relatif terhadapnya.)

Selanjutnya, kita akan mempertahankan beberapa nilai:

Ini hanyalah dimensi air.

Kita akan membutuhkan beberapa variabel publik yang dapat kita atur di editor juga. Pertama, sistem partikel yang akan kita gunakan untuk percikan kami:

Selanjutnya, materi yang akan kami gunakan untuk penyaji baris kami (jika Anda ingin menggunakan kembali skrip untuk asam, lava, bahan kimia, atau apa pun):

Plus, jenis mesh yang akan kita gunakan untuk badan utama air:

Ini semua akan didasarkan pada prefab, yang semuanya termasuk dalam file sumber.

Kami menginginkan objek permainan yang dapat menampung semua data ini, bertindak sebagai pengelola, dan menelurkan tubuh kami dengan air untuk spesifikasi. Untuk melakukan itu, kita akan menulis fungsi bernama SpawnWater ().

Fungsi ini akan mengambil input dari sisi kiri, lebar, bagian atas, dan bagian bawah badan air.

(Meskipun ini tampaknya tidak konsisten, ia bertindak untuk kepentingan desain tingkat cepat ketika membangun dari kiri ke kanan).


Menciptakan Nodes

Sekarang kita akan mencari tahu berapa banyak node yang kita butuhkan:

Kita akan menggunakan lima per satuan lebar, untuk memberi kita gerakan halus yang tidak terlalu berat. (Anda dapat memvariasikan ini untuk menyeimbangkan efisiensi terhadap kehalusan.) Ini memberi kita semua garis kita, maka kita memerlukan + 1 untuk simpul tambahan di bagian akhir.

Hal pertama yang akan kita lakukan adalah membuat badan air kita dengan komponen LineRenderer:

Apa yang telah kami lakukan di sini adalah memilih material kami, dan mengaturnya untuk tampil di atas air dengan memilih posisinya dalam antrean pembuatan. Kami telah menetapkan jumlah node yang benar, dan mengatur lebar garis menjadi 0,1.

Anda dapat memvariasikan ini tergantung pada seberapa tebal garis Anda. Anda mungkin telah memperhatikan bahwa SetWidth () mengambil dua parameter; ini adalah lebar di awal dan akhir baris. Kami ingin lebar itu menjadi konstan.

Sekarang setelah kami membuat simpul kami, kami akan menginisialisasi semua variabel teratas kami:

Jadi sekarang kami memiliki semua array kami, dan kami berpegang pada data kami.

Sekarang untuk benar-benar mengatur nilai dari array kami. Kita akan mulai dengan simpul:

Di sini, kami mengatur semua posisi-y untuk berada di bagian atas air, dan kemudian secara bertahap menambahkan semua simpul berdampingan. Kecepatan dan akselerasi kami nol awalnya, karena air tenang.

Kami menyelesaikan loop dengan mengatur setiap node di LineRenderer (Body) ke posisi yang benar.


Menciptakan jerat

Di sinilah ia menjadi rumit.

Kami memiliki saluran kami, tetapi kami tidak memiliki air itu sendiri. Dan cara kita dapat membuatnya adalah menggunakan Meshes. Kita mulai dengan membuat ini:

Sekarang, Meshes menyimpan banyak variabel. Variabel pertama cukup sederhana: ini berisi semua simpul (atau sudut).

Create 2D Dynamic Water Effects in Unity Unity3D

Diagram menunjukkan apa yang kita ingin segmen jala kita terlihat seperti. Untuk segmen pertama, simpul disorot. Kami ingin empat total.

Sekarang, seperti yang Anda lihat di sini, titik 0 adalah kiri atas, 1 di kanan atas, 2 di kiri bawah, dan 3 di kanan atas. Kita perlu mengingat itu untuk nanti.

Properti kedua yang membutuhkan mesh adalah UV. Jerat memiliki tekstur, dan UV memilih bagian mana dari tekstur yang ingin kita ambil. Dalam hal ini, kami hanya ingin sudut kiri atas, kanan atas, kiri bawah, dan kanan bawah tekstur kami.

Sekarang kita membutuhkan angka-angka itu dari sebelumnya. Jerat terdiri dari segitiga, dan kita tahu bahwa setiap segiempat dapat dibuat dari dua segitiga, jadi sekarang kita perlu memberitahu jaring bagaimana seharusnya menggambar segitiga tersebut.

Create 2D Dynamic Water Effects in Unity Unity3D

Lihatlah sudut-sudut dengan urutan simpul berlabel. Segitiga A menghubungkan simpul  1 dan 3; Triangle B menghubungkan node 3, 2 dan 0. Oleh karena itu, kami ingin membuat sebuah array yang berisi enam bilangan bulat, yang mencerminkan persisnya:

Ini menciptakan segiempat kami. Sekarang kita mengatur nilai mesh.

Sekarang, kami memiliki jaring kami, tetapi kami tidak memiliki Benda-Benda Gim untuk membuatnya dalam adegan. Jadi kita akan membuatnya dari prefab watermesh kami yang berisi Mesh Renderer dan Mesh Filter.

Kami mengatur jala, dan kami mengaturnya menjadi anak pengelola air, untuk membereskan semuanya.


Menciptakan Tabrakan Kita

Sekarang kami ingin collider kami juga:

Di sini, kami membuat colliders kotak, memberi mereka nama sehingga mereka sedikit lebih rapi di tempat kejadian, dan membuat mereka masing-masing anak dari pengelola air lagi. Kami mengatur posisi mereka untuk berada di tengah antara node, mengatur ukuran mereka, dan menambahkan kelas WaterDetector kepada mereka.

Sekarang kita memiliki jala kita, kita membutuhkan fungsi untuk memperbaruinya ketika air bergerak:

Anda mungkin memperhatikan bahwa fungsi ini hanya menggunakan kode yang kami tulis sebelumnya. Satu-satunya perbedaan adalah bahwa kali ini kita tidak perlu mengatur tris dan UV, karena ini tetap sama.

Tugas berikut adalah membuat air sendiri bekerja. Kami akan menggunakan FixedUpdate () untuk memodifikasi semuanya secara bertahap.


Implementing the Physics

Pertama, kita akan menggabungkan Hukum Hooke dengan metode Euler untuk menemukan posisi baru, percepatan dan kecepatan.

Jadi, Hukum Hooke adalah \ (F = kx \), di mana \ (F \) adalah gaya yang dihasilkan oleh pegas (ingat, kita permodelan permukaan air sebagai deretan pegas), \ (k \) adalah konstanta pegas, dan \ (x \) adalah perpindahan. Pergeseran kami hanya akan menjadi posisi y dari setiap node dikurangi ketinggian dasar dari node.

Selanjutnya, kita menambahkan faktor redaman sebanding dengan kecepatan gaya untuk meredam gaya.

Metode Euler sederhana; kita hanya menambahkan percepatan ke kecepatan dan kecepatan ke posisi, setiap frame.

Catatan: Saya hanya mengasumsikan massa setiap node adalah 1 di sini, tetapi Anda akan ingin menggunakan

jika Anda ingin massa yang berbeda untuk simpul Anda.

Kiat: Untuk fisika yang tepat, kami akan menggunakan integrasi Verlet, tetapi karena kami menambahkan redaman, kami hanya dapat menggunakan metode Euler, yang jauh lebih cepat untuk dihitung. Umumnya, meskipun, metode Euler akan secara eksponensial memperkenalkan energi kinetik dari mana saja ke sistem fisika Anda, jadi jangan menggunakannya untuk sesuatu yang tepat.

Sekarang kita akan menciptakan propagasi gelombang. Kode berikut ini diadaptasi dari tutorial Michael Hoffman.

Di sini, kami membuat dua larik. Untuk setiap node, kita akan memeriksa ketinggian node sebelumnya terhadap ketinggian node saat ini dan menempatkan perbedaan ke leftDeltas.

Kemudian, kita akan memeriksa ketinggian node berikutnya terhadap ketinggian node yang kita periksa, dan memasukkan perbedaan itu ke dalam rightDeltas. (Kami juga akan mengalikan semua nilai dengan sebaran yang konstan).

Kita dapat mengubah kecepatan berdasarkan perbedaan ketinggian dengan segera, tetapi kita sebaiknya hanya menyimpan perbedaan posisi pada titik ini. Jika kita mengubah posisi node pertama lurus dari kelelawar, pada saat kita melihat node kedua, node pertama sudah bergerak, sehingga akan merusak semua perhitungan kami.

Jadi setelah kami mengumpulkan semua data tinggi kami, kami dapat menerapkannya di bagian akhir. Kita tidak bisa melihat ke kanan node di paling kanan, atau ke kiri node di paling kiri, maka kondisi i> 0 dan i< xpositions.Length - 1.

Juga, perhatikan bahwa kami berisi seluruh kode ini dalam satu lingkaran, dan menjalankannya delapan kali. Ini karena kita ingin menjalankan proses ini dalam dosis kecil beberapa kali, daripada satu perhitungan besar, yang akan jauh lebih sedikit cairan.


Menambahkan percikan

Sekarang kita punya air yang mengalir, dan itu menunjukkan Selanjutnya, kita harus bisa mengganggu air!

Untuk ini, mari tambahkan fungsi yang disebut Splash (), yang akan memeriksa posisi x dari splash, dan kecepatan dari apa pun yang mengenai. Itu harus publik sehingga kita bisa memanggilnya dari kolektor kita nanti.

Pertama, kita perlu memastikan bahwa posisi yang ditentukan sebenarnya dalam batas-batas air kita:

Dan kemudian kita akan mengubah xpos sehingga memberi kita posisi relatif terhadap awal badan air:

Selanjutnya, kita akan mencari tahu simpul mana yang menyentuh. Kita dapat menghitungnya seperti ini

Jadi, inilah yang terjadi di sini

  1. Kami mengambil posisi splash relatif terhadap posisi tepi kiri air (xpos).
  2. Kami membagi ini dengan posisi tepi kanan relatif terhadap posisi tepi kiri air.
  3. Ini memberi kita sebagian kecil yang memberitahu kita di mana percikan itu Misalnya, percikan tiga perempat dari jalan di sepanjang badan air akan memberikan nilai 0,75.
  4. Kita mengalikannya dengan jumlah sisi dan membulatkan angka ini, yang memberi kita simpul percikan kita paling dekat.

Sekarang kita mengatur kecepatan objek yang menghantam air kita ke kecepatan simpul itu, sehingga terseret ke bawah oleh objek.

Catatan: Anda dapat mengubah baris ini menjadi apa pun yang cocok untuk Anda Misalnya, Anda dapat menambahkan kecepatan ke kecepatan saat ini, atau Anda bisa menggunakan momentum, bukan kecepatan dan membagi dengan massa simpul Anda.

Create 2D Dynamic Water Effects in Unity Unity3D

Sekarang kita ingin membuat sistem partikel yang akan menghasilkan percikan. Kami mendefinisikan itu sebelumnya; itu disebut "splash" (cukup kreatif). Pastikan untuk tidak mengacaukannya dengan Splash (). Yang akan saya gunakan termasuk dalam file sumber.

Pertama, kita ingin mengatur parameter percikan untuk berubah dengan kecepatan objek.

Di sini, kami telah mengambil partikel-partikel kami, mengatur masa hidup mereka sehingga mereka tidak akan mati segera setelah mereka menyentuh permukaan air, dan mengatur kecepatan mereka untuk didasarkan pada kuadrat kecepatan mereka (ditambah konstan, untuk percikan kecil) .

Anda mungkin melihat kode itu dan berpikir, "Mengapa dia mengatur startSpeed ​​dua kali?", Dan Anda akan benar bertanya-tanya itu. Masalahnya adalah, kami menggunakan sistem partikel (Shuriken, disediakan dengan proyek) yang memiliki kecepatan awal diatur ke "acak antara dua konstanta". Sayangnya, kami tidak memiliki banyak akses ke Shuriken melalui skrip, jadi untuk membuat perilaku itu berfungsi, kami harus menetapkan nilainya dua kali.

Sekarang saya akan menambahkan baris yang Anda mungkin atau mungkin tidak ingin hilangkan dari skrip Anda:

Partikel shuriken tidak akan hancur ketika mereka memukul benda Anda, jadi jika Anda ingin memastikan bahwa mereka tidak akan mendarat di depan benda Anda, Anda dapat mengambil dua langkah:

  1. Tempelkan di latar belakang. (Anda dapat mengatakan ini dengan posisi-z menjadi 5).
  2. Miringkan sistem partikel untuk selalu mengarah ke pusat tubuh air Anda - dengan cara ini, partikel-partikel tidak akan terciprat ke tanah.

Baris kedua kode mengambil titik tengah posisi, bergerak ke atas sedikit, dan menunjukkan emitor partikel ke arahnya. Saya telah menyertakan perilaku ini di demo. Jika Anda menggunakan badan air yang sangat luas, Anda mungkin tidak menginginkan perilaku ini. Jika air Anda berada di kolam kecil di dalam ruangan, Anda mungkin ingin menggunakannya. Jadi, jangan ragu untuk membuang garis tentang rotasi.

Sekarang, kita membuat percikan kita, dan mengatakannya untuk mati sedikit setelah partikel-partikel itu akan mati. Mengapa sedikit sesudahnya? Karena sistem partikel kita mengirimkan beberapa rentetan partikel berurutan, jadi meskipun batch pertama hanya bertahan sampai Time.time + lifetime semburan terakhir kita akan tetap sekitar sedikit setelah itu.

Iya! Kita akhirnya selesai, kan?


Deteksi Tabrakan

Salah! Kita perlu mendeteksi objek kita, atau ini semua sia-sia!

Ingat kami menambahkan skrip itu ke semua colliders kami sebelumnya? Yang disebut WaterDetector?

Yah kita akan membuatnya sekarang! Kami hanya ingin satu fungsi di dalamnya:

Dengan menggunakan OnTriggerEnter2D (), kita dapat menentukan apa yang terjadi ketika sebuah 2D Rigid Body memasuki tubuh air kita. Jika kita melewatkan parameter Collider2D kita dapat menemukan informasi lebih lanjut tentang objek itu

Kami hanya menginginkan objek yang berisi rigidbody2D.

Sekarang, semua colliders kami adalah anak-anak dari pengelola air. Jadi kita hanya mengambil komponen Water dari orang tua mereka dan memanggil Splash (), dari posisi collider.

Ingat lagi, saya katakan Anda bisa melewati kecepatan atau momentum, jika Anda ingin itu menjadi lebih akurat secara fisik? Nah di sinilah Anda harus melewati yang benar. Jika Anda mengalikan kecepatan y objek dengan massanya, Anda akan memiliki momentumnya. Jika Anda hanya ingin menggunakan kecepatannya, singkirkan massa dari garis itu.

Akhirnya, Anda akan ingin memanggil SpawnWater () dari suatu tempat. Mari kita lakukan saat peluncuran:

Dan sekarang kita selesai! Sekarang rigidbody2D apa pun dengan collider yang mengenai air akan menciptakan percikan, dan gelombang akan bergerak dengan benar.

Create 2D Dynamic Water Effects in Unity Unity3D

Bonus Latihan

Sebagai bonus tambahan, saya telah menambahkan beberapa baris kode ke atas SpawnWater()

Baris kode ini akan menambahkan collider kotak ke air itu sendiri Anda dapat menggunakan ini untuk membuat benda-benda melayang di air, menggunakan apa yang telah Anda pelajari.

Anda akan ingin membuat fungsi bernama OnTriggerStay2D() yang mengambil parameter Collider2D Hit Kemudian, Anda dapat menggunakan versi modifikasi dari rumus pegas yang kami gunakan sebelumnya yang memeriksa massa objek, dan menambahkan gaya atau kecepatan ke rigidbody2D untuk membuatnya mengambang di air.


Membuat percikan

Dalam tutorial ini, kami menerapkan simulasi air sederhana untuk digunakan dalam permainan 2D dengan kode fisika sederhana dan penyaji garis, penyaji jala, pemicu, dan partikel. Mungkin kamu akan menambahkan tubuh bergelombang cairan air sebagai penghalang untuk platformer berikutnya, siap untuk karakter kamu untuk menyelam ke dalam atau hati-hati menyeberang dengan batu loncatan mengambang, atau mungkin kamu bisa menggunakan ini dalam permainan berlayar atau selancar angin, atau bahkan permainan di mana kamu cukup melewatkan bebatuan melintasi air dari pantai yang cerah Semoga Berhasil!.

Advertisement
Advertisement
Advertisement
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.