Menciptakan gerakan di lingkungan apa pun dalam pengalaman membantu membuatnya merasa lebih imersif dan realistis kepada dunia kita, baik itu dari gerakan pohon ambient, reaksi pintu dari interaksi pengguna, atau bahkan
Menciptakan Badai
Badai itu melewati banyak iterasi sebelum kita menyelesaikan apa yang hidup di The Mystery of Duvall Drive. Awalnya, kami memikirkan badai sebagai pilar obsidian raksasa, dan dalam iterasi selanjutnya kami menganggapnya sebagai portal raksasa ke ruang korup. Setelah bereksperimen dengan banyak badai dengan tampilan dan perasaan yang unik, kami menyelesaikan badai
- Badai seharusnya memberi pemain perasaan tentang dampak acara ini pada dunia , termasuk pohon yang melayang dan debu terbang.
- Vortex berputar dari awan itu sendiri seharusnya memberi pemain pemandangan pada portal pusat tanpa mengungkapkan segalanya . Ini akan mengencourage pemain untuk menyelidiki lebih dekat untuk melihat apa yang terjadi.
- Poin cahaya yang lebih ketat akan memungkinkan kita untuk fokus pada komposisi rumah , yang merupakan karakter utama dan di mana sebagian besar permainan berada.
Untuk membuat badai merasa dinamis, agresif, dan selalu berubah di dalam lingkungannya, kami menggunakan sistem dan fitur berikut:
- TweenService > - Untuk gerakan cloud.
- Perubahan penerangan - Untuk membuat awan menjadi petir.
- Sinar-sinar volumetrik > - Untuk "lighting volumetrik" dan petir.
- Pengirim Partikel > - Untuk debu yang terbang ke portal dan terbang di sekitar karena angin bermandi.
- Animasi > - Untuk pohon yang terpatahkan di angin.
Menambahkan Awan dengan Textur
Sementara awan dinamis sangat bagus untuk normal, awan tinggi yang realistis, kami memerlukan sesuatu yang mer
Karena setiap mesh awan yang dibutuhkan untuk menjadi besar untuk sepenuhnya mengelilingi rumah dan menyampaikan betapa besarnya badai, kami tahu bahwa kami perlu menempelkan tekstur yang kami inginkan di cloud meshes individual sehingga itu akan berulang berkali-kali di seluruh permukaan meshes. Kami menguji bahan yang kami buat untuk cloud di bagian ini yang sederhana, lalu menerapkannya ke vortex!
Tidak seperti emitter partikel atau sinar, meshes memungkinkan kita untuk dapat mengembalikan cahaya dari setiap meshes, yang penting ketika kita ingin menerapkan petir cloud-to-cloud. Kami juga memodelkan dalam twisting sehingga sinar mengembalikan dari itu tampak seperti memiliki kedalaman! Ini penting terutama dalam situasi di mana tingkat kinerja pengalaman menurunkan tingkat kualitas tamp
Menggulir Jaringan Awan
Setelah kami puas dengan tampilan visual global awan, kami perlu menggerakkannya! Kami memiliki bentuk umum dari setiap lapisan awan di tempatnya, tetapi butuh beberapa trial dan error untuk memastikan bahwa efek berputar tersebut terlihat bagus dalam praktek. Kami awalnya mencoba menggunakan batasan
Kami menginginkan metode yang mudah digunakan untuk memutar instans yang terlalu jauh untuk berinteraksi, seperti awan, atau terlalu kecil at
Seperti dalam banyak kasus di demo, kami menggunakan label LocalSpaceRotation sehingga kami dapat mengelola instans yang terpengaruh di Studio menggunakan plugin tag instans. Kami menggunakan hanya satu LocalScript yang menangani semua instans yang di tag menggunakan plugin tagging. Jadi kami tidak memiliki banyak skrip untuk d
local function Init()
for _, obj in CollectionService:GetTagged("LocalSpaceRotation") do
if obj:IsDescendantOf(workspace) then
SetupObj(obj)
end
end
end
CollectionService:GetInstanceAddedSignal("LocalSpaceRotation"):Connect(function(obj)
objInfoQueue[obj] = true
end)
CollectionService:GetInstanceRemovedSignal("LocalSpaceRotation"):Connect(function(obj)
if objInfo[obj] then
objInfo[obj] = nil
if objInfoQueue[obj] then
objInfoQueue[obj] = nil
end
end
end)
Init()
Kami mengubah instans di dalam fungsi Update yang terhubung dengan detak jant
local parentTransformif parentObj:IsA("Model") thenif not parentObj.PrimaryPart then-- bagian utama mungkin tidak dapat disiarkan belumcontinue -- tunggu bagian utama untuk bereplikasiendparentTransform = parentObj.PrimaryPart.CFrameelseparentTransform = parentObj.CFrameendcurObjInfo.curAngle += dT * curObjInfo.timeToAnglelocal rotatedLocalCFrame = curObjInfo.origLocalCFrame * CFrame.Angles( curObjInfo.axisMask.X * curObjInfo.curAngle, curObjInfo.axisMask.Y * curObjInfo.curAngle, curObjInfo.axisMask.Z * curObjInfo.curAngle )if obj:IsA("Model") thenobj.PrimaryPart.CFrame = parentTransform * rotatedLocalCFrameelseobj.CFrame = parentTransform * rotatedLocalCFrameend
Kami memeriksa untuk set valid Model.PrimaryPart untuk ditetapkan untuk menangani streaming. Jika Pembaruan dipanggil pada objek kami sementara Model.PrimaryPart (yang dapat menunjukkan ke pengikat pada pengikat anak) belum ditayangkan
Mendesain Pukulan Petir
Karena Studio tidak menawarkan generator petir keluar dari kotak, dan sistem partikel memiliki beberapa batasan yang tidak akan bekerja untuk petir petir pahlawan, kami harus menjadi kreatif dengan solusi untuk petir pahlawan. Kami memutuskan dua sistem utama untuk membuat petir: sinar beam untuk petir pahlawan yang datang dari mata bada
Mengkompresi Raya
Kami biasanya menggunakan alat sequencer atau timeline untuk mengendalikan waktu tindikan lampu seperti ini, tetapi karena Studio belum menawarkan kemampuan ini, kami memutuskan untuk menulis skrip yang akan mengontrol waktu tindikan lampu. Skrip ini cukup sederhana, tetapi itu mencapai tujuan penting berikut:
- Elemen dari sambaran petir, seperti teksur, kecerahan, dan kesalahan, diacak dengan setiap sambaran.
- Perubahan FX audio dan pos-FX sinkron dengan strike FX.
- Pemain yang berada di dalam atau di daerah yang rusak tidak akan dapat melihat atau mendengar mereka.
Kami memiliki server-side Script yang menghitung berbagai parameter dan waktu, mengirimkan mereka ke semua klien, dan menunggu jumlah waktu acak:
local function LightningUpdate()
while true do
task.wait(rand:NextNumber(3.0, 10.0))
local info = CreateFXData()
lightningEvent:FireAllClients(info)
end
end
Di dalam CreateFXData, kami mengisi struktur informasi, sehingga semua klien mendapatkan parameter yang sama.
Pada sisi klien ( LightningVFXClient ), kami memeriksa apakah klien ini harus mengeksekusi FX:
local function LightningFunc(info)
…
-- Tidak ada FX saat berada di dalam
if inVolumesCheckerFunc:Invoke() then
return
end
-- Tidak ada FX saat Anda tidak berada di dunia "normal"
if not gameStateInfoFunc:Invoke("IsInNormal") then
return
end
…
Selain itu, kami mengeksekusi urutan untuk menetapkan tekstur, posisi, dan kecerahan, mengeksekusi tweens, dan menggunakan task.wait(number) . Parameter acak adalah dari struktur informasi yang kami terima dari server, dan beberapa angka diperbaiki.
beam.Texture = textures[info.textIdx]beamPart.Position = Vector3.new(info.center.X + og_center.X, og_center.Y, info.center.Y + og_center.Z)-- Hapusbeam.Brightness = 10ppCC.Brightness = maxPPBrightnessppBloom.Intensity = 1.1bottom.Position = top.PositiontweenBrightness:Play()tweenPPBrightness:Play()tweenPPBrightness:Play()tweenBottomPos:Play()tweenBrightness.Completed:Wait()-- audioif audioFolder and audioPart thenif audioFolder.Value and audioPart.Value thenaudioUtils.PlayOneShot(audioObj, audioFolder.Value, audioPart.Value)endendtask.wait(info.waitTillFlashes)-- and so on
Untuk memeriksa apakah seorang pemain berada di dalam ruangan kita menggunakan fungsi inVolumesCheckerFunc , yang pergi melalui volume yang ditempatkan sebelumnya dan memeriksa apakah posisi pemain berada di dalam salah satu dari mereka (PointInABox). Kami bisa menggunakan det
Untuk memeriksa apakah pemain berada di area yang rusak, kami mengaktifkan fungsi pembantu gameStateInfoFunc , yang memeriksa status permainan saat ini. Untuk memutar suara acak dari direktori, kami juga menggunakan fungsi pembantu PlayOneShot . Untuk petir sendiri, mereka sangat mudah untuk dib
Menggunakan Pengirim Partikel
Petir pahlawan didukung oleh sistem partikel yang menyarankan petir jauh dengan menciptakan kesan lapisan awan di latar belakang menangkap cahaya dari serangan jauh, atau lampu mawanan. Kami mencapai efek ini melalui sistem partikel yang sangat sederhana yang berkedip papan cloud di bagian belakang utama cloud. Sistem ini mengirimkan partikel awan secara periodik dengan kurva transparansi acak
Membuat Pohon Melayang di Angin
Setelah kami memiliki awan dan petir yang bekerja cara kami inginkan, kami kemudian perlu menambahkan dua komponen utama lainnya dari badai: angin dan hujan! Elemen ini menghadirkan beberapa tantangan, termasuk perlu bekerja dalam batasan saat ini Studio kami dari sistem fisika dan efek khusus kami. Misalnya,
Kami tahu untuk benar-benar menjual efek angin dan hujan, kami memerlukan pohon itu sendiri untuk bergerak. Ada beberapa cara Anda dapat melakukan ini dalam engine, termasuk menggerakkan bagian yang menggunakan plugin yang tersedia secara publik, menggunakan Class.TweenService</
Kami memulai dengan menyetir beberapa pohon dari Endorse Model Pack - Forest Assets . Karena pohon-pohon ini sudah ada, dan pengalaman kami berlangsung di Pasifik Utara Barat, itu menghemat waktu kami lebih awal dari harus membuat setiap model pohon.
Setelah kami memilih pohon kami, kami tahu kami perlu menykininya. Menykinning jaringan adalah aktivitas menambahkan joint (atau tulang) ke jaringan dalam aplikasi 3D lain, seperti Blender atau Maya, lalu menerapkan p
Kami tahu kami ingin menghemat waktu dan menggunakan animasi yang sama, jadi kami membangun rig pertama kami dan memastikan nama bergabungan generik karena kami ingin menggunakan nama-nama ini di ridge untuk menyesuaikan dengan angin, cab
Setelah kami telah menciptakan joints/骨 kami, saatnya untuk membuat animasi tes untuk bergerak di sekitar semua joints dan bones di Studio untuk melihat apakah itu bergerak seperti yang kami inginkan. Untuk melakukan ini, kami harus 导入树到 Studio
Setelah kami senang dengan hasil pada pohon itu, saatnya untuk menguji animasi yang sama di pohon yang berbeda! Kami sudah tahu itu akan menjadi animasi yang sama di antara rig-rig yang berbeda untuk setiap ketikpohon, jadi kami hanya memastikan animasi kami tersebut terlihat seperti itu cukup umum untuk bekerja di antara pohon Redwood tinggi dan kayu Birch yang kuat!
Untuk melakukan ini, kami mengambil pohon Beechwood dari Forest Pack tersebut dan membangun rig serupa, menggunakan nama yang sama persis untuk joint. Ini sehingga animasi yang kami import sebelumnya dapat diterapkan ke pohon ini juga. Karena animasi semuanya berdasarkan rotating joints, tidak masalah seberapa besar, kecil, tinggi, atau lebar pohon itu!
Setelah kami membungkukkan dan menykinasi pohon Beechwood, kami kemudian dapat mengimpornya dan menerapkan animasi yang sama persis. Ini berarti bahwaiterating dan mengedit hanya perlu dilakukan di satu file, dan itu juga disimpan dalam performa dengan lebih sedikit animasi saat mengeksekusi pengalaman.
Setelah kami memiliki semua jenis pohon yang kami inginkan ber Animasi, kami membuat masing-masing menjadi paket sehingga kami bisa terus mengedit dan menyetel saat bermain beberapa animasi di sekitar area utama pengalaman. Karena kami tahu mereka memiliki biaya kinerja, kami menggunakannya secara sparing di sekitar rumah di mana efeknya p
Membuat Sampah Badai
Kami ingin hujan terlihat berat, dan agar kabut dan debu menghantam pohon. Untuk melakukan ini, kami menyiapkan beberapa bagian yang tak terlihat untuk bertindak sebagai volume partikel dengan anak partikel emitter langsung di bawah cloud besar. Karena batas jumlah partikel di
Hujan partikel menggunakan emitter partikel baru ParticleEmitter.Squash yang memungkinkan Anda membuat partikel lebih panjang, atau squatter. Ini
Untuk kabut, kabut, dan daun yang melayang, sangat mudah untuk menambahkan satu volume bagian besar yang mencakup lebih sedikit area karena kami tidak memerlukan ton partikel berjalan sekaligus. Kami mulai dengan mengatur volume dan mendapatkan frekuensi partikel di mana mereka diinginkan.
Setelah itu, kami membuat teksur kulit daun dan angin, dan menetapkan partikel untuk semua berputar/bergerak dengan kecepatan yang berbeda, dan memulai partikel pada semua berputar/bergerak dengan kecepatan yang berbeda. Ini berarti bahwa partikel kulit lebih besar akan berinteraksi lebih alami dan tidak terlihat begitu banyak seperti teksur ulang berulang, terutama karena ukurannya.
Hasilnya adalah beberapa tindakan besar antara pohon bergerak, jendela meniup, dan petir untuk menciptakan efek badai di sekitar mata tengah badai.
Mengatur Mata Badai
Mata batu yang retak dengan core yang bersinar adalah dimaksudkan untuk memberi pemain petunjuk pertama bahwa ada sesuatu yang jahat dan misterius terjadi di rumah yang harus mereka jelajahi lebih lanjut. Karena adegan kita gelap dan mata berada jauh di langit, penting
Jarak dari pemain juga berarti bahwa kami dapat sepenuhnya mengandalkan peta normal untuk detail permukaan mata sehingga mesh hanya menjadi satu set spara! Kami menyulap detail menjadi spara rendah dan memanggang peta normal ke pola spara yang jauh lebih rendah sehingga kami dapat mendapatkan semua detail cantik tanpa biaya performa besar.
Untuk menambahkan perasaan supernatural ke mata dan untuk menyoroti kehadirannya, kami memutuskan untuk menciptakan glowing, neon magma yang menyebar melalui retakannya. Sementara tidak ad
Tantangan lain yang kami hadapi saat membuat mata adalah diborong oleh penggunaan streaming bersama dengan jarak mata dari p
Kami dapat menambahkan gerakan ke mata dan cincinnya dengan menggunakan script yang sama kami gunakan untuk memutar meshes awan. Untuk sentuhan akhir, k
Membuat Pantry yang Berluas
Salah satu hal paling menyenangkan untuk diproduksi adalah ruang korup, di mana kita bisa menyubverti harapan pemain tentang kenyataan dengan cara harfiah mengubahnya di sekitar mereka. Misalnya, dalam puzzle ayah kami kami ingin meniru momen serupa dengan mimpi buruk di mana tidak peduli seberapa cepat Anda berlari, ruangan terasa seperti itu terus menj
Kami menyiapkan ini dengan gerakan sederhana dari dinding, dan tata letak pintar dari kamar kami yang akan muncul di salah satu sisi dari pantry. Dalam keadaan normal ruang, pantry adalah koridor sederhana, tetapi di ruang yang rusak, itu sebenarnya jauh lebih panjang dengan beberapa sayap dan dinding palsu!
Dinding palsu adalah kumpulan model yang akan kami move back saat pemain memasuki volume pemutar, yang merupakan bagian transparan sebelum pantry bahwa mereka akan berjalan melalui. That trigger juga digunakan dalam script serupa dengan yang digunakan pada semua pintu kita, yang bernama TweenService untuk pindah dari satu goal ke another. K
Karena TweenService adalah sistem umum, semua model data dinding kami harus berisi adalah komponen yang sama. Misalnya, gambar berikut adalah contoh naskah pintu umum yang memanggil suara yang ditentukan oleh "值" di bawah model "Grow_Wall".
Skrip yang sama, dengan beberapa modifikasi dalam contoh kode berikut, juga mengaktifkan audio untuk pindahnya inventaris. Ini menambahkan banyak ke gerakan!
local Players = game:GetService("Players")
local TweenService = game:GetService("TweenService")
local model = script.Parent
local sound = model.Sound.Value
local trigger = model.Trigger
local left = model.TargetL_Closed
local right = model.TargetR_Closed
local tweenInfo = TweenInfo.new(
model.Speed.Value, --Waktu/Kecepatan Tween Pintu
Enum.EasingStyle.Quart, --Gaya Meredakan
Enum.EasingDirection.InOut, --Arah Mudah
0, --Ulangi Hitungan
false, --Terbalik benar
0 --Lambat
)
local DoorState = {
["Closed"] = 1,
["Opening"] = 2,
["Open"] = 3,
["Closing"] = 4,
}
local doorState = DoorState.Closed
local playersNear = {}
local tweenL = TweenService:Create(left, tweenInfo, {CFrame = model.TargetL_Open.CFrame})
local tweenR = TweenService:Create(right, tweenInfo, {CFrame = model.TargetR_Open.CFrame})
local tweenLClose = TweenService:Create(left, tweenInfo, {CFrame = model.TargetL_Closed.CFrame})
local tweenRClose = TweenService:Create(right, tweenInfo, {CFrame = model.TargetR_Closed.CFrame})
local function StartOpening()
doorState = DoorState.Opening
sound:Play()
tweenL:Play()
tweenR:Play()
end
local function StartClosing()
doorState = DoorState.Closing
--model ["Pintu"]:Mainkan()
tweenLClose:Play()
tweenRClose:Play()
end
local function tweenOpenCompleted(playbackState)
if next(playersNear) == nil then
StartClosing()
else
doorState = DoorState.Open
end
end
local function tweenCloseCompleted(playbackState)
if next(playersNear) ~= nil then
StartOpening()
else
doorState = DoorState.Closed
end
end
tweenL.Completed:Connect(tweenOpenCompleted)
tweenLClose.Completed:Connect(tweenCloseCompleted)
local function touched(otherPart)
if otherPart.Name == "HumanoidRootPart" then
local player = Players:GetPlayerFromCharacter(otherPart.Parent)
if player then
--print("触摸")
playersNear[player] = 1
if doorState == DoorState.Closed then
StartOpening()
end
end
end
end
Setelah kami memiliki dinding palsu bergerak ke belakang ruangan, kami memerlukan sisa konten untuk bergerak dengan itu. Untuk melakukan itu, kami memerlukan semua item longsor di pantrai untuk disatukan ke dinding saat bergerak. Menggunakan Bathtub Constraints, kami dapat dengan cepat menyatukan semua
Membuat Rumah Pohon Rusak
Studio adalah mesin fisik yang fantastis yang dapat Anda gunakan untuk menciptakan segala sesuatu dari pintu gerbang ayunan hingga platform berputar. Dengan demonya, kami ingin menggunakan fisika untuk menciptakan nuansa realisme dalam set environment yang sepenuhnya tidak realistis. Dengan menggunakan beberapa batasan , Anda dapat menciptakan beberapa tantangan kursus dalam pengalaman Anda sendiri!
Batasan Mengatur objek dan membatasi perilaku For example, you can use a batasan batang rod to connect to objects in order to keep them a fixed distance from each other, or the 1> batasan bat
Setelah para pemain bekerja ke area utama teka-teki, mereka disambut dengan pemandangan yang familiar di Roblox: tempat rintang rintang. Area rintang rintang ini terdiri dari beberapa platform berputar dan dinding berputar, bersama dengan "area aman" yang melanjutkan cerita. Kami akan fokus pada elemen berputar/berputar.
Mengapa kami menggunakan batasan di sini? Karena TweenService atau metode lainnya tidak akan menggerakkan pemain sementara mereka berdiri di atasnya. Tanpa objek pindah ke platform dan itu akan berputar dari bawah mereka. Alih-alih itu, kami ingin
Untuk melakukan ini, kami perlu menggunakan aset dari kit kami saat ini dan menambahkan konten baru untuk efek visual. Kami membuat beberapa dinding dan peron yang tidak selesai dengan lubang di dalamnya untuk menceritakan cerita nenek moyang membangun rumah pohon. Karena kami tidak ingin membuat banyak bagian pangkalan dan bagian peron yang unik, kami membu
Kami tahu bahwa karena kami menggunakan kendali, kami tidak akan dapat menambatkan meshes ini karena mereka tidak akan bergerak bahkan
Sekarang saatnya untuk mengatur perilaku aktual dari kendala hinge sendiri, dan menambahkan lampiran yang akan bertindak sebagai orientasi bagian dan kendala memiliki. Kami menempatkan lampiran pemutar di Motor_Turn, yang bagian
Untuk menjaga platform berputar dengan kecepatan konstan, kami kemudian mengatur HingeConstraint.AngularVelocity, HingeConstraint.MotorMaxAcceleration, dan HingeConstraint.MotorMaxTorque ke nilai yang memungkinkan gerakan dan mencegah interupsi jika seorang pemain melompat di atasnya.
Sekarang kita perlu membuat dinding berputar. Dinding perlu berputar di tengah yang jelas, dan kami tahu bahwa kita ingin mereka dapat menangani orientasi relatif terhadap sisa level. Seperti platform, kami membangun ini sehingga semua dinding tidak tertancam dan terikat ke Motor_Turn.
Kami menggunakan Texture objek di atas SurfaceAppearance objek untuk menambahkan beberapa variasi ke bahan dasar k
Setelah kami menguji beberapa platform dan dinding berputar, kami membuat beberapa variasi dan bermain dengan posisinya untuk memastikan bahwa kursus rintangan itu menantang, menakjubkan, dan juga jelas di mana pemain perlu mulai! Butuh beberapa penyesuaian untuk kedua nilai dan posisi mereka untuk berjalan dengan baik. Kami memiliki beberapa po
Jika Anda tidak yakin objek fisik Anda menghantam, Anda dapat menyalakan Ketahanan gesekan keteguhan dari widget Opsi Visualisasi di sudut atas kanan 3D viewport.
Seperti yang Anda lihat di bawah pintu/jendela, lubang-lubang ini terlihat, tetapi rincian kecil seperti sub-panelling tidak. Ini karena propperti CollisionFidelity untuk dinding dibatalkan menjadi Kotak . Kami tidak memerlukan persyaratan untuk panel ini, jadi