หลังจากสร้างสคริปต์ไปไม่กี่ตัว คุณจะต้องการนำโค้ดบางส่วนกลับมาใช้ระหว่างกันในไม่ช้า ขึ้นอยู่กับ ตำแหน่ง ModuleScripts ช่วยให้คุณนำโค้ดกลับมาใช้ใหม่ระหว่างสคริปต์ในสองฝั่งของขอบเขตคลิปหรือในฝั่งเดียวกันของขอบเขต
คุณสามารถวางโมดูลสคริปต์ไว้ที่ใดก็ได้ที่คุณใส่สคริปต์ แต่ ReplicatedStorage เป็นตำแหน่งที่ได้รับความนิยม; การจัดเก็บโมดูลสคริปต์ที่นี่ช่วยให้คุณใช้งานโค้ดเดียวกันระหว่างเซิร์ฟเวอร์และไคลเอ็นต์
โครงสร้างของโมดูลสคริปต์
ใน Roblox Studio ให้เพิ่มโมดูลสคริปต์ไปยัง ReplicatedStorage และเปลี่ยนชื่อเป็น PickupManager โดยแต่ละ ModuleScript จะเริ่มต้นด้วยโค้ดต่อไปนี้:
local module = {}return module
โค้ดนี้สร้าง ตาราง เปล่าใน Luau และคืนค่ามันไปยังสคริปต์ใดๆ ที่เรียกใช้โมดูลสคริปต์
ค่าที่คืนสามารถเป็น ประเภทข้อมูล ใดก็ได้ยกเว้น nil แต่โมดูลสคริปต์ส่วนใหญ่จะคืนค่าฟังก์ชัน ตาราง หรือฟังก์ชันในรูปแบบของตาราง เพื่อสร้างค่าที่คืน โมดูลสคริปต์สามารถรันโค้ดตามต้องการ ซึ่งรวมถึงการเรียกใช้งานโมดูลสคริปต์อื่น
ตัวอย่างต่อไปนี้จะคืนตารางที่มีฟังก์ชันเดียวชื่อว่า getPickupBonus ให้วางมันลงในโมดูลสคริปต์ใหม่:
-- โมดูลสคริปต์ใน ReplicatedStorage
local PickupManager = {}
local defaultMultiplier = 1.25
local rarityMultipliers = {
common = 10,
uncommon = 20,
rare = 50,
legendary = 100
}
-- เพิ่มฟังก์ชัน getPickupBonus ลงในตาราง PickupManager
PickupManager.getPickupBonus = function(rarity)
local bonus = rarityMultipliers[rarity] * defaultMultiplier
return bonus
end
return PickupManager
การเพิ่มฟังก์ชันลงในตารางไม่จำเป็นต้องทำก็ได้—คุณสามารถคืนค่าฟังก์ชันเองได้—แต่เป็นรูปแบบที่ดีในการทำตาม; มันทำให้คุณมีไวยากรณ์ที่เข้าใจง่ายเมื่อคุณเรียกใช้ฟังก์ชันจากสคริปต์อื่นและช่วยให้คุณเพิ่มฟังก์ชันเพิ่มเติมให้กับโมดูลสคริปต์ได้ในอนาคต
เรียกใช้โมดูลสคริปต์
ในการโหลดโมดูลสคริปต์ คุณเรียกใช้ฟังก์ชัน require() ใน ReplicatedStorage ให้เพิ่มสคริปต์ใหม่และเปลี่ยน RunContext เป็น Client จากนั้นให้เพิ่มโค้ดต่อไปนี้เพื่อเรียกฟังก์ชัน PickupManager.getPickupBonus:
คลิปสคริปต์ใน ReplicatedStoragelocal ReplicatedStorage = game:GetService("ReplicatedStorage")-- รับค่าที่คืนจากโมดูลสคริปต์local PickupManager = require(ReplicatedStorage:WaitForChild("PickupManager"))-- เรียกใช้ฟังก์ชันจากโมดูลสคริปต์local bonus = PickupManager.getPickupBonus("legendary")print(bonus) --> 125
การเก็บโมดูลสคริปต์ใน ReplicatedStorage ช่วยให้คุณแชร์โค้ดระหว่างเซิร์ฟเวอร์และไคลเอนต์ ดังนั้นคุณสามารถใช้โค้ดเดียวกันเพื่อเรียกใช้สคริปต์จาก ServerScriptService:
สคริปต์ใน ServerScriptServicelocal ReplicatedStorage = game:GetService("ReplicatedStorage")local PickupManager = require(ReplicatedStorage:WaitForChild("PickupManager"))
เมื่อคุณเรียกใช้ require() บน ModuleScript มันจะทำงานเพียงครั้งเดียวและคืนค่าไอเทมหรือตัวอ้างอิงเดียว เมื่อเรียก require() อีกครั้งจะคืนค่าอ้างอิงเดียวกัน หมายความว่าหากคุณแก้ไข ตาราง หรือ Instance ที่คืนค่ามา การเรียกใช้ require() ที่ตามมาจะคืนค่าอ้างอิงที่แก้ไขแล้ว โมดูลสคริปต์จะไม่ได้ทำงานหลายครั้ง
หากคุณเรียกใช้ ModuleScript จากทั้งสองฝั่งของขอบเขตเซิร์ฟเวอร์-ไคลเอนต์ เช่น ในตัวอย่างข้างต้น ModuleScript จะคืนค่าอ้างอิงที่ไม่ซ้ำกันสำหรับแต่ละฝั่ง
รูปแบบ
โมดูลสคริปต์มีรูปแบบที่พบบ่อยซึ่งคุณสามารถใช้เพื่อทำให้โค้ดของคุณง่ายขึ้นและหลีกเลี่ยงกับดักขณะที่เกมของคุณขยายขนาดและความซับซ้อน
การแชร์ข้อมูล
เพื่อเชื่อมโยงข้อมูลกับวัตถุแต่ละชิ้น คุณสามารถกำหนดแอตทริบิวต์ให้กับมันหรือสร้างโฟลเดอร์ Configuration พร้อมกับวัตถุค่าชนิดต่างๆ เช่น StringValue หรือ IntValue อย่างไรก็ตาม ทั้งสองแนวทางนี้มีปัญหา ถ้าคุณต้องการเพิ่มหรือแก้ไขวัตถุหรือค่าข้อมูลจำนวนหลายสิบรายการ นอกจากนี้ ยังไม่สามารถจัดเก็บตารางหรือฟังก์ชันได้
หากคุณต้องการปรับเปลี่ยนข้อมูลเดียวกันสำหรับสำเนาหลายชุดของวัตถุเดียวกันหรือทำการนำข้อมูลเดียวกันกลับมาใช้สำหรับวัตถุต่างๆ ให้เก็บข้อมูลใน ModuleScripts ซึ่งเป็นวิธีที่ง่ายกว่าที่จะนำข้อมูลนั้นไปใช้ในสคริปต์อื่นๆ และคุณสามารถจัดเก็บตารางและฟังก์ชันได้
ตัวอย่างต่อไปนี้เป็น ModuleScript ใน ReplicatedStorage ที่เก็บค่าการกำหนดค่าสำหรับปืนทั่วไป:
โมดูลสคริปต์ใน ReplicatedStoragelocal GunConfig = {}GunConfig.MagazineSize = 20GunConfig.AmmoCount = 100GunConfig.Firerate = 600GunConfig.Damage = {["Head"] = 50;["Torso"] = 40;["Body"] = 25;}return GunConfig
เหตุการณ์กำหนดเอง
เหตุการณ์กำหนดเองช่วยให้สคริปต์สื่อสารกับกันและกันได้ แต่การต้องติดตามอ้างอิงไปยังวัตถุ BindableEvent แต่ละตัวสามารถทำให้โค้ดของคุณยุ่งเหยิงได้
คุณสามารถใช้ ModuleScripts เพื่อเก็บ BindableEvents และให้ ตัวจัดการเหตุการณ์กำหนดเองที่เกี่ยวข้องกับวิธีการของ ModuleScript
ตัวอย่างของ ModuleScript ใน ReplicatedStorage มีเหตุการณ์กำหนดเองที่ถูกเรียกใช้เมื่อสวิตช์เปลี่ยนสถานะ:
โมดูลสคริปต์ใน ReplicatedStorage
local Switch = {}
-- สร้าง bindable เพื่อให้สคริปต์สามารถฟังได้เมื่อสวิตช์มีการเปลี่ยนแปลง
local bindableEvent = Instance.new("BindableEvent")
Switch.Changed = bindableEvent.Event
local state = false
function Switch.flip()
state = not state
bindableEvent:Fire(state)
end
return Switch
สคริปต์ไคลเอนต์ต่อไปนี้ใน ReplicatedStorage เชื่อมต่อฟังก์ชันที่จะเรียกเมื่อเหตุการณ์ Switch.Changed ถูกเรียกใช้
สคริปต์ใน ReplicatedStorage
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local Switch = require(ReplicatedStorage:WaitForChild("Switch"))
Switch.Changed:Connect(function(newState)
print("สถานะของสวิตช์ตอนนี้คือ", newState)
end)
-- ทดสอบการพลิกสวิตช์หลายครั้ง
task.wait(1)
Switch.flip()
task.wait(1)
Switch.flip()
การห่อหุ้ม
การห่อหุ้มคือการสร้างชั้นของนามธรรมรอบวัตถุหรือตรรกะการเขียนสคริปต์เพื่อซ่อนความซับซ้อน คุณสามารถใช้ ModuleScripts เพื่อห่อหุ้มวัตถุใน Roblox ด้วยฟังก์ชัน Luau ที่กำหนดเองเพื่อทำให้โค้ดเรียบง่าย
ตัวอย่างเช่น คุณสามารถใช้การห่อหุ้มเพื่อ:
- ทำให้การสื่อสารข้ามเครือข่ายเรียบง่ายด้วยวัตถุ RemoteEvent เดียว
- ห่อหุ้มโค้ดการจัดการข้อผิดพลาดรอบบริการที่สำคัญ เช่น DataStoreService
- กำหนดวิธีการที่กำหนดเองเพื่อควบคุมหรือขยายฟีเจอร์ของวัตถุใน Roblox
การติดตามอ้างอิงไปยังวัตถุ RemoteEvent ทีละตัวเพื่อใช้ในการสื่อสารในเกมอาจเป็นเรื่องยาก คุณสามารถใช้ ModuleScript เพื่อห่อหุ้มวัตถุ RemoteEvent เดียวเพื่อช่วยทำให้ปัญหานี้ง่ายขึ้น โดยการรวม id ที่ไม่ซ้ำกัน คุณสามารถส่งข้อความเครือข่ายที่แตกต่างกันได้โดยใช้เพียง RemoteEvent เดียว
ในตัวอย่างด้านล่าง ModuleScript ที่ชื่อว่า NetworkManagerClient จะห่อหุ้มวิธี RemoteEvent:FireServer() เพื่อรวม id ที่เพิ่มเข้าไป นอกจากนี้ยังอ้างอิงไปยังวัตถุ RemoteEvent เองเพื่อไม่ให้คุณต้องอ้างอิงมันในส่วนอื่นของโค้ด คุณเพียงแค่ต้องเรียกใช้ ModuleScript นี้เพื่อส่งข้อความเครือข่ายโดยไม่ต้องจัดการกับวัตถุ RemoteEvent ในส่วนอื่นของโค้ด
โมดูลสคริปต์ต่อไปนี้ใน ReplicatedFirst ให้ฟังก์ชันที่ห่อหุ้มที่คุณสามารถเรียกใช้ในสคริปต์คลิปของคุณเพื่อส่งข้อความเครือข่าย:
โมดูลเครือข่าย
-- โมดูลสคริปต์ใน ReplicatedFirst ชื่อ NetworkManagerClient
local NetworkManagerClient = {}
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local remoteEvent = ReplicatedStorage:WaitForChild("RemoteEvent")
-- ห่อหุ้มฟังก์ชัน FireServer ของวัตถุ remote
function NetworkManagerClient.FireServer(id, ...)
remoteEvent:FireServer(id, ...)
end
return NetworkManagerClient
โมดูลสคริปต์ต่อไปนี้ใน ServerScriptService ใช้ BindableEvents สำหรับสคริปต์แต่ละตัวเพื่อเชื่อมต่อกับ id ที่เฉพาะเจาะจง เมื่อไคลเอนต์ส่งข้อความเครือข่าย BindableEvent แต่ละอันที่เชื่อมโยงกับ id ที่ระบุจะถูกเรียกใช้
-- โมดูลสคริปต์ใน ServerScriptService ที่ชื่อว่า NetworkManagerServer
local NetworkManagerServer = {}
local networkSignalList = {}
function NetworkManagerServer.GetServerEventSignal(id)
local bindableEvent = Instance.new("BindableEvent")
-- เชื่อมโยง BindableEvent ใหม่กับ id
table.insert(networkSignalList, {
id = id,
bindableEvent = bindableEvent,
})
return bindableEvent.Event
end
-- เชื่อมต่อกับ
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local remoteEvent = ReplicatedStorage:WaitForChild("RemoteEvent")
remoteEvent.OnServerEvent:Connect(function(player, id, ...)
-- หา bindable event ทุกตัวที่ตรงกับ ID ของ remote event ที่ได้รับ
for _, signal in networkSignalList do
if signal.id == id then
signal.bindableEvent:Fire(player, ...)
end
end
end)
return NetworkManagerServer
สคริปต์ไคลเอนต์ต่อไปนี้ส่งข้อความพร้อม ID RequestA และอาร์กิวเมนต์เพิ่มเติม Hello
-- LocalScript ใน ReplicatedFirstlocal ReplicatedFirst = game:GetService("ReplicatedFirst")local NetworkManagerClient = require(ReplicatedFirst:WaitForChild("NetworkManagerClient"))NetworkManagerClient.FireServer("RequestA", "Hello")
ในส่วนนี้ สคริปต์ส่งที่เชื่อมต่อกับข้อความเครือข่าย ID RequestA และพิมพ์ข้อความออกมาพร้อมกับอาร์กิวเมนต์เพิ่มเติมเมื่อมันได้รับคำขอ
-- สคริปต์ใน ServerScriptService
local ServerScriptService = game:GetService("ServerScriptService")
local NetworkManagerServer = require(ServerScriptService:WaitForChild("NetworkManagerServer"))
NetworkManagerServer.GetServerEventSignal("RequestA"):Connect(function(player, ...)
print("ได้รับ RequestA จาก", player, ...)
end)