Roblox Guidebookقاعدة المعرفة
العربية ⌄

التطوير / ROBLOX

ProximityPrompt في Roblox: محطة تدريب بلوحة مفاتيح ويد تحكم ولمس

أنشئ مصباحاً مثبتاً مستقلاً مع Attachment وProximityPrompt. أسماء واضحة وشروط ظهور وفحص خادم وخطة اختبار أجهزة غير معبأة.

موضع المحطة والسكربتافتح الصورة بالحجم الكامل ↗
رسم أصلي؛ يحتاج الكود الأسماء الدقيقة.
آخر تحديث:

محطة واحدة وفعل مفهوم واحد #

تخيل نموذجاً مستقلاً: يقترب اللاعب من مصباح صغير ويبدل ضوءه. بدلاً من البحث عن زر غير مرئي يرى العنصر والفعل وإرشاد الإدخال المناسب. نستخدم ProximityPrompt القياسي وScript خادم عادياً. لا توجد مكافآت أو عملة أو مشتريات.

هذا تمرين مستقل لا تعديل لـPaws and Finds أو Cloud Nests أو ألعاب المؤلف الأخرى. الكود الأصلي يستهدف البنية المحددة؛ الفحص الساكن لا يعني تشغيله بمحرك Studio. احفظ مشروع تدريب منفصلاً، وطابق الأسماء في الرسم، وحدد النتيجة المتوقعة: يتغير الضوء ولون المحطة المشتركان، لا مخزون شخصي. وضوح النطاق يجعل تفسير النتيجة أسهل قبل توسيع النظام.

1. ابنِ التسلسل الدقيق في Explorer #

أنشئ Part باسم PracticeStation في Workspace. أضف داخله Attachment باسم PromptAnchor وPointLight باسم PracticeLight. داخل PromptAnchor ضع ProximityPrompt باسم SwitchPrompt. هما فرعان: الضوء داخل القطعة والإرشاد داخل المرفق. لا تضع الإرشاد بجوار Attachment بالخطأ.

أنشئ Script عادياً باسم PracticeStationServer في ServerScriptService، وفعله واضبط RunContext على Server. لا تستبدله بـLocalScript. يجب تطابق الأسماء حرفياً. ينتظر WaitForChild الاسم المحدد ولا ينشئ عنصراً مفقوداً. عند انتظار التنفيذ قارن الشجرة بالرسم أولاً. وجود SwitchPrompt في فرع مختلف مشكلة بنية لا مسافة، وتغيير مدى التفعيل لا يصلح اسماً أو موضعاً خاطئاً.

2. ثبت المصباح وضع نقطة الإرشاد #

للتمرين اضبط PracticeStation على Anchored=true وSize=(4,2,4) وPosition=(0,3,0). هذه قيمنا التعليمية لا شروط المحرك. ضع SpawnLocation قريباً وخارج القطعة ليتمكن اللاعب من الاقتراب. PromptAnchor.Position=(0,2,0) إزاحة محلية بالنسبة إلى المحطة وليست إحداثية عالمية مستقلة.

يمكن البدء بـBrightness=2 وRange=12 في PracticeLight. يبدأ السكربت بالضوء مطفأ. لا تضف نموذجاً معقداً أو وصلات متحركة أو نظام مكافآت موجوداً لهذا الفحص. تعطي القطعة المثبتة مرجعاً مستقراً؛ يقيس الخادم لاحقاً إلى anchor.WorldPosition. نقل المرفق يغير نقطة التفاعل، لذلك أعد فحص الحد بعد النقل ولا تفترض بقاء نتيجة الموقع القديم.

3. سمِّ العنصر والفعل بلغتك #

يجيب ObjectText عن «ما هذا؟» وActionText عن «ماذا سأفعل؟». اخترنا بالعربية «مصباح التدريب» و«تبديل الضوء». يحتوي الكود أزواجاً للغات ru/en/de/es/zh/ar. اختر لغة المشهد في UI_LANGUAGE، مثلاً "ar". لا تترجم أسماء Explorer مثل PracticeStation وSwitchPrompt.

هذا يحدد لغة واحدة لكل خادم الاختبار، لا لغة كل لاعب آلياً. يبقي AutoLocalize=false النصوص المختارة بلا استبدال تلقائي. تحتاج اللعبة متعددة اللغات إلى تصميم توطين مستقل وفحص النصوص الطويلة. لا تضع E داخل ActionText؛ اشرح الفعل، والإرشاد القياسي يعرض الإدخال بحسب طريقة التحكم الحالية. القاموس إعداد تمرين لا نظام توطين شخصي مكتمل لكل مستخدم.

4. افصل لوحة المفاتيح ويد التحكم واللمس #

يستخدم المثال KeyboardKeyCode=E وGamepadKeyCode=ButtonX وClickablePrompt=true. لا تعد كل لاعب برؤية E؛ يؤثر نوع الإدخال الحالي في العرض القياسي. يستطيع الهاتف أو اللوح التفاعل بالنقر على الشاشة؛ حتى ClickablePrompt=false لا يمنع النقر المحمول. هذه الخاصية ليست مفتاحاً عاماً لإيقاف الوصول باللمس.

يطلب HoldDuration=0.3 استمرار الضغط في الواجهة العادية، بينما 0 يعني التفعيل الفوري. اخترنا 0.3 للتدريب ولم نقسه كأفضل قيمة. جرب ضغطاً قصيراً وآخر كاملاً ثم إفلاتاً. بداية الاستمرار ليست إذناً لإنتاج النتيجة. يستخدم مثال الخادم حدث Triggered للاكتمال، لا حدث بداية الضغط؛ فهم الفرق أهم من جعل كل فعل معلقاً على أول إشارة.

5. الظهور وإذن الفعل أمران مختلفان #

يحدد MaxActivationDistance=10 مدى ظهور الإرشاد. يأخذ RequiresLineOfSight=true مساراً واضحاً من الكاميرا إلى العنصر؛ ليس القياس من HumanoidRootPart إلى Attachment. قد يخفي الجدار أو موضع الكاميرا الواجهة قرب المحطة. افحص سبباً واحداً: المسافة ثم الرؤية.

الإرشاد المخفي لا يستبدل قاعدة وصول الخادم. يمكن تغيير خصائص الواجهة في العميل. يفحص المثال شخصية حية ومسافة ومحطة مقصودة، لكنه لا ينفذ حظر خادم للتفاعل عبر جدار. إذا كانت العوائق مهمة لميكانيكيتك، صمم فحصاً إضافياً وفق قواعدها. لا تعتبر RequiresLineOfSight حماية جاهزة لباب أو شراء. المصباح هنا بسيط ولا يحول هذا القيد إلى تصريح بسلامة أنظمة أخرى.

الإعدادقيمة المثالما نفحص
ActionText / ObjectTextتبديل الضوء / مصباح التدريباسم الفعل والعنصر؛ UI_LANGUAGE="ar"
KeyboardKeyCode / GamepadKeyCodeE / ButtonXإرشاد مناسب للإدخال الحالي
ClickablePrompttrueالنقر واللمس؛ false لا يمنع النقر المحمول
HoldDuration0.3 ثانيةضغط قصير وكامل وإلغاء
MaxActivationDistance10حد الظهور ومسافة خادم منفصلة
RequiresLineOfSighttrueرؤية الكاميرا لا إذن الخادم
COOLDOWN0.5 ثانية، مشتركالتكرار السريع لا يبدل المصباح

6. صل معالج خادم واحداً #

ضع المثال الأصلي التالي في PracticeStationServer. بدايته تجد أربعة عناصر وتفحص أنواعها وتختار الأسماء وتضبط الخصائص، ثم تبدأ بالضوء مطفأ. لا تشغل نسخة ثانية معه: قد يبدل معالجان الحالة مرتين فيبدو الفعل بلا نتيجة.

يمرر Triggered اللاعب الذي أكمل التفاعل. يبحث الخادم عن شخصيته ويفحص الشروط قبل تغيير المصباح. لا يوجد انتظار بين فحص الفاصل وتغيير الحالة. لا نضيف RemoteEvent أو طلب سعر أو حفظاً؛ الفعل كله تبديل مصباح تدريب مشترك. إذا اختلط نوع العنصر وموضع التنفيذ، اقرأ أولاً دليل Script وLocalScript وModuleScript. نقل النص بين الحاويات لا يضمن تشغيله بالطريقة نفسها.

local Players = game:GetService("Players")
local station = workspace:WaitForChild("PracticeStation")
assert(station:IsA("BasePart") and station.Anchored, "Anchor PracticeStation")
local anchor = station:WaitForChild("PromptAnchor")
assert(anchor:IsA("Attachment"), "PromptAnchor must be an Attachment")
local prompt = anchor:WaitForChild("SwitchPrompt")
assert(prompt:IsA("ProximityPrompt"), "SwitchPrompt must be a ProximityPrompt")
local light = station:WaitForChild("PracticeLight")
assert(light:IsA("PointLight"), "PracticeLight must be a PointLight")

local UI_LANGUAGE = "en" -- Choose one language for this whole test server.
local labels = {
    ru = {action = "Переключить свет", object = "Учебная лампа"},
    en = {action = "Switch light", object = "Practice lamp"},
    de = {action = "Licht umschalten", object = "Übungslampe"},
    es = {action = "Cambiar la luz", object = "Lámpara de práctica"},
    zh = {action = "切换灯光", object = "练习灯"},
    ar = {action = "تبديل الضوء", object = "مصباح التدريب"},
}
local words = assert(labels[UI_LANGUAGE], "Unknown UI_LANGUAGE")
local MAX_DISTANCE = 10
local COOLDOWN = 0.5
prompt.Style = Enum.ProximityPromptStyle.Default
prompt.AutoLocalize = false
prompt.ActionText = words.action
prompt.ObjectText = words.object
prompt.KeyboardKeyCode = Enum.KeyCode.E
prompt.GamepadKeyCode = Enum.KeyCode.ButtonX
prompt.ClickablePrompt = true
prompt.HoldDuration = 0.3
prompt.MaxActivationDistance = MAX_DISTANCE
prompt.RequiresLineOfSight = true
prompt.Enabled = true

local isOn = false
local lastToggle = -COOLDOWN
light.Enabled = false
station.Color = Color3.fromRGB(70, 80, 95)
station:SetAttribute("PracticeLightOn", false)

prompt.Triggered:Connect(function(player)
    if player.Parent ~= Players or not prompt.Enabled then return end
    if not station:IsDescendantOf(workspace) or not station.Anchored then return end
    local character = player.Character
    if not character or not character:IsDescendantOf(workspace) then return end
    local humanoid = character:FindFirstChildOfClass("Humanoid")
    local root = character:FindFirstChild("HumanoidRootPart")
    if not humanoid or humanoid.Health <= 0 then return end
    if not root or not root:IsA("BasePart") then return end
    local distance = (root.Position - anchor.WorldPosition).Magnitude
    if distance ~= distance or distance > MAX_DISTANCE then return end
    local now = os.clock()
    if now - lastToggle < COOLDOWN then return end
    lastToggle = now
    isOn = not isOn
    light.Enabled = isOn
    station.Color = isOn and Color3.fromRGB(255, 190, 80) or Color3.fromRGB(70, 80, 95)
    station:SetAttribute("PracticeLightOn", isOn)
end)

7. اقرأ الشروط قبل سطر التبديل #

يتطلب المعالج لاعباً في Players وإرشاداً مفعلاً ومحطة مثبتة في Workspace. ثم يتطلب شخصية في العالم وHumanoid بصحة Health>0 وHumanoidRootPart من نوع BasePart. يحسب الخادم المسافة إلى PromptAnchor.WorldPosition ويقارن بحد العشر وحدات نفسه. الحالات المفقودة أو غير المناسبة لا تغير الضوء.

توضح الوثائق أن Triggered لديه فحص مسافة خاص على الخادم، بينما أحداث الإرشاد الأخرى لا تملكه. يظل فحصنا الصريح تعبيراً عن قاعدة النموذج. HoldDuration لا يثبت ضغطاً صادقاً من العميل. ليست هذه حماية كاملة لكل نظام؛ الحقوق والعوائق والموارد الإضافية تعتمد على الفعل، ولا توجد هنا متطلبات مكافأة تحتاج إلى منح أو حفظ.

من الإدخال إلى الضوء المشتركافتح الصورة بالحجم الكامل ↗
رسم المثال لا تقرير اختبار محرك.

8. افهم الحالة المشتركة والفاصل القصير #

isOn حالة محطة واحدة في هذا الخادم. يغير الفعل المقبول PointLight.Enabled ولون Part والسمة PracticeLightOn. ينبغي لعميل آخر تتاح له المحطة مشاهدة الحالة المشتركة نفسها. ليست إضاءة شخصية لكل لاعب. يبدأ خادم آخر أو تشغيل جديد مطفأ لعدم وجود حفظ.

COOLDOWN=0.5 فاصل مشترك للمحطة اختير للشرح. الطلب التالي الأسرع لا يبدلها. يختلف عن مدة استمرار الضغط ولا يضمن تقييد كل حمل ممكن. اترك الفاصل في فحص عميلين: يشغل أ، يلاحظ ب، يبدل ب، يلاحظ أ. فعل ب المقبول ليس دليلاً على فساد حالة أ؛ اشرح القاعدة المشتركة قبل الحكم على المشهد متعدد اللاعبين.

9. متى يفيد ProximityPromptService #

يكفي prompt.Triggered لمحطة واحدة. يراقب ProximityPromptService إرشادات مختلفة من مكان مركزي؛ يتلقى PromptTriggered الإرشاد أولاً ثم اللاعب. عند التوسع حدد المحطات المسموحة بدلاً من تنفيذ العملية لكل Prompt تجده في العالم.

لا تربط معالج العنصر ومعالج الخدمة بالمصباح نفسه دون سبب، فقد يعالج فعل واحد مرتين. أحداث الظهور والاختفاء تخص عرض العميل خاصة مع UI مخصص. يوفر Style=Default الواجهة القياسية هنا، فلا تحتاج إلى LocalScript يرسمها. ادرس المظهر الخاص بعد بنية تعمل وعملية خادم واضحة. يفيد التنظيم المركزي لكنه لا يلغي فحص كل فعل، ولا يحول تلقائياً حالة مشتركة إلى نتيجة شخصية.

10. ابحث عن سبب محدد عندما لا يظهر شيء #

إذا غاب الإرشاد افحص التسلسل وEnabled والمسافة وStyle والكاميرا. قد تتنافس إرشادات عديدة وفق Exclusivity في مشهد مزدحم؛ فحصنا الأول يستخدم محطة واحدة عمداً. لا تغير كل الخصائص معاً. اقترب برؤية واضحة، غير إعداداً واحداً وسجل ما حدث.

إذا ظهر الإرشاد ولم يتغير الضوء، افحص Output الخادم ونوع Script وRunContext والأسماء والفاصل. إذا تغير اللون بلا إضاءة، افحص PointLight وRange وBrightness وظروف المشهد منفصلة. تستخدم فروع الرفض return بلا طباعة السبب؛ قارن حالة الشخصية والمحطة بشروط الكود. تميز سمة الخادم حالة المنطق من انطباع السطوع. تظل نتائج جدول السيناريوهات فارغة إلى حين فحص فعلي. التوقع ليس ملاحظة، والكود المكتوب ليس تقرير اختبار جهاز.

السيناريوالمتوقع في المثالالجهاز / النسخة / النتيجة
شخصية حية قريبة وإدخال كاملتغير الضوء واللون والسمة مرة—
ضغط قصير ثم إفلاتلا اكتمال متوقع في UI العادي—
شخصية بعيدة/ميتة أو إرشاد متوقفالمعالج لا يغير الحالة—
تكرار قبل نهاية الفاصللا تبديل ثانياً—
عميلان وفعل بعد الفاصلكلاهما يلاحظ المحطة المشتركة—
هاتف/يد تحكم ولغة مختارةإدخال مناسب ونصوص مقروءة—

11. افصل المادة المفحوصة عن اختبار المحرك #

فُحصت بنية المقال واستخدام API مقابل المراجع الرسمية. اجتاز المثال مترجم Luau و13 فحصاً معزولاً للمعالج بكائنات بديلة. لم يعمل الكود في Roblox Studio أو هاتف أو يد تحكم حقيقيين. في المشروع المنفصل ابدأ بلاعب ثم افحص المسافة وإلغاء الضغط وإيقاف الإرشاد والتكرار السريع.

استخدم Test/F5 مع شخصية؛ Run/F8 دون شخصية لا يستبدل فحص التفاعل. لعميلين اختر Server & Clients وأنهِ الجلسة عبر End Session. بعدها افحص الأجهزة المطلوبة مع حفظ النسخة والملاحظات. تساعد المحاكاة في رؤية الترتيب ولا تستبدل إدخالاً أو أداء حقيقيين. نقل الفكرة لمنح حيوان أو شراء يعني نظاماً آخر بحقوق ومنح متسق واختبارات مستقلة. احصل أولاً على نتيجة واضحة في مصباح تدريب بسيط. هذا المثال المحدد أسهل للشرح وتسليمه لمطور آخر، ويبين بوضوح ما فُحص وما لا يزال يحتاج إلى تحقق.

المصادر الأصلية

Roblox Creator Hub — Proximity prompts
ProximityPrompt
ProximityPromptService
Securing the client-server boundary
Studio testing modes