ความแตกต่างระหว่างวิธีการอัปเดตและคงที่ใน Unity หรือไม่


14

ฉันเริ่มที่จะเรียนรู้ Unity3d และเป็นหนึ่งในความสับสนที่ฉันได้รับคือความแตกต่างระหว่างและUpdate()FixedUpdate()

ฉันกำลังติดตามการพัฒนาเกม Lynda Unity 2D อยู่ที่นั่นผู้สอนใช้Updateวิธีการผู้เล่นมีส่วนประกอบ RigidBody2D และกล่อง Collider เขาใช้Updateวิธีการแปลผู้เล่น แต่เมื่อฉันทำเช่นเดียวกันในUpdateผู้เล่นจะไม่ย้าย แต่เมื่อฉันทำ มันอยู่ในFixedUpdateงานทุกอย่าง เขากำลังให้การสอนจาก Unity 4.3 และฉันกำลังเรียนใน Unity 4.6

ฉันควรใช้ที่ไหนUpdateและFixedUpdate?

คำตอบ:


14

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

คำตอบปัจจุบันส่วนใหญ่จะถูกต้อง แต่บางสิ่งที่กล่าวมานั้นทำให้เข้าใจผิด / ผิด

โดยทั่วไปงานที่เกี่ยวข้องกับการเล่นเกมส่วนใหญ่จะเข้าUpdateมา

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

ฟิสิกส์ที่ได้รับการปรับปรุงอย่างต่อเนื่องเป็นงานที่เกี่ยวข้องกับเกมเท่านั้นที่FixedUpdateควรใช้ / ไม่ต่อเนื่องครั้งหนึ่งในขณะที่มีการโทรไปยังสิ่งที่ต้องการPhysics.Raycastหรือแม้กระทั่งเป็นของในRigidbody.AddForce Updateการกล่าวถึงของฉันRigidbody.AddForceดูเหมือนจะขัดกับสิ่งที่อาจเป็นนัยโดยเอกสารประกอบ แต่กุญแจคือต่อเนื่อง vs ไม่ต่อเนื่อง

เหตุผลหนึ่งที่ว่าทำไมขนาดใหญ่เพียงฟิสิกส์อย่างต่อเนื่องอยู่ในเป็นธรรมชาติที่แท้จริงของFixedUpdate FixedUpdateคำตอบอื่น ๆ ได้กล่าวถึงวิธีที่ FixedUpdate เรียกว่าที่ fixed interval, but that's slightly misleading. In reality, a script is passed a time in Time.deltaTime/ Time.fixedDeltaTime* ซึ่งไม่ตรงกับเวลาจริงระหว่างการโทร แต่เป็นการจำลองเวลาระหว่างการโทร

(* Time.deltaTimeและTime.fixedDeltaTimeเป็นค่าเดียวกันเมื่อถูกเรียกในFixedUpdate[Unity สามารถบอกได้ว่าการเรียกปัจจุบันไปยังTime.deltaTimeต้นกำเนิดในระหว่างFixedUpdateและส่งคืนTime.fixedDeltaTime])

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

... FixedUpdate: FixedUpdate มักถูกเรียกบ่อยกว่าการอัพเดท สามารถเรียกหลายครั้งต่อเฟรมหากอัตราเฟรมต่ำและอาจไม่สามารถเรียกระหว่างเฟรมได้เลยหากอัตราเฟรมสูง ...

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

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

หากคุณต้องการที่จะทำบางสิ่งบางอย่างที่คงใช้วิธีการอื่น ๆ ช่วงเวลาความสามัคคีให้เช่นและCoroutinesInvokeRepeating

และบันทึกย่อขนาดเล็กบนTime.deltaTimeและเวลาที่จะใช้:

วิธีที่ง่ายที่สุดในการอธิบายถึงผลกระทบของการ Time.deltaTime คือมันเปลี่ยนแปลงตัวเลขจากหน่วยต่อเฟรมไปยังหน่วยต่อวินาที ตัวอย่างเช่นถ้าคุณมีสคริปต์กับสิ่งที่ต้องการtransform.Translate(Vector3.up * 5)ใน Update คุณกำลังหลักย้ายแปลงในอัตรา 5 เมตรต่อกรอบ นั่นหมายความว่าถ้าอัตราเฟรมต่ำการเคลื่อนไหวก็จะช้าลงและถ้าอัตราเฟรมสูงการเคลื่อนไหวก็จะเร็วขึ้น

ถ้าคุณใช้รหัสเดียวกันกับที่และเปลี่ยนเป็นtransform.Translate(Vector3.up * 5 * Time.deltaTime)วัตถุที่จะถูกย้ายไปอยู่ในอัตรา 5 เมตรต่อวินาที นั่นหมายความว่าไม่ว่าจะเป็นอัตราเฟรมวัตถุจะเคลื่อนที่ 5 เมตรทุกวินาที (แต่ยิ่งช้าลงอัตราเฟรมจะเพิ่มขึ้นการเคลื่อนไหวของวัตถุจะยิ่งดีขึ้นเนื่องจากมันยังคงเคลื่อนที่เท่าเดิมทุก ๆ สิบวินาที)

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

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


4

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

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


นี่เป็นอีกทางเลือกหนึ่งในการคูณด้วย Time.delta หรือไม่ มีเหตุผลที่จะใช้อย่างใดอย่างหนึ่งหรือไม่?
เบ็น

@Ben พวกเขามีสองเป้าหมายที่แตกต่างกันและคุณควรใช้ฟังก์ชั่นที่ถูกต้องสำหรับสิ่งที่คุณกำลังทำ
o0 '

@ โลโฮริสขออภัยฉันหมายถึงมีเหตุผลที่จะใช้ FixedUpdate ในการอัปเดตและทวีคูณสิ่งต่าง ๆ ตาม Time.deltaTime เพื่อทำให้เฟรมเป็นอิสระหรือไม่
เบ็น

@ โดยใช่ความแม่นยำ ในระบบที่มีการเรนเดอร์Updateต่ำจะได้รับการเรียกน้อยลงเรื่อย ๆ และการจำลองของคุณจะได้รับผลกระทบมากมาย คุณอาจไม่สังเกตในขณะที่การจำลองนั้นง่าย แต่มันจะแตกหักอย่างน่ากลัวเมื่อไม่ได้
o0 '

1
@Ben no: หากคุณต้องการให้การจำลองของคุณแม่นยำคุณต้องทำตามขั้นตอนเล็ก ๆ หลายขั้นไม่ต้องสุ่มตัวอย่างใหญ่กว่าหรือเล็กกว่าทุกครั้ง และไม่จุดสำคัญของการอัพเดทคงที่ก็คือมันได้รับการเรียกหลายครั้งโดยที่ไม่มีคำถามถาม
o0 '

2

จาก: http://unity3d.com/learn/tutorials/modules/beginner/scripting/update-and-fixedupdate

ขั้นตอนเวลาที่ใช้ใน FixedUpdate ไม่แปรผัน

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

ตัวอย่างเช่น:

Update(float elapsedSeconds)
{
  Position += Velocity * 34.23423; //Windows Update is self-important
}
FixedUpdate(float elapsedSeconds)
{
  Position += Velocity * 0.0166; //60fps
}

ที่ไหน:

Update(34.23423)

==

FixedUpdate(10.0)
FixedUpdate(10.0)
FixedUpdate(10.0)
//4.23423 + 5.76577 game-seconds later...
FixedUpdate(10.0)

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

คนส่วนใหญ่ [Unity?] ไม่ทราบว่า Render / Update / FixedUpdate ถูกเรียกใช้จากวิธีการโทรกลับครั้งเดียวดังนั้นฉันจึงคิดว่า ขอบคุณสำหรับความพยายามของคุณ!
Jon

2

Updateเรียกว่าเร็วที่สุด ตัวแปร 'Time.deltaTime' ถูกตั้งค่าเป็นจำนวนเวลาจริงที่ส่งผ่านนับตั้งแต่การโทรครั้งล่าสุด หากล่าช้าหรือสิ่งที่คล้ายกันช้าลงเกมจะยังคงถูกเรียกว่าเพียงครั้งเดียวครั้งเดียวล่าช้าที่มีมากกว่าที่มีมูลค่าสูงของUpdatedeltaTime

FixedUpdateเรียกว่าในช่วงเวลาปกติ จะไม่ถูกเรียกใช้บ่อยกว่าอัตราส่วนที่ระบุใน 'Time.fixedDeltaTime' หากความล่าช้าหรือสิ่งที่คล้ายกันทำให้เกมช้าลงFixedUpdateจะมีการเรียกหลาย ๆ ครั้งอย่างต่อเนื่องเพื่อให้เกมดังกล่าวทัน Time.deltaTimeถูกตั้งค่าเท่ากับTime.fixedDeltaTimeก่อนที่FixedUpdateจะรัน แต่นี่เป็นเพียงความเหลวไหลเพื่อให้ง่ายต่อการโยกย้ายรหัสระหว่างทั้งสอง

โดยทั่วไปUpdateควรใช้สำหรับพฤติกรรมแบบปรับเปลี่ยนได้และFixedUpdateสำหรับพฤติกรรมที่ต้องคำนวณทีละขั้นตอนหรือขึ้นอยู่กับสิ่งที่ทำเช่นการเคลื่อนไหวตามฟิสิกส์ หากคุณกำลังเขียนวนรอบชนิดใด ๆ ลงUpdateไปในบรรทัดfor(time=0;time<=deltaTime;time+=someStep)...คุณควรจะทำเช่นนั้นใน FixedUpdate แทน

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