Sự khác biệt giữa phương pháp Cập nhật và FixedUpdate trong Unity?


14

tôi đang bắt đầu tìm hiểu Unity3d và một trong những nhầm lẫn tôi nhận được là sự khác biệt giữa Update()FixedUpdate().

Tôi đang theo hướng dẫn phát triển trò chơi Lynda Unity 2D ở đó, người hướng dẫn sử dụng Updatephương thức, người chơi có thành phần RigidBody2D và trình tạo hộp, anh ta sử dụng Updatephương pháp để dịch trình phát, nhưng khi tôi làm như vậy Updatethì người chơi không di chuyển nhưng khi tôi làm nó trong FixedUpdate, mọi thứ hoạt động. Anh ấy đang hướng dẫn từ Unity 4.3 và tôi đang tham gia khóa học về Unity 4.6.

Tôi nên sử dụng ở đâu UpdateFixedUpdate?

Câu trả lời:


14

Tôi sẽ viết nó như một bình luận, nhưng cuối cùng nó khá dài nên tôi đã biến nó thành một câu trả lời.

Các câu trả lời hiện tại hầu hết đều đúng, nhưng một vài điều được đề cập là sai / sai.

Nói chung, hầu hết các nhiệm vụ liên quan đến chơi trò chơi sẽ đi vào Update.

Ví dụ: bạn không muốn bỏ phiếu cho đầu vào FixedUpdate(không phải vì hiệu suất, mà vì các cuộc gọi đơn giản là không hoạt động chính xác). AI rơi vào cùng một chiếc thuyền.

Vật lý được cập nhật liên tục là nhiệm vụ duy nhất liên quan đến trò chơi FixedUpdatenên được sử dụng cho. Các cuộc gọi không liên tục / một lần trong một thời gian đến những thứ như Physics.Raycast, hoặc thậm chí Rigidbody.AddForcethuộc về Update. Đề cập của tôi Rigidbody.AddForcedường như trái ngược với những gì có thể được ngụ ý trong tài liệu, nhưng chìa khóa là Liên tục so với Không liên tục.

Một lý do lớn tại sao chỉ có vật lý liên tục thuộc về FixedUpdatebản chất thực tế của FixedUpdate. Các câu trả lời khác đã đề cập đến cách FixedUpdate được gọi ở mức cố định interval, but that's slightly misleading. In reality, a script is passed a time in Time.deltaTime/ Time.fixedDeltaTime* không tương ứng trực tiếp với thời gian thực tế giữa các cuộc gọi, mà là thời gian mô phỏng giữa các cuộc gọi.

(* Time.deltaTimeTime.fixedDeltaTimelà cùng một giá trị khi được gọi trong FixedUpdate[Unity có thể cho biết nếu cuộc gọi hiện tại được Time.deltaTimekhởi tạo trong FixedUpdatevà trả về Time.fixedDeltaTime])

Đương nhiên, cùng một cách Updatekhông thể được gọi một cách liên tục vì hiệu suất khác nhau, cũng không thể FixedUpdate. Sự khác biệt chính là, mỗi khung hình, nếu FixedUpdatekhông được gọi thường xuyên đủ để tính trung bình cho khoảng thời gian chính xác giữa các cuộc gọi, nó sẽ được gọi nhiều lần (hoặc không được gọi là mức trung bình quá cao). Đây là những gì các tài liệu trên Lệnh thực thi đề cập đến khi nói rằng FixedUpdate có thể được gọi nhiều lần trong một khung:

... FixedUpdate: FixedUpdate thường được gọi thường xuyên hơn Cập nhật. Nó có thể được gọi nhiều lần trên mỗi khung hình, nếu tốc độ khung hình thấp và có thể không được gọi giữa các khung hình nếu tốc độ khung hình cao ...

Điều này không ảnh hưởng đến Vật lý vì bản chất của phần còn lại của lệnh thực hiện và động cơ, nhưng bất kỳ thứ gì khác bạn đặt vào FixedUpdatesẽ bị ảnh hưởng và nó sẽ gây ra sự cố.

Ví dụ: nếu bạn đặt xử lý AI bên trong FixedUpdatethì không có lý do gì để cho rằng AI sẽ không bỏ qua các bản cập nhật cho nhiều khung hình liên tiếp. Ngoài ra, mỗi lần `FixedUpdate tụt lại phía sau, AI của bạn sẽ cập nhật nhiều lần trong một khung hình trước khi những thứ như vật lý và đầu vào / chuyển động của người chơi được xử lý, điều này rất lãng phí khi xử lý, nhưng cũng cực kỳ gây ra khó khăn để theo dõi lỗi và hành vi thất thường.

Nếu bạn cần làm gì đó trong một khoảng thời gian cố định, hãy sử dụng các phương pháp khác mà Unity cung cấp như CoroutinesInvokeRepeating.

Và một lưu ý nhỏ về Time.deltaTimevà khi nào nên sử dụng nó:

Cách dễ nhất để mô tả hiệu ứng của Time.deltaTime là thay đổi một số từ đơn vị trên mỗi khung, thành đơn vị mỗi giây . Ví dụ: nếu bạn có một tập lệnh giống như transform.Translate(Vector3.up * 5)trong Cập nhật, về cơ bản, bạn đang di chuyển biến đổi với tốc độ 5 mét mỗi khung hình . Điều đó có nghĩa là nếu tốc độ khung hình thấp thì chuyển động chậm hơn và nếu tốc độ khung hình cao thì chuyển động nhanh hơn.

Nếu bạn lấy cùng mã đó và đổi nó thành transform.Translate(Vector3.up * 5 * Time.deltaTime), đối tượng đang được di chuyển với tốc độ 5 mét mỗi giây . Điều đó có nghĩa là bất kể tốc độ khung hình, vật thể sẽ di chuyển 5 mét mỗi giây (nhưng tốc độ khung hình càng chậm, chuyển động của vật thể sẽ càng xuất hiện vì nó vẫn di chuyển cùng một lượng mỗi X giây)

Nói chung, bạn muốn chuyển động của bạn được mỗi giây. Theo cách đó, bất kể máy tính đang hoạt động ở tốc độ nào, vật lý / chuyển động của bạn sẽ hoạt động theo cùng một cách và bạn sẽ không gặp phải những lỗi lạ xuất hiện trên các thiết bị chậm hơn.

Và không có điểm nào trong việc sử dụng nó trong FixedUpdate. Vì những gì tôi đã đề cập ở trên, bạn sẽ nhận được cùng một giá trị cho mỗi cuộc gọi (giá trị Dấu thời gian cập nhật cố định) và nó sẽ không làm gì với giá trị của bạn. Chuyển động / Vật lý được xác định trong FixedUpdatesẽ có đơn vị mỗi giây vì vậy bạn không cần nó.


4

Các Updatehàm được gọi mỗi khung. Tần số của nó phụ thuộc vào tốc độ máy tính có thể kết xuất hình ảnh. Trên một máy tính chậm hơn, Updateđược gọi là ít thường xuyên hơn trên một máy tính nhanh hơn. Nếu bạn thực hiện các phép tính dựa trên thời gian, bạn có thể bình thường hóa chúng bằng cách sử dụng Time.deltaTimenó cho bạn biết đã bao lâu kể từ lần cuối cùng Updateđược gọi (áp dụng hãy cẩn thận).
Nói chung, bạn sẽ sử dụng Updateđể thực hiện các tác vụ liên quan đến hiển thị (ví dụ: cập nhật phần tử UI)

Các FixedUpdatehàm được gọi trong khoảng thời gian cố định. Cho dù hình ảnh được làm mới thường xuyên như thế nào, FixedUpdatesẽ được gọi là 1/Time.fixedDeltaTimethời gian mỗi giây
Bạn thường sẽ sử dụng FixedUpdateđể thực hiện các tác vụ liên quan đến trò chơi (ví dụ: cập nhật vật lý)


Đây có phải là một thay thế để nhân với thời gian Time.delta? Có một lý do để sử dụng cái này hay cái kia?
Ben

@Ben họ có hai mục tiêu khác nhau và bạn nên sử dụng đúng chức năng cho những gì bạn đang làm.
o0 '.

@Lohoris Xin lỗi, ý tôi là có lý do để sử dụng FixedUpdate trên Cập nhật và nhân số thứ theo Time.deltaTime để làm cho chúng có khung độc lập không?
Ben

@Ben có, chính xác. Trong một hệ thống có kết xuất chậm, Updateđược gọi ngày càng ít thường xuyên hơn và mô phỏng của bạn sẽ chịu đựng rất nhiều từ đó. Bạn có thể không nhận thấy trong khi mô phỏng đơn giản, nhưng nó sẽ dễ dàng bị phá vỡ khủng khiếp khi không.
o0 '.

1
@Ben không: nếu bạn muốn mô phỏng của mình chính xác, bạn phải thực hiện nhiều bước nhỏ, không phải bước lớn ngẫu nhiên lớn hơn hoặc nhỏ hơn mỗi lần. Và không, toàn bộ quan điểm của FixedUpdate là nó được gọi nhiều lần, không có câu hỏi nào.
o0 '.

2

Từ: http://unity3d.com/learn/tutorials/modules/beginner/scripting/update-and-fixedupdate

Bước thời gian được sử dụng trong FixedUpdate không thay đổi.

Nếu trò chơi của bạn bắt đầu bị lag, khi trò chơi bắt kịp, bạn không muốn> 10 giây vật lý trong một bản cập nhật, do đó, nó thường được thực hiện trong FixedUpdate, được gọi trong một khoảng thời gian cố định.

Ví dụ:

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

Ở đâu:

Update(34.23423)

==

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

Tôi đã đề cập đến điều này trong câu trả lời của mình, nhưng FixedUpdatethực tế không được gọi ở một khoảng thời gian cố định. Bản chất thực tế FixedUpdatelà ép nhiều chu kỳ vật lý vào một khung nếu trò chơi của bạn bắt đầu bị lag và bỏ qua các chu kỳ nếu quá nhanh để tốc độ trung bình hoạt động theo Dấu thời gian cập nhật cố định. Unity không phải là đa luồng, vì vậy sẽ không có cách nào để đảm bảo các cuộc gọi FixedUpdate ở một khoảng thời gian cố định (Điều gì xảy ra khi một FixedUpdate mất quá nhiều thời gian). Ngay cả khi nó có lẽ vẫn gần như không thể.
Selali Adobor 14/2/2015

Hầu hết mọi người [Unity?] Không biết rằng Render / Update / FixedUpdate đều được gọi từ trong một phương thức gọi lại duy nhất, vì vậy tôi đã khái niệm hóa. Cảm ơn nỗ lực của bạn!
Jon

2

Updateđược gọi là càng nhanh càng tốt. Biến số 'Time.deltaTime' được đặt thành lượng thời gian thực tế đã trôi qua kể từ cuộc gọi cuối cùng. Nếu độ trễ hoặc thứ gì đó tương tự làm chậm trò chơi, Updatevẫn sẽ chỉ được gọi một lần khi độ trễ kết thúc, với giá trị cao deltaTime.

FixedUpdateđược gọi trong khoảng thời gian thường xuyên. Nó sẽ không bao giờ được gọi thường xuyên hơn tỷ lệ được chỉ định trong 'Time.fixedDeltaTime'. Nếu độ trễ hoặc một cái gì đó tương tự làm chậm trò chơi, FixedUpdatesẽ được gọi nhiều lần liên tiếp để cho phép trò chơi bắt kịp. Time.deltaTimeđược đặt bằng với Time.fixedDeltaTimetrước khi FixedUpdatechạy, nhưng đây chỉ là một lỗi để giúp dễ dàng di chuyển mã giữa hai.

Nói chung, Updatenên được sử dụng cho các hành vi có thể nội suy và FixedUpdatecho các hành vi phải được tính toán từng bước hoặc phụ thuộc vào các hành vi đó, chẳng hạn như chuyển động dựa trên vật lý. Nếu bạn đang viết bất kỳ loại vòng lặp nào Updatedọc theo dòng for(time=0;time<=deltaTime;time+=someStep)...thì có lẽ bạn nên thực hiện nó trong FixedUpdate.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.