بعد إنشاء بعض النصوص، لا يمر وقت طويل قبل أن ترغب في إعادة استخدام بعض الكود بينها. وفقًا لـ الموقع، فإن ModuleScripts يتيح لك إعادة استخدام الكود بين النصوص على جوانب مختلفة من حدود العميل والخادم أو على نفس الجانب من الحدود.
يمكنك وضع نصوص الوحدة في أي مكان تضع فيه النصوص، ولكن ReplicatedStorage هو موقع شائع؛ تخزين نصوص الوحدة هنا يتيح لك إعادة استخدام الكود بين الخادم والعملاء.
بنية نص الوحدة
في Roblox Studio، أضف نص وحدة إلى ReplicatedStorage وأعد تسميته إلى PickupManager. يبدأ كل ModuleScript بالشيفرة التالية:
local module = {}return module
تخلق هذه الشيفرة جدولًا فارغًا بلغة لوا table وتعيده إلى أي نص يتطلب نص الوحدة.
يمكن أن تكون قيمة الإرجاع من أي نوع بيانات باستثناء nil، لكن معظم نصوص الوحدة تعيد دالة أو جدولًا أو جدولًا من الدوال. لتوليد قيمة الإرجاع، يمكن أن تقوم نصوص الوحدة بتشغيل كود عشوائي، بما في ذلك مطالبة نصوص الوحدة الأخرى.
المثال التالي يعيد جدولاً يحتوي على دالة واحدة تسمى getPickupBonus. قم بلصقها في نص الوحدة الجديد:
-- ModuleScript في 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:
Client script in ReplicatedStoragelocal ReplicatedStorage = game:GetService("ReplicatedStorage")-- الحصول على القيمة التي تعيدها ModuleScriptlocal PickupManager = require(ReplicatedStorage:WaitForChild("PickupManager"))-- استدعاء دالة ModuleScriptlocal bonus = PickupManager.getPickupBonus("legendary")print(bonus) --> 125
تخزين نصوص الوحدة في ReplicatedStorage يتيح لك مشاركة الكود بين الخادم والعميل، بحيث يمكنك استخدام نفس الكود للمطالبة بالنص من ServerScriptService:
Script in ServerScriptServicelocal ReplicatedStorage = game:GetService("ReplicatedStorage")local PickupManager = require(ReplicatedStorage:WaitForChild("PickupManager"))
عندما تستدعي require() على ModuleScript، يتم تنفيذها مرة واحدة وتعيد عنصرًا واحدًا كمرجع. استدعاء require() مرة أخرى يعيد نفس المرجع بالضبط، مما يعني أنه إذا قمت بتعديل جدول أو Instance المعاد، فإن استدعاءات require() اللاحقة تعيد ذلك المرجع المعدل. لا يتم تشغيل الوحدة نفسها عدة مرات.
إذا كنت تطلب ModuleScript من كلا الجانبين من حدود العميل والخادم، كما في المثال أعلاه، فإن ModuleScript يعيد مرجعًا فريدًا لكل جانب.
الأنماط
توجد بعض الأنماط الشائعة لنصوص الوحدة التي يمكنك استخدامها لتبسيط كودك وتجنب الفخاخ مع نمو لعبتك في الحجم والتعقيد.
مشاركة البيانات
لربط البيانات بأشياء فردية، يمكنك تعيين Attributes لها أو إنشاء مجلدات Configuration تحتوي على عناصر قياسية مثل StringValue أو IntValue. ومع ذلك، فإن كلا الطريقتين تعتبران مزعجتين إذا كنت ترغب في إضافة أو تعديل العشرات من العناصر أو قيم البيانات. كما أنها لا تخزن الجداول أو الدوال.
إذا كنت ترغب في تعديل نفس البيانات لنسخ متعددة من نفس العنصر أو إعادة استخدام نفس البيانات لعناصر مختلفة، قم بتخزين البيانات في ModuleScripts. إنها طريقة أسهل لإعادة استخدام البيانات في نصوص أخرى، ويمكنك تخزين الجداول والدوال.
المثال التالي ModuleScript في ReplicatedStorage يخزن القيم التكوينية لمدفع عام:
ModuleScript in ReplicatedStoragelocal GunConfig = {}GunConfig.MagazineSize = 20GunConfig.AmmoCount = 100GunConfig.Firerate = 600GunConfig.Damage = {["Head"] = 50;["Torso"] = 40;["Body"] = 25;}return GunConfig
الأحداث المخصصة
تمكّن الأحداث المخصصة النصوص من التواصل مع بعضها البعض، ولكن من الصعب تتبع المراجع الفردية لأشياء BindableEvent يمكن أن تزدحم كودك.
يمكنك استخدام ModuleScripts لتخزين BindableEvents وتوفير معالجات أحداث مخصصة ترتبط مباشرة بأساليب ModuleScript.
المثال التالي ModuleScript في ReplicatedStorage يحتوي على حدث مخصص يتم إطلاقه عندما يتغير حالة المفتاح:
ModuleScript in ReplicatedStorage
local Switch = {}
-- إنشاء قابل للاستجابة بحيث يمكن لأي نص الاستماع عندما يتغير المفتاح
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.
Script in 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 لتغليف الكائنات في روبلوكس مع دوال لوا مخصصة لتبسيط الكود.
على سبيل المثال، يمكنك استخدام التغليف لـ:
- تبسيط التواصل عبر الشبكة باستخدام كائن RemoteEvent واحد.
- لفّ كود معالجة الأخطاء حول خدمات حساسة مثل DataStoreService.
- تعريف أساليب مخصصة للتحكم أو توسيع ميزات كائنات روبلوكس.
من الصعب تتبع عشرات من كائنات RemoteEvent الفردية لتنفيذ الشبكات في لعبة. يمكنك استخدام ModuleScript لتغليف كائن RemoteEvent واحد للمساعدة في تبسيط هذه المشكلة. من خلال تضمين حجة id فريدة، يمكنك تشغيل رسائل الشبكة المختلفة بينما تستخدم فقط واحدًا من RemoteEvent.
في المثال أدناه، يقوم ModuleScript المسمى NetworkManagerClient بتغليف دالة RemoteEvent:FireServer() لتضمين هذه الحجة الإضافية id. بالإضافة إلى ذلك، يشير هذا ModuleScript إلى كائن RemoteEvent نفسه بحيث لا تحتاج إلى الإشارة إليه في أجزاء أخرى من كودك. تحتاج فقط إلى مطالبة هذا ModuleScript لإرسال رسائل الشبكة ولا تحتاج إلى التعامل مع كائنات RemoteEvent في بقية قاعدة كودك.
المثال التالي ModuleScript في ReplicatedFirst يوفر دالة مغلفة يمكنك استدعاؤها في نصوص العميل الخاصة بك لإرسال رسالة شبكة:
Network Module
-- ModuleScript في 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
المثال التالي ModuleScript في ServerScriptService يستخدم BindableEvents لكل نص للاتصال بمعرّف محدد. عندما يرسل العميل رسالة شبكة، يتم تشغيل كل BindableEvent المرتبطة بالمعرف المحدد.
-- ModuleScript في ServerScriptService يسمى NetworkManagerServer
local NetworkManagerServer = {}
local networkSignalList = {}
function NetworkManagerServer.GetServerEventSignal(id)
local bindableEvent = Instance.new("BindableEvent")
-- ربط BindableEvent الجديد بالمعرف
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, ...)
-- إيجاد كل حدث قابل للاستجابة الذي يتطابق مع معرف الحدث عن بعد
for _, signal in networkSignalList do
if signal.id == id then
signal.bindableEvent:Fire(player, ...)
end
end
end)
return NetworkManagerServer
المثال التالي LocalScript يرسل رسالة بالمعرف RequestA مع حجة اختيارية Hello.
-- LocalScript في ReplicatedFirstlocal ReplicatedFirst = game:GetService("ReplicatedFirst")local NetworkManagerClient = require(ReplicatedFirst:WaitForChild("NetworkManagerClient"))NetworkManagerClient.FireServer("RequestA", "Hello")
المثال التالي Script يتصل بمعرف رسالة الشبكة RequestA ويطبع بيانًا مع أي معلمات إضافية عندما يتلقى الطلب.
-- Script في ServerScriptService
local ServerScriptService = game:GetService("ServerScriptService")
local NetworkManagerServer = require(ServerScriptService:WaitForChild("NetworkManagerServer"))
NetworkManagerServer.GetServerEventSignal("RequestA"):Connect(function(player, ...)
print("تم استلام RequestA من", player, ...)
end)