Herhangi bir deneyim içindeki herhangi bir ortamda hareket oluşturmak, dünyaların daha canlı ve gerçekçi hissetmesine yardımcı olur, bu da ambient ağaç hareketinden, oyuncu etkileşimi veya ç
Fırtınayı Oluşturma
Fırtına, Gizem of Duvall Drive'ın içindeki şeyin ne olduğuna dair kararlaştığımızda birçok itera geçti. Başlangıçta, fırtınayı devasa bir obsidiyen pilara düşündük ve daha son itera itera düşündük. Gizli alanın bozulmuş alanı için büyük bir portal olarak düşündükten sonra, merakl
- Fırtına oyunculara ağaçların uçtuğu ve etkilerini dünyaya yayan gibi bir görünüm vermelidir.
- Bulutların kendi dönen vortex'i oyunculara merkezi portalı gizlemeden bir şekilde göstermelidir. Bu, oyuncuların merak etmeye başlasını teşvik eder.
- Daha sıkı bir ışık noktası, bizim evin kompozisyonuna odaklanmamızı sağlayacaktır, bu da oyunun çoğu yerleşim yeridir.
Fırtınanın çevresindeki ortamda dinamik, agresif ve sürekli değişen bir fırtına hissetmek için aşağıdaki sistemleri ve özellikleri kullandık:
- TweenService > - Bulut hareketi için.
- Yuva değişiklikleri - Bulut oluşturmak için yıldırım.
- Işınlar - "Ses yalıtıcı ışıklandırma" ve yıldırımlar için.
- Parçacık Emitterleri > - Yüksek kırılma nedeniyle portal ve rüzgar nedeniyle döndüğünde uçmak için.
- Animasyonları > - Rüzgarın esmesiyle ağaçlar için.
Metinuresiyle Bulutlar Ekleme
Normal, yüksek irtifalı gerçek bulutlar için dinamik bulutlar harika olsa da, bizim için d
Her bir bulut meshesinin evi çevrelemek ve fırtınanın ne kadar büyük olduğunu göstermek için her biri milyonlarca parçaya ihtiyacı olduğunu biliyorduk, bu yüzden biz kullanmak istediğimiz dokuyu kullanıcı bulut meshesine uygulamak için bu basit parçalarda test ettik ve vortex'e uyguladık!
Parçacık emitterleri veya ışınlar gibi, kumaşlar her kumaştan ışığı yenmek için mıknatıs olarak hizalanmıştır, bu da bulut-bulut ışınlanma için önemliydi. Ayrıca, kumaşların kenarında ışığın yenilmesi derin görünmesi için hizalanmıştır. Bu, deneyin performans
Dönen Bulut Ağları
Bulutların genel görünümüyle ilgili olduğumuzdan sonra, onu hareket ettirmemiz gerekiyordu! Her bulut katmanının genel şeklini dünyagetirdik, ancak dönen etkiyi pratikte iyi görünmesi için biraz deneme ve hata yapmak gerekiyordu. İlk olarak <
Bulutlar gibi çok yerleşik olmayan nesneleri oynatmak için kolay bir yöntem istedik, t
Demonstrasyondaki birçok durumda, etkilenen instansları Studio'da bir instans etiketleyici eklentikullanarak yönetebilmek için bir LocalSpaceRotation etiketi kullandık. Sadece bir LocalScript kullandık, tüm etiketlenmiş instansları Studio'da yönetmek için kullanılan bir
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()
objInfo bir haritadır, tüm ilgili nesnelerin bilgilerini içerir, türleri ve eksenleri gibi. Not
We rotated the instances in the Update function connected to heartbeat. We got the parent transform (parentTransform),累
local parentTransformif parentObj:IsA("Model") thenif not parentObj.PrimaryPart then-- birincil bölüm yine de yayınlanmayabilircontinue -- birincil parçanın kopyalanmasını bekleyinendparentTransform = 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
Class.Model.PrimaryPart ile yayınlanmayı sağlayacak geçerli bir Model.PrimaryPart ı kontrol ettik. Bir Class.Model.PrimaryPart (çocuk şebekesine işaret edebilir) ı yayınlamadıysa, hala
Yıldırım Çarpmalarını Tasarlama
Studio, kutu dışı bir ışınlanma jeneratörü sunmaz ve parçacı sistemi, kahraman ışınlanma çekimleri için çalışmayan bazı sınırlamalara sahiptir, bu yüzden kahraman ışınlanma çekimleri için çözüm için kahraman ışınlanma
Işınları Düzleştirme
Genellikle bir takılma efekti için çalışma zamanını sürüklemeyi sağlayacak bir sıraya veya zaman çizelgesine aletini kullanırız, ancak Studio henüz bu özelliği sunmaz, bu yüzden ışıklanma vuruşu etkisi gibi çalışma zamanını kontrol edecek kodlar yazmaya karar verdik. Bu kodun basit bir şekilde yapılması gerekir, ancak şu ön
- Yıldırım çarpmalarının öğeleri, tuzaklarının, parlaklıklarının ve gecikmelilerinin gibi, her çarpmaya rastgele yapılır.
- Oyun içi ses ve post-FX değişiklikleri Strike FX ile senkronize edilmiştir.
- Eğer içeride veya bozulmuş alanın içinde olan oyuncular onları göremez veya duymazdı.
Çeşitli parametreleri ve zamanları hesaplayan Script bir sunucu tarafından, tüm müşterilere gönderilir ve rastgele bir süre beklenir:
local function LightningUpdate()
while true do
task.wait(rand:NextNumber(3.0, 10.0))
local info = CreateFXData()
lightningEvent:FireAllClients(info)
end
end
İçinde CreateFXData , bilgi yapısını dolduruyoruz, böylece tüm müşteriler aynı parametreleri alır.
LightningVFXClient taraflındaki müşteri (işletim sistemi) FX'i çalıştırıp çalıştırmayacağını kontrol ederiz.
local function LightningFunc(info)
…
-- içerde FX yok
if inVolumesCheckerFunc:Invoke() then
return
end
-- normal dünyada olmayan FX yok
if not gameStateInfoFunc:Invoke("IsInNormal") then
return
end
…
Ayrıca, dokunmatik efektleri, pozisyonları ve parlaklığı ayarlamak için diziyi çalıştırırız, gençleri çalıştırırız ve task.wait(number) kullanırız. Rastgele parametreler, sunucudan aldığımız bilgi yapısından gelir ve bazı sayılar sabit.
beam.Texture = textures[info.textIdx]beamPart.Position = Vector3.new(info.center.X + og_center.X, og_center.Y, info.center.Y + og_center.Z)-- Silbeam.Brightness = 10ppCC.Brightness = maxPPBrightnessppBloom.Intensity = 1.1bottom.Position = top.PositiontweenBrightness:Play()tweenPPBrightness:Play()tweenPPBrightness:Play()tweenBottomPos:Play()tweenBrightness.Completed:Wait()-- sesif audioFolder and audioPart thenif audioFolder.Value and audioPart.Value thenaudioUtils.PlayOneShot(audioObj, audioFolder.Value, audioPart.Value)endendtask.wait(info.waitTillFlashes)-- and so on
Bir oyuncunun içerde olduğunu kontrol etmek için yardımcı bir işlev kullanırız, bu, iç alanların tahmini içinde yer alan sesleri geçer ve oyuncu pozisyonunun içinde olduğunu test eder (PointInABox). Dokunmatik algılama kullanmak y
Bir oyuncunun yanlış alanlarda olup olmadığını kontrol etmek için yardımcı bir işlev çağırırız, ki mevcut oyun durumunu kontrol eder. Bir klasik sesi bir klasik oyun içine çekmek için ise gameStateInfoFunc işlevini kullandık. Şimşek çı
Partikül Emitter Sistemlerini Kullanmak
Kahraman yıldırım çekişleri, etkili bir parçacık sistemi tarafından desteklenir, böylece uzaktaki bir yıldırım oluşturmak etkisini bir bulut katmanını yakalayan uzaktaki bir yıldırım gibi gösterir. Bu etkiyi, uzaktaki bir yıldırım gibi gösteren çok basit bir parçacık sistemi aracılığ
Ağaçları Rüzgarın İçine Ondan Koparma
Bulutları ve şimşeği istediğimiz şekilde çalıştırdıktan sonra, bir fırtınayı oluşturmak için iki diğer ana bileşenin eklenmesi gerektiğini gördük: rüzgar ve yağmur! Bu elemanlar, fiziksel ve özel efektler sistemlerimizin mevcut sını
Rüzgar ve yağmurun etkisini gerçekten satmak için, ağaçların kendilerini hareket ettirmek için ihtiyacımız olan ağaçların kendilerine ihtiyacımız vardı, bunu eşyaları kullanarak hareket ettirerek yapabiliriz. Engelleme modların
Biz başladık birkaç ağaç Endorse Model Pack - Forest Assets 'dan kabuk almak. Çünkü bu ağaçlar zaten mevcut olduğu için, deneyimimiz Pasifik Kuzeybatı'da gerçekleşti, biz böylece her ağaç modelini oluşturmak zorunda kalmadan erken bir şekilde birkaç saat biz kurtardı.
Ağaçlarımızı seçtikten sonra, onların deri olması gerektiğini biliyorduk. Bir kumaş üzerine eklemek (ya da kemikleri) bir kumaş başka bir 3D modelleme uygulamasında, Blender veya Maya g
Zamanı kaydetmek ve aynı animasyonu tekrar kullanmak istediğimizden ilk ağaç kulemizi inşa ettik ve ortak isimlerin genel olduğundan emin olduk, çünkü bu işlemleri için gerekenleri yapmak
Ortaklarımızı/kemikleri oluşturduktan sonra, Studio'daki tüm ortakları ve kemikleri hızlıca hareket ettirecek bir test animasyonu oluşturmak için zaman geldi. Bunu yapmak için, Özel Rig Ay
O ağacın sonuçlarından memnun olduktan sonra, aynı animasyonu farklı bir ağaçta test etme zamanı! Aynı yazher ağacı için farklı animasyonun olacağını biliyorduk, bu yüzden animasyonumuzu yüksek bir Redwood ve sağlam bir Beechwood ağacı arasında çalışacak kadar genel görünüyordu!
Bunu yapmak için, bu Orman Paketinden Beechwood ağacını aldık ve aynı isimlendirmeyi kullanarak benzer bir rakip yaptık. Bu, önce ithal ettiğimiz animasyonların da bu ağaca uygulanabileceğini gösterdi. Animasyonların hepsi çevirimi eşleştirme üzerine dayanıyordu, bu yüzden ağacın ne kadar büyük, küçük
Beechwood ağacını şekillendirdikten sonra, onu ithal edebilir ve aynı animasyonu uygulayabiliriz. Bu, sadece bir dosyada itelenip düzenlenmesi gerektiği anlamına geliyordu ve ayrıca deneyimin çalıştırıldığında daha az animasyon gerektiren daha az animasyon gerektiren daha az animasyon gerektiren daha az animasyon gerektiren daha az animasyon gerektiren daha az animasyon gerektiren
Tüm ağaç türlerine sahip olduğumuzda istediğimiz animasyonu istediğimiz gibi düzenlemek için her birini paketler yaptık, böylece birkaç animasyonun etrafındaki ana alanın düzenlediğimizden güncellemeyi sürdürebilirdik. Çünkü performans kaynağı olduğunu biliyorduk
Fırtına Parçaları Oluşturma
Yağmurun ağır görünmesini istedik ve sis ve kayaların ağaçların aracılığıyla solgunması için şişek hale getirmek için birkaç görünmez parçayı yaptık. Bunu yapmak için Studio'nun çekirdek alanındaki bir par
Yağmur parçacıları, yeni bir katı parçacı emitter özelliği ParticleEmitter.Squash kullanıyor ki, bir parçayı daha uz
Sis, sis ve yapraklar solgunan için, tek bir daha büyük bir parça hacmi eklemek çok daha basitti çünkü biz bir tonluk parçacıkların bir anda çalışmasına gerek yoktu. Bir dizi kurarak başladık ve istediğimiz parçacıkların frekansını aldık.
Ardından, yapraklarımızı solattık ve rüzgar kalıplarını ayarladık, ve parçaların tüm döndürmeleri/gitmeleri ve başlangıçları farklı hızlarda ve tüm döndürmeleri/gitmeleri başlangıç noktaları farklı hızlarda ve başlangıç noktaları farklı hızlarda başladı. Bu, daha büyük sis parçalarının daha doğal bir
Sonuç, ağaçların hareket etmesi, pencerenin patlaması ve fırtınanın etkisiyle oluşan fırtınanın etkisini oluşturmak için bazı harika eylemler oldu.
Fırtınanın Gözünü Ayarlama
Parçalanmış taş göz, parlayan çekirdeğiyle oyunculara evdeki bir şeyin sinister ve arcane olduğunu ilk gösterişi vermek için yaratılmıştır. Görsel sahneniz karanlık ve oyuncuların gözleri uzaktad
Oyuncudan mesafe, ayrıca normal bir haritaya gözün yüzey ayrıntıları için tümüyle güvenebileceğimizi de ifade ediyordu, böylece dokunmatik ağ gibi basit bir şeydi! Ayrıntıları yüksek bir polişe içine kazdık ve normal haritasını çok daha düşük bir polişe yazdık, böylece tüm bu güzel ayrıntıyı elde edebildik, h
Gözümüze bir doğal his eklemek ve onun varlığını vurgulamak için, gözümüzü çatlakalarından geçen parlak, parlak bir magma oluş
Gözü oluştururken kullandığımız bir başka meydan okuma zorluğu, gözün mesafesi oyuncu'den bağ
Göz ve gözlerinin halkalarına hareket eklemek için aynı kodu kullandığımız için göz ve halkalarının dışında bulunan
Genişleyen Pantrayı Oluşturma
Üretmenin en eğlenceli yanlarından biri de bozulmuş alanlar oldu, biz bunları kullanarak oyuncuların beklentilerini gerçekliğiyle bir şekilde değiştirebiliriz. Örneğin, babanın bulmacasında bir kabus gibi bekleyenleri olmayan bir odanın içinde hissettirmek istedik ki, her ne kadar hız
Duvarların basit bir hareketiyle ayarladık ve pantrinin her iki tarafında görünecek olan akıllı bir yerleşim planıyla odalarımızı kurduk. Duvarların normal durumunda, pantrinin koridoru basitti, ancak bozulmuş alanda, birkaç kanat ve sahte bir duvar ile çok daha uzun!
Sahte duvar, oyuncular bir gatlama hacmi girdiğinde geri döndüğümüz bir model grubuydu, bu da pantrideki şeffaf bir parçaydı. Bu gatlama işlemi, duvarın başlangıcı ve sonu konumlarını değiştiren TweenService kullanıldı. Duvarın başlangıcı ve son
Çünkü TweenService böyle genel bir sistem olduğundan, tüm duvar verilerimizin içeriği aynı olmalıdır. Örneğin, aşağıdaki görüntü, "Grow_Wall" modelinin altındaki bir ses tanımlayan genel bir kapı kısmının bir örneğidir.
Aynı kod örneğinde bazı değişikliklerle, dağıtım hareketi için de ses başlatılır. Bu harekete çok şey ekledi!
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, --Kapının Açılımı/Kapatılması Zamanı
Enum.EasingStyle.Quart, --Yumuşatma Tarzı
Enum.EasingDirection.InOut, --Yönlendirme
0, --Sayıyı Tekrarla
false, --Geri true
0 --Gecikme
)
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["Kapı"]:Oyna()
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
Sahte duvarın arkasına gittiğimizde içeriği taşımak için geriye kalan kısmı gerekti. Bunu yapmak için, pantrideki tüm serbest öğeleri duvarın hareket ettiği yere bağlamak için kullandık. Bunu yapmak için kısıtlayıcıları kullan
Bozulmuş Ağaç Kulübesini Oluşturma
Studio, swinging kapıdan dönen bir platforma her şeyi oluşturmak için kullanabileceğiniz harika bir fiziksel motor. Demomuzu kullanarak, fiziksel bir setin diğer yanlış bir şekilde unrealistik olmasını sağlayarak gerçekçi bir gerçeklik duygusu yaratmak istedik. Sadece birkaç kısıtlayıcı kullanarak eğlenceli ve me
Sınırları Kısıtlama eşyaları, nesneleri yerine almak ve davranışları sınırlamak için fizyiksel olarak motorların bir grubudur. Ör
Oyuncular bulmacanın ana alanına çalıştıklarında, Roblox'ta tanıdık bir görüşle karşılandılar: bir engel kursu. Bu özel engel kursu, bir dizi dönen platform ve dönen duvarlardan oluşuyordu, "güvenli alanlar" hikayeyi ilerleten. We'll focus on the rotating/spinning elements.
Neden burada kısıtlamalar kullandık? Çünkü TweenService veya diğer yöntemler oyuncuların ayaklarının üstünde dururken hareket etmezdi. Oyuncuların oyunu yapmak için dönen bir platforma atlağında h
Bunu yapmak için, mevcut kit'imizden ilk olarak kaynakları kullanıp herhangi bir görsel efekte herhangi bir yeni içeriği eklememiz gerekiyordu. Birkaç tamamlanmamış duvar ve platform ekledik burada, büyük annenin ağaç evini inşa ettiği hikayeyi anlatmak için onları birbirine karıştı
Kısıtlamaları kullandığımız için, bu kısıtlamaların yerleştirileceği mesafe mesafe değiş
Şimdi hareket kısıtlayıcının kendisiyle ilgili gerçek davranışı ayarlanmış ve parça ve kısıtlayıcıyla birlikteki yönlendirme davranışını etkileyen bağlantılar eklen
Platformların daimi hızla döndüğünden emin olmak için, HingeConstraint.AngularVelocity, HingeConstraint.MotorMaxAcceleration ve HingeConstraint.MotorMaxTorque özelliklerini değerleri ayarlarız ki bir oyuncu o platforma zıplarsa hareketi durdurabilir veya kesintiye
Şimdi dönen duvarları yapmamız gerekiyordu. Duvarlar, görünür merkezlerinde döndüğü için döndürmelerdi ve biz, onların herhangi bir yönüne bağlı olarak seviye geri kalanına dayanabileceğinden emin olmak istedik. Platformlar gibi, bunları oluşturduk, böylece tüm duvarlar bağlantısız ve Motor_Turn'a kaynaklanmış olabilir.
Biz, üstteki Texture nesneleri kullandıkSurfaceAppearance nesnelerinin üzerine biraz değiş
Birkaç platformu ve dönen duvarları test ettikten sonra, birkaç çeşit yaptık ve onların yerleşimini garanti etmek için onların yerleşimini garanti etmek için birkaç çeşit yaptık. Onların yerleşimini garanti etmek için birkaç nokta vardı, ancak birkaç hareket etti
Fiziksel nesnelerinize ne vurduğundan emin değilseniz, sağ üst köşedeki 3D görüntü ortamındaki <a href="https://www.nvidia.com/gear/gear-api/">Collision Fidelity</a> widget'ınızı açabilirsiniz.
Kapı/pencere deliklerinin altındaki kapı/pencere delikleri görünebilir, ancak CollisionFidelity gibi daha küçük ayrıntılar görünmez. Bunun nedeni, duvarlar için kutu özelliği kutu olarak ayarlandığ