การนำพฤติกรรมบลาสเตอร์ไปใช้ คือกระบวนการเขียนโปรแกรมกลไกการบลาสต์ในประสบการณ์เกมยิงมุมมองบุคคลที่หนึ่ง ขณะที่ผู้เล่นสามารถบลาสต์ได้ด้วยการคลิกเดี่ยวหรือกดปุ่ม การสร้างพฤติกรรมบลาสต์ที่น่าพอใจและแม่นยำนั้นมีความสำคัญ เพราะมันเพิ่มความเพลิดเพลินให้กับผู้เล่นในเกมโดยรวม
โดยใช้ ตัวอย่างประสบการณ์เลเซอร์แท็ก เป็นการอ้างอิง ส่วนนี้ของการสอนจะสอนเกี่ยวกับสคริปต์ที่ใช้ในการนำพฤติกรรมบลาสเตอร์ไปใช้สำหรับบลาสเตอร์สองประเภท รวมถึงคำแนะนำเกี่ยวกับ:
- การตรวจจับเมื่อผู้เล่นกดปุ่มบลาสต์
- การตรวจสอบว่าผู้เล่นสามารถใช้บลาสเตอร์ได้ไหม หากพวกเขาเพิ่งกดปุ่มบลาสต์ไป
- การสร้างข้อมูลบลาสต์ที่บอกเซิร์ฟเวอร์ว่าใครเป็นผู้เริ่มบลาสต์ จุดเริ่มต้นมาจากไหน และปลายทางสุดท้ายของเลเซอร์แต่ละลำเป็นที่ไหน
- การแจ้งเซิร์ฟเวอร์เกี่ยวกับข้อมูลบลาสต์เพื่อให้สามารถดำเนินการที่เหมาะสมได้หากบลาสต์ไปชนผู้เล่นคนอื่น
- การรีเซ็ตบลาสเตอร์ระหว่างแต่ละบลาสต์เพื่อให้บลาสเตอร์มีเวลาเพียงพอในการระบายความร้อนก่อนที่จะบลาสต้อไปอีกครั้ง
เมื่อคุณทำส่วนนี้เสร็จแล้ว คุณจะได้เรียนรู้เกี่ยวกับสคริปต์ที่ช่วยให้บลาสเตอร์ตรวจจับเมื่อบลาสต์ของมันไปชนกับผู้เล่นคนอื่น จากนั้นหักจำนวนชีวิตที่เหมาะสมตามประเภทของบลาสเตอร์
ตรวจจับการป้อนข้อมูลผู้เล่น
ขั้นตอนแรกในการนำพฤติกรรมบลาสเตอร์ไปใช้คือการฟังเมื่อผู้เล่นกดปุ่มบลาสต์ ประเภทการป้อนข้อมูลที่ผู้เล่นใช้กดปุ่มบลาสต์นั้นขึ้นอยู่กับว่าใช้อุปกรณ์ชนิดใดในการเข้าถึงประสบการณ์ ตัวอย่างเช่น ตัวอย่างประสบการณ์เลเซอร์แท็กสนับสนุนการควบคุมผ่านเมาส์และคีย์บอร์ด, เกมแพด, และการควบคุมแบบสัมผัส คุณสามารถดูประเภทการป้อนข้อมูลแต่ละประเภทได้ที่ ReplicatedStorage ⟩ UserInputHandler
สคริปต์ลูกค้านี้ใช้ ContextActionService เพื่อเพิ่มการผูก MouseButton1 และ ButtonR2 กับการกระทำการยิงบลาสต์ นั่นหมายความว่าทุกครั้งที่ผู้เล่นกดปุ่มเมาส์ซ้ายหรือปุ่ม R2 ของเกมแพด จะทำให้เกิดแสงเลเซอร์พุ่งออกมาจากบลาสเตอร์ โปรดทราบว่า HUDGui มีปุ่มสำหรับการยิงบลาสต์บนอุปกรณ์พกพา ซึ่งมันจะทำการเชื่อมโยงในภายหลังในสคริปต์
UserInputHandlerContextActionService:BindAction("_", onBlasterActivated, false,Enum.UserInputType.MouseButton1,Enum.KeyCode.ButtonR2)
หมายเหตุอีกอย่างที่สำคัญคือการใช้ Enum.UserInputState.Begin ในการกำหนดฟังก์ชัน onBlasterActivated() การโต้ตอบหลายอย่างในส่วนติดต่อผู้ใช้ เช่น การเลือกลูกบลาสเตอร์ในตัวอย่างนี้ จะเกิดขึ้นหลังจากที่ปุ่มเมาส์เลิกกด (Enum.UserInputState.End) ซึ่งให้โอกาสผู้ใช้หลีกเลี่ยงการโต้ตอบในวินาทีสุดท้าย อย่างไรก็ตาม กลไกการบลาสต์จะรู้สึกว่าไม่ตอบสนอง หากมันเกิดขึ้นทันทีที่ปุ่มถูกกด
เพื่อแสดงให้เห็น คุณสามารถเปลี่ยน Enum.UserInputState.Begin เป็น Enum.UserInputState.End จากนั้นเล่นทดสอบเพื่อดูผลกระทบของความตอบสนองของบลาสต์ต่อการเล่นเกม ตัวอย่างเช่น หากผู้เล่นสามารถกดปุ่มค้างไว้โดยไม่เกิดบลาสต์ ผลลัพธ์นี้จะเปลี่ยนแปลงประสบการณ์ของพวกเขาในขณะที่กำลังแท็กผู้เล่นคนอื่นอย่างไร?
UserInputHandler
local function onBlasterActivated(_actionName: string,
inputState: Enum.UserInputState, _inputObject: InputObject)
if inputState == Enum.UserInputState.End then -- อัปเดตบรรทัด, อย่าลืมเปลี่ยนกลับ
attemptBlastClient()
end
end
ตรวจสอบว่าผู้เล่นสามารถบลาสต์ได้ไหม
หลังจาก UserInputHandler ตรวจจับการกดปุ่มหรือการสัมผัสที่หน้าจอแล้ว จะเรียกใช้ ReplicatedStorage ⟩ Blaster ⟩ attemptBlastClient เพื่อเพื่อตรวจสอบว่าผู้เล่นสามารถบลาสต์ได้หรือไม่ เช่นเดียวกับการตรวจสอบส่วนใหญ่ในตัวอย่างประสบการณ์เลเซอร์แท็ก มันจะเกิดขึ้นสองครั้ง: แรกในลูกค้า และต่อมาบนเซิร์ฟเวอร์ attemptBlastClient จะเรียกใช้ ReplicatedStorage ⟩ Blaster ⟩ canLocalPlayerBlast เพื่อตรวจสอบสภาพของ blasterStateClient ของผู้เล่น:
canLocalPlayerBlast
local function canLocalPlayerBlast(): boolean
return localPlayer:GetAttribute(PlayerAttribute.blasterStateClient) == BlasterState.Ready
end
หากคุณตรวจสอบ ReplicatedStorage ⟩ Blaster ⟩ BlasterState คุณจะเห็นว่าประสบการณ์มีสามสถานะของบลาสเตอร์: Ready, Blasting, และ Disabled หากต้องการดูผลกระทบของแต่ละสถานะเหล่านี้ คุณสามารถเล่นทดสอบประสบการณ์ เลือกผู้เล่นของคุณภายใต้บริการ Players จากนั้นสังเกตคุณสมบัติ blasterStateClient ในหน้าต่าง Properties สังเกตว่ามันแสดงค่า Disabled ขณะที่คุณเลือกลูกบลาสเตอร์ของคุณ, Ready ส่วนใหญ่ของเวลา, และ Blasting น้อยกว่าหนึ่งวินาทีหลังจากที่คุณกดปุ่ม
การหยุดชะงักเล็กน้อยนี้ป้องกันไม่ให้คุณบลาสต์ได้เร็วเท่าที่คุณคลิกได้ ตัวอย่างเช่น หากคุณเปลี่ยนฟังก์ชันให้คืนค่าจริงเสมอ คุณจะสามารถบลาสต์บลาสเตอร์ของคุณได้อย่างรวดเร็วโดยไม่เกิดความล่าช้า ซึ่งไม่สมจริงสำหรับการเล่นเกมเลเซอร์แท็ก
canLocalPlayerBlast
local function canLocalPlayerBlast(): boolean
return true -- อัปเดตบรรทัด, อย่าลืมเปลี่ยนกลับ
end
สร้างข้อมูลบลาสต์
หลังจากที่ยืนยันว่าบลาสเตอร์ของผู้เล่นอยู่ในสถานะ Ready แล้ว, attemptBlastClient จะเรียกใช้ ReplicatedStorage ⟩ attemptBlastClient ⟩ blastClient ขั้นตอนแรกที่ blastClient จะทำคือการตั้งค่าแอตทริบิวต์ผู้เล่น blasterStateClient เป็น Blasting ซึ่งหลีกเลี่ยงกรณีการยิงอย่างรวดเร็วจากก่อนหน้านี้
ขั้นตอนถัดไปคือการสร้างข้อมูลบลาสต์ หากคุณตรวจสอบ ReplicatedStorage ⟩ Blaster ⟩ BlastData คุณจะเห็นว่าบลาสต์แต่ละลำประกอบไปด้วยข้อมูลสามชิ้น:
- ผู้เล่นที่เริ่มบลาสต์
- DataType.CFrame ที่แทนจุดเริ่มต้นของบลาสต์
- ตาราง RayResult ที่ประกอบด้วยปลายทางสุดท้ายของเลเซอร์และผู้เล่นที่ถูกตีถ้าหากไปตีผู้เล่นคนอื่น
เพื่อสร้างข้อมูลนี้ blastClient จะเรียกใช้ ReplicatedStorage ⟩ attemptBlastClient ⟩ blastClient ⟩ generateBlastData ซึ่งคุณสามารถตรวจสอบด้านล่างนี้
generateBlastData
local function generateBlastData(): BlastData.Type
local blasterConfig = getBlasterConfig()
local rayDirections = getDirectionsForBlast(
currentCamera.CFrame, blasterConfig)
local rayResults = castLaserRay(
localPlayer, currentCamera.CFrame.Position, rayDirections)
local blastData: BlastData.Type = {
player = localPlayer,
originCFrame = currentCamera.CFrame,
rayResults = rayResults,
}
return blastData
end
ฟังก์ชันนี้เริ่มต้นด้วยการใช้ getBlasterConfig เพื่อดึงประเภทของบลาสเตอร์ของผู้เล่น ตัวอย่างมีบลาสเตอร์สองประเภท: หนึ่งที่ผลิตหลายลำแสงพร้อมการกระจายแนวนอนกว้าง, และอีกหนึ่งที่ผลิตลำแสงเดียว คุณสามารถหาการตั้งค่าของพวกเขาได้ใน ReplicatedStorage ⟩ Instances ⟩ LaserBlastersFolder
ฟังก์ชันนี้จะใช้ currentCamera.CFrame เป็นจุดเริ่มต้นสำหรับบลาสต์ ส่งให้กับ getDirectionsForBlast ในจุดนี้ รหัสไม่เกี่ยวกับบลาสเตอร์อีกต่อไป แต่จะเกี่ยวข้องกับลำแสงซึ่งคุณจะได้เรียนรู้เพิ่มเติมในส่วน ตรวจจับการตี ของการสอน ในที่สุด หลังจากสร้างตาราง rayResults ฟังก์ชัน generateBlastData ก็มีข้อมูลทั้งหมดที่จำเป็นสำหรับการคืนค่าข้อมูลบลาสต์ให้กับ blastClient
แจ้งเซิร์ฟเวอร์
เมื่อ blastClient ได้ข้อมูลบลาสต์ครบแล้ว มันจะส่งสองเหตุการณ์:
blastClientlocal laserBlastedBindableEvent = ReplicatedStorage.Instances.LaserBlastedBindableEventlocal laserBlastedEvent = ReplicatedStorage.Instances.LaserBlastedEventlaserBlastedBindableEvent:Fire(blastData)laserBlastedEvent:FireServer(blastData)
BindableEvent จะทำการแจ้งสคริปต์ลูกค้าอื่นๆ ของบลาสต์ ยกตัวอย่างเช่น ReplicatedStorage ⟩ FirstPersonBlasterVisuals ใช้เหตุการณ์นี้เพื่อทราบเมื่อไหร่ที่จะแสดงเอฟเฟกต์ภาพ เช่น แอนิเมชันบลาสต์และบาร์ความเย็น ในทำนองเดียวกัน RemoteEvent จะทำการแจ้งสคริปต์เซิร์ฟเวอร์เกี่ยวกับบลาสต์ ซึ่งเริ่มต้นการประมวลผลบลาสต์ใน ServerScriptService ⟩ LaserBlastHandler
LaserBlastHandler
local function onLaserBlastedEvent(playerBlasted: Player, blastData: BlastData.Type)
local validatedBlastData = getValidatedBlastData(playerBlasted, blastData)
if not validatedBlastData then
return
end
if not canPlayerBlast(playerBlasted) then
return
end
blastServer(playerBlasted)
processTaggedPlayers(playerBlasted, blastData)
for _, replicateToPlayer in Players:GetPlayers() do
if playerBlasted == replicateToPlayer then
continue
end
replicateBlastEvent:FireClient(replicateToPlayer, playerBlasted, blastData)
end
end
เพื่อช่วยป้องกันการโกง เซิร์ฟเวอร์ต้องตรวจสอบข้อมูลทั้งหมดที่แต่ละคล้านส่งมา การตรวจสอบเหล่านี้รวมถึง:
- BlastData เป็นตารางหรือไม่? มันมี Class.CFrame และตารางอื่นชื่อ rayResults หรือไม่?
- ผู้เล่นมีบลาสเตอร์ติดตั้งอยู่ไหม?
- ผู้เล่นมีตัวละครและตำแหน่งในโลกหรือไม่?
- หลังจากส่งข้อมูลบลาสต์ หากผู้เล่นได้เคลื่อนย้ายระยะทางเกินไปจากจุดที่พวกเขาได้ยิงเลเซอร์?
การตรวจสอบข้อสุดท้ายเกี่ยวข้องกับการตัดสินใจ ที่ขึ้นอยู่กับความล่าช้าของเซิร์ฟเวอร์และความเร็วในการเคลื่อนที่ของผู้เล่น คุณอาจตัดสินใจว่าค่าต่าง ๆ ที่ถือว่าเกินไปสำหรับประสบการณ์ส่วนตัวของคุณจะเป็นเท่าไหร่ อย่างไรก็ตามเพื่อแสดงให้เห็นถึงแนวทางในการตัดสินใจในการตรวจสอบคุณสามารถเพิ่มคำสั่งพิมพ์ใน getValidatedBlastData และเล่นทดสอบประสบการณ์
getValidatedBlastDatalocal distanceFromCharacterToOrigin = blastData.originCFrame.Position - rootPartCFrame.Positionprint(distanceFromCharacterToOrigin.Magnitude) -- อัปเดตบรรทัด, อย่าลืมลบif distanceFromCharacterToOrigin.Magnitude > ToleranceValues.DISTANCE_SANITY_CHECK_TOLERANCE_STUDS thenwarn(`ผู้เล่น {player.Name} ล้มเหลวในการตรวจสอบความถูกต้องของจุดเริ่มต้นในขณะที่บลาสต์`)returnend
เมื่อคุณเคลื่อนที่และบลาสต์ ให้สังเกตผลลัพธ์ มันอาจดูเหมือนประมาณนี้:
1.90196299552917483.15495586395263672.57428836822509774.80445861816406252.6434271335601807
หากคุณเพิ่มความเร็วในการเคลื่อนที่ของผู้เล่นใน ReplicatedStorage ⟩ PlayerStateHandler ⟩ togglePlayerMovement จากนั้นเล่นทดสอบอีกครั้ง คุณจะพบการตรวจสอบที่ล้มเหลวหลายครั้งเนื่องจากการเคลื่อนที่เกินค่าระยะทางระหว่างบลาสต์
togglePlayerMovementlocal ENABLED_WALK_SPEED = 60 -- อัปเดตบรรทัด, อย่าลืมเปลี่ยนกลับ
หลังจากนั้นเซิร์ฟเวอร์จะทำการดำเนินการดังนี้:
- ตรวจสอบ rayResults
- ตรวจสอบว่าผู้เล่นสามารถบลาสต์ได้ไหม
- รีเซ็ตสถานะบลาสเตอร์
- ลดจำนวนชีวิตสำหรับผู้เล่นที่แท็ก
- ทำซ้ำบลาสต์ไปยังผู้เล่นคนอื่น ๆ เพื่อให้พวกเขาเห็นเอฟเฟกต์ภาพมุมมองบุคคลที่สาม
สำหรับข้อมูลเพิ่มเติมเกี่ยวกับการทำงานของเซิร์ฟเวอร์เหล่านี้ ดูที่ส่วน ตรวจจับการตี ของการสอน
รีเซ็ตบลาสเตอร์
ในตัวอย่างประสบการณ์เลเซอร์แท็ก บลาสเตอร์ใช้กลไกความร้อน แทนที่จะโหลดใหม่หลังจากจำนวนบลาสต์ที่กำหนด มันต้องใช้เวลาที่จะ "ระบายความร้อน" ระหว่างการบลาสต์แต่ละครั้ง การหยุดชะงักนี้จะเกิดขึ้นทั้งในลูกค้า (blastClient) และในเซิร์ฟเวอร์ (blastServer) โดยเซิร์ฟเวอร์ทำหน้าที่เป็นแหล่งข้อมูลที่ถูกต้อง
blastServer
local blasterConfig = getBlasterConfig(player)
local secondsBetweenBlasts = blasterConfig:GetAttribute("secondsBetweenBlasts")
task.delay(secondsBetweenBlasts, function()
local currentState = player:GetAttribute(PlayerAttribute.blasterStateServer)
if currentState == BlasterState.Blasting then
player:SetAttribute(PlayerAttribute.blasterStateServer, BlasterState.Ready)
end
end)
แอตทริบิวต์ secondsBetweenBlasts เป็นส่วนหนึ่งของการกำหนดค่าบลาสเตอร์ใน ReplicatedStorage ⟩ Instances ⟩ LaserBlastersFolder หลังจากที่การหน่วงเวลา secondsBetweenBlasts หมดลง ผู้เล่นสามารถบลาสต์ได้อีกครั้ง และขั้นตอนทั้งหมดจะทำซ้ำ เพื่อช่วยให้ผู้เล่นเข้าใจเมื่อใดพวกเขาสามารถบลาสต์ได้อีกครั้ง ประสบการณ์จะรวมบาร์ความเย็นเข้าไป
ในช่วงนี้ผู้เล่นสามารถเกิดใหม่และเกิดซ้ำ, เล็งและบลาสตได้ แต่ประสบการณ์ยังต้องกำหนดผลลัพธ์จากแต่ละบลาสต์ ในส่วนถัดไปของการสอน คุณจะได้เรียนรู้วิธีการเขียนโปรแกรมความสามารถของบลาสเตอร์เพื่อตรวจจับเมื่อบลาสต์ไปชนกับผู้เล่นคนอื่น จากนั้นลดจำนวนชีวิตผู้เล่นตามการตั้งค่าของบลาสเตอร์