إنشاء وإعادة إنعاش

*This content is translated using AI (Beta) and may contain errors. To view this page in English, click here.

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

باستخدام تجربة لعبة الليزر النموذجية كمرجع، يعلمك هذا الجزء من البرنامج التعليمي كيفية استخدام وتخصيص الميزات المدمجة في Roblox للتعامل مع إنشاء وإعادة الإنشاء، بما في ذلك إرشادات البرمجة حول:

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

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

تكوين مواقع الإنشاء

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

لمواجهة هذه المشكلة، تقوم تجربة الليزر النموذجية بتكوين كلا الموقعين باستخدام خاصية Neutral مضبوطة على غير صحيح لتقييد لاعبي الفريق المنافس من الظهور في منطقة الإنجاز الخاطئة، وخاصية TeamColor مضبوطة على القيمة المعنية Team.Color من تخصيص ألوان الفريق في القسم السابق من البرنامج التعليمي:

  • TeamASpawn – موقع الظهور في منطقة إنجاز الفريق الأخضر مع خاصية TeamColor مضبوطة على Mint.
  • TeamBSpawn – موقع الظهور في منطقة إنجاز الفريق الوردي مع خاصية TeamColor مضبوطة على Carnation Pink.
TeamASpawn
TeamBSpawn

عندما ينضم أحد اللاعبين إلى التجربة، فإن ServerScriptServiceGameplayRoundsspawnPlayersInMap يتحقق من عدد اللاعبين الموجودين بالفعل في كل فريق، ثم يعيد الفريق الذي لديه أقل عدد من اللاعبين.

spawnPlayersInMap

local function getSmallestTeam(): Team
local teams = Teams:GetTeams()
-- ترتيب الفرق بترتيب تصاعدي من الأصغر إلى الأكبر
table.sort(teams, function(teamA: Team, teamB: Team)
return #teamA:GetPlayers() < #teamB:GetPlayers()
end)
-- إعادة الفريق الأصغر
return teams[1]
end

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

spawnPlayersInMap

local function spawnPlayersInMap(players: { Player })
for _, player in players do
player.Team = getSmallestTeam()
player.Neutral = false
player:SetAttribute(PlayerAttribute.playerState, PlayerState.SelectingBlaster)
task.spawn(function()
player:LoadCharacter()
end)
end
end

إذا فحصت WorkspaceWorldMapSpawns، يمكنك أن ترى أن هناك موقع إنجاز واحد آخر في الخريطة: NeutralSpawn. هذا الموقع مختلف عن الآخرين لأنه ليس لديه خاصية TeamColor مضبوطة على أحد الفريقين في التجربة؛ بدلاً من ذلك، يحتوي هذا الموقع على خاصية Neutral التي تتغير حسب ما إذا كانت الجولة نشطة.

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

Neutral

لإظهار ذلك، إذا كنت تفحص ServerScriptServiceGameplayRoundsSpawnPlayersInLobby، التي تعمل في نهاية الجولة، يمكنك أن ترى أنه بالنسبة لكل لاعب يتم تمريره إلى جدول players: { Player }، يقوم السكربت:

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

لمزيد من المعلومات حول منطقة الإنشاء المحايدة ووظيفتها لكل جولة، راجع إضافة جولات في القسم التالي من البرنامج التعليمي.

spawnPlayersInLobby

local function spawnPlayersInLobby(players: { Player })
for _, player in players do
player.Neutral = true
player:SetAttribute(PlayerAttribute.playerState, PlayerState.InLobby)
task.spawn(function()
player:LoadCharacter()
end)
end
end

توصيل لاعبين جدد

كود Luau في الاستوديو غالبًا ما يعتمد على الأحداث، مما يعني أن السكربتات تستمع للأحداث من خدمة Roblox ثم تستدعي دالة استجابة. على سبيل المثال، عند إضافة لاعبين جدد إلى تجربة متعددة اللاعبين، يجب أن تكون هناك حدث تتعامل معه كل ما هو ضروري لاتصال اللاعبين بنجاح. في تجربة لعبة الليزر النموذجية، يكون هذا الحدث المقابل هو Players.PlayerAdded:Connect.

Players.PlayerAdded:Connect هو جزء من عدة سكربتات في التجربة. إذا استخدمت اختصار Ctrl/Cmd+Shift+F وابحث عن Players.PlayerAdded:Connect، فإن النتائج توفر نقطة انطلاق جيدة لفهم إعداد التجربة الأولي.

نافذة البحث Find All الخاصة بالاستوديو مع النتائج المميزة لـ Players.PlayerAdded.

لإظهار ذلك، افتح ServerScriptServiceSetupHumanoid. التمييز بين Player و Character هو المفتاح لفهم هذا السكربت:

  • اللاعب هو عميل متصل، والشخصية هي نموذج Humanoid.
  • يحتاج اللاعبون إلى اختيار مدفع بلاستيك وإضافتهم إلى لوحة المتصدرين. تحتاج الشخصيات إلى الظهور والحصول على مدفع بلاستيك.

يقوم SetupHumanoid بفحص ما إذا كان لدى اللاعب شخصية (لقد انضم للتو) أو لا (يتم إعادة إنشائه). بعد أن يجد واحدة، يستدعي onCharacterAdded()، ويحصل على نموذج Humanoid من الشخصية، ويمررها إلى ServerScriptServiceSetupHumanoidsetupHumanoidAsync للتخصيص. بعد تعيين هذه القيم، ينتظر السكربت حتى تصل صحة الشخصية إلى صفر. سوف تتعلم المزيد عن إعادة الإنعاش لاحقًا في هذا القسم من البرنامج التعليمي.

setupHumanoidAsync

local function setupHumanoidAsync(player: Player, humanoid: Humanoid)
humanoid.DisplayDistanceType = Enum.HumanoidDisplayDistanceType.Subject
humanoid.NameDisplayDistance = 1000
humanoid.HealthDisplayDistance = 1000
humanoid.NameOcclusion = Enum.NameOcclusion.OccludeAll
humanoid.HealthDisplayType = Enum.HumanoidHealthDisplayType.AlwaysOn
humanoid.BreakJointsOnDeath = false
humanoid.Died:Wait()
onHumanoidDied(player, humanoid)
end

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

  • إذا كنت تريد أن تظهر أسماء الشخصيات على مسافات أقرب، قم بتقليل قيمة Humanoid.NameDisplayDistance.
  • إذا كنت تريد أن تظهر صحة الشخصية فقط إذا كانت أقل من 100%، قم بضبط Humanoid.HealthDisplayType على DisplayWhenDamaged.
  • إذا كنت تريد أن تتفكك الشخصيات عندما تصل صحتها إلى 0، قم بضبط Humanoid.BreakJointsOnDeath على صحيح.

إذا قمت بتغيير قيم هذه الخصائص، فمن المهم أن تختبر لعبة التجربة لتتمكن من رؤية تأثير إعداداتك الجديدة. يمكنك إعادة إنشاء ما يختبره اللاعبون في محاكاة متعددة العملاء من خلال اختيار شخصيتين على الأقل في اختبار Server & Clients من المنطقة المتوسطة.

خيار الخادم والعملاء في قائمة أوضاع الاختبار في منطقة الاستوديو.

مثال آخر لحدث Players.PlayerAdded:Connect موجود في ServerScriptServicePlayerStateHandler. تمامًا كما هو الحال في المثال السابق، يقوم PlayerStateHandler على الفور بفحص وجود شخصية. إذا لم يكن اللاعب في اللوبي، يقوم السكربت بتعيين خاصية للاعب إلى حالة SelectingBlaster، وهي الحالة الأولية للجولة التي يمكن للاعبين الاختيار من بين نوعين مختلفين من المدافع البلاستيكية بعد الظهور في الساحة. تتضمن هذه الحالة أيضًا حقل قوة يمنع اللاعبين من تلقي الضرر أثناء قيامهم باختيارهم.

PlayerStateHandler

local function onPlayerAdded(player: Player)
player.CharacterAdded:Connect(function()
if not player.Neutral then
player:SetAttribute(PlayerAttribute.playerState, PlayerState.SelectingBlaster)
onPlayerStateChanged(player, PlayerState.SelectingBlaster)
end
end)

هناك متغير محدد في PlayerStateHandler يستحق المناقشة: attributeChangedConnectionByPlayer. يخزن هذا الجدول جميع اللاعبين واتصالاتهم Connections لـ GetAttributeChangedSignal. سبب تخزين هذا الاتصال في جدول هو حتى يتمكن PlayerStateHandler من فصله عندما يغادر اللاعب التجربة. تعمل هذه العملية كنوع من إدارة الذاكرة لمنع عدد الاتصالات من النمو بشكل كبير مع مرور الوقت.

PlayerStateHandler

local attributeChangedConnectionByPlayer = {}
local function onPlayerAdded(player: Player)
-- التعامل مع جميع التحديثات المستقبلية لحالة اللاعب
attributeChangedConnectionByPlayer[player] = player
:GetAttributeChangedSignal(PlayerAttribute.playerState)
:Connect(function()
local newPlayerState = player:GetAttribute(PlayerAttribute.playerState)
onPlayerStateChanged(player, newPlayerState)
end)
end
-- فصل الاتصال عند تغير الخاصية عند مغادرة اللاعب
local function onPlayerRemoving(player: Player)
if attributeChangedConnectionByPlayer[player] then
attributeChangedConnectionByPlayer[player]:Disconnect()
attributeChangedConnectionByPlayer[player] = nil
end
end

يمكنك أن ترى أن كل من الدالتين المتصلتين في onPlayerAdded() تستدعي onPlayerStateChanged(). أثناء الإعداد الأولي بعد أن يترتب على اللاعب الانتقال إلى فريق، يتم تعيين PlayerState إلى SelectingBlaster، لذا فإن الجملة الشرطية الأولى تقوم بتقييمها على أنها خاطئة وتعطل BlasterState. في قسم تنفيذ المدافع اللاحق من البرنامج التعليمي، ستتعلم المزيد من التفاصيل حول هذه العملية.

PlayerStateHandler

local function onPlayerStateChanged(player: Player, newPlayerState: string)
-- حالة المدفع تكون 'جاهزة' فقط إذا كانت حالة اللاعب هي 'تلعب'
local newBlasterState = if newPlayerState == PlayerState.Playing then BlasterState.Ready else BlasterState.Disabled
-- جدولة منطق تدمير مجال القوة عندما يبدأ اللاعب في اللعب
if newPlayerState == PlayerState.Playing then
scheduleDestroyForceField(player)
end
player:SetAttribute(PlayerAttribute.blasterStateServer, newBlasterState)
end

إذا قمت بإضافة نقاط تفتيش أو مجرد بيان print()، يمكنك أن ترى أن onPlayerStateChanged() يتم استدعاؤه كثيرًا طوال التجربة: مثل أثناء الإعداد الأولي للجولة، لضبط نفسه على المسار الرئيسي، بعد أن يختار اللاعب مدفع بلاستيك، وعندما يعود اللاعب إلى اللوبي، أو منطقة الإنشاء Neutral. علاوة على ذلك، بعد أن يختار اللاعب مدفع بلاستيك، يقوم ServerScriptServiceBlasterSelectedHandler بتعيين PlayerState إلى Playing، ويمكن أخيرًا أن يقوم PlayerStateHandler بإزالة حقل القوة عن طريق استدعاء scheduleDestroyForceField().

تخصيص مجالات القوة

بدلاً من استخدام تنفيذ مخصص، تستخدم تجربة الليزر النموذجية فئة ForceField المدمجة في الاستوديو لمنع اللاعبين من تلقي الضرر أثناء اختيار مدفع البلاستيك الخاص بهم. وهذا يضمن أن المتطلب الوحيد للاعبين للظهور مع حقل قوة هو تضمين مواقع إنجاز بها خاصية SpawnLocation.Duration أكبر من 0. تستخدم العينة قيمة تعسفية تبلغ 9999 لتمكين مجالات القوة، ثم تدير المدة الفعلية برمجيًا في ReplicatedStorageForceFieldClientVisuals.

على غرار setupHumanoidAsync، معظم الأسطر في ForceFieldClientVisuals اختيارية. على سبيل المثال، إذا قمت بالتعليق على محتويات الدالة كما يفعل السكربت التالي، ستستخدم التجربة حقل القوة المتلألئ الافتراضي بدلاً من السكربت السداسي في StarterGuiForceFieldGui.

Commenting Out Properties in ForceFieldClientVisuals

local function onCharacterAddedAsync(character: Model)
-- local forceField = character:WaitForChild("ForceField", 3)
-- if not forceField then
-- return
-- end
-- forceField.Visible = false
-- localPlayer.PlayerGui:WaitForChild("ForceFieldGui").Enabled = true
-- forceField.Destroying:Wait()
-- localPlayer.PlayerGui.ForceFieldGui.Enabled = false
end

لأن حقل القوة المخصص هو واجهة مستخدم بدلاً من ParticleEmitter جديدة، يؤثر سكربت ForceFieldClientVisuals فقط على المرئيات من منظور الشخص الأول لكل لاعب، لا المرئيات من منظور الشخص الثالث عندما ينظر اللاعبون إلى اللاعبين الآخرين. تحتفظ المرئيات من منظور الشخص الثالث بالمظهر الافتراضي لـ Roblox. لمزيد من المعلومات حول تعديل مجالات القوة، راجع ForceField.Visible.

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

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

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

تستدعي كل من هذه التحققات في سكربت scheduleDestroyForceField دالة endForceField() لهذه الشروط.

scheduleDestroyForceField

-- إنهاء حقل القوة إذا قام اللاعب بإطلاق النار
local blasterStateAttribute = getBlasterStateAttribute()
attributeChangedConnection = player:GetAttributeChangedSignal(blasterStateAttribute):Connect(function()
local currentBlasterState = player:GetAttribute(blasterStateAttribute)
if currentBlasterState == BlasterState.Blasting then
endForceField()
end
end)
-- إنهاء حقل القوة إذا قام اللاعب بإعادة الضبط
characterRespawnedConnection = player.CharacterRemoving:Connect(endForceField)
-- إنهاء حقل القوة بعد 8 ثوان
task.delay(MAX_FORCE_FIELD_TIME, endForceField)

تتضمن endForceField() جملة شرطية غريبة حول المتغير forceFieldEnded. بسبب التحقق من الشروط بشكل متسلسل، يمكن أن يستدعي السكربت دالة endForceField() مرتين أو حتى ثلاث مرات. تضمن الجملة الشرطية forceFieldEnded أن الدالة تحاول تدمير حقل القوة مرة واحدة فقط.

scheduleDestroyForceField

local function endForceField()
if forceFieldEnded then
return
end
forceFieldEnded = true
attributeChangedConnection:Disconnect()
characterRespawnedConnection:Disconnect()
destroyForceField(player)
end

التعامل مع حالة العميل

بينما يركز معظم هذا القسم على ServerScriptServicePlayerStateHandler، هناك سكربت آخر بنفس الاسم في ReplicatedStorage. سبب الانقسام هو بنية العميل-الخادم:

  • يحتاج العميل إلى فهم معلومات حالة اللاعب حتى يتمكن من الاستجابة بشكل مناسب في الزمن الحقيقي، مثل عرض العناصر الصحيحة لواجهة المستخدم، أو تمكين اللاعبين من الحركة وإطلاق النار.

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

لرؤية هذا المنطق الأساسي، استعرض السكربت التالي في ReplicatedStoragePlayerStateHandler الذي يتحقق من حالة المستخدم الحالية، ثم يستدعي الدالة المناسبة التي تتعامل مع الإجراءات المقابلة لتلك الحالة.

PlayerStateHandler

local function onPlayerStateChanged(newPlayerState: string)
if newPlayerState == PlayerState.SelectingBlaster then
onSelectingBlaster()
elseif newPlayerState == PlayerState.Playing then
onPlaying()
elseif newPlayerState == PlayerState.TaggedOut then
onTaggedOut()
elseif newPlayerState == PlayerState.InLobby then
onInLobby()
else
warn(`حالة لاعب غير صالحة ({newPlayerState})`)
end
end

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

PlayerStateHandler

local function onSelectingBlaster()
togglePlayerCamera(true)
togglePlayerMovement(false)
setGuiExclusivelyEnabled(playerGui.PickABlasterGui)
localPlayer:SetAttribute(PlayerAttribute.blasterStateClient, BlasterState.Disabled)
end

تكون دالة onPlaying() بنفس القدر من البساطة. تقوم بتمكين الحركة، وتنتقل إلى شاشة عرض المعلومات الرئيسية (HUD)، وتمكن المدفع البلاستيكي، وتستدعي نفس دالة حقل القوة كما في الخادم.

PlayerStateHandler

local function onPlaying()
togglePlayerMovement(true)
setGuiExclusivelyEnabled(playerGui.HUDGui)
localPlayer:SetAttribute(PlayerAttribute.blasterStateClient, BlasterState.Ready)
scheduleDestroyForceField()
end

إعادة إنشاء الشخصيات

تتعامل تجربة لعبة الليزر النموذجية مع إعادة إنشاء الشخصيات في جولة من خلال الحالة onTaggedOut() في ReplicatedStoragePlayerStateHandler. مثل حالة onSelectingBlaster() و onPlaying()، تحفز onTaggedOut() سلوكًا فريدًا وفقًا للتغيرات في خاصية playerState. تحديدًا، تعطّل حركة اللاعب، وتعرض واجهة المستخدم لإعادة الإنشاء، وتعطل المدفع البلاستيكي.

PlayerStateHandler

local function onTaggedOut()
-- تعطيل التحكم أثناء الطرد
togglePlayerMovement(false)
togglePlayerCamera(false)
setGuiExclusivelyEnabled(playerGui.OutStateGui)
-- تعطيل المدفع البلاستيكي أثناء الطرد
localPlayer:SetAttribute(PlayerAttribute.blasterStateClient, BlasterState.Disabled)
end

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

قائمة إعدادات Roblox مع زر إعادة ضبط الشخصية المميز.
زر إعادة ضبط الشخصية
تظهر شاشة إعادة الإنشاء أثناء اعادة اللاعب للظهور في الجولة.
شاشة إعادة الإنشاء

من المهم أن نلاحظ أن هذا السكربت لا يعيد فعليًا إنشاء الشخصيات، بل يوقفهم فقط عن العمل ويوفر تغذية بصرية للاعبين بأن الخادم يعيد إنشاء شخصياتهم. لإظهار ذلك، إذا كنت تفحص ServerScriptServiceSetupHumanoidsetupHumanoidAsynconHumanoidDied، يقوم السكربت بتعيين PlayerState إلى TaggedOut (الذي يقوم بشكل أساسي بإعلام ReplicatedStoragePlayerStateHandler)، ويضيف بعض المؤشرات البصرية. إن المنطق الفعلي لإعادة الإنشاء هو سلوك مدمج في Roblox.

عندما تعيد الشخصيات الظهور في الجولة، فإنهم يعيدون الظهور في منطقة إنجاز فريقهم وفقًا لخاصية SpawnLocation.TeamColor. لتخصيص وقت إعادة الإنشاء، يمكنك إضافة السطر التالي إلى الجزء العلوي من SetupHumanoid. لمعرفة المزيد عن هذه التقنية، راجع Players.RespawnTime.

SetupHumanoid

local Players = game:GetService("Players")
Players.RespawnTime = 10 -- سطر جديد، بالثواني

إعدادات متنوعة

كجزء من الإعداد الأولي، تقوم تجربة لعبة الليزر النموذجية أيضًا ببعض الخطوات الصغيرة، لكنها حاسمة:

  • تتضمن التجربة سكربتًا فارغًا يسمى StarterPlayerStarterCharacterScriptsHealth الذي يعطل تجديد الصحة الافتراضي في Roblox. للحصول على شرح لسلوك هذه الخاصية، راجع Humanoid.Health.

  • تستخدم التجربة كاميرا من منظور الشخص الأول عن طريق ضبط خاصية StarterPlayer.CameraMode.LockFirstPerson. لاحظ أنه إذا كنت ترغب في السماح للمستخدمين بالتبديل بين الكاميرات من منظور الشخص الأول والثالث، يجب عليك تغير الخاصية برمجيًا بدلاً من ضبطها مرة واحدة فقط في الاستوديو، وتعديل عناصر التحكم وواجهة المستخدم لتعويض تغيير المنظور.

  • تستخدم التجربة لوحة المتصدرين المدمجة في Roblox بوحدة "نقاط"، والتي يكسبها اللاعبون كلما قاموا بطرد لاعب آخر. يمكنك رؤية التكوين في ServerScriptServiceSetupLeaderboard، ولكن لوحات المتصدرين داخل التجربة تقدم نظرة كاملة. لاحظ أن onPlayerTagged يضيف نقاطًا إلى لوحة المتصدرين، والتي ستتعلم عنها في إضافة جولات و كشف الضربات.

الآن بعد أن أصبح بإمكان اللاعبين الظهور، اختيار مدفع بلاستيك، وتصويبه من وجهة نظر الشخص الأول، يعلمك القسم التالي عن السكربتات وراء إنشاء أسلوب اللعب القائم على الجولات.

©2026 شركة Roblox Corporation. تُعد منصّة Roblox، وشعار Roblox وشعار "توسيع حدود المخيلة"، من ضمن علاماتنا التجارية المسجّلة وغير المسجّلة في الولايات المتحدة وبلدان أخرى.