Bagaimana saya membuat Daur Ulang! VR



Pada artikel sebelumnya, kami mencoba membuat adegan dasar dalam A-Frame untuk mencoba konsep dasar kerangka kerja dalam praktik. Pada artikel ini, saya ingin berbagi pengalaman saya dalam membuat game di A-Frame - Recycle! VR Repositori proyek tersedia di tautan berikut .

Daur ulang!?


Gagasan untuk membuat game muncul segera setelah saya mengetahui tentang Web VR. Meskipun secara umum, saya percaya bahwa permainan di web dalam hal apa pun akan lebih rendah daripada proyek yang baik bahkan untuk perangkat seluler, belum lagi komputer pribadi dan konsol. Tapi, menurut saya, permainan adalah ujian yang paling sulit. Saya mulai berpikir tentang apa yang bisa saya lakukan. Saya menonton proyek-proyek lain dan saya langsung dikejutkan oleh kesempatan untuk mengambil sesuatu menggunakan controller. Dan karena saya telah terhubung dengan organisasi yang bergerak dalam pengumpulan sampah terpisah untuk beberapa waktu, jawabannya datang dengan sendirinya. Daur ulang. Kami mengambil sampah dan membuangnya ke tempat sampah. Apa yang bisa lebih mudah. Tetapi semuanya ternyata tidak begitu sederhana, dan ini, pada kenyataannya, akan dibahas lebih lanjut.

Temukan kerangka kerja


Pada saat dimulainya permainan, saya hanya tahu sekitar 2 kerangka kerja yang lebih atau kurang serius: Bereaksi 360, A-Frame. Jelas, A-Frame paling cocok untuk membuat gim. Ya, sekarang saya tahu bahwa masih ada mesin game PlayCanvas yang juga mendukung VR, tetapi sudah terlambat. Apalagi, ternyata A-Frame juga tidak buruk untuk membuat game.

Di mana untuk memulai?


Saya mulai dengan mempelajari contoh-contoh game resmi dari pengembang A-Frame. Manfaatnya tidak cukup. A-Blast, A-Painter, Museum, Super Craft dan sekarang juga Gunters of Oasis. Dari semua proyek yang disajikan, saya paling suka A-Blast - penembak di mana Anda harus bertarung dengan makhluk paling lucu di alam semesta. Karena itu, saya ingin menjadikan game ini sebagai templat untuk saya. Tapi itu tidak berhasil. Dan alasan untuk ini adalah struktur permainan. Tampak bagi saya bahwa dia terlalu berantakan dan tidak dipikirkan. Mungkin lebih banyak tidak diperlukan, tetapi saya ingin melakukan sesuatu yang lebih nyaman dan lebih mudah dipahami.

Struktur


Struktur A-Blast hanya mewakili satu titik masuk - file index.html, yang berisi satu adegan dengan semua aset, entitas game dasar, kontrol, dan semuanya secara umum.



Seperti yang dapat Anda lihat di tangkapan layar, di samping komponen dan sistem yang diperlukan (A-Frame menggunakan pola Entity Component System), ada juga peluru dan musuh - pada dasarnya sistem yang sama, tetapi untuk beberapa alasan memiliki pembungkus mereka sendiri. Secara umum mengatakan bahwa kode ini tidak mudah dimengerti. Jadi saya memutuskan untuk memikirkan bagaimana kode ini dapat disusun. Gagasan pertama adalah memecah adegan menjadi bagian-bagian penyusunnya. Mengapa router dan templat berguna, yang akan membuat ini atau itu bagian dari adegan. Setelah mencari yang pertama dan kedua (tidak, tidak lima menit), saya tidak menemukan apa pun. Meski saya pendukung aturan, jangan menulis sepeda, tapi kali ini saya harus menulis keputusan. Meskipun, di suatu tempat dalam 2-3 minggu saya menemukan template dari Kevin Ngo. Tapi sudah terlambat.

Router dan pola




Maka, a-frame-router-templates memasuki adegan. Apa yang bisa dia lakukan? Seperti disebutkan di atas, tugas utamanya adalah membuat bagian-bagian yang diperlukan dari permainan, misalnya, layar judul, lapangan bermain, layar akhir permainan, dll. Bagaimana cara melakukannya? Pada prinsipnya, Anda dapat menemukan semua yang Anda butuhkan dalam dokumentasi untuk modul di github, tetapi singkatnya, kami memiliki yang berikut:

<a-scene router> ... <!-- Routes --> <a-route id="start-screen" template="start-screen"></a-route> <a-route id="game-field" template="game-field"></a-route> <a-route id="game-over" template="game-over"></a-route> <a-route id="how-to-play" template="how-to-play"></a-route> <!-- End Routes --> ... <!-- Templates --> <a-template name="controls"></a-template> <!-- End Templates --> ... </a-scene> 

  1. Kami menambahkan komponen router ke tempat kejadian.
  2. Tambahkan-rute untuk setiap bagian dari aplikasi (frame adegan). Satu rute untuk layar beranda, lainnya untuk lapangan bermain, dll.
  3. Berikan template secara langsung melalui template-a
  4. Jika perlu, kami mengubah rute melalui

     this.el.systems.router.changeRoute('game-field'); 

    Catatan : contoh ini merujuk pada kode adegan, sehingga kita dapat memanggil sistem router secara langsung.
  5. Kami menetapkan dan menghubungkan template, kira-kira seperti ini:

     AFRAME.registerTemplate('game-field', ` <a-sub-assets> <a-asset-item id="glass" src="/assets/models/glass_bottle.gltf"></a-asset-item> ... <audio id="fail" src="/assets/sounds/fail.wav" preload></audio> </a-sub-assets> <a-template name="button" options="text: EXIT; position: 0 1 4; rotation: 0 180 0; event: stop-game"></a-template> <a-entity id="indicator" indicator visible="false" position="0 1 -2" text="align: center; width: 4; color: #00A105; value: -1" ></a-entity> <a-entity game-field-manager></a-entity> `); 

    Catatan: a-sub-aset memungkinkan Anda memuat aset serta a-aset, tetapi hanya dengan perbedaan bahwa ada cek secara default dan jika aset sudah ditambahkan, itu tidak akan ditambahkan lagi ketika rute diubah.

    Catatan 2: Biasanya Anda dapat menggunakan templat hanya dengan string templat ES6. Kalau tidak, itu bisa berubah menjadi "string" + var + "string", tidak keren. Kevin, misalnya, memiliki dukungan untuk mesin templat. Tapi mengapa menyulitkannya, kan?

Dengan demikian, Anda dapat membuat struktur aplikasi yang nyaman yang akan berisi yang berikut ini: komponen, sistem, templat, status, libs . Tidak ada yang lebih dan semuanya ada di rak.

Memanipulasi benda




Tugas pertama yang harus dipecahkan adalah manipulasi objek. Saya membutuhkan fungsional seperti ambil - lempar. Awalnya, saya mulai merenungkan cara membuat komponen seperti itu dari awal. Murni pada tingkat filistin, refleksi seperti itu diperbolehkan: kami memiliki controller (dalam kasus desktop itu adalah kursor), ia memiliki posisi. Kami juga memiliki objek tertentu, misalnya kubus, mereka juga memiliki posisi. Dengan mengubah posisi pengontrol, kita harus mengubah posisi objek. Apakah ini sederhana? Jadi, sebenarnya, ya, tapi itu tidak akan berhasil. Saya akan menyebutkan beberapa poin dari daftar yang sangat panjang untuk meyakinkan Anda tentang ini:

  • Kursor dalam A-Frame adalah keturunan dari kamera-dan memiliki koordinat relatif;
  • Posisi pengontrol tidak cukup, Anda masih perlu mempertimbangkan orientasi, jarak ke objek, posisi kamera (pemain);
  • Untuk objek dengan tubuh fisik, ini tidak akan berfungsi sama sekali, karena koordinat geometri terhubung dengan koordinat tubuh.

Bagus sekali bahwa Tuan Wil Murphy dan teman-temannya yang baik melakukan hal-hal-tangan-super . Intinya, perpustakaan ini mengandung semua komponen yang diperlukan:

  • melayang Bimbingan Arahkan pengontrol atau kursor ke zona tabrakan objek (biasanya seluruh objek)
  • grabbable : Capture. Ambil objek menggunakan tombol yang sesuai dan seret
  • merenggang : Ambil dengan kedua tangan dan regang \ meremas
  • draggable \ dropable : Pada dasarnya diperlukan untuk menentukan acara "item dilemparkan ke lokasi tertentu"

Anda dapat menemukan semua yang Anda butuhkan tentang pengaturan dan menghubungkan tangan-super dalam repositori yang disebutkan di atas. Saya hanya ingin menarik sejumlah nuansa:

  • Buat mixin terpisah untuk tangan kanan dan kiri. Pisahkan komponen berdasarkan jenis perangkat yang didukung. Misalnya, di sebelah kanan, selain oculus-touch, vive-kontrol, windows-motion-kontrol, mungkin ada juga oculus-go-kontrol dan gear-vr-kontrol. Tangan kiri harus disembunyikan untuk helm seluler BP. Setiap pengontrol harus mengandung kedua tangan mixin dan komponen super tangan. Sebuah contoh ;
  • Jika Anda menentukan objek: .clsname untuk reycaster, jangan lupa untuk menambahkannya ke setiap elemen yang dapat diambil menggunakan pengontrol, jika tidak, satu acara untuk tangan super tidak akan gagal. Tentu saja, jika colliderEvent: raycaster-intersection ;
  • Menyeret dengan mouse memproyeksikan koordinat 2d ke dunia 3d, jadi lebih baik menggunakan kursor untuk desktop.

Tambahkan fisika


Menambahkan fisika ke a-frame sebenarnya sangat sederhana. Ada sistem khusus untuk ini. Itu ditambahkan ke adegan dan voila, fisika sudah ada di saku Anda.

 <a-scene physics="debug: false"> <a-box dynamic-body position="0 1 -2"></a-box> <a-box id="floor" static-body></a-box> </a-scene> 

Mark : debug: true memungkinkan kemampuan untuk melihat tubuh fisik yang terikat pada geometri. Akan lebih mudah bila Anda perlu "menjabarkan" suatu objek.

Bahkan, ini adalah pembungkus untuk cannon.js yang melakukan semua pekerjaan kotor membandingkan geometri dan tubuh fisik untuk Anda. Sekali lagi, tentang cara kerja sistem ini, Anda dapat menemukannya di deskripsi repositori. Dan saya ingin memikirkan satu hal yang penting untuk permainan saya.

Saya perlu memastikan bahwa dengan menekan tombol ke tempat sampah gaya tertentu telah ditetapkan (semakin Anda menahan tombol, semakin besar gaya). Ternyata, tugas ini tidak sesederhana seperti yang terlihat pada pandangan pertama. Nah, apa yang begitu rumit? - Anda berkata, kami melakukan applyImpluse dan voila. Tidak juga ... Ini mengatur rotasi objek di sepanjang vektor yang diterapkan ke pusat tubuh. Dengan menggunakan metode ini, kita hanya dapat meniru yule. Meskipun, jika Anda mengatur vektor dengan sudut yang benar ke pesawat, Anda mungkin mendapatkan sesuatu yang mirip dengan dorongan. Tapi ini bukan yang saya butuhkan.

Ternyata, saya membutuhkan kecepatan ketika mengatur parameter ini, objek mulai bergerak ke arah tertentu. Arah ini ditentukan oleh vektor. Dan di sini kesenangan dimulai. Bagaimana menemukan vektor ini? Saya menemukan dua opsi:

  1. Dapatkan angka empat controller (atau kamera untuk desktop), yang menggambarkan orientasinya dalam ruang. Buat vektor V1 = <1,1,1>, kalikan dengan gaya lempar dan terapkan orientasi untuk semua ini.

     const velocityVector = new THREE.Vector3(1,1,1); velocityVector.multiplyScalar(this.force); velocityVector.applyQuaternion(controllerQuaternion); this.grabbed.body.velocity.set(velocityVector.x, velocityVector.y, velocityVector.z); 
  2. Cari posisi pengontrol (kursor) dan posisi objek yang dilemparkan. Hitung vektor arah untuk dua titik. Menormalkan vektor. Dan gandakan dengan paksa.

     const directionX = (trashPosition.x - zeroPosition.x); const directionZ = (trashPosition.z - zeroPosition.z); const vectorsLength = Math.sqrt(Math.pow(directionX, 2) + Math.pow(directionZ, 2)); const x = (directionX / vectorsLength) * this.force; const y = this.force; const z = (directionZ / vectorsLength) * this.force; this.grabbed.body.velocity.set(x , y, z ); 

Saya memilih opsi kedua karena di dalamnya saya hanya dapat menghitung x dan z. Dan atur sendiri, karena saya perlu membuang sepanjang busur sehingga sampah yang dibuang akan jatuh ke keranjang, meskipun pengguna memegang controller.

Beberapa kata tentang model




Sejak awal, saya memutuskan untuk membuat game bergaya low-poly . Meskipun WebGL mampu menampilkan adegan yang relatif kompleks saat ini, kinerjanya masih kalah dengan perpustakaan canggih seperti DirectX, Vulkan, Mantle, dll. Itu juga semua tergantung pada kinerja perangkat pengguna. Karena saya ingin fokus pada helm seluler BP yang lebih terjangkau (Oculus Go, Gear VR), saya pikir low-poly adalah salah satu dari sedikit solusi untuk membuat aplikasi atau game VR. Meskipun, tentu saja, semuanya tergantung volume.

Oke, low-poly sangat low-poly, tapi bagaimana melakukan itu semua? Semuanya sangat sederhana, ada alat open source yang bagus - Blender . Percayalah, ia mampu melakukan banyak hal, tetapi untuk tugas-tugas sederhana ia tidak begitu cocok. Ada banyak materi pelatihan yang terkait dengan pemodelan di Blender dan tidak akan sulit menemukannya. Saya hanya ingin memusatkan perhatian Anda pada sejumlah poin terkait pengembangan web:

  1. Eksportir Three-js kedaluwarsa. Perlu menemukan dan memasok eksportir GLTF . GLTF adalah format khusus yang dirancang untuk web. Dan ya, ini JSON.
  2. GLTF tidak mendukung Cycles Renderer, jadi Anda harus menggunakan Blender Renderer. Dan ini berarti bahwa tidak akan ada simpul keren, transformasi warna, sorotan logam (dapat dilakukan secara berbeda).
  3. Anda hanya perlu mengekspor item yang dipilih. Anda tidak perlu kamera dan lampu tambahan? File> Ekspor> gltf 2.0. Di menu sebelah kiri, Ekspor GLTF 2.0> Ekspor hanya dipilih.
  4. Kami mulai mengekspor dari posisi <0, 0, 0> di Blender. Lebih baik untuk skala di tempat yang sama, sehingga nanti Anda tidak menggunakan komponen skala dalam bingkai-a.
  5. Jika Anda menggambar ruang terbuka seperti di Daur Ulang! VR, Anda perlu menambahkan objek hanya ke tempat pemain secara teoritis dapat melihat. Di belakang, di belakang rumah, di Daur Ulang! ada beberapa pohon dan hanya di tempat di mana pengguna dapat melihatnya. Tidak perlu membebani tempat kejadian.
  6. Jika Anda perlu mengubah bahan model, Anda harus menunggu sampai memuat, dapatkan model itu sendiri, tarik semua node dari itu (GLTF berisi informasi tidak hanya tentang jerat)

     e.detail.model.traverse((node) => { if (node.isMesh) { node.material.color = new THREE.Color(someColor); } }); 

Kesimpulannya


Terima kasih atas perhatian Anda! Saya mengingatkan Anda sekali lagi bahwa repositori proyek tersedia di tautan berikut . Siapa pun yang ingin membawa sesuatu yang baru ke permainan ini - selamat datang.

Source: https://habr.com/ru/post/id443062/


All Articles