Sistem Gameplay Dasar

*Konten ini diterjemahkan menggunakan AI (Beta) dan mungkin mengandung kesalahan. Untuk melihat halaman ini dalam bahasa Inggris, klik di sini.

Sistem berikut adalah dasar dalam membangun gameplay yang kami inginkan untuk The Mystery of Duvall Drive .

Manajer GameState

The GameStateManager / GameStateClient mungkin merupakan sistem yang paling rumit dalam pengalaman, karena berurusan dengan:

  • Memulai pemain di dalam lobi, memulai hitung mundur untuk teleportasi kelompok ke area permainan utama, dan teleportasi pemain ke server yang direservasi.
  • Mengkloning kamar yang rusak, menyinkronisasi mereka, dan meneleportasi pemain ke dan dari koordinat Datatype.CFrame tertentu.
  • Mengambil dan menempatkan mekanik tanda tangani.
  • Mengunci dan membuka kunci pintu.
  • Menginisialisasi teleport terakhir ke foyer dan bermain adegan akhir.

Kami menerapkannya sebagai mesin negara sederhana (Update function), dan negara-negara ada di DemoConfig (GameStates enum). Beberapa negara menangani berteleportasilobi/diberikan server, sementara yang lain menangani menemukan misi, mengaktifkan puzzle, dan menyelesaikan misi. Catat bahwa selain seals, kami mencoba untuk tidak memiliki kode misi di GameStateManager .

GameStates adalah sebagian besar server-side, tetapi ketika klien perlu melakukan sesuatu, seperti menunjukkan countdown, lore, atau menonaktifkan streaming pause UI, server dan klien (GameStatusClient) berkomunikasi melalui acara remote yang disebut GameStateEvent . Seperti kebanyakan kasus, data acara setelah itu adalah data acara "jenis" (Config.GameEvents) sebagai parameter pertama.

Status Permainan Teleportasi

Ada sekelompok 3 game state yang menjalankan tiga cutscene unik yang menyembunyikan teleportasi ke ruangan yang rusak: Warmup, In

Saat streaming sedang ditangani, InFlight berjalan, menjaga layar gelap yang sedikit berdengung. Saat Class.Player.RequestStream

Sebuah set serupa dari Warmup, InFlight, dan Cooldown cutscenes terjadi ketika kami mengirim pemain kembali ke status normal dari ruangan, TeleportWarmupBack , TeleportInFlightBack

Status Permainan Lighting dan Atmosphere

Kami tahu bahwa kami ingin setiap ru

Mengunci Status Pintu

Manajer Acara

EventManager memungkinkan kita untuk mengeksekusi "tindakan" selama waktu dengan menggunakan keyframe, seperti:

  • Menginterpolasi propinsi dan属性 instans.
  • Menjalankan skrip.
  • Memutar audio.
  • Menjalankan trem kamera.

Kami idealnya menggunakan alat dengan UI berbasis track, tetapi untuk demo ini, kami mengetik kunci dan nama propinsi secara manual. Sistem EventManager terdiri dari beberapa script dan acara/fungsi, termasuk:

  • EventManager - Logika umum untuk menciptakan dan menghentikan acara, serta tindakan sisi server.
  • EventManagerClient - Tindakan pihak klien.
  • EventManagerModule - Kode umum untuk kedua tindakan server dan client.
  • EventManagerConfig - File kecil dengan beberapa deklarasi komando.
  • EventManagerDemo - Di mana semua acara aktual untuk demo ini di definisikan dalam naskah khusus game.
  • EventManagerEvent , EventManagerFunc - Fungsi acara dan terikat jauh untuk mengeksekusi dan menghentikan acara dari klien atau server. Ini adalah cara sistem lain dapat mengatur, mengeksekusi, dan menghentikan acara.

Setiap acara memiliki nama, bagian dengan informasiopsional tentang cooldown, fungsi untuk dijalankan pada awal atau akhiri, parameter acara, dan bagian dengan interpolator (menginterpolasi setiap nomor proporsi atau属ribut selama waktu), skrip (mengeksekusikan skrip terdaftar di keyframe), dan bola kamera, dan bermain audio.

Menerjemahkan

Interpolation memungkinkan속性 dan属性 objek dengan mudah beralih dari satu nilai ke nilai lain tanpa melompat secara bergantian di antara keyframe.Kami mendefinisikan interpolant untuk mengubah berbagai efek visual; misalnya, kode berikut menunj


interpolants = {
objectParam = "TextLabel",
property = "TextTransparency",
keys = {
{value = 1},
{time = .5, value = 0},
{time = 2.25, value = 0},
{time = 3, value = 1}
}
}

Sementara kami dapat mendefinisikan mana atribut atau objek mana yang dimiliki oleh objek seperti dalam contoh kode berikut, kami ingin dapat menggunakan ulang acara yang sama di berbagai "kelompok objek" untuk memungkinkan itu bekerja dengan streaming di klien, dan dengan objek yang dibuat pada waktu pembuatan.


object = workspace.SomeFolder.SomeModel

Untuk mencapai ini, kami mengizinkan referensi oleh nama objek dan menyebutkan parameter nama pada saat pemulaan acara. Untuk menemukan objek bernama, kami mengizinkan spesifikasi "akar" untuk acara, yang memungkinkan objek ditemukan berdasarkan nama di bawah ini saat acara dimulai. Mis


params = {
["RootObject"] = workspace.Content.Interior.Foyer["Ritual-DemoVersion"],
},
interpolants = {
objectName = "Wander",
attribute = "TimeScale",
keys = {
{value = 0.2}
}
}

Kami mengizinkan menyampaikan parameter ke dalam acara di bagian param, dan skrip yang dijalankan pada saat acara dimulai dapat mengubah parametar yang ada, atau menambahkan lebih banyak parameter ke tabel param. Dalam contoh berikut, kami memil


params = {
isEnabled = false
},
interpolants = {
{
objectName = "FocuserGlow",
property = "Enabled",
keys = {
{valueParam = "isEnabled"}
}
}

Parameter memungkinkan kita untuk mengacu pada objek yang bahkan tidak ada di awal pengalaman. Misalnya, dalam contoh kode berikut, fungsi yang dijalankan pada saat pembukaan acara akan menciptakan objek, dan menetapkan entri BlackScreenObject di parametre untuk menunjuk ke objek yang dibuat.


{objectParam = "BlackScreenObject",
property = "BackgroundTransparency",
keys = {
{value = 0},
{time = 19, value = 0},
{value = 1},
}}

Menyiarkan Acara, Instans Acara, dan Menghubungkan dengan Trigger

Untuk mengeksekusi acara, kami menggunakan acara remote dari klien, atau fungsi dari server. Dalam contoh berikut, kami menyebutkan beberapa parameter kepada RootObject dan isEnabled acara. Secara internal, instans deskripsi acara dibuat, parameter dibuat ke objek aktual, dan fungsi mengembalikan id untuk kejadianacara.


local params = {
RootObject = workspace.Content.Interior.Foyer["Ritual-DemoVersion"]["SealDropoff_" .. missionName],
isEnabled = enabled
}
local eventId = eventManagerFunc:Invoke("Run", {eventName = "Ritual_Init_Dropoff", eventParams = params} )

Kita bisa berhenti menjalankan acara dengan menyebutkan fungsi "Stop":


eventManagerFunc:Invoke("Stop", {eventInstId = cooldownId} )

Interpolants atau tindakan lain yang "cosmetic" (jangan mengubah simulasi untuk semua pemain) dapat dijalankan di klien, yang dapat menyebabkan interpolasi yang lebih halus. Dalam deskripsi acara, kami dapat menyediakan nilai default untuk semua tindakan sebagai onServer = true (tanpa itu, default adalah klien). Setiap tindakan dapat menyebar melalui menetapkan nilai sendiri di onServer.

Untuk dengan mudah menghubungkan menjalankan acara ke pemutar, kami menggunakan fungsi pembantu ConnectTriggerToEvent atau ConnectSpawnedTriggerToEvent, yang kemudian menemukan pemutar berdasarkan nama. Untuk memungkinkan acara yang

Parameter Acara

Selain parameter acara khusus yang dilewati dari skrip, data lain yang dapat diberikan ketika membuat acara termasuk pemain, panggilan (untuk dipanggil ketika acara berakhir), dan penggunaan panggilan. Beberapa acara harus dijalankan hanya untuk satu pemain (acara dengan tindakan berlangsung di klien), sementara yang lain harus dijalankan untuk semua. Unt

Acara dapat memiliki cooldown yang didefinisikan oleh minCooldownTime dan maxCooldownTime. Min dan max menyediakan rentang untuk skalasi berdasarkan jumlah pemain, tetapi kami tidak meng

Memanggil Skrip

Kita bisa memanggil Scripts di keyframe tertentu di bagian Skrip . Misalnya:


scripts = {
{startTime = 2, scriptName = "EnablePlayerControls", params = {true}, onServer = false }
}

Dalam contoh sebelumnya, EnablePlayerControls Script harus terdaftar dengan modul manajer acara, seperti berikut:


emModule.RegisterFunction("EnablePlayerControls", EnablePlayerControls)

Fungsi RegisterFunction harus dipanggil dalam script klien untuk fungsi yang dipanggil di klien, dan dalam script server untuk onServer = true . Fungsi itu sendiri akan mendapatkan eventInstance dan parameter dilewati, tetapi dalam kasus ini, hanya satu parameter yang dilewati dengan nilai benar.


local function EnablePlayerControls(eventInst, params)

Memutar Audio

Kami memiliki dukungan terbatas untuk bermain non-positional audio di keyframe di bagian Suara , misalnya:


sounds = {
{startTime = 2, name = "VisTech_ethereal_voices-001"},
}

Catat bahwa panggilan acara selesai dimatikan saat durasi acara berakhir, tetapi tindakan audio mungkin masih berjalan setelahnya.

Menjalankan Guncangan Kamera

Kita bisa mendefinisikan getaran kamera di bagian cameraShakes , seperti berikut:


cameraShakes = {
{startTime = 15, shake = "small", sustainDuration = 7, targets = emConfig.ShakeTargets.allPlayers, onServer = true},
}

“targets” dapat diinisialisasi hanya untuk pemain yang mengaktifkan acara, semuaPlayer, atau pemainInRadius ke pemain yang mengaktifkan acara. Kami menggunakan script pihak ketiga untuk guncangan kamera, dan guncangan tersebut telah dipraktis: eventManagerDemo.bigShake dan eventManagerDemo.smallShake .

Misi Logik

Ada 7 misi total, dan hanya 6 dari mereka yang menggunakan selubung. Kebanyakan misi memiliki parameter umum, meskipun beberapa hanya untuk misi dengan selubung dan teleportasi ke ruang yang rusak. Setiap misi memiliki entri di script DemoConfig dengan set serangkaian parameter di peta Config.Missions :

  • MissionRoot : Folder semua versi non-corrupt dari objek.
  • Pintu : Pintu untuk menahan sampai seorang pemain mengambil kunci.
  • SealName / SolvedSealName : Nama seal dan nama seal yang tidak bermasalah.
  • SealPlaceName : Tempat untuk menempatkan selubung.
  • Tempat penempatan sealPlaceholderName : Objek penempatan di tempat untuk menempatkan seal.
  • TeleportPositionsName : Nama dari folder dengan meshes pengganti untuk mendefinisikan posisi dan rotasi pemain saat pindah ke ruangan yang rusak, dan kembali ke area normal. Nama yang sama digunakan dalam kedua kasus.
  • CorruptRoomName : Nama klasir root (relatif terhadap ServerStorage) untuk ruang korup. Klon ruang korup di bawah TempStorage.Cloned saat misi dimulai, dan mereka dihancurkan saat misi selesai.
  • MissionCompleteButtonName : Tombol cheat di kamar-kamar yang rusak untuk menyelesaikan misi secara instan. Ini untuk tujuan debugging .
  • CheatKey : Cheat yang sama seperti nomor atau CtrlShift[Number] .

Beberapa logika misi ada di GameStateManager skrip, karena seals dan pintu memberikan aliran permainan utama untuk kebanyakan misi, tetapi sebagian besar logika misi khusus ada di MissionsLogic dan 2> MissionsLogicClient2> skrip yang mendefinisikan

  • Gunakan kunci pada kunci. - Pertama misi untuk membuka pintu. Jenis ini ditentukan oleh LockName , KeyName .
  • Menghubungkan item. - 4 misi menghubungkan item. Jenis ini ditentukan oleh MatchItems.
  • Berpakaian mannequin menggunakan pakaian berkilau - 1 misi di lantai atap memiliki pemain mengumpulkan tiga item. Jenis ini ditentukan oleh DressItemsTagList .
  • Klik item untuk menyelesaikan - 1 misi memiliki ketikini, yang ditentukan oleh ClickTargetName.

Setiap jenis misi memiliki fungsi pemulai sendiri StartMissionFunc dan CompleteMissionFunc . Fungsi pemulai biasanya membaca parameter

Logika mencocokkan item memungkinkan untuk "menggunakan" (klik saat menahan) item yang ditandai dengan PuzzlePieceXX tag di atas item dengan PuzzleSlotXXY tag. Ada beberapa opsi tersedia sebagai parameter dalam MatchItems map

Mengambil

Kami mengembangkan sistem penangkapan sederhana untuk mengambil objek dengan menghubungkan objek ke lengan kanan karakter. Penang

Pada setiap frame, kami memeriksa apakah upaya penangkapan sedang berlangsung. Jika pemain berada di dalam mencapaiDist , kami memulai bermain ToolHoldAnim . Ketika pemain berada di dalam mencapai maxGrabDistance, klien mengeksekusi permintaan ke server untuk benar-benar mengambil model ( 2> ployGrab2> fungsi).

Skrip sisi server memiliki 2 fungsi utama:

  • Tangkap - Mengambil permintaan klien untuk mengambil model.
  • Rilis - Mengelola permintaan untuk melepaskan model yang diambil.

Informasi tentang apa yang dimiliki setiap pemain dipertahankan dalam peta playerInfos . Dalam fungsi grab, kami memeriksa apakah model ini sudah diambil oleh pemain lain. Jika demikian - "EquipWorldFail" dikirim ke klien, dan itu men取消 berupayagrab. Catat bahwa kami perlu menangani situasi di mana pemain mengambil bagian yang ber

Jika menangkap diizinkan, script menciptakan dua Attachments , satu di sebelah kanan dan satu di sebelah kiri objek meng

Untuk melepaskan model yang disambut, script klien terhubung ke tombol GrabReleaseButton di HUD ScreenGUI. Fungsi Connected mengeksekusi acara ke server. Di server, melepaskan menghapus data Attachments dan 2>