ในบทแนะนำนี้ คุณจะเรียนรู้วิธีการโค้งเลเซอร์จากเบลาสเตอร์ใน สร้างเครื่องมือผู้เล่น และตรวจสอบว่ามันโดนผู้เล่นหรือไม่
การโค้งรัศมีเพื่อค้นหาการชนกัน
การโค้งรัศมี สร้างรัศมีล่องหนจากตำแหน่งเริ่มต้นไปยังทิศทางที่กำหนดไว้ด้วยความยาวที่กำหนดหากลำแสงชนกับวัตถุหรือพื้นที่ในเส้นทางของมัน มันจะส่งคืนข้อมูลเกี่ยวกับการชนเช่นตำแหน่งและวัตถุที่มันชน

ค้นหาตำแหน่งของเมาส์
ก่อนที่จะยิงเลเซอร์ได้ คุณต้องรู้ก่อนว่าผู้เล่นกำลังมองไปที่ไหนสิ่งนี้สามารถค้นหาได้โดยการส่องแสงจากตำแหน่งเมาส์ 2D ของผู้เล่นบนหน้าจอโดยตรงไปยังโลกเกมจากกล้องลำแสงจะชนกับสิ่งที่ผู้เล่นกำลังมุ่งเป้าไปที่ด้วยเมาส์
เปิดสคริปต์ ToolController ภายในเครื่องมือ Blaster จาก สร้างเครื่องมือผู้เล่นหากคุณยังไม่ได้เสร็จสิ้นบทแนะนำการใช้งานนั้น คุณสามารถดาวน์โหลดรูปแบบ Blaster และใส่ลงใน StarterPack ได้
ที่ด้านบนของสคริปต์ ประกาศคงที่ชื่อ MAX_MOUSE_DISTANCE ด้วยค่า 1000
สร้างฟังก์ชันที่เรียกว่า getWorldMousePosition
local tool = script.Parentlocal MAX_MOUSE_DISTANCE = 1000local function getWorldMousePosition()endlocal function toolEquipped()tool.Handle.Equip:Play()endlocal function toolActivated()tool.Handle.Activate:Play()end-- เชื่อมต่อเหตุการณ์กับฟังก์ชันที่เหมาะสมtool.Equipped:Connect(toolEquipped)tool.Activated:Connect(toolActivated)ใช้ฟังก์ชัน GetMouseLocation ของ UserInputService เพื่อรับตำแหน่งเมาส์ 2D ของผู้เล่นบนหน้าจอกำหนดสิ่งนี้ให้กับตัวแปรที่ชื่อ mouseLocation
local UserInputService = game:GetService("UserInputService")local tool = script.Parentlocal MAX_MOUSE_DISTANCE = 1000local function getWorldMousePosition()local mouseLocation = UserInputService:GetMouseLocation()end
ตอนนี้ตำแหน่งเมาส์ 2D เป็นที่รู้จักแล้ว คุณสมบัติ X และ Y สามารถใช้เป็นพารามิเตอร์สำหรับฟังก์ชัน ซึ่งสร้าง 3D จากหน้าจอสู่โลกเกม
- ใช้คุณสมบัติ X และ Y ของ mouseLocation เป็นอาร์กิวเมนต์สำหรับฟังก์ชัน ViewportPointToRay()กำหนดสิ่งนี้ให้กับตัวแปรชื่อ screenToWorldRaylocal function getWorldMousePosition()local mouseLocation = UserInputService:GetMouseLocation()-- สร้างลําแสงจากตําแหน่งเมาส์ 2Dlocal screenToWorldRay = workspace.CurrentCamera:ViewportPointToRay(mouseLocation.X, mouseLocation.Y)end
ถึงเวลาที่จะใช้ฟังก์ชัน Raycast เพื่อตรวจสอบว่ารังสีชนกับวัตถุหรือไม่สิ่งนี้ต้องใช้ตําแหน่งเริ่มต้นและเวกเตอร์ทิศทาง: ในตัวอย่างนี้คุณจะใช้คุณสมบัติที่มาจากและทิศทางของ screenToWorldRay
ความยาวของเวกเตอร์ทิศทางกำหนดระยะที่ลำแสงจะเดินทางไปได้ลำแสงต้องยาวเท่ากับ MAX_MOUSE_DISTANCE ดังนั้นคุณจะต้องคูณเวกเตอร์ทิศทางด้วย MAX_MOUSE_DISTANCE
ประกาศตัวแปรชื่อ directionVector และกำหนดมูลค่าของ screenToWorldRay.Direction คูณด้วย MAX_MOUSE_DISTANCE
local function getWorldMousePosition()local mouseLocation = UserInputService:GetMouseLocation()-- สร้างลําแสงจากตําแหน่งเมาส์ 2Dlocal screenToWorldRay = workspace.CurrentCamera:ViewportPointToRay(mouseLocation.X, mouseLocation.Y)-- เวกเตอร์ทิศทางหน่วยของรังสีที่คูณด้วยระยะสูงสุดlocal directionVector = screenToWorldRay.Direction * MAX_MOUSE_DISTANCEเรียกฟังก์ชัน Raycast ของพื้นที่ทำงานโดยส่งคุณสมบัติ Origin ของ screenToWorldRay เป็นอาร์กิวเมนต์แรกและ directionVector เป็นอาร์กิวเมนต์ที่สองกำหนดสิ่งนี้ให้กับตัวแปรชื่อ raycastResult
local function getWorldMousePosition()local mouseLocation = UserInputService:GetMouseLocation()-- สร้างลําแสงจากตําแหน่งเมาส์ 2Dlocal screenToWorldRay = workspace.CurrentCamera:ViewportPointToRay(mouseLocation.X, mouseLocation.Y)-- เวกเตอร์ทิศทางหน่วยของรังสีที่คูณด้วยระยะสูงสุดlocal directionVector = screenToWorldRay.Direction * MAX_MOUSE_DISTANCE-- เรย์คาสต์จากจุดกำเนิดของรังสีไปสู่ทิศทางของมันlocal raycastResult = workspace:Raycast(screenToWorldRay.Origin, directionVector)
ข้อมูลการชนกัน
หากการโจมตีรังสีพบวัตถุที่ถูกโจมตีโดยรังสี มันจะส่งคืน RaycastResult ซึ่งมีข้อมูลเกี่ยวกับการชนกันระหว่างรังสีและวัตถุ
คุณสมบัติ RaycastResult | คําอธิบาย |
---|---|
ตัวอย่าง | เซลล์ BasePart หรือ Terrain ที่เรย์สัมผัส |
ตำแหน่ง | ที่ที่จุดบรรจบเกิดขึ้น; โดยปกติจะเป็นจุดโดยตรงบนพื้นผิวของชิ้นส่วนหรือพื้นที่ |
วัสดุ | วัสดุที่จุดการชนกัน |
ปกติ | เวกเตอร์ปกติของใบหน้าที่ซ้อนทับกัน สามารถใช้เพื่อกำหนดว่าใบหน้าชี้ไปทางไหน |
คุณสมบัติ ตำแหน่ง จะเป็นตำแหน่งของวัตถุที่เมาส์เลื่อนอยู่เหนือหากเมาส์ไม่ได้ลอยอยู่เหนือวัตถุใดๆ ในระยะ MAX_MOUSE_DISTANCE , raycastResult จะเป็น nil
สร้างคำสั่ง if เพื่อตรวจสอบว่า raycastResult มีอยู่หรือไม่
หาก raycastResult มีค่า, ส่งค่า ตำแหน่ง ของมันกลับ
หาก raycastResult เป็น nil แล้วค้นหาจุดสิ้นสุดของ raycastคำนวณตำแหน่ง 3D ของเมาส์โดยเพิ่ม screenToWorldRay.Origin และ directionVector รวมกัน
local function getWorldMousePosition()
local mouseLocation = UserInputService:GetMouseLocation()
-- สร้างลําแสงจากตําแหน่งเมาส์ 2D
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
-- ส่งคืนจุดแยกที่ 3D
return raycastResult.Position
else
-- ไม่มีวัตถุถูกโจมตีดังนั้นจึงคำนวณตำแหน่งในตอนท้ายของรังสี
return screenToWorldRay.Origin + directionVector
end
end
ยิงไปที่เป้าหมาย
ตอนนี้ตำแหน่งเมาส์ 3D เป็นที่รู้จักแล้ว สามารถใช้เป็นตำแหน่งเป้าหมาย เพื่อยิงเลเซอร์ไปข้างหน้า ลำแสงที่สองสามารถโยนระหว่างอาวุธของผู้เล่นและตำแหน่งเป้าหมายโดยใช้ฟังก์ชัน Raycast
ประกาศคงที่ที่เรียกว่า MAX_LASER_DISTANCE ที่ด้านบนของสคริปต์และกำหนดให้กับ 500 หรือช่วงที่คุณเลือกสำหรับเลเซอร์บลาสเตอร์
local UserInputService = game:GetService("UserInputService")local tool = script.Parentlocal MAX_MOUSE_DISTANCE = 1000local MAX_LASER_DISTANCE = 500สร้างฟังก์ชันที่เรียกว่า fireWeapon ภายใต้ฟังก์ชัน getWorldMousePosition
โทร getWorldMousePosition และกำหนดผลลัพธ์ให้กับตัวแปรชื่อ mousePosition นี่จะเป็นตำแหน่งเป้าหมายสําหรับการโค้งรังสี
-- ไม่มีวัตถุถูกโจมตีดังนั้นจึงคำนวณตำแหน่งในตอนท้ายของรังสีreturn screenToWorldRay.Origin + directionVectorendendlocal function fireWeapon()local mouseLocation = getWorldMousePosition()endlocal function toolEquipped()tool.Handle.Equip:Play()end
ครั้งนี้เวกเตอร์ทิศทางสำหรับฟังก์ชันการโค้งรัศมีจะแทนที่ทิศทางจากตำแหน่งเครื่องมือของผู้เล่นไปยังตำแหน่งเป้าหมาย
ประกาศตัวแปรชื่อ เป้าหมายทิศทาง และคำนวณเวกเตอร์ทิศทางโดยการหักตำแหน่งเครื่องมือออกจาก mouseLocation
ปรับเวกเตอร์โดยใช้คุณสมบัติ หน่วย ของมัน สิ่งนี้ทำให้มันมีขนาด 1 ซึ่งทำให้ง่ายต่อการคูณด้วยระยะในภายหลัง
local function fireWeapon()local mouseLocation = getWorldMousePosition()-- คำนวณเวกเตอร์ทิศทางปกติและคูณด้วยระยะทางเลเซอร์local targetDirection = (mouseLocation - tool.Handle.Position).Unitendประกาศตัวแปรชื่อ directionVector และกำหนดให้มันมี targetDirection คูณด้วย MAX_LASER_DISTANCE
local targetDirection = (mouseLocation - tool.Handle.Position).Unit-- ทิศทางในการยิงอาวุธที่คูณด้วยระยะสูงสุดlocal directionVector = targetDirection * MAX_LASER_DISTANCEend
วัตถุ RaycastParams สามารถใช้เพื่อเก็บพารามิเตอร์เพิ่มเติมสําหรับฟังก์ชันการโค้งรังสีจะใช้ในเลเซอร์บลาสเตอร์ของคุณเพื่อให้แน่ใจว่าการโจมตีด้วยรังสีไม่ได้ชนกับผู้เล่นที่ยิงอาวุธส่วนใดก็ได้ที่รวมอยู่ในคุณสมบัติ FilterDescendantsInstances ของวัตถุ RaycastParams จะถูก เพิกเฉย ในการส่งลำแสง
ดำเนินการต่อฟังก์ชัน fireWeapon และประกาศตัวแปรที่เรียกว่า weaponRaycastParams กำหนดวัตถุ RaycastParams ใหม่ให้กับมัน
สร้างตารางที่มีตัวอักษรท้องถิ่นของผู้เล่น และกำหนดให้เป็นคุณสมบัติ
เรย์คาสต์จากตําแหน่งจัดการเครื่องมือของผู้เล่นในทิศทางไปที่ 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
ในที่สุดคุณจะต้องตรวจสอบว่าการดำเนินการรังสีโค้งส่งคืนค่าหากมีการส่งค่ากลับ วัตถุถูกโจมตีโดยรังสีและสามารถสร้างเลเซอร์ระหว่างอาวุธและตำแหน่งที่โจมตีได้หากไม่มีอะไรถูกส่งคืน ตำแหน่งสุดท้ายจะต้องคำนวณเพื่อสร้างเลเซอร์
ประกาศตัวแปรว่างเปล่าชื่อ hitPosition
ใช้คำสั่ง ถ้า เพื่อตรวจสอบว่า weaponRaycastResult มีค่าหรือไม่ หากวัตถุถูกโจมตีให้กำหนด weaponRaycastResult.Position ให้กับ hitPosition
local weaponRaycastResult = workspace:Raycast(tool.Handle.Position, directionVector, weaponRaycastParams)-- ตรวจสอบว่ามีวัตถุใดถูกโจมตีระหว่างตำแหน่งเริ่มต้นและสิ้นสุดหรือไม่local hitPositionif weaponRaycastResult thenhitPosition = weaponRaycastResult.Positionendหาก weaponRaycastResult ไม่มีค่าใดๆ ให้คำนวณตำแหน่งสุดท้ายของการโค้งรัศมีโดยเพิ่มตำแหน่ง **** ของด้ามจับเครื่องมือกับ directionVectorกำหนดนี้ให้กับ hitPosition .
local weaponRaycastResult = workspace:Raycast(tool.Handle.Position, directionVector, weaponRaycastParams)-- ตรวจสอบว่ามีวัตถุใดถูกโจมตีระหว่างตำแหน่งเริ่มต้นและสิ้นสุดหรือไม่local hitPositionif weaponRaycastResult thenhitPosition = weaponRaycastResult.Positionelse-- คำนวณตำแหน่งสุดท้ายตามระยะเลเซอร์สูงสุดhitPosition = tool.Handle.Position + directionVectorendendนําทางไปยังฟังก์ชัน toolActivated และโทรฟังก์ชัน fireWeapon เพื่อให้เลเซอร์ยิงในแต่ละครั้งที่เครื่องมือถูกเปิดใช้งาน
local function toolActivated()tool.Handle.Activate:Play()fireWeapon()end
ตรวจสอบวัตถุที่โดน
เพื่อหาว่าวัตถุที่ถูกโจมตีโดยเลเซอร์เป็นส่วนหนึ่งของตัวละครของผู้เล่นหรือเพียงแค่เป็นส่วนหนึ่งของทิวทัศน์ คุณจะต้องมองหา Humanoid เพราะทุกตัวละครมีหนึ่ง
ก่อนอื่นคุณจะต้องหา รูปแบบตัวอักษร หากส่วนหนึ่งของตัวละครถูกโจมตีคุณไม่สามารถเดาได้ว่าผู้ปกครองของวัตถุที่โจมตีจะเป็นตัวละครเลเซอร์อาจชนกับส่วนของร่างกาย อุปกรณ์เสริม ไอเท็มเสริมซึ่งทั้งหมดตั้งอยู่ในส่วนต่างๆ ของห่วงโซ่ตัวละคร
คุณสามารถใช้ FindFirstAncestorOfClass เพื่อค้นหาบรรพบุรุษรูปแบบตัวละครของวัตถุที่ถูกโจมตีโดยเลเซอร์ถ้ามีอยู่หากคุณพบรูปแบบและมันมีมนุษย์หุ่นในส่วนใหญ่คุณสามารถเดาได้ว่ามันเป็นตัวละคร
เพิ่มโค้ดที่ไฮไลต์ด้านล่างไปยังคําสั่ง weaponRaycastResult ถ้า เพื่อตรวจสอบว่าตัวละครถูกโจมตีหรือไม่
-- ตรวจสอบว่ามีวัตถุใดถูกโจมตีระหว่างตำแหน่งเริ่มต้นและสิ้นสุดหรือไม่local hitPositionif weaponRaycastResult thenhitPosition = weaponRaycastResult.Position-- การโจมตีตัวอย่างจะเป็นลูกของโมเดลตัวละคร-- หากพบหุ่นยนต์ในโมเดลแล้วมันอาจเป็นตัวละครของผู้เล่นlocal characterModel = weaponRaycastResult.Instance:FindFirstAncestorOfClass("Model")if characterModel thenlocal humanoid = characterModel:FindFirstChildWhichIsA("Humanoid")if humanoid thenprint("Player hit")endendelse-- คำนวณตำแหน่งสุดท้ายตามระยะเลเซอร์สูงสุดhitPosition = tool.Handle.Position + directionVectorend
ตอนนี้เลเซอร์บลาสเตอร์ควรพิมพ์ Player hit ไปยังหน้าต่างเอาต์พุตทุกครั้งที่การดำเนินการรังสีโจมตีผู้เล่นคนอื่น
ทดสอบกับผู้เล่นหลายคน
ต้องมีผู้เล่นสองคนเพื่อทดสอบว่ารังสีอาวุธกำลังค้นหาผู้เล่นคนอื่นหรือไม่ดังนั้นคุณจึงต้องเริ่มต้นเซิร์ฟเวอร์ท้องถิ่น
เลือกแท็บ ทดสอบ ใน Studio
ตรวจสอบให้แน่ใจว่าการดรอปดาวน์ของผู้เล่นถูกตั้งค่าเป็น '2 ผู้เล่น' และคลิกปุ่มเริ่มต้นเพื่อ เริ่มต้น เซิร์ฟเวอร์ท้องถิ่นด้วย 2 ไคลเอนต์จะปรากฏหน้าต่างสามบานหน้าต่างแรกจะเป็นเซิร์ฟเวอร์ท้องถิ่น หน้าต่างอื่น ๆ จะเป็นไคลเอนต์สำหรับ Player1 และ Player2
บนไคลเอนต์เดียว ทดสอบการยิงผู้เล่นอีกคนด้วยอาวุธโดยคลิกที่พวกเขาการโจมตี "ผู้เล่น" ควรแสดงในออกในแต่ละครั้งที่ผู้เล่นถูกยิง
คุณสามารถค้นหาข้อมูลเพิ่มเติมเกี่ยวกับแท็บ ทดสอบ ที่นี่
ค้นหาตำแหน่งเลเซอร์
ตัวเร่งควรยิงลำแสงสีแดงไปยังเป้าหมายฟังก์ชันสำหรับสิ่งนี้จะอยู่ภายใน ModuleScript ดังนั้นจึงสามารถนำกลับมาใช้ในสคริปต์อื่นในภายหลังได้ก่อนอื่นสคริปต์จะต้องหาตำแหน่งที่ลำแสงเลเซอร์ควรแสดงผล
สร้าง ModuleScript ที่ชื่อว่า LaserRenderer ซึ่งเป็นบุตรของ StarterPlayerScripts ภายใต้ StarterPlayer
เปิดสคริปต์และเปลี่ยนชื่อตารางโมดูลเป็นชื่อของสคริปต์ LaserRenderer
ประกาศตัวแปรชื่อ SHOT_DURATION ด้วยค่า 0.15 นี่จะเป็นระยะเวลา (ในวินาที) ที่เลเซอร์สามารถมองเห็นได้
สร้างฟังก์ชันของ LaserRenderer ชื่อ createLaser ด้วยพารามิเตอร์สองตัวที่เรียกว่า toolHandle และ endPosition
local LaserRenderer = {}local SHOT_DURATION = 0.15 -- เวลาที่เลเซอร์สามารถมองเห็นได้-- สร้างลำแสงเลเซอร์จากตําแหน่งเริ่มต้นไปยังตําแหน่งสิ้นสุดfunction LaserRenderer.createLaser(toolHandle, endPosition)endreturn LaserRendererประกาศตัวแปรชื่อ startPosition และตั้งค่าคุณสมบัติ ตำแหน่ง ของ toolHandle เป็นค่าของมันนี่จะเป็นตำแหน่งของเลเซอร์บลาสเตอร์ของผู้เล่น
ประกาศตัวแปรชื่อ laserDistance และหัก endPosition จาก startPosition เพื่อหาความแตกต่างระหว่างสองเวกเตอร์ใช้คุณสมบัติ ความเข้ม ของสิ่งนี้เพื่อรับความยาวของลำแสงเลเซอร์
function LaserRenderer.createLaser(toolHandle, endPosition)local startPosition = toolHandle.Positionlocal laserDistance = (startPosition - endPosition).Magnitudeendประกาศตัวแปร laserCFrame เพื่อเก็บตำแหน่งและทิศทางของลำแสงเลเซอร์ตำแหน่งจะต้องเป็นจุดกลางของจุดเริ่มต้นและจุดสิ้นสุดของลำแสงใช้ CFrame.lookAt เพื่อสร้างใหม่ CFrame ที่ตั้งอยู่ที่ startPosition และหันไปทาง endPositionคูณสิ่งนี้ด้วย CFrame ใหม่ที่มีค่าแกน Z เป็นครึ่งของลบ laserDistance เพื่อรับจุดกลาง
function LaserRenderer.createLaser(toolHandle, endPosition)local startPosition = toolHandle.Positionlocal laserDistance = (startPosition - endPosition).Magnitudelocal laserCFrame = CFrame.lookAt(startPosition, endPosition) * CFrame.new(0, 0, -laserDistance / 2)end
สร้างชิ้นส่วนเลเซอร์
ตอนนี้คุณรู้แล้วว่าควรสร้างลำแสงเลเซอร์ที่ไหน คุณต้องเพิ่มลำแสงเอง ซึ่งสามารถทำได้ง่ายด้วยชิ้นส่วนนีออน
ประกาศตัวแปร laserPart และกำหนดให้มันเป็นตัวอย่างใหม่ Part
ตั้งค่าคุณสมบัติต่อไปนี้ของ laserPart :
- ขนาด : Vector3.new(0.2, 0.2, ระยะเลเซอร์)
- CFrame : ลาเซอร์CFrame
- ถูกยึด : จริง
- CanCollide : ไม่ใช่
- สี : Color3.fromRGB(225, 0, 0) (สีแดงสดใส)
- วัสดุ : Enum.Material.Neon
พ่อ laserPart ไปยัง พื้นที่ทำงาน .
เพิ่มส่วนให้บริการ Debris เพื่อให้มันถูกลบหลังจากจำนวนวินาทีในตัวแปร SHOT_DURATION
function LaserRenderer.createLaser(toolHandle, endPosition)local startPosition = toolHandle.Positionlocal laserDistance = (startPosition - endPosition).Magnitudelocal 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 = laserCFramelaserPart.Anchored = truelaserPart.CanCollide = falselaserPart.Color = Color3.fromRGB(225, 0, 0)laserPart.Material = Enum.Material.NeonlaserPart.Parent = workspace-- เพิ่มลำแสงเลเซอร์ในบริการกำจัดเศษซากที่จะถูกลบและทำความสะอาดDebris:AddItem(laserPart, SHOT_DURATION)end
ตอนนี้ฟังก์ชันที่จะแสดงลำแสงเลเซอร์สมบูรณ์แล้ว สามารถเรียกได้โดย ตัวควบคุมเครื่องมือ
ที่ด้านบนของสคริปต์ 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ที่ด้านล่างของฟังก์ชัน fireWeapon เรียกฟังก์ชัน LaserRenderer createLaser โดยใช้จัดการเครื่องมือและ hitPosition เป็นอาร์กิวเมนต์
-- คำนวณตำแหน่งสุดท้ายตามระยะเลเซอร์สูงสุดhitPosition = tool.Handle.Position + directionVectorendLaserRenderer.createLaser(tool.Handle, hitPosition)endทดสอบอาวุธโดยคลิกที่ปุ่มเล่น ลำแสงเลเซอร์ควรมองเห็นได้ระหว่างอาวุธและเมาส์เมื่อเครื่องมือถูกเปิดใช้งาน
ให้คะแนน
อาวุธต้องการความล่าช้าระหว่างแต่ละยิงเพื่อหยุดผู้เล่นจากการสร้างความเสียหายมากเกินไปในเวลาอันสั้นสามารถควบคุมได้โดยตรวจสอบว่าผ่านไปเวลาเพียงพอแล้วนับตั้งแต่ผู้เล่นยิงครั้งล่าสุด
ประกาศตัวแปรที่ด้านบนของ ToolController ที่เรียกว่า FIRE_RATE นี่จะเป็นเวลาขั้นต่ำระหว่างแต่ละยิงให้ค่าที่คุณเลือก; ตัวอย่างนี้ใช้เวลา 0.3 วินาที
ประกาศตัวแปรอื่นที่อยู่ด้านล่างเรียกว่า timeOfPreviousShot ด้วยค่า 0 สิ่งนี้จะบันทึกครั้งล่าสุดที่ผู้เล่นยิงและจะได้รับการอัปเดตในแต่ละยิง
local MAX_MOUSE_DISTANCE = 1000local MAX_LASER_DISTANCE = 300local FIRE_RATE = 0.3local timeOfPreviousShot = 0สร้างฟังก์ชันชื่อ canShootWeapon โดยไม่มีพารามิเตอร์ฟังก์ชันนี้จะดูว่าผ่านไปกี่นาทีนับตั้งแต่การยิงครั้งก่อนและคืนค่าเป็นจริงหรือเท็จ
local FIRE_RATE = 0.3local timeOfPreviousShot = 0-- ตรวจสอบว่าผ่านไปเวลาเพียงพอแล้วนับตั้งแต่ยิงครั้งล่าสุดlocal function canShootWeapon()endlocal function getWorldMousePosition()ภายในฟังก์ชันประกาศตัวแปรชื่อ เวลาปัจจุบัน และกำหนดให้มันเป็นผลลัพธ์ของการเรียกใช้ฟังก์ชัน tick()สิ่งนี้จะส่งคืนเวลาที่ผ่านไปเท่าใดในวินาทีตั้งแต่วันที่ 1 มกราคม 1970 (วันที่มีการใช้กันอย่างแพร่หลายเพื่อคำนวณเวลา)
ลบ timeOfPreviousShot จาก currentTime และส่งคืน ปลอม หากผลลัพธ์เล็กกว่า FIRE_RATE มิฉะนั้นส่งคืน จริง
-- ตรวจสอบว่าผ่านไปเวลาเพียงพอแล้วนับตั้งแต่ยิงครั้งล่าสุดlocal function canShootWeapon()local currentTime = tick()if currentTime - timeOfPreviousShot < FIRE_RATE thenreturn falseendreturn trueendในตอนท้ายของฟังก์ชัน fireWeapon อัปเดต timeOfPreviousShot ทุกครั้งที่อาวุธถูกยิงโดยใช้ tick
hitPosition = tool.Handle.Position + directionVectorendtimeOfPreviousShot = tick()LaserRenderer.createLaser(tool.Handle, hitPosition)endภายในฟังก์ชัน toolActivated สร้างคำสั่ง ถ้า และโทร canShootWeapon เพื่อตรวจสอบว่าอาวุธสามารถยิงได้หรือไม่
local function toolActivated()if canShootWeapon() thentool.Handle.Activate:Play()fireWeapon()endend
เมื่อคุณทดสอบเบลาสเตอร์คุณควรพบว่าไม่ว่าคุณจะคลิกเร็วแค่ไหน จะมีช่วงเวลาชั่วครู่ 0.3 วินาทีระหว่างแต่ละยิงเสมอ
ทำลายผู้เล่น
ลูกค้าไม่สามารถทำลายลูกค้าอื่นโดยตรง; เซิร์ฟเวอร์ต้องรับผิดชอบในการออกความเสียหายเมื่อผู้เล่นถูกโจมตี
ลูกค้าสามารถใช้ RemoteEvent เพื่อบอกเซิร์ฟเวอร์ว่าตัวละครถูกโจมตีแล้วควรจัดเก็บไว้ใน ReplicatedStorage ซึ่งพวกเขาสามารถมองเห็นได้ทั้งในไคลเอนต์และเซิร์ฟเวอร์
สร้างโฟลเดอร์ ใน ReplicatedStorage ชื่อว่า อีเวนต์ .
ใส่อีเวนต์ระยะไกลลงในโฟลเดอร์กิจกรรมและตั้งชื่อว่า DamageCharacter
ใน 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.Parentlocal eventsFolder = ReplicatedStorage.Eventslocal MAX_MOUSE_DISTANCE = 1000local MAX_LASER_DISTANCE = 500เปลี่ยนคำสั่งพิมพ์ "Player hit" ใน fireWeapon ด้วยบรรทัด Luau เพื่อยิงเหตุการณ์ระยะไกล DamageCharacter ด้วยตัวแปร characterModel เป็นอาร์กิวเมนต์
local characterModel = weaponRaycastResult.Instance:FindFirstAncestorOfClass("Model")if characterModel thenlocal humanoid = characterModel:FindFirstChildWhichIsA("Humanoid")if humanoid theneventsFolder.DamageCharacter:FireServer(characterModel)endendelse-- คำนวณตำแหน่งสุดท้ายตามระยะเลเซอร์สูงสุดhitPosition = tool.Handle.Position + directionVectorend
เซิร์ฟเวอร์ต้องสร้างความเสียหายให้กับผู้เล่นที่ถูกโจมตีเมื่อเหตุการณ์ถูกยิง
ใส่ สคริปต์ ใน ServerScriptService และตั้งชื่อว่า ServerLaserManager
ประกาศตัวแปรชื่อ LASER_DAMAGE และตั้งค่าเป็น 10 หรือค่าที่คุณเลือก
สร้างฟังก์ชันชื่อ damageCharacter ที่มีพารามิเตอร์สองตัวที่เรียกว่า playerFired และ characterToDamage
ภายในฟังก์ชันค้นหา Humanoid ของตัวละครและลบ LASER_DAMAGE ออกจากสุขภาพของมัน
เชื่อมฟังก์ชัน damageCharacter กับอีเวนต์ระยะไกล DamageCharacter ในโฟลเดอร์อีเวนต์
local ReplicatedStorage = game:GetService("ReplicatedStorage")local eventsFolder = ReplicatedStorage.Eventslocal LASER_DAMAGE = 10function damageCharacter(playerFired, characterToDamage)local humanoid = characterToDamage:FindFirstChildWhichIsA("Humanoid")if humanoid then-- ลบสุขภาพออกจากตัวละครhumanoid.Health -= LASER_DAMAGEendend-- เชื่อมต่อเหตุการณ์กับฟังก์ชันที่เหมาะสมeventsFolder.DamageCharacter.OnServerEvent:Connect(damageCharacter)ทดสอบเบลาสเตอร์ด้วยผู้เล่น 2 คนโดยเริ่มเซิร์ฟเวอร์ท้องถิ่นเมื่อคุณยิงผู้เล่นคนอื่น สุขภาพของพวกเขาจะลดลงตามจํานวนที่กำหนดไว้ LASER_DAMAGE
แสดงลำแสงเลเซอร์ของผู้เล่นอื่น
ในปัจจุบันลำแสงเลเซอร์จะถูกสร้างโดยไคลเอนต์ที่ยิงอาวุธดังนั้นพวกเขาจะสามารถเห็นลำแสงเลเซอร์ได้เท่านั้น
หากลำแสงเลเซอร์ถูกสร้างบนเซิร์ฟเวอร์แล้วทุกคนจะสามารถเห็นได้อย่างไรก็ตาม จะมีความล่าช้าเล็กน้อย ระหว่างการยิงอาวุธของไคลเอนต์และเซิร์ฟเวอร์ที่ได้รับข้อมูลเกี่ยวกับการยิง ซึ่งจะหมายความว่าลูกค้าที่ยิงอาวุธจะเห็นความล่าช้าระหว่างเมื่อพวกเขาเปิดใช้งานอาวุธและเมื่อพวกเขาเห็นลำแสงเลเซอร์; ผลการค้นหา
เพื่อแก้ปัญหานี้ ลูกค้าแต่ละรายจะสร้างลำแสงเลเซอร์ของตนเองซึ่งหมายความว่าลูกค้าที่ยิงอาวุธจะเห็นลำแสงเลเซอร์ทันทีลูกค้าอื่นจะประสบกับความล่าช้าเล็กน้อยระหว่างเมื่อผู้เล่นคนอื่นยิงและลำแสงปรากฏนี่คือสถานการณ์ที่ดีที่สุด: ไม่มีวิธีที่จะสื่อสารเลเซอร์ของลูกค้ารายหนึ่งไปยังลูกค้ารายอื่นได้เร็วขึ้น
ไคลเอนต์ของนักยิง
ก่อนอื่น ไคลเอนต์ต้องบอกเซิร์ฟเวอร์ว่ามันได้ยิงเลเซอร์และให้ตำแหน่งสิ้นสุด
ใส่ อีเวนต์ระยะไกล ในโฟลเดอร์อีเวนต์ใน ReplicatedStorage และตั้งชื่อว่า LaserFired
ค้นหาฟังก์ชัน fireWeapon ในสคริปต์ ToolController เมื่อสิ้นสุดฟังก์ชัน ให้ยิงเหตุการณ์ระยะไกล LaserFired โดยใช้ hitPosition เป็นอาร์กิวเมนต์
hitPosition = tool.Handle.Position + directionVectorendtimeOfPreviousShot = tick()eventsFolder.LaserFired:FireServer(hitPosition)LaserRenderer.createLaser(tool.Handle, hitPosition)end
เซิร์ฟเวอร์
ตอนนี้เซิร์ฟเวอร์ต้องรับเหตุการณ์ที่ลูกค้าได้ยิงและแจ้งให้ลูกค้าทั้งหมดทราบตำแหน่งเริ่มต้นและสิ้นสุดของลำแสงเลเซอร์เพื่อให้พวกเขาสามารถแสดงผลได้เช่นกัน
ในสคริปต์ ServerLaserManager สร้างฟังก์ชันชื่อ playerFiredLaser เหนือ damageCharacter ด้วยพารามิเตอร์สองตัวที่ชื่อ playerFired และ endPosition
เชื่อมฟังก์ชันกับอีเวนต์ระยะไกล LaserFired
-- แจ้งให้ลูกค้าทั้งหมดทราบว่ามีการยิงเลเซอร์เพื่อให้พวกเขาสามารถแสดงเลเซอร์ได้local function playerFiredLaser(playerFired, endPosition)end-- เชื่อมต่อเหตุการณ์กับฟังก์ชันที่เหมาะสมeventsFolder.DamageCharacter.OnServerEvent:Connect(damageCharacter)eventsFolder.LaserFired.OnServerEvent:Connect(playerFiredLaser)
เซิร์ฟเวอร์ต้องการตำแหน่งเริ่มต้นของเลเซอร์สิ่งนี้สามารถส่งจากไคลเอนต์ แต่เป็นการดีที่สุดที่จะหลีกเลี่ยงการเชื่อถือไคลเอนต์โดยเป็นไปได้ตําแหน่งการจัดการอาวุธของตัวละครจะเป็นตําแหน่งเริ่มต้นดังนั้นเซิร์ฟเวอร์สามารถค้นหาได้จากที่นั่น
สร้างฟังก์ชัน getPlayerToolHandle เหนือฟังก์ชัน playerFiredLaser ด้วยพารามิเตอร์ชื่อว่า player
ใช้รหัสต่อไปนี้เพื่อค้นหาตัวละครของผู้เล่นสำหรับอาวุธและส่งคืนวัตถุจัดการ
local LASER_DAMAGE = 10-- ค้นหาตัวจัดการของเครื่องมือที่ผู้เล่นกําลังถือlocal function getPlayerToolHandle(player)local weapon = player.Character:FindFirstChildOfClass("Tool")if weapon thenreturn weapon:FindFirstChild("Handle")endend-- แจ้งให้ลูกค้าทั้งหมดทราบว่ามีการยิงเลเซอร์เพื่อให้พวกเขาสามารถแสดงเลเซอร์ได้local function playerFiredLaser(playerFired, endPosition)
เซิร์ฟเวอร์สามารถโทรไปที่ FireAllClients ในอีเวนต์ระยะไกล LaserFired เพื่อส่งข้อมูลที่จำเป็นในการแสดงเลเซอร์ให้กับลูกค้าซึ่งรวมถึงผู้เล่น ที่ยิงเลเซอร์ (ดังนั้นไคลเอนต์สำหรับผู้เล่นคนนั้นจะไม่เรนเดอร์เลเซอร์สองครั้ง) ตัวจัดการของเลเซอร์ (ซึ่งทำหน้าที่เป็นตําแหน่งเริ่มต้นสำหรับเลเซอร์) และตําแหน่งสุดท้ายของเลเซอร์
ในฟังก์ชัน playerFiredLaser โทรไปที่ฟังก์ชัน getPlayerToolHandle ด้วย playerFired เป็นอาร์กิวเมนต์และกำหนดค่ามูลค่าให้กับตัวแปรชื่อว่า toolHandle
หากเครื่องมือ toolHandle มีอยู่ ให้ยิงอีเวนต์ LaserFired สำหรับลูกค้าทั้งหมดที่ใช้ playerFired และ toolHandle และ endPosition เป็นอาร์กิวเมนต์
-- แจ้งให้ลูกค้าทั้งหมดทราบว่ามีการยิงเลเซอร์เพื่อให้พวกเขาสามารถแสดงเลเซอร์ได้local function playerFiredLaser(playerFired, endPosition)local toolHandle = getPlayerToolHandle(playerFired)if toolHandle theneventsFolder.LaserFired:FireAllClients(playerFired, toolHandle, endPosition)endend
เรนเดอร์บนไคลเอนต์
ตอนนี้ FireAllClients ถูกเรียกแล้วแต่ละไคลเอนต์จะได้รับอีเวนต์จากเซิร์ฟเวอร์เพื่อแสดงลำแสงเลเซอร์แต่ละไคลเอนต์สามารถใช้ซ้ำโมดูล LaserRenderer จากก่อนหน้านี้เพื่อเรนเดอร์ลำแสงเลเซอร์โดยใช้ตำแหน่งจัดการของเครื่องมือและตำแหน่งสิ้นสุดของเลเซอร์ที่ส่งโดยเซิร์ฟเวอร์ผู้เล่นที่ยิงลำแสงเลเซอร์ในตอนแรกควรเพิกเฉยเหตุการณ์นี้มิฉะนั้นพวกเขาจะเห็นลำแสงเลเซอร์ 2 อัน
สร้าง สคริปท้องถิ่น ใน StarterPlayerScripts ที่เรียกว่า ClientLaserManager
ภายในสคริปต์ต้องใช้โมดูล LaserRenderer
สร้างฟังก์ชันชื่อ createPlayerLaser ด้วยพารามิเตอร์ playerWhoShot , toolHandle และ endPosition
เชื่อมฟังก์ชันกับอีเวนต์ระยะไกล LaserFired ในโฟลเดอร์อีเวนต์
ในฟังก์ชันใช้คำสั่ง ถ้า เพื่อตรวจสอบว่า playerWhoShot ไม่เท่ากับ LocalPlayer
ภายในคำสั่ง 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 thenLaserRenderer.createLaser(toolHandle, endPosition)endendeventsFolder.LaserFired.OnClientEvent:Connect(createPlayerLaser)ทดสอบเบลาสเตอร์ด้วยผู้เล่น 2 คนโดยเริ่มเซิร์ฟเวอร์ท้องถิ่นตำแหน่งแต่ละไคลเอนต์บนด้านต่างๆ ของมอนิเตอร์ของคุณเพื่อให้คุณสามารถมองเห็นทั้งสองหน้าต่างได้พร้อมกันเมื่อคุณยิงบนไคลเอนต์เดียวคุณควรเห็นเลเซอร์บนไคลเอนต์อื่น
เอฟเฟกต์เสียง
เอฟเฟกต์เสียงการยิงปัจจุบันเล่นเฉพาะบนไคลเอนต์ที่ยิงกระสุนเท่านั้นคุณจะต้องย้ายโค้ดเพื่อเล่นเสียงเพื่อให้ผู้เล่นคนอื่นได้ยินเช่นกัน
ในสคริปต์ ToolController ค้นหาฟังก์ชัน toolActivated และลบบรรทัดที่เล่นเสียงเปิดใช้งาน
local function toolActivated()if canShootWeapon() thenfireWeapon()endendที่ด้านล่างของฟังก์ชัน createLaser ใน LaserRenderer ประกาศตัวแปรชื่อ ยิงเสียง และใช้วิธี FindFirstChild() ของ toolHandle เพื่อตรวจสอบเสียง เปิดใช้งาน
ใช้คำสั่ง ถ้า เพื่อตรวจสอบว่ามี shootingSound หรือไม่; ถ้ามีให้โทรไปที่ฟังก์ชัน เล่น ของมัน
laserPart.Parent = workspace-- เพิ่มลำแสงเลเซอร์ในบริการกำจัดเศษซากที่จะถูกลบและทำความสะอาดDebris:AddItem(laserPart, SHOT_DURATION)-- เล่นเสียงการยิงของอาวุธlocal shootingSound = toolHandle:FindFirstChild("Activate")if shootingSound thenshootingSound:Play()endend
รักษารีโมทโดยใช้การตรวจสอบ
หากเซิร์ฟเวอร์ไม่ตรวจสอบข้อมูลจากคำขอที่เข้ามา แฮกเกอร์สามารถละเมิดฟังก์ชันและอีเวนต์ระยะไกลและใช้พวกมันเพื่อส่งค่าปลอมไปยังเซิร์ฟเวอร์เป็นสิ่งสำคัญที่ต้องใช้การตรวจสอบด้านเซิร์ฟเวอร์ เพื่อป้องกันไม่ให้เกิดสิ่งนี้ ในรูปแบบปัจจุบัน การโจมตีตัวละครความเสียหาย DamageCharacter ระยะไกลมีความเสี่ยงมากต่อการโจมตีแฮกเกอร์สามารถใช้เหตุการณ์นี้เพื่อทำลายผู้เล่นที่ต้องการในเกมโดยไม่ยิงพวกเขา
การตรวจสอบคือกระบวนการตรวจสอบว่ามูลค่าที่ส่งไปยังเซิร์ฟเวอร์มีความเป็นจริง ในกรณีนี้เซิร์ฟเวอร์จะต้อง:
- ตรวจสอบว่าระยะห่างระหว่างผู้เล่นและตำแหน่งที่ถูกโจมตีโดยเลเซอร์อยู่ภายในขอบเขตที่กำหนดไว้หรือไม่
- เรย์คาสต์ระหว่างอาวุธที่ยิงเลเซอร์และตำแหน่งที่โจมตีเพื่อให้แน่ใจว่าการยิงเป็นไปได้และไม่ผ่านผนังใดๆ
ไคลเอนต์
ไคลเอนต์ต้องส่งเซิร์ฟเวอร์ตำแหน่งที่ถูกโจมตีโดยเรย์คาสต์เพื่อให้สามารถตรวจสอบระยะได้ว่าเป็นจริง
ใน ToolController นำทางไปยังบรรทัดที่ DamageCharacter รีโมทอีเวนต์ถูกเรียกในฟังก์ชัน fireWeapon
เพิ่ม hitPosition เป็นอาร์กิวเมนต์
if characterModel thenlocal humanoid = characterModel:FindFirstChildWhichIsA("Humanoid")if humanoid theneventsFolder.DamageCharacter:FireServer(characterModel, hitPosition)endend
เซิร์ฟเวอร์
ตอนนี้ไคลเอนต์กำลังส่งพารามิเตอร์เพิ่มเติมผ่านอีเวนต์ระยะไกล DamageCharacter ดังนั้น ServerLaserManager จะต้องปรับเพื่อยอมรับมัน
ในสคริปต์ ServerLaserManager เพิ่มพารามิเตอร์ hitPosition ให้กับฟังก์ชัน damageCharacter
function damageCharacter(playerFired, characterToDamage, hitPosition)local humanoid = characterToDamage:FindFirstChildWhichIsA("Humanoid")if humanoid then-- ลบสุขภาพออกจากตัวละครhumanoid.Health -= LASER_DAMAGEendendด้านล่างฟังก์ชัน getPlayerToolHandle สร้างฟังก์ชันชื่อ isHitValid ที่มีพารามิเตอร์สามตัว: playerFired , characterToDamage และ hitPosition
endlocal function isHitValid(playerFired, characterToDamage, hitPosition)end
การตรวจสอบครั้งแรกจะเป็นระยะห่างระหว่างตําแหน่งที่โจมตีและตัวละครที่โจมตี
ประกาศตัวแปรชื่อ MAX_HIT_PROXIMITY ที่ด้านบนของสคริปต์และกำหนดค่าให้มีค่าเป็น 10 นี่จะเป็นระยะสูงสุดที่อนุญาตระหว่างการโจมตีและตัวละครต้องใช้ความอดทนเพราะตัวละครอาจเคลื่อนที่เล็กน้อยตั้งแต่ไคลเอนต์ยิงเหตุการณ์
local ReplicatedStorage = game:GetService("ReplicatedStorage")local eventsFolder = ReplicatedStorage.Eventslocal LASER_DAMAGE = 10local MAX_HIT_PROXIMITY = 10ในฟังก์ชัน isHitValid คำนวณระยะห่างระหว่างตัวละครและตำแหน่งการโจมตีหากระยะเวลาใหญ่กว่า MAX_HIT_PROXIMITY จากนั้นจะส่งคืน เท็จ
local function isHitValid(playerFired, characterToDamage, hitPosition)-- ตรวจสอบระยะห่างระหว่างตัวละครที่โจมตีและตำแหน่งที่โจมตีlocal characterHitProximity = (characterToDamage.HumanoidRootPart.Position - hitPosition).Magnitudeif characterHitProximity > MAX_HIT_PROXIMITY thenreturn falseendend
การตรวจสอบครั้งที่สองจะเกี่ยวข้องกับการโค้งรังสีระหว่างอาวุธที่ยิงและตําแหน่งการโจมตีหากการโค้งรัศมีส่งคืนวัตถุที่ไม่ใช่ตัวละครคุณสามารถเดาได้ว่าการยิงไม่ถูกต้องเนื่องจากมีบางอย่างบล็อกการยิง
คัดลอกโค้ดด้านล่างเพื่อดำเนินการตรวจสอบนี้ คืน true ในตอนท้ายของฟังก์ชัน: ปิด
local function isHitValid(playerFired, characterToDamage, hitPosition)-- ตรวจสอบระยะห่างระหว่างตัวละครที่โจมตีและตำแหน่งที่โจมตีlocal characterHitProximity = (characterToDamage.HumanoidRootPart.Position - hitPosition).Magnitudeif characterHitProximity > 10 thenreturn falseend-- ตรวจสอบว่ายิงผ่านผนังหรือไม่local toolHandle = getPlayerToolHandle(playerFired)if toolHandle thenlocal rayLength = (hitPosition - toolHandle.Position).Magnitudelocal rayDirection = (hitPosition - toolHandle.Position).Unitlocal raycastParams = RaycastParams.new()raycastParams.FilterDescendantsInstances = {playerFired.Character}local rayResult = workspace:Raycast(toolHandle.Position, rayDirection * rayLength, raycastParams)-- หากตัวอย่างถูกโจมตีที่ไม่ใช่ตัวละครแล้วเพิกเฉยการยิงif rayResult and not rayResult.Instance:IsDescendantOf(characterToDamage) thenreturn falseendendreturn trueendประกาศตัวแปรในฟังก์ชัน damageCharacter ที่เรียกว่า validShot กำหนดให้กับมันผลของการโทรไปที่ฟังก์ชัน isHitValid ด้วยสามอาร์กิวเมนต์: playerFired , characterToDamage และ hitPosition
ในคำสั่ง if ด้านล่างเพิ่มตัวประกอบ และ เพื่อตรวจสอบว่า validShot เป็น จริง
function damageCharacter(playerFired, characterToDamage, hitPosition)local humanoid = characterToDamage:FindFirstChildWhichIsA("Humanoid")local validShot = isHitValid(playerFired, characterToDamage, hitPosition)if humanoid and validShot then-- ลบสุขภาพออกจากตัวละครhumanoid.Health -= LASER_DAMAGEendend
ตอนนี้อีเวนต์ระยะไกลของตัวละครความเสียหายมีความปลอดภัยมากขึ้นและจะป้องกันไม่ให้ผู้เล่นส่วนใหญ่ละเมิดมันโปรดทราบว่าผู้เล่นที่มีเจตนาไม่ดีบางคนมักจะหาวิธีรอบการตรวจสอบ; การรักษาอีเวนต์ระยะไกลให้ปลอดภัยเป็นความพยายามอย่างต่อเนื่อง
เลเซอร์บลาสเตอร์ของคุณเสร็จสมบูรณ์แล้วด้วยระบบตรวจจับการโจมตีพื้นฐานโดยใช้รังสีลองใช้บทแนะนำการสอน การตรวจจับการใส่ข้อมูลของผู้ใช้ เพื่อค้นหาวิธีที่คุณสามารถเพิ่มการดำเนินการรีโหลดไปยังเลเซอร์บลาสเตอร์ของคุณหรือสร้างแผนที่เกมสนุกๆ และลองใช้เลเซอร์บลาสเตอร์ของคุณกับผู้เล่นคนอื่น!
รหัสสุดท้าย
ตัวควบคุมเครื่องมือ
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()
-- สร้างลําแสงจากตําแหน่งเมาส์ 2D
local screenToWorldRay = workspace.CurrentCamera:ViewportPointToRay(mouseLocation.X, mouseLocation.Y)
-- เวกเตอร์ทิศทางหน่วยของรังสีที่คูณด้วยระยะสูงสุด
local directionVector = screenToWorldRay.Direction * MAX_MOUSE_DISTANCE
-- เรย์คาสต์จากจุดเริ่มต้นของ roy ไปยังทิศทางของมัน
local raycastResult = workspace:Raycast(screenToWorldRay.Origin, directionVector)
if raycastResult then
-- ส่งคืนจุดแยกที่ 3D
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)
เลเซอร์เรนเดอร์
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:AddItem(laserPart, SHOT_DURATION)
-- เล่นเสียงการยิงของอาวุธ
local shootingSound = toolHandle:FindFirstChild("Activate")
if shootingSound then
shootingSound:Play()
end
end
return LaserRenderer
ผู้จัดการเลเซอร์เซิร์ฟเวอร์
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)
ผู้จัดการเลเซอร์ลูกค้า
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)