كشف الاصطدام باستخدام الليزر

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

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

استخدام الأشعة للعثور على الاصطدامات

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

شعاع من A نحو B يصطدم بجدار

العثور على موقع الماوس

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

  1. افتح سكربت ToolController داخل أداة Blaster من إنشاء أدوات اللاعب. إذا لم تكمل هذا الدليل بعد، يمكنك تنزيل نموذج Blaster وإدراجه في StarterPack.

  2. في أعلى السكربت، أعلن عن ثابت يسمى MAX_MOUSE_DISTANCE بقيمة 1000.

  3. أنشئ دالة تسمى getWorldMousePosition.

    local tool = script.Parent
    local MAX_MOUSE_DISTANCE = 1000
    local function getWorldMousePosition()
    end
    local function toolEquipped()
    tool.Handle.Equip:Play()
    end
    local function toolActivated()
    tool.Handle.Activate:Play()
    end
    -- ربط الأحداث بالوظائف المناسبة
    tool.Equipped:Connect(toolEquipped)
    tool.Activated:Connect(toolActivated)
  4. استخدم دالة GetMouseLocation من UserInputService للحصول على موقع الماوس ثنائي الأبعاد للاعب على الشاشة. قم بتعيين ذلك إلى متغير يسمى mouseLocation.

    local UserInputService = game:GetService("UserInputService")
    local tool = script.Parent
    local MAX_MOUSE_DISTANCE = 1000
    local function getWorldMousePosition()
    local mouseLocation = UserInputService:GetMouseLocation()
    end

الآن بعد أن أصبح موقع الماوس ثنائي الأبعاد معروفًا، يمكن استخدام خصائصه X و Y كمعلمات لدالة Camera:ViewportPointToRay()، التي تنشئ Ray من الشاشة إلى العالم ثلاثي الأبعاد.

  1. استخدم خصائص X و Y من mouseLocation كوسائط لدالة ViewportPointToRay(). قم بتعيين ذلك إلى متغير يسمى screenToWorldRay.

    local function getWorldMousePosition()
    local mouseLocation = UserInputService:GetMouseLocation()
    -- إنشاء شعاع من موقع الماوس ثنائي الأبعاد
    local screenToWorldRay = workspace.CurrentCamera:ViewportPointToRay(mouseLocation.X, mouseLocation.Y)
    end

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

يحدد طول متجه الاتجاه مدى سفر الشعاع. يحتاج الشعاع إلى أن يكون بطول MAX_MOUSE_DISTANCE، لذا سيتعين عليك ضرب متجه الاتجاه بـ MAX_MOUSE_DISTANCE.

  1. أعلن عن متغير يسمى directionVector وقم بتعيينه إلى قيمة screenToWorldRay.Direction مضروبة في MAX_MOUSE_DISTANCE.

    local function getWorldMousePosition()
    local mouseLocation = UserInputService:GetMouseLocation()
    -- إنشاء شعاع من موقع الماوس ثنائي الأبعاد
    local screenToWorldRay = workspace.CurrentCamera:ViewportPointToRay(mouseLocation.X, mouseLocation.Y)
    -- متجه الاتجاه للوحدة من الشعاع مضروبًا في مسافة قصوى
    local directionVector = screenToWorldRay.Direction * MAX_MOUSE_DISTANCE
  2. استدعِ دالة Raycast من workspace، مع تمرير خاصية Origin من screenToWorldRay كأول وسيط و directionVector كالثاني. قم بتعيين ذلك إلى متغير يسمى raycastResult.

    local function getWorldMousePosition()
    local mouseLocation = UserInputService:GetMouseLocation()
    -- إنشاء شعاع من موقع الماوس ثنائي الأبعاد
    local screenToWorldRay = workspace.CurrentCamera:ViewportPointToRay(mouseLocation.X, mouseLocation.Y)
    -- متجه الاتجاه للوحدة من الشعاع مضروبًا في مسافة قصوى
    local directionVector = screenToWorldRay.Direction * MAX_MOUSE_DISTANCE
    -- استخدام الأشعة من أصل الشعاع نحو اتجاهه
    local raycastResult = workspace:Raycast(screenToWorldRay.Origin, directionVector)

معلومات الاصطدام

إذا وجدت عملية الأشعة جسمًا تم إصابته بالشعاع، فسترجع RaycastResult، والتي تحتوي على معلومات حول الاصطدام بين الشعاع والجسم.

خاصية RaycastResultالوصف
Instanceالـ BasePart أو خلية Terrain التي تقاطع معها الشعاع.
Positionحيث حدث التقاطع؛ عادةً نقطة مباشرة على سطح جزء أو تضاريس.
Materialالمادة عند نقطة الاصطدام.
Normalمتجه الوحدة للوجه المتقاطع. يمكن استخدام ذلك لتحديد الاتجاه الذي يشير إليه الوجه.

ستكون خاصية Position هي موقع الجسم الذي يمر الماوس فوقه. إذا لم يكن الماوس يمر فوق أي جسم ضمن مسافة MAX_MOUSE_DISTANCE، فسيكون raycastResult هو nil.

  1. أنشئ عبارة if للتحقق مما إذا كان raycastResult موجودًا.

  2. إذا كان لـ raycastResult قيمة، ارجع خاصية Position الخاصة به.

  3. إذا كان raycastResult هو nil، فابحث عن نهاية عملية الأشعة. احسب الموقع ثلاثي الأبعاد للماوس عن طريق إضافة screenToWorldRay.Origin و directionVector معًا.

local function getWorldMousePosition()
local mouseLocation = UserInputService:GetMouseLocation()
-- إنشاء شعاع من موقع الماوس ثنائي الأبعاد
local screenToWorldRay = workspace.CurrentCamera:ViewportPointToRay(mouseLocation.X, mouseLocation.Y)
-- متجه الاتجاه للوحدة من الشعاع مضروبًا في مسافة قصوى
local directionVector = screenToWorldRay.Direction * MAX_MOUSE_DISTANCE
-- استخدام الأشعة من أصل الشعاع نحو اتجاهه
local raycastResult = workspace:Raycast(screenToWorldRay.Origin, directionVector)
if raycastResult then
-- ارجع النقطة ثلاثية الأبعاد للاصطدام
return raycastResult.Position
else
-- لم يتم إصابة أي جسم، لذا احسب الموقع في نهاية الشعاع
return screenToWorldRay.Origin + directionVector
end
end

أطلق نحو الهدف

الآن بعد أن أصبح موقع الماوس ثلاثي الأبعاد معروفًا، يمكن استخدامه كنقطة هدف لإطلاق الليزر نحوها. يمكن إطلاق شعاع ثانٍ بين سلاح اللاعب ونقطة الهدف باستخدام دالة Raycast.

  1. أعلن عن ثابت يسمى MAX_LASER_DISTANCE في أعلى السكربت وقم بتعيينه إلى 500، أو النطاق الذي تختاره لسلاح الليزر.

    local UserInputService = game:GetService("UserInputService")
    local tool = script.Parent
    local MAX_MOUSE_DISTANCE = 1000
    local MAX_LASER_DISTANCE = 500
  2. أنشئ دالة تسمى fireWeapon تحت دالة getWorldMousePosition.

  3. استدعِ getWorldMousePosition وقم بتعيين النتيجة إلى متغير يسمى mousePosition. ستكون هذه هي نقطة الهدف لعملية الأشعة.

    -- لم يتم إصابة أي جسم، لذا احسب الموقع في نهاية الشعاع
    return screenToWorldRay.Origin + directionVector
    end
    end
    local function fireWeapon()
    local mouseLocation = getWorldMousePosition()
    end
    local function toolEquipped()
    tool.Handle.Equip:Play()
    end

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

  1. أعلن عن متغير يسمى targetDirection واحسب متجه الاتجاه عن طريق طرح موقع الأداة من mouseLocation.

  2. قم بتطبيع المتجه باستخدام خاصيته Unit. هذا يمنحه مقدارًا قدره 1، مما يسهل ضربه بطول لاحقًا.

    local function fireWeapon()
    local mouseLocation = getWorldMousePosition()
    -- احسب متجه الاتجاه المعياري واضربه في مسافة الليزر
    local targetDirection = (mouseLocation - tool.Handle.Position).Unit
    end
  3. أعلن عن متغير يسمى directionVector وقم بتعيين قيمته إلى targetDirection مضروبًا في MAX_LASER_DISTANCE.

    local targetDirection = (mouseLocation - tool.Handle.Position).Unit
    -- الاتجاه لإطلاق السلاح، مضروبًا في مسافة قصوى
    local directionVector = targetDirection * MAX_LASER_DISTANCE
    end

يمكن استخدام كائن RaycastParams لتخزين معلمات إضافية لدالة الأشعة. سيتم استخدامه في سلاح الليزر الخاص بك للتأكد من أن عملية الأشعة لا تصطدم عن طريق الخطأ باللاعب الذي يطلق السلاح. سيتم تجاهل أي أجزاء مدرجة في خاصية FilterDescendantsInstances لكائن RaycastParams في عملية الأشعة.

  1. تابع دالة fireWeapon وأعلن عن متغير يسمى weaponRaycastParams. قم بتعيين كائن RaycastParams جديد له.

  2. أنشئ جدولًا يحتوي على character المحلي للاعب وقم بتعيينه إلى خاصية weaponRaycastParams.FilterDescendantsInstances.

  3. استخدم الأشعة من موقع مقبض أداة اللاعب، في اتجاه نحو directionVector. تذكر إضافة weaponRaycastParams كوسيط هذه المرة. قم بتعيين ذلك إلى متغير يسمى weaponRaycastResult.

local UserInputService = game:GetService("UserInputService")
local Players = game:GetService("Players")
local tool = script.Parent
local MAX_MOUSE_DISTANCE = 1000
local MAX_LASER_DISTANCE = 500
local function getWorldMousePosition()
local function fireWeapon()
local mouseLocation = getWorldMousePosition()
-- احسب متجه الاتجاه المعياري واضربه في مسافة الليزر
local targetDirection = (mouseLocation - tool.Handle.Position).Unit
-- الاتجاه لإطلاق السلاح مضروبًا في مسافة قصوى
local directionVector = targetDirection * MAX_LASER_DISTANCE
-- تجاهل شخصية اللاعب لمنعهم من إيذاء أنفسهم
local weaponRaycastParams = RaycastParams.new()
weaponRaycastParams.FilterDescendantsInstances = {Players.LocalPlayer.Character}
local weaponRaycastResult = workspace:Raycast(tool.Handle.Position, directionVector, weaponRaycastParams)
end

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

  1. أعلن عن متغير فارغ يسمى hitPosition.

  2. استخدم عبارة if للتحقق مما إذا كان weaponRaycastResult يحتوي على قيمة. إذا تم إصابة جسم، قم بتعيين weaponRaycastResult.Position إلى hitPosition.

    local weaponRaycastResult = workspace:Raycast(tool.Handle.Position, directionVector, weaponRaycastParams)
    -- تحقق مما إذا كانت أي أجسام قد تم إصابتها بين نقطة البداية والنهاية
    local hitPosition
    if weaponRaycastResult then
    hitPosition = weaponRaycastResult.Position
    end
  3. إذا لم يكن لـ weaponRaycastResult قيمة، احسب الموقع النهائي لعملية الأشعة عن طريق إضافة موقع مقبض الأداة مع directionVector. قم بتعيين ذلك إلى hitPosition.

    local weaponRaycastResult = workspace:Raycast(tool.Handle.Position, directionVector, weaponRaycastParams)
    -- تحقق مما إذا كانت أي أجسام قد تم إصابتها بين نقطة البداية والنهاية
    local hitPosition
    if weaponRaycastResult then
    hitPosition = weaponRaycastResult.Position
    else
    -- احسب الموقع النهائي بناءً على مسافة الليزر القصوى
    hitPosition = tool.Handle.Position + directionVector
    end
    end
  4. انتقل إلى دالة toolActivated واستدعِ دالة fireWeapon بحيث يتم إطلاق الليزر في كل مرة يتم فيها تفعيل الأداة.

    local function toolActivated()
    tool.Handle.Activate:Play()
    fireWeapon()
    end

تحقق من الجسم المصاب

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

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

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

  1. أضف الكود المميز أدناه إلى عبارة if الخاصة بـ weaponRaycastResult للتحقق مما إذا كانت شخصية قد تم إصابتها.

    -- تحقق مما إذا كانت أي أجسام قد تم إصابتها بين نقطة البداية والنهاية
    local hitPosition
    if weaponRaycastResult then
    hitPosition = weaponRaycastResult.Position
    -- ستكون الكائن المصاب طفلًا لنموذج شخصية
    -- إذا تم العثور على إنسان في النموذج، فمن المحتمل أن تكون شخصية لاعب
    local characterModel = weaponRaycastResult.Instance:FindFirstAncestorOfClass("Model")
    if characterModel then
    local humanoid = characterModel:FindFirstChildWhichIsA("Humanoid")
    if humanoid then
    print("تم إصابة اللاعب")
    end
    end
    else
    -- احسب الموقع النهائي بناءً على مسافة الليزر القصوى
    hitPosition = tool.Handle.Position + directionVector
    end

الآن يجب أن يقوم سلاح الليزر بطباعة "تم إصابة اللاعب" في نافذة الإخراج في كل مرة تصطدم فيها عملية الأشعة بلاعب آخر.

اختبار مع لاعبين متعددين

تحتاج إلى لاعبين اثنين لاختبار ما إذا كانت عملية الأشعة للسلاح تجد لاعبين آخرين، لذا تحتاج إلى بدء خادم محلي. راجع محاكاة متعددة العملاء للحصول على التعليمات.

على عميل واحد، اختبر إطلاق النار على اللاعب الآخر باستخدام السلاح عن طريق النقر عليهم. يجب عرض "تم إصابة اللاعب" في الإخراج في كل مرة يتم فيها إطلاق النار على لاعب.

العثور على موقع الليزر

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

  1. أنشئ ModuleScript يسمى LaserRenderer، متفرعًا إلى StarterPlayerScripts تحت StarterPlayer.

  2. افتح السكربت وأعد تسمية جدول الوحدة إلى اسم السكربت LaserRenderer.

  3. أعلن عن متغير يسمى SHOT_DURATION بقيمة 0.15. ستكون هذه هي المدة (بالثواني) التي يكون فيها الليزر مرئيًا.

  4. أنشئ دالة من LaserRenderer تسمى createLaser مع معلمين يسمى toolHandle و endPosition.

    local LaserRenderer = {}
    local SHOT_DURATION = 0.15 -- الوقت الذي يكون فيه الليزر مرئيًا
    -- إنشاء شعاع ليزر من نقطة البداية نحو نقطة النهاية
    function LaserRenderer.createLaser(toolHandle, endPosition)
    end
    return LaserRenderer
  5. أعلن عن متغير يسمى startPosition وقم بتعيين خاصية Position من toolHandle كقيمته. ستكون هذه هي موقع سلاح الليزر الخاص باللاعب.

  6. أعلن عن متغير يسمى laserDistance واطرح endPosition من startPosition للعثور على الفرق بين المتجهين. استخدم خاصية Magnitude للحصول على طول شعاع الليزر.

    function LaserRenderer.createLaser(toolHandle, endPosition)
    local startPosition = toolHandle.Position
    local laserDistance = (startPosition - endPosition).Magnitude
    end
  7. أعلن عن متغير laserCFrame لتخزين الموقع والاتجاه لشعاع الليزر. يجب أن يكون الموقع هو منتصف البداية والنهاية للشعاع. استخدم CFrame.lookAt لإنشاء CFrame يقع عند startPosition ويواجه نحو endPosition. اضرب ذلك في CFrame جديد بقيمة محور Z تساوي نصف -laserDistance للحصول على المنتصف.

    function LaserRenderer.createLaser(toolHandle, endPosition)
    local startPosition = toolHandle.Position
    local laserDistance = (startPosition - endPosition).Magnitude
    local laserCFrame = CFrame.lookAt(startPosition, endPosition) * CFrame.new(0, 0, -laserDistance / 2)
    end

إنشاء جزء الليزر

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

  1. أعلن عن متغير laserPart وقم بتعيينه إلى كائن Part جديد.

  2. قم بتعيين الخصائص التالية لـ laserPart:

    1. Size: Vector3.new(0.2, 0.2, laserDistance)
    2. CFrame: laserCFrame
    3. Anchored: true
    4. CanCollide: false
    5. Color: Color3.fromRGB(225, 0, 0) (لون أحمر قوي)
    6. Material: Enum.Material.Neon
  3. اجعل laserPart كائنًا فرعيًا لـ Workspace.

  4. أضف الجزء إلى خدمة Debris بحيث يتم إزالته بعد عدد الثواني في متغير SHOT_DURATION.

    function LaserRenderer.createLaser(toolHandle, endPosition)
    local startPosition = toolHandle.Position
    local laserDistance = (startPosition - endPosition).Magnitude
    local laserCFrame = CFrame.lookAt(startPosition, endPosition) * CFrame.new(0, 0, -laserDistance / 2)
    local laserPart = Instance.new("Part")
    laserPart.Size = Vector3.new(0.2, 0.2, laserDistance)
    laserPart.CFrame = laserCFrame
    laserPart.Anchored = true
    laserPart.CanCollide = false
    laserPart.Color = Color3.fromRGB(225, 0, 0)
    laserPart.Material = Enum.Material.Neon
    laserPart.Parent = workspace
    -- إضافة شعاع الليزر إلى خدمة Debris ليتم إزالته وتنظيفه
    Debris:AddItem(laserPart, SHOT_DURATION)
    end

الآن أصبحت الدالة لعرض شعاع الليزر مكتملة، يمكن استدعاؤها بواسطة ToolController.

  1. في أعلى سكربت ToolController، أعلن عن متغير يسمى LaserRenderer واستدعِ وحدة LaserRenderer الموجودة في PlayerScripts.

    local UserInputService = game:GetService("UserInputService")
    local Players = game:GetService("Players")
    local LaserRenderer = require(Players.LocalPlayer.PlayerScripts.LaserRenderer)
    local tool = script.Parent
  2. في أسفل دالة fireWeapon، استدعِ دالة createLaser من LaserRenderer باستخدام مقبض الأداة و hitPosition كوسائط.

    -- احسب الموقع النهائي بناءً على مسافة الليزر القصوى
    hitPosition = tool.Handle.Position + directionVector
    end
    LaserRenderer.createLaser(tool.Handle, hitPosition)
    end
  3. اختبر السلاح عن طريق الضغط على زر التشغيل. يجب أن يكون شعاع الليزر مرئيًا بين السلاح والماوس عند تفعيل الأداة.

التحكم في معدل إطلاق السلاح

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

  1. أعلن عن متغير في أعلى ToolController يسمى FIRE_RATE. ستكون هذه هي الحد الأدنى من الوقت بين كل طلقة. أعطه قيمة من اختيارك؛ يستخدم هذا المثال 0.3 ثانية.

  2. أعلن عن متغير آخر أسفل ذلك يسمى timeOfPreviousShot بقيمة 0. يخزن هذا آخر وقت أطلق فيه اللاعب وسيتم تحديثه مع كل طلقة.

    local MAX_MOUSE_DISTANCE = 1000
    local MAX_LASER_DISTANCE = 300
    local FIRE_RATE = 0.3
    local timeOfPreviousShot = 0
  3. أنشئ دالة تسمى canShootWeapon بدون معلمات. ستنظر هذه الدالة في مقدار الوقت الذي مر منذ الطلقة السابقة وتعيد true أو false.

    local FIRE_RATE = 0.3
    local timeOfPreviousShot = 0
    -- تحقق مما إذا كان قد مر وقت كافٍ منذ إطلاق الطلقة السابقة
    local function canShootWeapon()
    end
    local function getWorldMousePosition()
  4. داخل الدالة، أعلن عن متغير يسمى currentTime؛ قم بتعيين قيمته إلى نتيجة استدعاء دالة tick() هذه الدالة تعيد مقدار الوقت الذي انقضى، بالثواني، منذ 1 يناير 1970 (تاريخ اعتباطي يُستخدم على نطاق واسع لحساب الوقت).

  5. اطرح timeOfPreviousShot من currentTime وأعد false إذا كانت النتيجة أقل من FIRE_RATE؛ خلاف ذلك، أعد true.

    -- تحقق مما إذا كان قد مر وقت كافٍ منذ إطلاق الطلقة السابقة
    local function canShootWeapon()
    local currentTime = tick()
    if currentTime - timeOfPreviousShot < FIRE_RATE then
    return false
    end
    return true
    end
  6. في نهاية دالة fireWeapon، قم بتحديث timeOfPreviousShot في كل مرة يتم فيها إطلاق السلاح باستخدام tick.

    hitPosition = tool.Handle.Position + directionVector
    end
    timeOfPreviousShot = tick()
    LaserRenderer.createLaser(tool.Handle, hitPosition)
    end
  7. داخل دالة toolActivated، أنشئ عبارة if واستدعِ canShootWeapon للتحقق مما إذا كان يمكن إطلاق السلاح.

    local function toolActivated()
    if canShootWeapon() then
    tool.Handle.Activate:Play()
    fireWeapon()
    end
    end

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

إلحاق الضرر باللاعب

لا يمكن للعملاء إلحاق الضرر بالعملاء الآخرين مباشرة؛ يجب أن يكون الخادم مسؤولًا عن إصدار الضرر عندما يتم إصابة لاعب.

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

  1. أنشئ مجلدًا في ReplicatedStorage يسمى Events.

  2. أدخل RemoteEvent في مجلد الأحداث وسمه DamageCharacter.

  3. في ToolController، أنشئ متغيرات في بداية السكربت لـ ReplicatedStorage ومجلد الأحداث.

    local UserInputService = game:GetService("UserInputService")
    local Players = game:GetService("Players")
    local ReplicatedStorage = game:GetService("ReplicatedStorage")
    local LaserRenderer = require(Players.LocalPlayer.PlayerScripts.LaserRenderer)
    local tool = script.Parent
    local eventsFolder = ReplicatedStorage.Events
    local MAX_MOUSE_DISTANCE = 1000
    local MAX_LASER_DISTANCE = 500
  4. استبدل عبارة الطباعة "تم إصابة اللاعب" في fireWeapon بسطر من Luau لإطلاق حدث DamageCharacter عن طريق تمرير متغير characterModel كوسيط.

    local characterModel = weaponRaycastResult.Instance:FindFirstAncestorOfClass("Model")
    if characterModel then
    local humanoid = characterModel:FindFirstChildWhichIsA("Humanoid")
    if humanoid then
    eventsFolder.DamageCharacter:FireServer(characterModel, hitPosition)
    end
    end
    else
    -- احسب الموقع النهائي بناءً على مسافة الليزر القصوى
    hitPosition = tool.Handle.Position + directionVector
    end

يحتاج الخادم إلى إلحاق الضرر باللاعب الذي تم إصابته عندما يتم إطلاق الحدث.

  1. أدخل سكربت في ServerScriptService وسمه ServerLaserManager.

  2. أعلن عن متغير يسمى LASER_DAMAGE واضبطه على 10، أو قيمة من اختيارك.

  3. أنشئ دالة باسم damageCharacter مع معلمين يسمى playerFired و characterToDamage.

  4. داخل الدالة، ابحث عن إنسان الشخصية واطرح LASER_DAMAGE من صحته.

  5. اربط دالة damageCharacter بحدث DamageCharacter في مجلد الأحداث.

    local ReplicatedStorage = game:GetService("ReplicatedStorage")
    local eventsFolder = ReplicatedStorage.Events
    local LASER_DAMAGE = 10
    function damageCharacter(playerFired, characterToDamage)
    local humanoid = characterToDamage:FindFirstChildWhichIsA("Humanoid")
    if humanoid then
    -- إزالة الصحة من الشخصية
    humanoid.Health -= LASER_DAMAGE
    end
    end
    -- ربط الأحداث بالوظائف المناسبة
    eventsFolder.DamageCharacter.OnServerEvent:Connect(damageCharacter)
  6. اختبر سلاح الليزر مع لاعبين اثنين عن طريق بدء خادم محلي. عندما تطلق النار على اللاعب الآخر، ستنخفض صحته بمقدار القيمة المعينة لـ LASER_DAMAGE.

عرض أشعة الليزر للاعبين الآخرين

حاليًا، يتم إنشاء شعاع الليزر بواسطة العميل الذي يطلق السلاح، لذا فقط هم من سيتمكنون من رؤية شعاع الليزر.

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

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

عميل الرامي

أولاً، يحتاج العميل إلى إخبار الخادم بأنه قد أطلق شعاعًا وتوفير موقع النهاية.

  1. أدخل RemoteEvent في مجلد الأحداث في ReplicatedStorage وسمه LaserFired.

  2. ابحث عن دالة fireWeapon في سكربت ToolController. في نهاية الدالة، أطلق حدث LaserFired باستخدام hitPosition كوسيط.

    hitPosition = tool.Handle.Position + directionVector
    end
    timeOfPreviousShot = tick()
    eventsFolder.LaserFired:FireServer(hitPosition)
    LaserRenderer.createLaser(tool.Handle, hitPosition)
    end

الخادم

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

  1. في سكربت ServerLaserManager، أنشئ دالة باسم playerFiredLaser فوق damageCharacter مع معلمين يسمى playerFired و endPosition.

  2. اربط الدالة بحدث LaserFired.

    -- إبلاغ جميع العملاء بأن شعاعًا قد تم إطلاقه حتى يتمكنوا من عرض الشعاع
    local function playerFiredLaser(playerFired, endPosition)
    end
    -- ربط الأحداث بالوظائف المناسبة
    eventsFolder.DamageCharacter.OnServerEvent:Connect(damageCharacter)
    eventsFolder.LaserFired.OnServerEvent:Connect(playerFiredLaser)

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

  1. أنشئ دالة getPlayerToolHandle فوق دالة playerFiredLaser مع معلمة تسمى player.

  2. استخدم الكود التالي للبحث عن سلاح اللاعب وإرجاع كائن المقبض.

    local LASER_DAMAGE = 10
    -- العثور على مقبض الأداة التي يحملها اللاعب
    local function getPlayerToolHandle(player)
    local weapon = player.Character:FindFirstChildOfClass("Tool")
    if weapon then
    return weapon:FindFirstChild("Handle")
    end
    end
    -- إبلاغ جميع العملاء بأن شعاعًا قد تم إطلاقه حتى يتمكنوا من عرض الشعاع
    local function playerFiredLaser(playerFired, endPosition)

يمكن للخادم الآن استدعاء FireAllClients على حدث LaserFired لإرسال المعلومات المطلوبة لعرض الشعاع للعملاء. يتضمن ذلك اللاعب الذي أطلق الشعاع (حتى لا يقوم عميل ذلك اللاعب بعرض الشعاع مرتين)، والمقبض الخاص بالليزر (الذي يعمل كنقطة بداية للشعاع) وموقع النهاية للشعاع.

  1. في دالة playerFiredLaser، استدعِ دالة getPlayerToolHandle مع playerFired كوسيط وقم بتعيين القيمة إلى متغير يسمى toolHandle.

  2. إذا كان toolHandle موجودًا، أطلق حدث LaserFired لجميع العملاء باستخدام playerFired و toolHandle و endPosition كوسائط.

    -- إبلاغ جميع العملاء بأن شعاعًا قد تم إطلاقه حتى يتمكنوا من عرض الشعاع
    local function playerFiredLaser(playerFired, endPosition)
    local toolHandle = getPlayerToolHandle(playerFired)
    if toolHandle then
    eventsFolder.LaserFired:FireAllClients(playerFired, toolHandle, endPosition)
    end
    end

العرض على العملاء

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

  1. أنشئ LocalScript في StarterPlayerScripts يسمى ClientLaserManager.

  2. داخل السكربت، استدعِ وحدة LaserRenderer.

  3. أنشئ دالة باسم createPlayerLaser مع المعلمات playerWhoShot و toolHandle و endPosition.

  4. اربط الدالة بحدث LaserFired في مجلد الأحداث.

  5. في الدالة، استخدم عبارة if للتحقق مما إذا كان playerWhoShot لا يساوي Players.LocalPlayer.

  6. داخل عبارة if، استدعِ دالة createLaser من وحدة LaserRenderer باستخدام toolHandle و endPosition كوسائط.

    local Players = game:GetService("Players")
    local ReplicatedStorage = game:GetService("ReplicatedStorage")
    local LaserRenderer = require(script.Parent:WaitForChild("LaserRenderer"))
    local eventsFolder = ReplicatedStorage.Events
    -- عرض شعاع لاعب آخر
    local function createPlayerLaser(playerWhoShot, toolHandle, endPosition)
    if playerWhoShot ~= Players.LocalPlayer then
    LaserRenderer.createLaser(toolHandle, endPosition)
    end
    end
    eventsFolder.LaserFired.OnClientEvent:Connect(createPlayerLaser)
  7. اختبر سلاح الليزر مع لاعبين اثنين عن طريق بدء خادم محلي. ضع كل عميل على جوانب مختلفة من شاشتك حتى تتمكن من رؤية كلا النافذتين في نفس الوقت. عندما تطلق النار على عميل واحد، يجب أن ترى الشعاع على العميل الآخر.

تأثيرات الصوت

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

  1. في سكربت ToolController، انتقل إلى دالة toolActivated وأزل السطر الذي يقوم بتشغيل صوت التفعيل.

    local function toolActivated()
    if canShootWeapon() then
    fireWeapon()
    end
    end
  2. في أسفل دالة createLaser في LaserRenderer، أعلن عن متغير يسمى shootingSound واستخدم طريقة FindFirstChild() الخاصة بـ toolHandle للتحقق من وجود صوت Activate.

  3. استخدم عبارة if للتحقق مما إذا كان shootingSound موجودًا؛ إذا كان موجودًا، استدعِ دالة Play() الخاصة به.

    laserPart.Parent = workspace
    -- إضافة شعاع الليزر إلى خدمة Debris ليتم إزالته وتنظيفه
    Debris:AddItem(laserPart, SHOT_DURATION)
    -- تشغيل صوت إطلاق السلاح
    local shootingSound = toolHandle:FindFirstChild("Activate")
    if shootingSound then
    shootingSound:Play()
    end
    end

تأمين الأحداث باستخدام التحقق

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

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

التحقق هو عملية التحقق من أن القيم المرسلة إلى الخادم واقعية. في هذه الحالة، سيحتاج الخادم إلى:

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

العميل

يحتاج العميل إلى إرسال موقع الإصابة الذي تم بواسطة الأشعة إلى الخادم حتى يتمكن من التحقق من أن المسافة واقعية.

  1. في ToolController، انتقل إلى السطر حيث يتم إطلاق حدث DamageCharacter في دالة fireWeapon.

  2. أضف hitPosition كوسيط.

    if characterModel then
    local humanoid = characterModel:FindFirstChildWhichIsA("Humanoid")
    if humanoid then
    eventsFolder.DamageCharacter:FireServer(characterModel, hitPosition)
    end
    end

الخادم

العميل الآن يرسل معلمة إضافية من خلال حدث DamageCharacter، لذا يحتاج ServerLaserManager إلى التعديل لقبولها.

  1. في سكربت ServerLaserManager، أضف معلمة hitPosition إلى دالة damageCharacter.

    function damageCharacter(playerFired, characterToDamage, hitPosition)
    local humanoid = characterToDamage:FindFirstChildWhichIsA("Humanoid")
    if humanoid then
    -- إزالة الصحة من الشخصية
    humanoid.Health -= LASER_DAMAGE
    end
    end
  2. أسفل دالة getPlayerToolHandle، أنشئ دالة باسم isHitValid مع ثلاث معلمات: playerFired و characterToDamage و hitPosition.

    end
    local function isHitValid(playerFired, characterToDamage, hitPosition)
    end

ستكون أول فحص هي المسافة بين موقع الإصابة والشخصية المصابة.

  1. أعلن عن متغير يسمى MAX_HIT_PROXIMITY في أعلى السكربت وقم بتعيينه إلى قيمة 10. ستكون هذه هي المسافة القصوى المسموح بها بين الإصابة والشخصية. هناك حاجة إلى تسامح لأن الشخصية قد تكون قد تحركت قليلاً منذ أن أطلق العميل الحدث.

    local ReplicatedStorage = game:GetService("ReplicatedStorage")
    local eventsFolder = ReplicatedStorage.Events
    local LASER_DAMAGE = 10
    local MAX_HIT_PROXIMITY = 10
  2. في دالة isHitValid، احسب المسافة بين الشخصية وموقع الإصابة. إذا كانت المسافة أكبر من MAX_HIT_PROXIMITY، فارجع false.

    local function isHitValid(playerFired, characterToDamage, hitPosition)
    -- التحقق من المسافة بين الشخصية المصابة وموقع الإصابة
    local characterHitProximity = (characterToDamage.HumanoidRootPart.Position - hitPosition).Magnitude
    if characterHitProximity > MAX_HIT_PROXIMITY then
    return false
    end
    end

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

  1. انسخ الكود أدناه لإجراء هذا الفحص. ارجع true في نهاية الدالة: إذا وصلت إلى النهاية، فقد اجتازت جميع الفحوصات.

    local function isHitValid(playerFired, characterToDamage, hitPosition)
    -- التحقق من المسافة بين الشخصية المصابة وموقع الإصابة
    local characterHitProximity = (characterToDamage.HumanoidRootPart.Position - hitPosition).Magnitude
    if characterHitProximity > 10 then
    return false
    end
    -- تحقق مما إذا كان يتم إطلاق النار عبر الجدران
    local toolHandle = getPlayerToolHandle(playerFired)
    if toolHandle then
    local rayLength = (hitPosition - toolHandle.Position).Magnitude
    local rayDirection = (hitPosition - toolHandle.Position).Unit
    local raycastParams = RaycastParams.new()
    raycastParams.FilterDescendantsInstances = {playerFired.Character}
    local rayResult = workspace:Raycast(toolHandle.Position, rayDirection * rayLength, raycastParams)
    -- إذا تم إصابة كائن لم يكن الشخصية، فتجاهل الطلقة
    if rayResult and not rayResult.Instance:IsDescendantOf(characterToDamage) then
    return false
    end
    end
    return true
    end
  2. أعلن عن متغير في دالة damageCharacter يسمى validShot. قم بتعيينه إلى نتيجة استدعاء دالة isHitValid مع ثلاث معلمات: playerFired و characterToDamage و hitPosition.

  3. في عبارة if أدناه، أضف عامل and للتحقق مما إذا كان validShot هو true.

    function damageCharacter(playerFired, characterToDamage, hitPosition)
    local humanoid = characterToDamage:FindFirstChildWhichIsA("Humanoid")
    local validShot = isHitValid(playerFired, characterToDamage, hitPosition)
    if humanoid and validShot then
    -- إزالة الصحة من الشخصية
    humanoid.Health -= LASER_DAMAGE
    end
    end

الآن أصبح حدث damageCharacter أكثر أمانًا وسيساعد في منع معظم اللاعبين من استغلاله. لاحظ أن بعض اللاعبين الخبيثين سيجدون غالبًا طرقًا للتغلب على التحقق؛ الحفاظ على أمان الأحداث عن بُعد هو جهد مستمر.

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

الكود النهائي

ToolController

local UserInputService = game:GetService("UserInputService")
local Players = game:GetService("Players")
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local LaserRenderer = require(Players.LocalPlayer.PlayerScripts.LaserRenderer)
local tool = script.Parent
local eventsFolder = ReplicatedStorage.Events
local MAX_MOUSE_DISTANCE = 1000
local MAX_LASER_DISTANCE = 500
local FIRE_RATE = 0.3
local timeOfPreviousShot = 0
-- تحقق مما إذا كان قد مر وقت كافٍ منذ إطلاق الطلقة السابقة
local function canShootWeapon()
local currentTime = tick()
if currentTime - timeOfPreviousShot < FIRE_RATE then
return false
end
return true
end
local function getWorldMousePosition()
local mouseLocation = UserInputService:GetMouseLocation()
-- إنشاء شعاع من موقع الماوس ثنائي الأبعاد
local screenToWorldRay = workspace.CurrentCamera:ViewportPointToRay(mouseLocation.X, mouseLocation.Y)
-- متجه الاتجاه للوحدة من الشعاع مضروبًا في مسافة قصوى
local directionVector = screenToWorldRay.Direction * MAX_MOUSE_DISTANCE
-- استخدام الأشعة من أصل الشعاع نحو اتجاهه
local raycastResult = workspace:Raycast(screenToWorldRay.Origin, directionVector)
if raycastResult then
-- ارجع النقطة ثلاثية الأبعاد للاصطدام
return raycastResult.Position
else
-- لم يتم إصابة أي جسم، لذا احسب الموقع في نهاية الشعاع
return screenToWorldRay.Origin + directionVector
end
end
local function fireWeapon()
local mouseLocation = getWorldMousePosition()
-- احسب متجه الاتجاه المعياري واضربه في مسافة الليزر
local targetDirection = (mouseLocation - tool.Handle.Position).Unit
-- الاتجاه لإطلاق السلاح، مضروبًا في مسافة قصوى
local directionVector = targetDirection * MAX_LASER_DISTANCE
-- تجاهل شخصية اللاعب لمنعهم من إيذاء أنفسهم
local weaponRaycastParams = RaycastParams.new()
weaponRaycastParams.FilterDescendantsInstances = {Players.LocalPlayer.Character}
local weaponRaycastResult = workspace:Raycast(tool.Handle.Position, directionVector, weaponRaycastParams)
-- تحقق مما إذا كانت أي أجسام قد تم إصابتها بين نقطة البداية والنهاية
local hitPosition
if weaponRaycastResult then
hitPosition = weaponRaycastResult.Position
-- ستكون الكائن المصاب طفلًا لنموذج شخصية
-- إذا تم العثور على إنسان في النموذج، فمن المحتمل أن تكون شخصية لاعب
local characterModel = weaponRaycastResult.Instance:FindFirstAncestorOfClass("Model")
if characterModel then
local humanoid = characterModel:FindFirstChildWhichIsA("Humanoid")
if humanoid then
eventsFolder.DamageCharacter:FireServer(characterModel, hitPosition)
end
end
else
-- احسب الموقع النهائي بناءً على مسافة الليزر القصوى
hitPosition = tool.Handle.Position + directionVector
end
timeOfPreviousShot = tick()
eventsFolder.LaserFired:FireServer(hitPosition)
LaserRenderer.createLaser(tool.Handle, hitPosition)
end
local function toolEquipped()
tool.Handle.Equip:Play()
end
local function toolActivated()
if canShootWeapon() then
fireWeapon()
end
end
tool.Equipped:Connect(toolEquipped)
tool.Activated:Connect(toolActivated)

LaserRenderer

local LaserRenderer = {}
local Debris = game:GetService("Debris")
local SHOT_DURATION = 0.15 -- الوقت الذي يكون فيه الليزر مرئيًا
-- إنشاء شعاع ليزر من نقطة البداية نحو نقطة النهاية
function LaserRenderer.createLaser(toolHandle, endPosition)
local startPosition = toolHandle.Position
local laserDistance = (startPosition - endPosition).Magnitude
local laserCFrame = CFrame.lookAt(startPosition, endPosition) * CFrame.new(0, 0, -laserDistance / 2)
local laserPart = Instance.new("Part")
laserPart.Size = Vector3.new(0.2, 0.2, laserDistance)
laserPart.CFrame = laserCFrame
laserPart.Anchored = true
laserPart.CanCollide = false
laserPart.Color = Color3.fromRGB(255, 0, 0)
laserPart.Material = Enum.Material.Neon
laserPart.Parent = workspace
-- إضافة شعاع الليزر إلى خدمة Debris ليتم إزالته وتنظيفه
Debris:AddItem(laserPart, SHOT_DURATION)
-- تشغيل صوت إطلاق السلاح
local shootingSound = toolHandle:FindFirstChild("Activate")
if shootingSound then
shootingSound:Play()
end
end
return LaserRenderer

ServerLaserManager

local ReplicatedStorage = game:GetService("ReplicatedStorage")
local eventsFolder = ReplicatedStorage.Events
local LASER_DAMAGE = 10
local MAX_HIT_PROXIMITY = 10
-- العثور على مقبض الأداة التي يحملها اللاعب
local function getPlayerToolHandle(player)
local weapon = player.Character:FindFirstChildOfClass("Tool")
if weapon then
return weapon:FindFirstChild("Handle")
end
end
local function isHitValid(playerFired, characterToDamage, hitPosition)
-- التحقق من المسافة بين الشخصية المصابة وموقع الإصابة
local characterHitProximity = (characterToDamage.HumanoidRootPart.Position - hitPosition).Magnitude
if characterHitProximity > MAX_HIT_PROXIMITY then
return false
end
-- تحقق مما إذا كان يتم إطلاق النار عبر الجدران
local toolHandle = getPlayerToolHandle(playerFired)
if toolHandle then
local rayLength = (hitPosition - toolHandle.Position).Magnitude
local rayDirection = (hitPosition - toolHandle.Position).Unit
local raycastParams = RaycastParams.new()
raycastParams.FilterDescendantsInstances = {playerFired.Character}
local rayResult = workspace:Raycast(toolHandle.Position, rayDirection * rayLength, raycastParams)
-- إذا تم إصابة كائن لم يكن الشخصية، فتجاهل الطلقة
if rayResult and not rayResult.Instance:IsDescendantOf(characterToDamage) then
return false
end
end
return true
end
-- إبلاغ جميع العملاء بأن شعاعًا قد تم إطلاقه حتى يتمكنوا من عرض الشعاع
local function playerFiredLaser(playerFired, endPosition)
local toolHandle = getPlayerToolHandle(playerFired)
if toolHandle then
eventsFolder.LaserFired:FireAllClients(playerFired, toolHandle, endPosition)
end
end
function damageCharacter(playerFired, characterToDamage, hitPosition)
local humanoid = characterToDamage:FindFirstChildWhichIsA("Humanoid")
local validShot = isHitValid(playerFired, characterToDamage, hitPosition)
if humanoid and validShot then
-- إزالة الصحة من الشخصية
humanoid.Health -= LASER_DAMAGE
end
end
-- ربط الأحداث بالوظائف المناسبة
eventsFolder.DamageCharacter.OnServerEvent:Connect(damageCharacter)
eventsFolder.LaserFired.OnServerEvent:Connect(playerFiredLaser)

ClientLaserManager

local Players = game:GetService("Players")
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local LaserRenderer = require(Players.LocalPlayer.PlayerScripts:WaitForChild("LaserRenderer"))
local eventsFolder = ReplicatedStorage.Events
-- عرض شعاع لاعب آخر
local function createPlayerLaser(playerWhoShot, toolHandle, endPosition)
if playerWhoShot ~= Players.LocalPlayer then
LaserRenderer.createLaser(toolHandle, endPosition)
end
end
eventsFolder.LaserFired.OnClientEvent:Connect(createPlayerLaser)
©2026 شركة Roblox Corporation. تُعد منصّة Roblox، وشعار Roblox وشعار "توسيع حدود المخيلة"، من ضمن علاماتنا التجارية المسجّلة وغير المسجّلة في الولايات المتحدة وبلدان أخرى.