ใช้การจำลองทางฟิสิกส์บนทั้งไคลเอนต์และเซิร์ฟเวอร์หรือไม่?


13

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

  1. ขณะนี้ฉันมีเซิร์ฟเวอร์เกมจำลองสถานการณ์จริงที่มี box2d และส่งสถานะของโลกให้กับลูกค้าประมาณ 20 ครั้งต่อวินาที ลูกค้าแต่ละรายติดตามสแน็ปช็อตสองสามครั้งสุดท้ายที่ได้รับและ lerps ระหว่างสองสถานะเพื่อให้การเคลื่อนไหวของสไปรต์ราบรื่นขึ้น อย่างไรก็ตามมันไม่ราบรื่น มันอาจจะราบรื่นสักพักหนึ่งแล้วก็กระตุกนิดหน่อยจากนั้นก็กลับมาราบรื่น ฯลฯ ฉันลองทั้ง TCP และ UDP แล้วทั้งคู่ก็เหมือนกัน ความคิดใดที่ปัญหาของฉันอาจเป็นอย่างไร (หมายเหตุ: ฉันใช้สิ่งนี้กับผู้เล่นคนแรกก่อนและการเคลื่อนไหวของสไปรต์นั้นราบรื่นที่ 60fps เมื่ออัปเดตโลกฟิสิกส์เพียง 20 ครั้งต่อวินาที)

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

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

ขอบคุณ!

คำตอบ:


10

เรียกใช้การจำลองบนไคลเอนต์และเซิร์ฟเวอร์แน่นอน สิ่งอื่นใดมีเวลาแฝงนานเกินไป คุณควรตรวจสอบให้แน่ใจว่าแบบจำลองตรงกันโดยการแทรกวัตถุในลำดับเดียวกันโดยใช้ขั้นตอนเวลาที่แน่นอนและหลีกเลี่ยงการเปรียบเทียบตัวชี้ ฉันไม่ได้ลองกับ Box2D แต่โดยทั่วไปแล้วมันเป็นไปได้ที่จะบรรลุพฤติกรรมเดียวกันในทุกเครื่องในการจำลองทางฟิสิกส์ คณิตศาสตร์ทั้งหมดมักขึ้นอยู่กับ IEEE 754 binary32 ลอยและพฤติกรรมของพวกเขาจะถูกกำหนดอย่างเคร่งครัดสำหรับการดำเนินงานเช่น+-*/การตั้งชื่อไม่กี่ คุณจะต้องระมัดระวังเกี่ยวกับsin,cosและสิ่งที่ชอบยากเนื่องจากพวกเขาสามารถแตกต่างกันระหว่าง runtimes (นี้เป็นสิ่งสำคัญโดยเฉพาะอย่างยิ่งเมื่อการพัฒนาสำหรับหลายแพลตฟอร์ม) ตรวจสอบให้แน่ใจด้วยว่าคุณใช้การตั้งค่าที่เข้มงวดสำหรับการปรับให้เหมาะสมแบบลอยในคอมไพเลอร์ของคุณ คุณยังสามารถซิงโครไนซ์วัตถุได้โดยส่งสถานะของวัตถุออกจากเซิร์ฟเวอร์เป็นระยะ อย่าอัปเดตเว้นแต่ความแตกต่างใหญ่กว่าเกณฑ์เพื่อหลีกเลี่ยงการพูดติดอ่างที่ไม่จำเป็น

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


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

Erin Catto คิดว่าการพยายามรักษาสถานะทั้งหมดของโลก Box2D หลายแห่งไว้ในการซิงค์คือการต่อสู้ที่พ่ายแพ้ ( box2d.org/forum/viewtopic.php?f=3&t=8462 )
Pavel

คำสั่ง"IEEE 754 binary32 floats [.. ] พฤติกรรมถูกกำหนดไว้อย่างเคร่งครัดสำหรับการดำเนินการเช่น+-*/"เป็นเท็จโดยสมบูรณ์ การดำเนินการทั้งหมดใน IEEE-754 อาจแตกต่างกันไปตามการนำไปใช้ ดูที่นี่และที่นี่สำหรับข้อมูลเพิ่มเติม
BlueRaja - Danny Pflughoeft

1
ไม่มันเป็นความจริงอย่างสมบูรณ์ ปัญหาที่ลิงก์ของคุณอธิบายเกี่ยวข้องกับโหมดที่แตกต่างกันของ x87 fpu และการใช้งานของยอดเยี่ยม IEEE 754 binary32 ถูกกำหนดไว้อย่างเคร่งครัดสำหรับการดำเนินงานขั้นพื้นฐาน มันขึ้นอยู่กับคุณที่จะตั้งโหมดที่ถูกต้องและใช้คำแนะนำที่ถูกต้องเพื่อให้เป็นไปตามมาตรฐาน เพียงแค่ใช้คำสั่ง SSE ไม่ใช่ x87 fpu ช่วยได้มาก
rasmus

4

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

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


นี่อาจเป็นกรณี สิ่งที่ฉันพยายามทำคือความล่าช้าจนกว่าฉันจะได้รับ 3 snapshots จากเซิร์ฟเวอร์ ที่จุดฉัน lerp จาก shot 1 ถึง shot 2 จากนั้นจาก 2 shot ถึง shot 3 ถ้า ณ จุดใดฉันพลาดแพ็คเก็ตฉันสามารถ lerp จาก 1 ถึง 3, แทน 1 ถึง 2, ถ้านั่นเหมาะสม ฉันอาจไม่ได้ใช้งานอย่างถูกต้อง แต่ ขอบคุณสำหรับลิงค์ไปยังบทความ!
Venesectrix

1

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

แน่นอนปัญหาที่นี่คือไม่มีการควบคุมจากส่วนกลางสำหรับเอนทิตี แต่ฉันคิดว่าสามารถทำได้บนฝั่งเซิร์ฟเวอร์ด้วยโดยทำการจำลองฝั่งเซิร์ฟเวอร์ของฟิสิกส์เช่นกัน


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

1

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

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

สำหรับคำถามที่ 1 ฉันบอกว่าปัญหาน่าจะเกิดจากความล่าช้าในการตอบสนองเนื่องจากไม่มีการรับประกันที่แน่นอนว่าจะมีช่วงเวลาที่สมบูรณ์แบบ 20 วินาทีที่สมบูรณ์แบบระหว่างการรับสแนปชอตแต่ละครั้ง ให้ฉันอธิบาย (เป็น "t" เวลาที่วัดในหน่วยมิลลิวินาที):

1) ที่ t = 20 ตั้งแต่เริ่มเกมลูกค้าได้รับสแนปชอตและทำการแก้ไขสำเร็จและราบรื่น

2) ที่ t = 40 มีความล่าช้าระหว่างเซิร์ฟเวอร์และไคลเอนต์และสแน็ปช็อตเกิดขึ้นที่ t = 41 เท่านั้น

3) ที่ t = 60 เซิร์ฟเวอร์ส่งสแน็ปช็อตอีกครั้ง แต่หนึ่งวินาทีของการจำลองนั้นเสียลูกค้าไปเนื่องจากความล่าช้า หากสแน็ปช็อตมาถึงที่ t = 60 ไคลเอนต์จะไม่ทำการแก้ไขของ 40 และ 60 instants แต่จริง ๆ แล้วจาก instants 41 ถึง 60 สร้างลักษณะการทำงานที่แตกต่างกัน ความไม่แน่นอนนี้อาจเป็นสาเหตุของ "กระตุก" ในที่สุด

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


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

ลูกค้าทราบตำแหน่งเริ่มต้นและปัจจุบันความเร็วและการเร่งความเร็วของวัตถุและจะอัปเดตตำแหน่งที่คิดว่าวัตถุนั้น (เป็นอิสระจากเซิร์ฟเวอร์) ตามลำดับ เซิร์ฟเวอร์จะเปลี่ยนคุณสมบัติดังกล่าวในไคลเอนต์ผ่านทางข้อความในที่สุดเพราะเป็นเซิร์ฟเวอร์ที่กำลังทำการตรวจจับทางฟิสิกส์และการชนกันของข้อมูล (ซึ่งถูกผูกไว้เพื่อเปลี่ยนความเร็ว / ความเร่งและทิศทางของวัตถุที่กำหนดไม่ช้าก็เร็ว)
UBSophung
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.