Saya memutuskan untuk merilis versi baru dari gim browser lama saya, yang selama beberapa tahun telah berhasil sebagai aplikasi di jejaring sosial. Kali ini saya mulai mendesainnya juga sebagai aplikasi untuk Windows (7-8-10) dan menempatkannya di berbagai toko. Tentu saja, di masa depan Anda dapat membuat rakitan untuk MacOS dan Linux.
Kode permainan ditulis seluruhnya dalam javascript murni. Untuk menampilkan grafik 3D, pustaka three.js digunakan sebagai tautan antara skrip dan WebGL. Namun, ini adalah kasus di versi browser lama. Yang paling penting dalam proyek ini bagi saya adalah alasannya, bersamaan dengan permainan, untuk menambah perpustakaan saya sendiri, yang dirancang untuk melengkapi three.js dengan alat untuk pekerjaan yang mudah dengan objek adegan, animasi mereka dan banyak fitur lainnya. Saya kemudian meninggalkannya untuk waktu yang lama. Sudah waktunya untuk kembali padanya.
Pustaka saya berisi alat yang mudah digunakan untuk menambah dan menghapus objek dari adegan, mengubah properti masing-masing objek (jerat), animasi frame-independent dari objek 3D, shader langit dengan tekstur langit berbintang di malam hari, dan banyak lagi. Saya akan memberi tahu Anda tentang beberapa di antaranya. Mengenai langit, saya mengimplementasikan penciptaannya dengan satu fungsi yang mengambil sejumlah parameter input, menginisialisasi shader, memuat tekstur cloud (jika perlu) dan mulai memperbarui langit dengan iterasi yang diberikan.
Namun, semuanya sedikit lebih rumit di sana - untuk secara berkala, tetapi jarang disebut fungsi, konstruksi lain benar-benar berfungsi, menggunakan setInterval (), di mana peristiwa dapat dilemparkan pada interval yang berbeda, dan itu akan mengurangi semua ini menjadi penyebut yang sama dan menyelesaikannya di sebelah kanan. waktu yang dibutuhkan peristiwa dalam daftar. Di sana Anda juga dapat membuang interval pembaruan langit. Tetapi pergerakan objek game 3D untuk kelancaran yang lebih besar telah dilaksanakan melalui requestAnimationFrame () ...
Jadi, karena kita berbicara tentang langit, kita akan mulai dengan itu.
Langit
Menambahkan cakrawala ke adegan adalah sebagai berikut.
Pertama, Anda perlu menambahkan lampu standar three.js ke adegan dengan nilai kecerahan (awal) maksimum. Seluruh adegan dengan objeknya, cahaya dan atribut lainnya, agar tidak mengacaukan ruang global, akan disimpan di ruang nama apscene.
Setelah itu, Anda sudah dapat menjalankan animasi langit dengan shader, tekstur (blackjack dan ... yah, oke) melalui salah satu fungsi saya:
m3d.graph.skydom.initWorld(
Akibatnya, langit yang dinamis muncul di tempat kejadian dengan perubahan halus pada ketinggian matahari dan, karenanya, perubahan waktu.
Tidak perlu menggunakan semua jenis pencahayaan di atas panggung. Dan tidak perlu mengubah semua parameter tergantung pada waktu hari. Namun, bermain dengan kecerahannya, Anda dapat membuat gambar yang cukup realistis tentang perubahan siang dan malam. Anda dapat memberi nama parameter yang Anda inginkan, hal utama adalah mengamati kunci objek di dalamnya seperti yang ditentukan dalam three.js.
Bagaimana tampilannya, Anda dapat melihat video dari adegan demo:
Ini adalah permainan yang berbeda. Hanya saja cakrawala tidak berantakan dengan berbagai objek, dan karena itu karya skrip ini paling jelas terlihat. Namun dalam game yang sedang didiskusikan cerita tersebut, pendekatan yang persis sama digunakan. Kecepatan tinggi dari perjalanan waktu di sini ditetapkan hanya untuk tujuan demonstrasi, dan sehingga waktu mengalir, tentu saja, lebih lambat, dengan langkah yang sama dari iterasi memperbarui cakrawala. Dalam demo ini, omong-omong, shader air terlibat, juga dengan parameter variabel, tergantung pada ketinggian matahari ... Tapi saya belum menyelesaikannya.
Performa
Semua ini sangat sedikit menuntut zat besi. Bekerja di browser Chrome, ia memuat Xeon E5440 di bawah LGA775 (dan dengan 4 gigs RAM) sebesar 20%, dan inti dari kartu grafis GT730 sebesar 45%. Tapi ini murni karena animasi air. Jika kita berbicara tentang permainan di mana tidak ada air, tetapi ada kota, yang ini:
kemudian pada saat mobil bergerak di sekitar kota - persen 45%, kartu video 50%. Pada prinsipnya, dengan beberapa penarikan fps (hingga sekitar 30 frame per detik), ia bekerja dengan cukup baik bahkan pada Pentium4 3GHz (RAM 1Gb) dan pada tablet pada Intel Atom 1.3GHz (RAM 2Gb).
Semua perangkat keras ini sangat lemah dan permainan serupa lainnya di WebGL dan HTML5, bahkan beberapa 2D, melambat pada saya tanpa dewa, sampai-sampai tidak mungkin untuk memainkannya. Seperti kata mereka, tulis sendiri gimnya, sesuai kebutuhan, dan mainkan.
Adegan
Adegan 3D di three.js adalah objek adegan dan array anak-anaknya, pada kenyataannya, semua model 3D dimuat ke dalam adegan. Agar tidak mendaftarkan panggilan bootloader untuk setiap model, saya memutuskan bahwa seluruh adegan game akan ditetapkan dalam bentuk konfigurasi tertentu, dengan satu locd array asosiatif besar: {} (seperti data lokasi), yang akan berisi semua pengaturan - lampu, jalur tekstur yang dimuat sebelumnya dan gambar untuk antarmuka, jalur ke semua model yang harus dimuat ke atas panggung, dan banyak lagi. Secara umum, ini adalah konfigurasi penuh adegan. Sudah diatur sekali dalam file js game dan diumpankan ke pemuat adegan saya.
Dan objek locd: {} ini, khususnya, berisi jalur ke masing-masing model 3D yang perlu dimuat. Jalur nol adalah jalur umum, dan kemudian jalur relatif untuk setiap objek, seperti:
['path/myObj', scale, y, x,z, r*Math.PI, 1, '', '', '', 1, ['','','',''], 'scene']
Dapat dipahami bahwa semua model diekspor dari editor 3D ke format json, yaitu mereka memiliki jalur seperti jalur / myObj.json. Ini diikuti oleh skala (karena editor dapat disimpan dengan skala yang tidak cocok untuk permainan), posisi objek dengan tinggi (y), sepanjang sumbu (x) dan (z), kemudian sudut rotasi ยฎ model di (y), sejumlah parameter opsional nama adegan tempat memuat model - di adegan utama (adegan) atau di latar belakang (sceneb).
Ya, itu perlu untuk mengimplementasikan ini bukan dalam bentuk yang sederhana, tetapi dalam bentuk array asosiatif. Jadi urutan parameter tidak dapat dipahami bahkan tanpa dokumentasi, atau setidaknya tanpa jenis fungsi yang mengambil parameter ini, Anda tidak akan mengerti. Saya pikir di masa depan saya akan membuat ulang garis-garis ini dalam array asosiatif. Sementara itu, tampilannya seperti ini:
landobj: [ ['gamePath/'], [ ['landscape/ground', 9.455, 0, 0,0, 0*Math.PI, 1, '', '', '', 1, ['','','',''], 'scene'], ['landscape/plants', 9.455, 0, 0,0, 0*Math.PI,1, '', '', '', 1, ['','','',''], 'scene'], ['landscape/buildings/house01', 2, 0, -420,420, -0.75*Math.PI, 1, '', '', '', 1, ['','','',''], 'scene'], ... ] ],
Model-model ini dimuat ke atas panggung dan ditempatkan di koordinat yang diberikan di sini dalam ruang. Pada prinsipnya, semua model dapat dimuat sebagai objek tunggal, yaitu, diekspor dari editor sebagai adegan permainan keseluruhan dan dimuat ke dalam koordinat (0; 0; 0). Maka hanya akan ada satu baris: landscape / ground - I have ground.json - ini adalah bagian utama dari dunia game. Tetapi dalam kasus ini akan sulit untuk memanipulasi objek individual dari adegan tersebut, karena Anda harus terlebih dahulu melihat di konsol browser dan ingat anak-anak mana dari tanah besar ini. Dan kemudian hubungi mereka dengan nomor. Oleh karena itu, model permainan roaming paling baik dimuat dengan objek yang terpisah. Kemudian mereka dapat diakses dengan nama dari array asosiatif, yang akan secara otomatis dibuat khusus untuk tujuan ini.
Konfigurasi penuh gim ini mungkin terlihat, misalnya, seperti ini:
locd:{
Ya, lebih baik untuk mengulang semua sub-array ini ke dalam array asosiatif, jika tidak urutan parameter di dalamnya tidak jelas ...
Model 3D

Hal lain yang menarik. Memuat model. Pustaka saya menerima model 3D dengan tekstur dan secara otomatis menetapkan beberapa parameter untuk masing-masing elemen (jerat), tergantung pada namanya. Faktanya adalah bahwa jika, misalnya, model diatur untuk memberikan bayangan, maka itu akan dilemparkan oleh setiap jaring yang termasuk dalam komposisinya. Tidak selalu diperlukan bahwa seluruh model membuat bayangan sepenuhnya atau memperoleh properti lain yang sangat memengaruhi kinerja. Oleh karena itu, jika Anda menyalakan bendera tertentu yang menandakan bahwa perlu untuk mempertimbangkan setiap mesh secara terpisah, maka ketika memuat dimungkinkan untuk menentukan mesh mana yang memiliki properti ini atau itu dan mana yang tidak. Sebagai contoh, sama sekali tidak perlu bayangan dilemparkan oleh atap datar datar rumah atau oleh banyak detail kecil yang tidak relevan dari model dengan latar belakang yang besar. Semua sama, pemain tidak akan dapat melihat bayangan ini, dan kekuatan prosesor video akan digunakan untuk memprosesnya.
Untuk melakukan ini, di editor grafis (Blender, Max, dll.), Anda dapat segera menentukan nama jerat (di bidang nama objek) sesuai dengan aturan tertentu. Harus ada garis bawah (_). Karakter kontrol bersyarat harus berada di sisi kiri, misalnya: d - doubleside (mesh dua arah, sebaliknya - satu arah), c (bayangan bayangan) - melemparkan bayangan, r (menerima bayangan) - mengambil bayangan. Misalnya, nama mesh pipa di rumah mungkin cr_tube. Banyak surat lain juga digunakan. Sebagai contoh, "l" adalah collider, yaitu dinding rumah, yang memiliki nama crl_wall01, tidak akan membiarkan pemain melewati dirinya sendiri, dan juga akan melemparkan dan mengambil bayangan. Tidak perlu membuat colliders, seperti atap atau pegangan pintu, dan dengan demikian menurunkan kinerja. Seperti yang sudah Anda pahami, saat memuat model, perpustakaan saya mem-parsing nama-nama jerat dan memberi mereka properti yang sesuai di tempat kejadian. Tetapi untuk ini, perlu menyebutkan semua jerat dengan benar sebelum mengekspor model dari editor 3D. Ini secara signifikan akan menghemat kinerja.
Semua flag kontrol untuk jerat di dalam objek:
col_ ... adalah collider. Jala seperti itu akan ditampilkan hanya sebagai collider transparan dan tidak terlihat. Di editor, dia bisa terlihat seperti apa saja, hanya bentuknya yang penting. Sebagai contoh, itu bisa menjadi paralelepiped sekitar seluruh model jika perlu bagi pemain untuk tidak dapat melewati model ini (bangunan, batu besar, dll.).
l_ ... adalah objek yang dapat dikoleksi. Memberi mesh apapun sifat collider.
i_ ... - persimpangan. Mesh akan ditambahkan ke daftar persimpangan, yang dapat digunakan, misalnya, untuk mengkliknya, yaitu, untuk memberikan interaktivitas ke permainan.
j_ ... juga persimpangan. Sama seperti di atas, hanya versi yang lebih baru - dengan algoritma yang ditingkatkan untuk menemukan persimpangan dalam permainan dan konsumsi sumber daya yang lebih sedikit.
e_ ... - persimpangan untuk pintu rumah (masuk / keluar). Tidak termasuk persimpangan di atas objek jala lainnya. Ini digunakan jika diperlukan di rumah pada suatu saat untuk membuat hanya pintu interaktif, tidak termasuk semua elemen interaktif lainnya. Dengan imajinasi, Anda dapat menemukan ini dan banyak kegunaan lain.
c_ ... - melemparkan bayangan. Jala melemparkan bayangan.
r_ ... - menerima bayangan. Jala menerima bayangan dari semua jala lain yang melemparkannya.
d_ ... - bilateral (dua sisi). Terlihat di kedua sisi, teksturnya ditumpangkan di kedua sisi.
t_ ... - transparan (transparan), jika seluruh objek diatur ke alphatest dalam three.js.
u_ ... - transparan (transparan), dengan kerapatan tetap (0,4), jika seluruh objek tidak menentukan alphatest dalam three.js.
g_ ... - gelas. Transparansi tetap diatur (0,2).
h_ ... - tidak terlihat (tersembunyi). Untuk bagian-bagian dari objek (jerat) yang harus disembunyikan saat menambahkan objek ke adegan. Dimasukkan dalam daftar tersembunyi.
v_ ... terlihat. Semua objek kecuali yang ditandai dengan "h" sudah terlihat, tetapi dengan bendera "v" mereka dimasukkan dalam daftar terpisah yang terlihat untuk penyembunyian lebih lanjut atau manipulasi lainnya.
Akibatnya, nama mesh mungkin menjadi sesuatu seperti ini: crltj_box1 (gips, menerima bayangan, collider, transparan, interaktif). Dan jala lain sebagai bagian dari model yang sama: cr_box2 (hanya menampilkan dan mengambil bayangan), Secara alami, karakter kontrol dapat diatur dalam urutan apa pun. Dengan demikian, dari editor Anda dapat mengontrol tampilan bagian objek di game di masa depan, atau lebih tepatnya, beberapa propertinya, menghemat, pada saat yang sama, daya komputasi.
Inti dari permainan
Artinya, sebenarnya, dari permainan tentang mana cerita itu, adalah untuk bergerak di sekeliling lapangan persegi dan membeli perusahaan. Lapangan dibuat dalam bentuk jalan-jalan 3D. Model ekonomi gim ini sangat berbeda dari modelnya. Dalam permainan saya, ketika seseorang memulai bisnis, keuntungan yang Anda harapkan turun. Dan sebaliknya, ketika Anda menemukan sesuatu, itu meningkat. Semua perhitungan untung dan rugi dilakukan di Inspektorat Pajak di bidang Awal. Anda juga dapat mengambil pinjaman dari bank, perdagangan sekuritas dan melakukan sejumlah hal lainnya. Saya telah meningkatkan perilaku AI dibandingkan dengan versi lama. Redid hampir semua model 3D dan tekstur permainan dan kinerja yang dioptimalkan. Membuat lebih banyak pengaturan dan banyak lagi.
Animasi
Untuk menggerakkan pergerakan objek-objek game, mesin paling sederhana digunakan, yang dengan frame rate yang diberikan (terbatas pada ke-60) mengubah parameter numerik apa pun untuk interval waktu tertentu, membagikan nilai-nilai antara ke pawang. Dan di pawang, misalnya, model ditampilkan.
Sebagai contoh. Kita perlu memindahkan objek objek di ruang angkasa dari posisi (10; 10; 50) ke titik (100; 300; 60). Kami menetapkan 3 parameter dengan menunjukkan nilai awal dan akhir. Koordinat x akan bervariasi dari 10 hingga 100, y - dari 10 hingga 300 dan z - dari 50 hingga 60. Dan semua ini akan terjadi, katakanlah, dalam 4 detik.
m3d.lib.anim.add( 'moveobj', 1, 4000, 'and', {userpar1:111, obj:my3DObject}, [ {lim1:10, lim2:100, sstart:10, sfin:100, t:0}, {lim1:10, lim2:300, sstart:10, sfin:300, t:0}, {lim1:50, lim2:60, sstart:50, sfin:60, t:0} ], function(){ myPeriodicFun(this); }, function(){ myFinishFun(this); } ); m3d.lib.anim.play();
Baris pertama dari 5 parameter: moveobj - nama animasi (apa saja), nomor 1-stream (Anda dapat menghidupkan objek secara paralel dalam jumlah stream yang tidak terbatas), 4000 - waktu animasi 4 detik, dan - hingga parameter yang tidak digunakan, yang di masa depan akan bertanggung jawab atas logika transisi antara animasi dalam aliran yang sama, userpar adalah sembarang array asosiatif yang akan diteruskan ke pawang sebagai parameter, misalnya, dengan jari-jari yang dihitung, sinus, cosinus, dan umumnya nilai apa pun yang dihitung untuk animasi ini, sehingga tidak akan dihitung dalam tentang waktu setiap iterasi. Atau dengan merujuk ke objek 3D, yang, pada kenyataannya, akan hidup.
Berikutnya adalah array dengan parameter yang bisa berubah. Kami menemukan bahwa parameter pertama adalah perubahan dalam koordinat x, yang kedua adalah y, yang ketiga adalah z. Kami menulis untuk masing-masing dalam lim1 dan lim2, dari apa dan untuk ukuran apa itu akan berubah. Di sstart dan sfin kami menentukan nilai yang sama. Di sini Anda dapat menentukan awal, misalnya, dari beberapa nilai lain, maka parameter akan "gulir" dalam lingkaran dari itu ke sana, melewati lim2 dan memulai "revolusi" baru dengan lim1. Sebagai contoh, ini diperlukan jika animasi kita dilingkarkan di antara beberapa nilai (lim1 dan lim2), tetapi kita harus memulainya bukan dari awal (yaitu, bukan dari lim1), tetapi dari beberapa nilai menengah.
t: 0 hanya menetapkan bahwa animasi untuk parameter ini dilakukan 1 kali, sesuai dengan total waktu (4000), seolah-olah membentang ke sana. Jika kita menetapkan angka lain, kurang dari waktu utama, maka parameter ini akan diulang dan akan diulang sampai waktu animasi utama (4000). Ini nyaman, misalnya, untuk mengatur rotasi objek ketika sudut harus berulang kali melewati garis 360 derajat dan mengatur ulang ke 0.
Berikutnya datang 2 panggilan balik - yang akan dieksekusi dengan setiap iterasi dan yang akan dieksekusi sekali setelah menyelesaikan seluruh animasi (titik keluar).
MyPeriodicFun callback pertama (ini), misalnya, bisa seperti ini:
myPeriodicFun:function(self) { var state=self.par[0].state, state_old=self.par[0].state_old; var state2=self.par[1].state, state_old2=self.par[1].state_old; var state3=self.par[2].state, state_old3=self.par[2].state_old; if ((state!=state_old)||(state2!=state_old2)||(state3!=state_old3)) { var obj=self.userpar.obj; obj.position.x=state; obj.position.y=state2; obj.position.z=state3; ap.cameraFollowObj(obj); }; },
Yaitu, pada setiap iterasi gerakan, parameter (diri) dilemparkan ke fungsi ini yang berisi nilai-nilai perantara yang dihitung untuk semua parameter animasi yang diberikan: self.par [0] .state, self.par [1] .state, self.par [2] .state. Ini adalah x, y, dan z kami saat ini. Misalnya, jika animasi berlangsung 4 detik, setelah 2 detik x akan sama dengan (100-10) / 2 = 45. Dan untuk semua koordinat. Dengan demikian, dalam myPeriodicFun kita cukup menampilkan objek kita di koordinat ini.
Jika browser mulai berjalan lambat atau hanya berjalan lambat pada perangkat keras ini, itu tidak menakutkan: total waktu animasi tidak akan berubah, hanya frame rate akan turun dan gambar akan berubah menjadi peragaan slide.Mengapa memeriksa f ((status! = Status_old) ..., yaitu, apakah nilai yang baru dihitung sama dengan nilai lama (status_old mengingat yang dihitung dalam iterasi sebelumnya), yah, misalnya, sehingga jika beberapa parameter berubah kurang dari satu, maka jangan menggambar ulang seluruh objek dan tidak menghabiskan daya sistem di atasnya, dan mesin animasi menghasilkan bilangan bulat dalam keadaan dan state_old, yang, katakanlah, dapat diartikan sebagai langkah yang sama dengan piksel. Dan jika objek tidak bergerak relatif terhadap posisi sebelumnya bahkan dengan 1 pixel, maka tidak perlu menggambar ulang, karena e Posisi di layar tidak berubah.Secara umum, animasi dipahami sebagai perubahan sederhana dalam sejumlah parameter dalam waktu tertentu dengan pengiriman nilai-nilai perantara ke fungsi panggilan balik. Misalnya, Anda dapat menambahkan parameter ke-4 lainnya, yang akan bertanggung jawab atas sudut rotasi objek. Dan Anda biasanya dapat menjejalkan parameter banyak objek menjadi satu animasi jika bergerak entah bagaimana seragam. Anda dapat menempatkan animasi di aliran yang berbeda, kemudian animasi akan diproses secara paralel. Anda dapat menambahkan (m3d.lib.anim.add ()) ke satu utas seluruh urutan animasi, dan mereka akan dieksekusi satu demi satu. Selain itu, setiap utas akan memiliki urutan independennya sendiri. Yang utama adalah bahwa sistem memiliki kekuatan yang cukup dan semuanya tidak berubah menjadi tampilan slide.NB. Aliran di sini direalisasikan hanya dengan enumerasi berurutan pada setiap iterasi dari semua animasi paralel dan perhitungan untuk masing-masing dari mereka nilai-nilai menengah dari semua parameter mereka. Artinya, tidak ada multithreading nyata dalam javascript."Mesin" yang sama juga dapat digunakan untuk menghidupkan elemen elemen antarmuka dengan mengaturnya untuk mengubah 2 koordinat pada bidang layar dan menampilkan elemen-elemen ini dalam fungsi panggilan balik sesuai dengan nilai perantara yang diperoleh. Yang sebenarnya dilakukan dalam gim saya.Bayangan dinamis
Menampilkan bayang-bayang di seluruh adegan ternyata sangat sia-sia sehingga ketika diaktifkan, fps turun beberapa kali. Ini tidak baik. Kami akan menampilkan bayangan dari objek di kotak kecil tertentu di sekitar pemain. Saya akan segera mengatakan bahwa teknik seperti itu secara signifikan meningkatkan kecepatan frameTidak ada yang rumit di sini. Bayangan three.js dilemparkan ke dalam kamera bayangan tertentu yang ditentukan oleh kotak (shadowCameraLeft, shadowCameraRight, shadowCameraTop, shadowCameraBottom). Itu dapat diregangkan ke seluruh adegan, atau dapat dibuat sehingga mengikuti kamera utama dan bayangan hanya dilemparkan ke sekitarnya. Satu-satunya hal yang saya tambahkan ke sistem ini adalah langkah melalui mana bayangan akan diperbarui. Sama sekali tidak perlu melakukan pembaruan ini setiap kali pemain berkedut, karena ini memuat sistem dengan perhitungan. Biarkan dia mengatasi jarak minimum tertentu di sepanjang salah satu dari ketiga sumbu sehingga bayangan diperbarui.Di perpustakaan saya, ketika menginisialisasi dunia 3D, objek contr dibuat, yang setiap saat berisi koordinat kamera. Di sana Anda juga dapat mengatur parameter pengguna contr.cameraForShadowStep, yang berisi langkah posisi kamera di mana posisi kamera bayangan berubah.Jika, misalnya, paralelepiped dari kamera bayangan memiliki dimensi 700x700x700, maka contr.cameraForShadowStep dapat diatur ke, misalnya, 20. Dan ketika pemain bergerak 20 pada salah satu sumbu, posisi awal akan diingat lagi dan bayangan di sekitar pemain akan diperbarui. Skala dunia 3D dapat berupa apa saja, tergantung pada skala di mana semua model dibuat dalam editor 3D. Dan sepertinya bukan 700x700x700 dan 20, Anda harus menggunakan 7000x7000x7000 dan 200. Tetapi ini tidak mengubah esensi dengan cara apa pun.Omong-omong, ketika matahari bergerak di langit, bayangan diperbarui secara independen dari sistem ini, karena arah bayangan harus berubah di sana. Artinya, mereka akan diperbarui bahkan jika pemain berdiri tanpa gerakan. Di sana, fungsi memperbarui bayangan sesuai dengan periode memperbarui langit disebut dengan bodoh.Sistem Titik Cahaya
Kehadiran lebih dari selusin sumber cahaya di panggung sama kuatnya dengan bayangan dinamis. Dan bahkan membuatnya tidak mungkin untuk memainkan "Rami" yang lama. Selain itu, tidak masalah apakah sumber-sumber ini ada di bidang tampilan pemain (rentang render dunia dapat diatur) atau pada jarak yang cukup jauh. Jika mereka secara bodoh hadir di atas panggung, maka semuanya berjalan lambat. Oleh karena itu, saya telah menyediakan di menu pengaturan permainan, yang dapat dipanggil sebelum memuat dunia 3D, opsi untuk sejumlah sumber tersebut (2, 4 atau 8) yang disebut "Light of Lanterns".
Jadi, pada malam hari, menyalakan semua lampu yang ditempatkan di atas panggung pada saat yang sama tidak akan berhasil. Di atas, dalam uraian skema inisialisasi dunia, saya menyajikan array tentang userPointLights dan lightsPDynamicAr. Di userPointLights, koordinat semua lampu lampu di atas panggung diatur dalam sebuah array. Dan lightsPDynamicAr berisi pengaturan cahaya untuk semua 8 instance. Bergantung pada pengaturan jumlah lampu, perpustakaan akan mengambil yang pertama dan menambahkan adegan di bidang tampilan pemain.Bahkan, saat pemain bergerak, pencarian dilakukan untuk 2-8 lentera yang paling dekat dengan pemain dengan susunan koordinat dari lentera userPointLights. Dan titik sumber cahaya bergerak di bawahnya. Dengan kata lain, 2-8 lampu penerangan mengikuti pemain, mengelilinginya. Selain itu, ini juga dilakukan tidak dengan setiap frame fps, tetapi dengan langkah yang diberikan. Sama sekali tidak perlu memulai fungsi pencarian 60 kali per detik, terutama jika pemain tidak bergerak - maka biarkan lampu yang ada di sekelilingnya menyala.Begini tampilannya (Xeon E5440, GeForce GT730):Membangun distribusi
Karena saya tidak menggunakan lingkungan pengembangan yang canggih (kecuali untuk notepad canggih), saya menulis file bat di mana Google Closure Compiler dipanggil untuk mengaburkan kode setiap file * .js. Dan kemudian nwjc.exe dari bundel nw.js dipanggil ke sana untuk mengkompilasi js ke dalam binari (* .bin). Saya akan memberikan contoh untuk salah satu file:java -jar D: \ webservers \ Penutupan \ compiler.jar --js D: \ webservers \ proj \ m3d \ www \ game \ bus \ bus.js --js_output_file D: \ webservers \ proj \ nwProjects \ bus \ game \ bus \ bus.js
cd D: \ "Program Files" \ Web2Exe \ down \ nwjs-sdk-v0.35.5-menang-ia32
D: \ "Program Files" \ Web2Exe \ down \ nwjs-sdk-v0.35.5-win -ia32 \ nwjc.exe D: \ webservers \ proj \ nwProjects \ bus \ game \ bus \ bus.js D: \ webservers \ proj \ nwProjects \ bus \ game \ bus \ bus \ bus.bin
del D: \ webservers \ proj \ nwProjects \ bus \ game \ bus \ bus.js
Selanjutnya, saya menggunakan utilitas Web2Executable sederhana untuk membuat file exe dengan perakitan di bawah Windows. Saya memilih nw.js versi 0.35.5, walaupun versi yang lebih baru juga tersedia. Saya tidak melihat adanya efek dari mereka, kecuali untuk meningkatkan ukuran perakitan.Utilitas ini mampu mengunduh versi nw.js yang dipilih ke folder yang ditentukan itu sendiri. Outputnya adalah perakitan. File eksekusi 35 megabyte sebenarnya berisi game itu sendiri. Yang lainnya adalah node-webkit. Folder locales berisi file, tentu saja, dengan beberapa sumber daya dalam bahasa yang berbeda. Saya menghapusnya dan hanya menyisakan yang terkait dengan Bahasa Inggris. Ngomong-ngomong, ini tidak mencegah peluncuran versi game berbahasa Rusia (dalam game itu bahasa berganti antara Rusia dan Inggris). Mengapa semua file ini, saya tidak tahu. Tetapi tanpa bahasa Inggris, tidak ada yang dimulai.Seluruh perakitan akhirnya mengambil 167 MB.Kemudian saya mengemas semuanya menjadi satu file distribusi yang dapat dieksekusi menggunakan salah satu utilitas gratis yang dirancang untuk tujuan ini, dan hasilnya adalah 70,2 MB Businessman3DSetup.exe.Posting
Saya mengirim perakitan ke berbagai toko aplikasi. Sebagian besar dari mereka masih dalam proses memoderasi permainan saya. Saat ini, hanya gatal yang telah menerbitkannya sejauh ini. Saya memperingatkan Anda segera, permainan dibayar, harganya $ 3. Belum ada pembelian, tapi saya belum terlibat dalam promosinya. GOG menolak untuk menerbitkan, mengutip fakta bahwa permainannya cukup sederhana dan niche. Saya, pada prinsipnya, setuju. Epic Store, saya pikir, akan melakukan hal yang sama.Versi permainan yang diterbitkan adalah pengguna tunggal, dengan jumlah bot dari 1 hingga 5. Bahasa - Rusia dan Inggris. Saya bermaksud untuk menyelesaikan versi jaringan. Tetapi masih dalam pemikiran - untuk merilisnya dalam bentuk aplikasi yang sama atau dalam bentuk versi browser web, tersedia segera di Windows, Linux, iOs dan MacOs, dan umumnya di mana pun browser mendukung WebGL. Memang, pada kenyataannya, webkit adalah browser dan permainan berfungsi dengan baik di dalamnya, di Firefox, di Edge dan bahkan di IE11 di bawah Windows, meskipun pada yang terakhir ini sangat lambat.Kesimpulan
Saya kira saya belum siap untuk mengeluarkan mesin saya untuk penggunaan umum, karena belum selesai. Saya pertama-tama akan menulis di atasnya game lain, hanya itu, dari video demo, tentang kapal, karena pada game itu Anda dapat "menjalankan" bekerja dengan shader air. Selain itu, saya berencana untuk mengimplementasikan mesin fisika sederhana di sana. Ya, dan Anda masih harus menyelesaikan semua fitur lainnya, perbaiki semua kekurangannya. Dan lebih baik melakukan ini pada dua game daripada pada satu, karena beberapa nuansa mungkin terjadi. Sementara itu, mesin saya, menurut saya, masih terlalu tajam untuk satu game.Selain itu, saya sama sekali tidak yakin bahwa ada yang membutuhkan semua ini. Jika Anda terlihat serius, tidak ada yang menulis game dalam javascript murni. Tapi saya suka karena gimnya cukup mudah dan cepat untuk peramban. Mereka memuat dengan cepat, tidak memerlukan banyak RAM dan bekerja cukup cepat dibandingkan dengan pesaing di HTML5, bahkan jika dibandingkan dengan 2D. Saya pikir saya akan merilis lebih dari satu permainan browser (dan tidak hanya) pada semua perkembangan ini.