ฉันควรใช้ขั้นตอนเวลาแบบคงที่หรือแบบแปรผันเมื่อใด


256

ลูปเกมควรเป็นไปตามขั้นตอนเวลาคงที่หรือแปรผันหรือไม่? เป็นหนึ่งที่เหนือกว่าเสมอหรือตัวเลือกที่เหมาะสมแตกต่างกันไปตามเกม?

ขั้นตอนเวลาผันแปร

การอัปเดตทางฟิสิกส์จะถูกส่งผ่านอาร์กิวเมนต์ "เวลาที่ผ่านไปนับตั้งแต่การอัปเดตครั้งล่าสุด" และขึ้นอยู่กับอัตราเฟรม position += distancePerSecond * timeElapsedซึ่งอาจหมายถึงทำคำนวณเป็น

จุดเด่น : ราบรื่นและง่ายต่อการเขียนโค้ดจุด
ด้อย : ไม่สามารถกำหนดค่าได้คาดเดาไม่ได้ในขั้นตอนเล็กหรือใหญ่

ตัวอย่างdeWiTTERS :

while( game_is_running ) {
    prev_frame_tick = curr_frame_tick;
    curr_frame_tick = GetTickCount();
    update( curr_frame_tick - prev_frame_tick );
    render();
}

ขั้นตอนเวลาคงที่

การอัปเดตอาจไม่ยอมรับ "เวลาที่ผ่านไป" เนื่องจากจะถือว่าการอัปเดตแต่ละรายการเป็นช่วงเวลาที่แน่นอน การคำนวณอาจทำได้position += distancePerUpdateดังนี้ ตัวอย่างมีการแก้ไขระหว่างการเรนเดอร์

จุดเด่น : สามารถคาดการณ์ได้กำหนดขึ้น (ซิงค์เครือข่ายง่ายกว่า) รหัสการคำนวณที่ชัดเจนจุด
ด้อย : ไม่ซิงค์กับการตรวจสอบ v-sync (ทำให้เกิดภาพกราฟิกที่กระวนกระวายใจเว้นแต่ว่าคุณจะแก้ไข) อัตราเฟรมสูงสุดที่ จำกัด สมมติขั้นตอนเวลาที่ผันแปร (เช่นPygletหรือFlixel )

ตัวอย่างdeWiTTERS :

while( game_is_running ) {
    while( GetTickCount() > next_game_tick ) {
        update();
        next_game_tick += SKIP_TICKS;
    }
    interpolation = float( GetTickCount() + SKIP_TICKS - next_game_tick )
                    / float( SKIP_TICKS );
    render( interpolation );
}

ทรัพยากรบางอย่าง


6
ใช้การประทับเวลาผันแปรสำหรับเกมของคุณและขั้นตอนคงที่สำหรับฟิสิกส์
Daniel Little

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

จริงฉันคิดว่าฉันหมายถึงว่าคุณไม่จำเป็นต้องสอดแทรกขั้นตอนของเวลาแปรผัน
Nick Sonneveld

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

คุณสามารถตรวจสอบ visuall เหล่านี้ได้จากเครื่องมือนี้: s3.amazonaws.com/picobots/assets/unity/jerky-motion/ …ถึงแม้ว่ามันจะไม่ได้ให้ความคิดกับคุณเกี่ยวกับว่าพวกเขาจะดูอย่างไรเมื่ออัตราเฟรมเปลี่ยนแปลง
Buddy

คำตอบ:


134

มีสองประเด็นที่เกี่ยวข้องกับคำถามนี้

  • อัตราขั้นตอนทางฟิสิกส์ควรเชื่อมโยงกับอัตราเฟรมหรือไม่
  • ฟิสิกส์ควรจะก้าวด้วยสันดอนคงที่หรือไม่

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

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

ในคำแนะนำของ Erin Catto สำหรับ Box2D เขาก็สนับสนุนสิ่งนี้เช่นกัน

ดังนั้นอย่าผูกขั้นตอนกับอัตราเฟรมของคุณ (เว้นแต่คุณจะต้องทำจริงๆ)

อัตราขั้นตอนทางฟิสิกส์ควรเชื่อมโยงกับอัตราเฟรมของคุณหรือไม่ เลขที่


ความคิดของ Erin เกี่ยวกับขั้นตอนคงที่และการก้าวตัวแปร:

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

ความคิดของ Glen เกี่ยวกับการแก้ไขค่าคงที่และตัวแปร:

แก้ไขการประทับเวลาหรือการระเบิดของคุณ

... หากคุณมีข้อ จำกัด แบบสปริงแข็งสำหรับโช้คอัพในการจำลองรถยนต์การเปลี่ยนแปลงเล็กน้อยใน dt สามารถทำให้การจำลองระเบิดได้จริง ...

ฟิสิกส์ควรจะก้าวด้วยสันดอนคงที่หรือไม่ ใช่.


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

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

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


1
ฉันเคยเล่น The Floor เป็น Jelly มาก่อนและหลังการอัพเกรดเครื่องของฉันและมันก็งี่เง่า: มันไม่เหมือนกันเพราะฟิสิกส์ถูกเรียกมาจากวงเกมจริง ๆ (และเชื่อมโยงกับอัตราเฟรม) และไม่ใช่จาก จับเวลา เครื่องเก่าของฉันแย่มากดังนั้นมันจึงสลับระหว่างสโลว์โมชั่นและสโลว์โมชั่นเร็วเกินไปและมันส่งผลกระทบอย่างมากต่อการเล่นเกม ตอนนี้มันเป็นภาพเคลื่อนไหวที่รวดเร็วมาก อย่างไรก็ตามเกมนั้นเป็นตัวอย่างที่ดีว่าปัญหานี้เป็นอย่างไร (ยังเป็นเกมที่น่ารักอยู่ดี)
MasterMastic

55

ฉันคิดว่ามี 3 ตัวเลือกจริง ๆ แต่คุณแสดงรายการเป็น 2 เท่านั้น:

ตัวเลือกที่ 1

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

ตัวเลือก 2

ใช้เวลาเดลต้าระหว่างการอัพเดทแต่ละครั้งเพื่อเปลี่ยนแปลงการเคลื่อนที่ของวัตถุ ดีมากในทางทฤษฎีโดยเฉพาะอย่างยิ่งถ้าไม่มีอะไรในเกมของคุณเร่งความเร็วหรือชะลอตัวลง แต่เพียงแค่เคลื่อนที่ด้วยความเร็วคงที่ ในทางปฏิบัติผู้พัฒนาจำนวนมากใช้สิ่งนี้ไม่ดีและอาจนำไปสู่การตรวจจับการชนและฟิสิกส์ที่ไม่สอดคล้องกัน ดูเหมือนว่านักพัฒนาบางคนคิดว่าวิธีนี้ง่ายกว่าที่คิด หากคุณต้องการใช้ตัวเลือกนี้คุณจะต้องเพิ่มเกมของคุณออกมาอย่างมากและนำเอาคณิตศาสตร์และอัลกอริธึมขนาดใหญ่ออกมาตัวอย่างเช่นการใช้ Verlet Physics Integrator (แทนที่จะเป็น Euler มาตรฐานที่คนส่วนใหญ่ใช้) ค่อนข้างง่ายกว่าการตรวจสอบระยะทางพีทาโกรัส ฉันถามคำถามเกี่ยวกับเรื่องนี้ใน Stack Overflow ย้อนกลับไปและได้รับคำตอบที่ดี:

https://stackoverflow.com/questions/153507/calculate-the-position-of-an-accelerating-body-after-a-certain-time

ตัวเลือก 3

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

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


เกี่ยวกับตัวเลือกที่ 2: ฉันไม่แน่ใจว่า raycast จะเร็วกว่าการตรวจสอบระยะทาง pythagoras ยกเว้นว่าคุณเป็นสัตว์เดรัจฉานที่แรงมากในการประยุกต์ใช้ pythagoras แต่ raycast นั้นจะมีราคาแพงมากถ้าคุณไม่เพิ่ม broadphase
Kaj

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

ตัวเลือก 3 - ดูเหมือนคำอธิบายวิธี XNA ของ Joel Martinez
topright

1
นี่เป็นคำตอบที่ดีจริงๆ ทั้งสามตัวเลือกมีที่ของพวกเขาและเป็นสิ่งสำคัญที่จะเข้าใจเมื่อพวกเขามีความเหมาะสม
Adam Naylor

MMO ทั้งหมดที่ฉันได้ทำงาน (EQ, Landmark / EQNext [ร้องไห้], PS2 [สั้น ๆ ] และ ESO) เราใช้กรอบเวลาแบบผันแปรเสมอ ฉันไม่เคยเป็นปาร์ตี้ในการตัดสินใจนั้นเพียง แต่ปรากฏตัวขึ้นหลังจากความจริงและใช้ประโยชน์จากสิ่งที่คนอื่นตัดสินใจ
Mark Storer

25

ฉันชอบวิธีที่XNA Frameworkใช้ขั้นตอนเวลาแบบตายตัว หากการเรียกการดึงที่กำหนดใช้เวลานานเกินไปมันจะเรียกการอัปเดตซ้ำ ๆ จนกระทั่ง "จับได้" Shawn Hargreaves อธิบายได้ที่นี่:
http://blogs.msdn.com/b/shawnhar/archive/2007/11/23/game-timing-in-xna-game-studio-2-0.aspx

ใน 2.0 พฤติกรรมการวาดมีการเปลี่ยนแปลง:

  • เรียกการอัปเดตหลาย ๆ ครั้งตามต้องการเพื่อให้ทันกับเวลาปัจจุบัน
  • โทรวาดหนึ่งครั้ง
  • รอจนกว่าจะถึงเวลาสำหรับการอัพเดทครั้งต่อไป

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

หมายเหตุ: xna รองรับการตั้งเวลาตัวแปรได้เช่นกันมันเป็นเพียงการตั้งค่า


นี่เป็นวิธีที่ใช้กันโดยทั่วไปในการทำลูปเกม อย่างไรก็ตามมันไม่ดีสำหรับอายุการใช้งานแบตเตอรี่เมื่อทำงานกับอุปกรณ์พกพา
knight666

1
@ knight666; คุณแนะนำว่าการใช้เวลาที่นานขึ้นการลดจำนวนการทำซ้ำจะช่วยประหยัดแบตเตอรี่
falstro

ยังคงเป็นการอัปเดตตัวแปร - การเปลี่ยนแปลงเดลต้าจะเปลี่ยนแปลงตามระยะเวลาที่เฟรมใช้ในการเรนเดอร์แทนที่จะเป็นค่าคงที่ (เช่น 1 / 30th ของวินาที)
Dennis Munsie

1
@Dennis: ที่ผมเข้าใจมันฟังก์ชั่นการปรับปรุงเรียกว่ามีเดลต้าคง ...
RCIX

3
@ knight666 เอ่อ - คุณคิดยังไง หากคุณมี vsync และไม่ได้พูดติดอ่าง - วิธีการเหล่านี้ควรเหมือนกัน! และถ้าคุณมี Vsync ปิดคุณอัปเดตมากขึ้นบ่อยกว่าที่คุณต้องและอาจจะเสีย CPU (และแบตเตอรี่) โดยไม่ปล่อยให้มันว่าง!
Andrew Russell

12

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

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

นี่ไม่ใช่เรื่องง่ายที่จะนำมาใช้ แต่อาจพิสูจน์ได้ว่าเป็นข้อพิสูจน์ในอนาคต


8

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

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

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

การใช้งานที่ไม่ดีของสิ่งนี้จะทำให้ F = เวลาปัจจุบัน - อัปเดตเวลาของเฟรมล่าสุด แต่ถ้าการคำนวณอยู่ไกลเกินไป (บางครั้งเกิดจากสถานการณ์ที่อยู่นอกเหนือการควบคุมของคุณเช่นกระบวนการอื่นที่จะขโมยเวลา CPU) คุณจะเห็นการกระโดดที่น่ากลัวอย่างรวดเร็ว FPS ที่เสถียรที่คุณพยายามรักษาไว้จะกลายเป็นค่า SPF อย่างรวดเร็ว

ในเกมของฉันฉันอนุญาตให้ "ช้า" (เรียงลำดับ) การชะลอตัวเพื่อ จำกัด ปริมาณของตรรกะการติดตามที่ควรจะเป็นไปได้ระหว่างสองเสมอ ฉันทำได้โดยการหนีบ: F = min (F, MAX_FRAME_DELTA) ซึ่งมักจะมี MAX_FRAME_DELTA = 2/100 * s หรือ 3/100 * s ดังนั้นแทนที่จะข้ามเฟรมเมื่ออยู่หลังตรรกะของเกมมากเกินไปให้ทิ้งการสูญเสียเฟรมจำนวนมาก (ซึ่งทำให้สิ่งต่าง ๆ ช้าลง) กู้คืนเฟรมไม่กี่วาดและลองอีกครั้ง

ด้วยการทำเช่นนี้ฉันต้องแน่ใจว่าผู้เล่นควบคุมการซิงค์อย่างใกล้ชิดกับสิ่งที่แสดงบนหน้าจอจริง

รหัสผลิตภัณฑ์สุดท้ายคืออะไรเช่นนี้ (เดลต้าคือ F ที่กล่าวถึงก่อนหน้า):

// Assume timers have 1/100 s resolution
const MAX_FRAME_DELTA = 2
// Calculate frame gap.
var delta = current time - last frame time
// Clamp.
delta = min(delta, MAX_FRAME_RATE)
// Update in discrete steps
for(i = 0; i < delta; i++)
{
    update single step()
}
// Caught up again, draw.
render()

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


เห็นด้วยอย่างยิ่งกับจุดสุดท้ายนั้น ในเกมทุกเกมการป้อนข้อมูลควร 'ช้าลง' เมื่ออัตราเฟรมลดลง แม้ว่านี่จะเป็นไปไม่ได้ในบางเกม (เช่นผู้เล่นหลายคน) แต่มันจะดีกว่าถ้าเป็นไปได้ : P มันให้ความรู้สึกที่ดีกว่าการมีกรอบยาว ๆ แล้วให้โลกของเกม 'กระโดด' ไปสู่สถานะ 'ถูกต้อง'
Ipsquiggle

หากไม่มีฮาร์ดแวร์ที่คงที่เช่นเครื่องอาร์เคดการมีเกมอาร์เคดจะทำให้การจำลองช้าลงเมื่อฮาร์ดแวร์ไม่สามารถติดตามได้ทำให้การเล่นบนเครื่องช้าลง

โจนั้นสำคัญถ้าเราใส่ใจกับ "การโกง" เกมสมัยใหม่ส่วนใหญ่ไม่ได้เกี่ยวกับการแข่งขันระหว่างผู้เล่นเพียงแค่สร้างประสบการณ์ที่สนุกสนาน
Iain

1
ตอนนี้เรากำลังพูดถึงเกมสไตล์อาร์เคดโดยเฉพาะที่นี่ซึ่งเป็นเกมที่ทำคะแนนสูง / ผู้นำลีดเดอร์ ฉันเล่น shmups มากมายและฉันรู้ว่าฉันพบว่ามีใครบางคนกำลังโพสต์คะแนนด้วยการชะลอการประดิษฐ์ไปยังกระดานผู้นำฉันต้องการให้คะแนนของพวกเขาเช็ด

ไม่พยายามลดคำตอบของคุณลง แต่ฉันจะตีความว่านี่เป็นขั้นตอนคงที่โดยที่การแสดงผลไม่ได้เชื่อมโยงกับอัตราการอัปเดตของฟิสิกส์โดยตรง มันมีคุณสมบัติที่ดีแน่นอน
AaronLS

6

โซลูชันนี้ใช้ไม่ได้กับทุกสิ่ง แต่มีระดับการประทับเวลาอีกระดับหนึ่ง - การประทับเวลาแบบแปรผันสำหรับแต่ละวัตถุในโลก

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

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

หากต้องการดูการดำเนินงานที่ซับซ้อนของรูปแบบนี้ให้ดูที่จำลองพื้นที่EXOFLIGHT มันใช้รูปแบบการดำเนินการที่แตกต่างจากเครื่องจำลองการบินส่วนใหญ่ - แบบจำลองตามเหตุการณ์มากกว่ารูปแบบการกำหนดเวลาแบบดั้งเดิม ลูปหลักพื้นฐานของการจำลองประเภทนี้มีลักษณะเช่นนี้ในรหัสหลอก:

while (game_is_running)
{
   world.draw_to_screen(); 
   world.get_player_input(); 
   world.consume_events_until(current_time + time_step); 
   current_time += time_step; 
}

เหตุผลหลักสำหรับการใช้งานหนึ่งตัวในโปรแกรมจำลองอวกาศคือความจำเป็นในการเร่งความเร็วตามอำเภอใจโดยไม่สูญเสียความแม่นยำ ภารกิจบางอย่างใน EXOFLIGHT อาจใช้เวลาเป็นปีของเกมให้เสร็จและแม้แต่ตัวเลือกการเร่งความเร็ว 32x ก็ยังไม่เพียงพอ คุณต้องการความเร่งมากกว่า 1,000,000 เท่าสำหรับซิมที่ใช้งานได้ซึ่งยากที่จะทำในรูปแบบการแบ่งเวลา ด้วยโมเดลอิงเหตุการณ์เราจะได้รับอัตราเวลาตามอำเภอใจจาก 1 วินาที = 7 ms เป็น 1 วินาที = 1 ปี

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

ดังนั้นสรุป: เราสามารถจำลองยานพาหนะหนึ่งคันในวงโคจรที่ยาวสบาย ๆ (โดยใช้การผสานแบบ Runge-Kutta) และยานพาหนะอีกคันที่กระเด้งไปตามพื้นพร้อมกัน - ยานพาหนะทั้งสองจะถูกจำลองด้วยความแม่นยำที่เหมาะสมเนื่องจากเราไม่มีเวลาทั่วโลก

ข้อด้อย: ความซับซ้อนและการขาดเอ็นจิ้นฟิสิกส์นอกตัวที่รองรับโมเดลนี้ :)


5

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

มันเป็นโค้ดง่ายๆที่จะเป็นประโยชน์ในการลองใช้งานและดูว่ามันเหมาะกับเกมของคุณหรือไม่

now = currentTime
frameTime = now - lastTimeStamp // time since last render()
while (frameTime > updateTime)
    update(timestep)
    frameTime -= updateTime     // update enough times to catch up
                                // possibly leaving a small remainder
                                // of time for the next frame

lastTimeStamp = now - frameTime // set last timestamp to now but
                                // subtract the remaining frame time
                                // to make sure the game will still
                                // catch up on those remaining few millseconds
render()

ปัญหาหลักของการใช้ขั้นตอนเวลาที่แน่นอนคือผู้เล่นที่ใช้คอมพิวเตอร์อย่างรวดเร็วจะไม่สามารถใช้ความเร็วได้ แสดงผลที่ 100fps เมื่อเกมอัปเดตที่ 30fps เท่านั้นเช่นเดียวกับการแสดงที่ 30fps

ดังที่กล่าวมาอาจเป็นไปได้ที่จะใช้มากกว่าหนึ่งขั้นตอนเวลาคงที่ 60fps สามารถใช้เพื่ออัปเดตวัตถุเล็ก ๆ น้อย ๆ (เช่น UI หรือภาพเคลื่อนไหวสไปรต์) และ 30fps เพื่ออัปเดตระบบที่ไม่สำคัญ (เช่นฟิสิกส์และ) และแม้แต่ตัวนับเวลาช้าลงเพื่อจัดการเบื้องหลังเช่นการลบวัตถุที่ไม่ได้ใช้ทรัพยากร ฯลฯ


2
หากมีการทำเกมอย่างระมัดระวังวิธีการเรนเดอร์สามารถทำการแก้ไขเพื่อทำการอัปเดต 30fps จริง ๆ แล้วไม่เหมือนกับการเรนเดอร์ที่ 30fps
Ricket

3

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

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

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


5
คุณควรอ่าน Gaffer ในลิงค์ของเกมในโพสต์ดั้งเดิม ผมไม่คิดว่านี่เป็นคำตอบที่ไม่ดีต่อ se ดังนั้นฉันจะไม่ลงลงคะแนน แต่ผมไม่เห็นด้วยกับข้อโต้แย้งใด ๆ ของคุณ
falstro

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

0

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

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


หากคุณจะขโมยคำตอบอย่างน้อยเครดิตคน!
PrimRock

0

ฉันพบว่าการประทับเวลาคงที่ที่ซิงโครไนซ์กับ 60fps ให้ภาพเคลื่อนไหวราบรื่น สิ่งนี้สำคัญอย่างยิ่งสำหรับแอปพลิเคชั่น VR สิ่งอื่นใดที่น่ารังเกียจทางร่างกาย

การกำหนดเวลาแปรผันไม่เหมาะสมสำหรับ VR ดูตัวอย่าง Unity VR ที่ใช้การประทับเวลาแบบแปรผัน มันไม่เป็นที่พอใจ

กฎคือถ้าเกม 3D ของคุณราบรื่นในโหมด VR มันจะยอดเยี่ยมในโหมดที่ไม่ใช่ VR

เปรียบเทียบสองสิ่งนี้ (แอพ Cardboard VR)

(เวลาประทับแปรผัน)

(แก้ไขเวลาที่กำหนด)

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

เกมมือถือเป็น esp ท้าทายเนื่องจากซีพียูและ GPU ในตัวมีประสิทธิภาพ จำกัด ใช้ GLSL (สแลง) อย่างไม่ จำกัด เพื่อลดการทำงานของ CPU ให้มากที่สุด ระวังให้ดีกว่าการส่งพารามิเตอร์ไปที่ GPU นั้นจะสิ้นเปลืองทรัพยากรบัส

แสดง framerate ของคุณเสมอในระหว่างการพัฒนา เกมจริงคือให้คงที่ 60fps นี่คืออัตราการซิงค์ดั้งเดิมสำหรับหน้าจอส่วนใหญ่และสำหรับดวงตาส่วนใหญ่

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


0

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

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

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

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

ทุกอย่างอื่นสามารถจัดการแบบอะซิงโครนัสทำให้กำหนดเวลาเป็นจุดที่สงสัย

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