สิ่งที่จะส่งไปยังเซิร์ฟเวอร์ในเกม FPS แบบเรียลไทม์?


23

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

ด้วยวิธีการส่งอินพุต: ฉันควรทำอย่างไรหากผู้เล่นกดปุ่มทิศทางค้างไว้ มันหมายความว่าฉันต้องส่งแพคเกจไปยังเซิร์ฟเวอร์ในทุก ๆ เฟรม มันไม่มากเกินไปเหรอ? และยังมีการหมุนของผู้เล่นจากอินพุตของเมาส์ นี่คือตัวอย่าง:

http://www.gabrielgambetta.com/fpm_live.html

สิ่งที่เกี่ยวกับการส่งตำแหน่งในแนวทางช่วงเวลาคงที่ มันส่งข้อความน้อยเกินไปไปยังเซิร์ฟเวอร์ แต่มันยังลดการตอบสนอง

แล้วทางไหนดีกว่ากัน?

คำตอบ:


19

คำตอบง่ายๆ: โกงหรือทำไม่ถูกต้อง!

หากคุณเคยเล่นเกมยิงปืนทางออนไลน์คุณอาจจะเคยเจอ "แถบยาง" ถ้าการเชื่อมต่อกับเซิร์ฟเวอร์ไม่ดี

สิ่งนี้เกิดจากลูกค้าของคุณแก้ไขตำแหน่งของคุณเป็นครั้งคราว

โดยพื้นฐานแล้วจะเกิดอะไรขึ้นกับทั้งสองฝ่าย:

  • เซิร์ฟเวอร์จะติดตามการเคลื่อนไหวของคุณและส่งการอัปเดตไปยังลูกค้าตามที่คาดไว้ สิ่งเหล่านี้ไม่จำเป็นต้องเป็นการอัพเดทแบบสมบูรณ์เสมอไป ทุกเฟรม x อาจมีการอัปเดตแบบเต็มเฟรมอื่น ๆ ทั้งหมดที่คุณส่งเวกเตอร์ความเร็วใหม่เท่านั้น (หากมีการเปลี่ยนแปลง)

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

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

ใช่วิธีการแก้ไขช่วงเวลาที่แน่นอนของคุณจะทำงานได้และเพียงพอ

แต่แม้ว่าคุณต้องการส่งอินพุตและจัดการการเคลื่อนไหวทั้งสองด้านโปรดทราบว่าคุณไม่ต้องกดปุ่ม "ยังคงกดปุ่ม" ให้ส่งเหตุการณ์หนึ่งเมื่อกดปุ่มและอีกครั้งเมื่อปล่อยปุ่ม


5
ใช่ฉันสามารถติดตามการกดและปล่อยปุ่ม แต่แล้วอินพุตของเมาส์ล่ะ? มันเปลี่ยนแปลงอยู่ตลอดเวลา
syloc

6
"ส่งเหตุการณ์หนึ่งเมื่อกดปุ่มและอีกครั้งเมื่อปล่อยปุ่ม" - จริง แต่ไม่จำเป็นต้องมีการตรวจสอบเพื่อให้แน่ใจว่าในที่สุดเหตุการณ์ "ในการเปิดตัว" จะถูกบังคับในที่สุดขึ้นอยู่กับกฎของเกม ตัวอย่างเช่นในเกมมัลติเพลเยอร์Rainbow Six Vegas 2ผู้เล่นสามารถเริ่มยิงปืนของเขาและข้อผิดพลาด (น่าเสียดายที่เป็นเรื่องธรรมดา) ทำให้ข้อความ "หยุดการยิง" ไม่สามารถเข้าถึงเซิร์ฟเวอร์ได้ ส่งผลให้เสียงกระสุนปืนที่เหลืออยู่ในการวนซ้ำไม่สิ้นสุดสำหรับการแข่งขันที่เหลือ เพียงตัวอย่างเดียวที่ต้องระวัง youtu.be/GOQIbLCy7m8?t=9m10s
Mike Baxter

@syloc: เพียงจัดการฝั่งไคลเอ็นต์และให้เซิร์ฟเวอร์ตัดสินว่าการเคลื่อนไหวนั้นถูกต้อง / เป็นไปได้ (เพื่อป้องกันสิ่งต่าง ๆ เช่นแฮ็กเทเลพอร์ตและคล้ายกัน)
Mario

@syloc เพียงกำหนดช่วงเวลาสำหรับเมาส์ แต่เพื่อบันทึกแบนด์วิดท์เพิ่มเติมยังคงทำการตรวจสอบฝั่งไคลเอ็นต์เพื่อดูว่ามีการเปลี่ยนแปลงหรือไม่ หากมีช่วงเวลาที่ไม่มีการเคลื่อนไหวของเมาส์คุณไม่จำเป็นต้องส่งข้อความเกี่ยวกับมันต่อไป
agweber

ที่หนึ่งในงานของฉันเรามีวิศวกรขับตัวเองอย่างบ้าคลั่งปรับพฤติกรรมฤดูใบไม้ผลิสำหรับการอัพเดทตำแหน่งที่ไม่ได้รับสำหรับการหมุนโทรศัพท์ (13 ปีที่แล้ว) ตอนนี้ฉันเห็นเกมที่มีแบนด์วิดท์จำนวนมากและความทรมานที่แฝงเร้นต่ำจากปัญหานี้ดูเหมือนว่าปัญหาจะไม่มีวันหมดหรือผู้คนให้ความสำคัญกับเรื่องนี้น้อยลง
Andon M. Coleman

5

หากคุณยังไม่ได้ผมขอแนะนำให้คุณอ่านบทความทั้งสองลึก แต่เข้าใจ: https://developer.valvesoftware.com/wiki/Source_Multiplayer_Networkingและhttp://fabiensanglard.net/quake3/network.php

สิ่งเหล่านี้อธิบายว่าเหตุใดจึงแนะนำให้ใช้การส่งแพ็คเก็ตแบบ 'ช่วงเวลาแน่นอน' โดยย่อแล้วอันที่จริงแล้วมันสำคัญสำหรับแพ็คเก็ตที่ส่งโดยเซิร์ฟเวอร์

การส่งแพ็คเก็ตมีค่าใช้จ่ายคงที่และขนาดสูงสุดของแพ็กเก็ตเครือข่ายคือประมาณ 1.5 KB ดังนั้นหากคุณมีผู้เล่นตัวอย่าง 16 คนบนเซิร์ฟเวอร์ของคุณแต่ละเฟรมเมื่อคุณคำนวณการเคลื่อนที่ของผู้เล่นรหัสไร้เดียงสาสามารถส่งแพ็กเก็ตอัปเดตไปยังผู้เล่นแต่ละคนหลังจากความละเอียดการเคลื่อนไหวแต่ละครั้งดังนั้น 16 * 16 = 256 แพ็กเก็ต ถ้าคุณมีอัตรา 30 เป็น 7680 แพ็คเก็ต

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

ตอนนี้คุณส่งเพียง 480 แพ็คเก็ตโดยวินาทีเพื่อผลลัพธ์เดียวกัน

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

เกี่ยวกับคำถามที่สองของคุณ - วิธีที่ฉันเลือกเพื่อลดความรู้สึกล้าหลังคือการส่งข้อมูลนี้ไปยังเซิร์ฟเวอร์ในแต่ละเฟรม:

  • ตำแหน่งปัจจุบันจริงของผู้เล่น (ใช้โดยเซิร์ฟเวอร์เพื่อตรวจสอบว่าตำแหน่งฝั่งเซิร์ฟเวอร์และฝั่งผู้เล่นไม่ถูกซิงโครไนซ์มากเกินไป)

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

  • ตำแหน่งที่เขามอง

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

ผู้เล่นไม่ได้ทำการซิงโครไนซ์อย่างแน่นอน แต่การตอบสนองของอินพุตนั้นทันที (สำคัญที่สุดสำหรับฉัน) และฉันพบว่าตำแหน่งที่คาดการณ์มีความแม่นยำเพียงพอ


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

สิ่งนี้ไม่มีใครในใจที่ถูกต้องใช้ TCP สำหรับ FPS พวกเขาค่อนข้างจะจัดการกับการเรียงลำดับใหม่ที่ซับซ้อนและขาดดาตาแกรมมากกว่าการใช้ TCP
Andon M. Coleman
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.