Aşağıdaki sistemler, The Mystery of Duvall Drive için istediğimiz oyun oynatışını kurmak için temeldi.
Oyun Durumu Yöneticisi
The GameStateManager / GameStateClient is probably the most complicated system in the experience, as it deals with:
- Lobideki oyuncuları başlatıyor, grubu ana oyun alanına ışınlanmak için sayıyı başlatıyor ve oyuncuları rezerve sunuculara ışınlanıyor.
- Korup odaları klonlayın, onları asen yayınlayın ve oyuncuları belirli bir CFrame koordinatına ışınlatın.
- Mekanikleri yakalamak ve yerleştirmek.
- Kapıları kilitleme ve açma.
- Son ışınlanmayı lobiye başlatın ve son kesinti sahnesini oynayın.
We implemented it as a simple state machine (Update function), ve devletler DemoConfig (GameStates枚) içinde bulunur. Some states deal with initial lobby/reserved server ışınlan, while others deal with finding a mission, triggering the puzzle, and solving the mission. Note that apart from seals, we tried to not have mission-specific code in the GameStateManager .
GameStates çoğunlukla sunucu tarafından yönetilir, ancak müşteri bir şey yapması gerektiğinde, örneğin sayıyı göster, gelenekleri veya yayınlanma durdurma UI'sini devre dışı bırakmak gibi, sunucu ve müşteri (GameStatusClient) arasında şu anki olay olayı GameStateEvent ile iletiş
Işınlanma Oyun Durumları
Teleportasyonu bozuk odaya gizleyen üç benzersiz cutscene'i içeren 3 oyun devleti vardır: Warmup, InFlight
Yayınlanırken, InFlight çalışır, birazcık solgun bir ekran tutan. Bir Class.Player.
Oyuncuları normal odanın durumuna ışınladığımızda, TeleportWarmupBack, TeleportInFlightBack ve TeleportCooldownBack , ve deneyimin sonunda, TeleportW
Yıldırım ve Atmosphere Oyun Durumları
Her odanın normal ve bozulmuş durumunun f
Kapı kilitleme Oyun Durumları
O
Etkinlik Yöneticisi
Etkinlik Yöneticiyi kullanarak "eylemleri" zamanla yürütmemize izin verdiği gibi:
- İн스턴스 özellikleri ve öznitelikleri arasındaki bağlantıyı sağlar.
- Kodları çalıştırıyor.
- Oynama sesi.
- Kamera sarsıntılarını çekiyor.
İdeal olarak, iz tabanlı UI'ye sahip bir araç kullanırız, ancak bu demoda, anahtar ve özellik isimlerini manuel olarak yazdık. Etkinlik Yöneticisi sistemi birkaç script ve bir etkinlik/fonksiyon içerir, bunlar arasında:
- EventManager - Etkinlikleri oluşturma ve durdurma için genel mantık, sunucu-taraflı eylemler de dahil.
- EventManagerClient - Klient tarafı eylemleri.
- EventManagerModule - Her sunucu ve müşteri tarafı eylemler için ortak kod.
- EventManagerConfig - Birkaç komut deklarasyonu içeren küçük bir dosya.
- EventManagerDemo - Bu demo için tüm gerçek olayların oyun spesifik kodunda tanımlanmasının nerede.
- EventManagerEvent , EventManagerFunc - Klient veya sunucudan etkinlikleri çalıştırmak ve durdurmak için uzaktan etkinlik ve bağlantılı işlev. Bu, diğer sistemlerin etkinlikleri nasıl ayarlayabileceğini, çalıştırılabilir ve durdurulabilir işlevleri nasıl ayarlayabileceğini gösterir.
Her etkinliğin bir adı, başlatma veya bitirme için gerekli bilgilerin bulunduğu bir bölüm, etkinliğin parametreleri ve gecikme için işlevi vardır. Kameraya sallanır ve ses oynatır.
Yer İşaretlemesi
Yerleşik olarak, anahtar çerçeveler arasında zıplayan objelerin yerleri değiştirmek için nesne özellikleri ve öznitelikleri arasındaki boşlukları doldurabilirsiniz. Örneğin, a
interpolants = {objectParam = "TextLabel",property = "TextTransparency",keys = {{value = 1},{time = .5, value = 0},{time = 2.25, value = 0},{time = 3, value = 1}}}
Aşağıdaki kod örneğinde gibi, hangi nesne özelliğinin veya özelliğinin hangi nesneye ait olduğunu tanımlayabildiğimizden memnuniyet duyuyorduk, böylece müşterideki yayınlanma ile ilgili olarak ve "objelerin oluşturulma zamanında" ile ilgili olarak çalışabilir.
object = workspace.SomeFolder.SomeModel
Bunu başarabilmek için, etkinliğin başlatbir nesneyi referans etmeye ve bir isimli parametreleri etkinliğe bağlı olarak geçerli kılmaya izin verdik. Named olan nesneleri etkinliğin altında bulmak için, etkinliğin başlangıcında bir "r
params = {["RootObject"] = workspace.Content.Interior.Foyer["Ritual-DemoVersion"],},interpolants = {objectName = "Wander",attribute = "TimeScale",keys = {{value = 0.2}}}
Özellikler bölümünde etkinliklere parametreleri geçirebilirsiniz ve etkinlik başlangıcında çalışan kodlar varsayılan değerleri değiştirebilir veya "param" tablosunda daha fazla parametre ekleyebilir
params = {isEnabled = false},interpolants = {{objectName = "FocuserGlow",property = "Enabled",keys = {{valueParam = "isEnabled"}}}
Parametreler, deneyimin başlangıcında bile mevcut olmayan nesneleri işaret etmemize izin verir. Örneğin, aşağıdaki kod örneğinde, etkinliğin başlangıcında çalışan bir işlev, bir nesne oluşturur ve parametrelerde BlackScreenObject girişini ayarlar, oluşturulan nesneye işaret edilir.
{objectParam = "BlackScreenObject",property = "BackgroundTransparency",keys = {{value = 0},{time = 19, value = 0},{value = 1},}}
Etkinlikler, Etkinlik Instanları ve Tetiklere Bağlanma
Bir etkinliği çalıştırmak için, klijlerden bir uzaktan etkinlik kullanırız veya sunucudan bir işlev. Aşağıdaki örnekte, birkaç parametreyi RootObject ve isEnabled etkinliklerine veriyoruz. İçeride, etkinliğin açıklamasının bir kopyası oluşturulur, parametreler gerç
local params = {RootObject = workspace.Content.Interior.Foyer["Ritual-DemoVersion"]["SealDropoff_" .. missionName],isEnabled = enabled}local eventId = eventManagerFunc:Invoke("Run", {eventName = "Ritual_Init_Dropoff", eventParams = params} )
Bir etkinliği "Dur" ile durdurmak için işlevi çağırabiliriz:
eventManagerFunc:Invoke("Stop", {eventInstId = cooldownId} )
“Kozmetik” (tüm oyuncular için simülasyonu değiştirmeyin) eylemleri, kliplerde yürütülebilir ve bu da daha pürüzsüz bir işleme sonuçlanabilir. Etkinliğin açıklamasında, tüm eylemler için varsayılan değeri sunabilirsiniz (bu, varsayılan olmadan, klipler üzerindeki herhangi bir eylemi geçersiz kılar). Her klip, kendi
Bir etkinliği bir başlatıcıya kolayca bağlamak için yardımcı işlevleri kullandık ConnectTriggerToEvent veya ConnectSpawnedTriggerToEvent, bu da ismiyle etkinliği bulur. Aynı etkinliği farklı başlatıcılarla
Etkinlik Parçaları
Etkinliği oluştururken geçerli kullanıcı tarafından atanan özel etkinlik parametreleri dışında, oluşturulan etkinliğin gerektiğinde göçebileceği diğer veriler de dahil olmak üzere, oluşturulan etkinliğin gerektiğinde göçebileceği diğer oyuncude dahil olmak üzere, oluşturul
Etkinliklerin bekleme sürelerini minCooldownTime ve maxCooldownTime ile belirleyebilirsiniz. Min ve max, oyuncu sayısına bağlı olarak ölçeği artırma için
Kullanılan Kodlar
Class.Script|Scripts ile özel anahtar çerçevelerinde Scriptler bölümünde adlandırabiliriz. Örneğin:
scripts = {{startTime = 2, scriptName = "EnablePlayerControls", params = {true}, onServer = false }}
Önceki örnekte, EnablePlayerControls Script eylem menajer modülüne kaydedilmesi gerekir, şu şekilde:
emModule.RegisterFunction("EnablePlayerControls", EnablePlayerControls)
ClientScript'teki işlevler için kullanıcı tarafından çağrılan işlevler ve ServerScript'teki işlevler için onServer = true için kullanıcı tarafından çağrılan işlevler olarak kaydedilir. İşlevin kendisi etkinliği alır, ancak bu durumda, sadece bir parametre etkinliği geçerlidir.
local function EnablePlayerControls(eventInst, params)
Oynatma Audio
Anahtar karelerindeki non-positional audio oynatmak için sınırlı desteğimiz var, örneğin:
sounds = {{startTime = 2, name = "VisTech_ethereal_voices-001"},}
Etkinliğin bitmesi çağrısının olay süresi dolduğunda ateşlenmesine注意avatar, ancak ses eylemleri hala oynatıyor olabilir.
Kamera Titremeleri
Kamerası Shake'leri kamerası Shake'leri bölümünde, şu şekilde tanımlayabiliriz:
cameraShakes = {{startTime = 15, shake = "small", sustainDuration = 7, targets = emConfig.ShakeTargets.allPlayers, onServer = true},}
“hedefler” sadece etkinliği başlatan oyuncuya, tümOyuncu veya playersInRadius'e bağlı olan oyuncular için başlatılabilir. Kamerası sarsıntılar için üçüncü taraf bir kod kullandık ve sarsıntılar önceden tanımlanmış: eventManagerDemo.bigShake ve
Görevlerin mantığı
Toplam 7 görev var ve sadece 6'sı kullanıyor kullanıyor. çoğu görevin ortak parametreleri var, ancak bazıları sadece kullanıyor ve hizmet odasına ışınlanmak için kullanıyor. Her görevin bir DemoConfig kriptiyle bir seti içinde parametreleri var:
- MissionRoot : Tüm olmayan versiyonlarınızın bir klasörü.
- Kapılar : Bir oyuncu bir kilidi seçene kadar kilit kapatır.
- SealName / SolvedSealName : Bozulmamış ve bozulmuş kalem isimleri.
- SealPlaceName : Mührü yerleştirmeniz gereken yerler.
- PlacedSealPlaceholderName : Mührü yerleştirmek için yerleştirme nesneyi yerleştirir.
- TeleportPositionsName : Oyuncu teleport pozisyonlarını ve dönüşleri belirlemek için bozulmuş oda, ve normal alan ile yeniden oluştururken kullanıcının konumlarını ayarlayan bir klasörün adı. Bu aynı ad kullanılır.
- CorruptRoomName : İçe aktarma için kök klasörlerinin adları (ServerStorage'a göre) bozulmuş odalar için. İçe aktarma başladığında, TempStorage.Cloned altında gösterilir ve görev tamamlandığında yok edilir.
- MissionCompleteButtonName : Koruma odalarındaki bir hile butonu, hemen görevi bitirmeye yarar. Bu, depresyon amaçları için.
- CheatKey : Aynı şey bir sayı veya CtrlShift[Numara] ile aynı.
Görev mantığının bir kısmı GameStateManager skriptlerinde, halkalar ve kapılar en çok oyun akışını sağlayan ana oyun akışını sağlar, ancak görev özelliği için çoğu görev için ana oyun akışını sa
- kilit üzerinde bir anahtar kullanın - Kapıyı açmak için ilk görevi. Bu tip LockName , KeyName tarafından tanımlanır.
- Eşleştirme öğeleri - 4 görev eşleştirme öğelerine eşittir. Bu tip MatchItems tarafından tanımlanır.
- Bir mankeni katmanlı kumaş kullanarak giydirmeye çalışıyorsunuz - 1 görevi atıkta olan oyuncular üç öğeyi toplar. Bu tip DressItemsTagList tarafından tanımlanır.
- Click on item to finish. - 1 görevi bu yaztanımlar ClickTargetName .
Her görevi tipinin kendi öz StartMissionFunc ve CompleteMissionFunc . Giriş işlevi genellikle MaçEşyası</
Eşleştirme öğelerin mantığına göre, "kullanmak" (takılırken tıklayın) öğeleri PuzzlePieceXX etiketleriyle takılan öğeleri kullanmak için mümkündür. MatchItems haritasındaki
Alınıyor
Bir nesneyi yakalamak için basit bir yakalama sistemi geliştirdik. Yakalama GrabServer2 ve Grab
Her karede, bir yakalama denemesi devam edip etmediğini kontrol ederiz. Eğer oyuncu reachDist içindedirse, ToolHoldAnim oynayı başlatırız. Bir oyuncu maxGrabDistance içindedirse, istemcisi sunucuya bir model almak için bir istek gönderir (1> playerGrab1> işlevi).
Sunucu tarafı kodun 2 ana işlevi vardır:
- Alın - Bir modeli almak için bir istemciyenin isteğini ele alır.
- Bırakma Talebini Geri Alma: - Yakalanmış bir modeli serbest bırakma isteğini işleyin.
Her oyuncunun ne sakladığının bilgisi playerInfos haritasında saklanır. Takip girişim, bu modelin zaten başka bir oyuncu tarafından alınmış olup olmadığını kontrol ederiz. Eğer öyleyse - bir "EquipWorldFail" gönderilir kliya ve kayış denemesini iptal eder. Aynı
Erişim izin verilirse, Attachments , sağ elinizde ve diğer elinizde birer Class.Attach|E
Bir yakalanmış modeli serbest bırakmak için, client script HUD ScreenGUI'deki GrabReleaseButton düğmesine bağlanır. Bir Connected işlevi, serbest bırakma işlemi için sunucuya bir etkinliği başlatır. Sunuc