Khi nào tôi nên sử dụng một bước thời gian cố định hoặc thay đổi?


256

Một vòng lặp trò chơi nên dựa trên các bước thời gian cố định hoặc thay đổi? Là một luôn luôn vượt trội, hoặc sự lựa chọn đúng thay đổi theo trò chơi?

Bước thời gian biến

Các cập nhật vật lý được thông qua một đối số "thời gian trôi qua kể từ lần cập nhật cuối" và do đó phụ thuộc vào tốc độ khung hình. Điều này có thể có nghĩa là làm tính toán như position += distancePerSecond * timeElapsed.

Ưu điểm : trơn tru, dễ mã hóa
Nhược điểm : không xác định, không dự đoán được ở các bước rất nhỏ hoặc lớn

ví dụ deWiTTERS :

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

Bước thời gian cố định

Các bản cập nhật thậm chí có thể không chấp nhận "thời gian đã trôi qua", vì chúng cho rằng mỗi bản cập nhật là trong một khoảng thời gian cố định. Tính toán có thể được thực hiện như position += distancePerUpdate. Ví dụ bao gồm một phép nội suy trong khi kết xuất.

Ưu điểm : có thể dự đoán, xác định (đồng bộ mạng dễ dàng hơn?), Mã tính toán rõ ràng hơn
Nhược điểm : không được đồng bộ hóa để giám sát v-sync (gây ra đồ họa lộn xộn trừ khi bạn nội suy), tốc độ khung hình tối đa (trừ khi bạn nội suy), khó hoạt động trong các khung mà giả sử các bước thời gian thay đổi (như Pyglet hoặc Flixel )

ví dụ 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 );
}

Một số tài nguyên


6
Sử dụng dấu thời gian thay đổi cho trò chơi của bạn và các bước cố định cho vật lý
Daniel Little

7
Tôi sẽ không nói rằng bước thời gian biến đổi dễ dàng hơn để mã hóa chính xác bởi vì với bước thời gian cố định, bạn "không phải nhầm lẫn tất cả các phép tính với biến timeElapsed ở mọi nơi". Không khó lắm, nhưng tôi sẽ không thêm "mã dễ dàng hơn" như một người chuyên nghiệp.
pek

Đúng, tôi nghĩ rằng tôi đã đề cập đến cách bạn sẽ không cần phải nội suy các bước thời gian khác nhau.
Nick Sonneveld

@pek Tôi đồng ý với bạn. Bước thời gian biến có một vòng lặp trò chơi được mã hóa đơn giản hơn nhưng bạn có nhiều mã hơn trong các thực thể của mình để đối phó với sự biến đổi đó để "tăng tốc". Bước thời gian cố định có một vòng lặp trò chơi mã phức tạp hơn (vì bạn phải bù chính xác cho các phương sai gần đúng thời gian và tính toán lại độ trễ thêm nào để thêm hoặc có bao nhiêu cập nhật để bỏ qua để giữ cố định) nhưng có mã hóa đơn giản hơn cho các thực thể sẽ luôn luôn phải đối phó với khoảng thời gian giống nhau. Nhìn chung, không có sự chấp thuận nào rõ ràng đơn giản hơn cái kia.
Shivan Dragon

Bạn có thể kiểm tra các visuall này từ công cụ này: s3.amazonaws.com/picobots/assets/unity/jerky-motion/ trộm mặc dù nó không cho bạn biết họ sẽ trông như thế nào khi tốc độ khung hình thay đổi
Buddy

Câu trả lời:


134

Có hai vấn đề liên quan đến câu hỏi.

  • Tốc độ bước vật lý có nên được gắn với tốc độ khung hình?
  • Vật lý nên được bước với deltas liên tục?

Trong Glen fielder Fix, bước thời gian của bạn, anh ta nói "Giải phóng vật lý". Điều đó có nghĩa là tốc độ cập nhật vật lý của bạn không nên được gắn với tốc độ khung hình của bạn.

Ví dụ: nếu tốc độ khung hình hiển thị là 50 khung hình / giây và mô phỏng được thiết kế để chạy ở tốc độ 100 khung hình / giây thì chúng ta cần thực hiện hai bước vật lý mỗi lần cập nhật màn hình để giữ cho vật lý đồng bộ.

Trong các khuyến nghị của Erin Catto cho Box2D, ông cũng ủng hộ điều này.

Vì vậy, đừng buộc bước thời gian với tốc độ khung hình của bạn (trừ khi bạn thực sự, thực sự phải làm).

Tốc độ bước Vật lý có nên được gắn với tốc độ khung hình của bạn? Không.


Suy nghĩ của Erin về bước cố định so với bước thay đổi:

Box2D sử dụng một thuật toán tính toán được gọi là tích hợp. Các nhà tích hợp mô phỏng các phương trình vật lý tại các thời điểm riêng biệt. ... Chúng tôi cũng không thích bước thời gian để thay đổi nhiều. Bước thời gian thay đổi tạo ra kết quả khác nhau, điều này gây khó khăn cho việc gỡ lỗi.

Suy nghĩ của Glen về bước cố định so với bước thay đổi:

Sửa dấu thời gian của bạn hoặc phát nổ

... Nếu bạn có một loạt các ràng buộc lò xo thực sự cứng cho giảm xóc trong mô phỏng xe hơi thì những thay đổi nhỏ trong dt thực sự có thể làm cho mô phỏng phát nổ. ...

Vật lý nên được bước với deltas liên tục? Đúng.


Cách để bước vật lý với các đồng bằng không đổi và không ràng buộc tốc độ cập nhật vật lý của bạn với tốc độ khung hình vẫn là sử dụng bộ tích lũy thời gian. Trong trò chơi của tôi, tôi tiến một bước xa hơn. Tôi áp dụng một chức năng làm mịn cho thời gian đến. Bằng cách đó, các xung FPS lớn không khiến vật lý nhảy quá xa, thay vào đó chúng được mô phỏng nhanh hơn cho một hoặc hai khung hình.

Bạn đề cập rằng với một tỷ lệ cố định, vật lý sẽ không đồng bộ với màn hình. Điều này đúng nếu tốc độ vật lý đích gần với tốc độ khung hình đích. Điều tồi tệ hơn là tốc độ khung hình lớn hơn tốc độ vật lý. Nói chung, tốt hơn là nhắm mục tiêu tốc độ cập nhật vật lý gấp đôi FPS mục tiêu của bạn, nếu bạn có đủ khả năng.

Nếu bạn không đủ khả năng cập nhật tốc độ cập nhật vật lý lớn, hãy xem xét nội suy các vị trí của đồ họa giữa các khung để làm cho đồ họa được vẽ dường như di chuyển trơn tru hơn so với vật lý thực sự di chuyển.


1
Tôi đã chơi The Floor is Jelly trước và sau khi nâng cấp máy của mình và điều đó thật ngớ ngẩn: đó không phải là điều tương tự vì vật lý thực sự được gọi từ vòng lặp trò chơi (và được gắn với tốc độ khung hình) chứ không phải từ một bộ đếm thời gian. Máy cũ của tôi rất tệ nên nó liên tục chuyển đổi giữa chuyển động chậm và chuyển động quá nhanh và nó có tác động lớn đến lối chơi. Bây giờ nó chỉ ở một chuyển động rất nhanh. Dù sao thì trò chơi đó là một ví dụ điển hình cho thấy vấn đề này có thể trở nên rắc rối như thế nào (mặc dù vẫn là một trò chơi dễ thương).
MasterMastic

55

Tôi nghĩ thực sự có 3 tùy chọn, nhưng bạn chỉ liệt kê chúng là 2:

lựa chọn 1

Không làm gì cả. Cố gắng cập nhật và kết xuất ở một khoảng thời gian nhất định, ví dụ 60 lần mỗi giây. Nếu nó tụt lại phía sau, hãy để nó và đừng lo lắng. Các trò chơi sẽ chậm lại thành chuyển động chậm giật nếu CPU không thể theo kịp trò chơi của bạn. Tùy chọn này hoàn toàn không hoạt động đối với các trò chơi nhiều người dùng thời gian thực, nhưng tốt cho các trò chơi một người chơi và đã được sử dụng thành công trong nhiều trò chơi.

Tùy chọn 2

Sử dụng thời gian delta giữa mỗi lần cập nhật để thay đổi chuyển động của các đối tượng. Tuyệt vời về lý thuyết, đặc biệt là nếu không có gì trong trò chơi của bạn tăng tốc hoặc giảm tốc, mà chỉ di chuyển với tốc độ không đổi. Trong thực tế, nhiều nhà phát triển thực hiện điều này rất tệ, và nó có thể dẫn đến phát hiện va chạm và vật lý không nhất quán. Có vẻ như một số nhà phát triển nghĩ rằng phương pháp này dễ dàng hơn nó. Nếu bạn muốn sử dụng tùy chọn này, bạn cần đẩy mạnh trò chơi của mình lên và đưa ra một số thuật toán và thuật toán súng lớn, ví dụ như sử dụng bộ tích hợp vật lý Verlet (chứ không phải Euler tiêu chuẩn mà hầu hết mọi người sử dụng) và sử dụng tia để phát hiện va chạm thay vì kiểm tra khoảng cách Pythagoras đơn giản. Tôi đã hỏi một câu hỏi về điều này trên Stack Overflow một lúc trước và nhận được một số câu trả lời tuyệt vời:

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

Lựa chọn 3

Sử dụng phương pháp "sửa bước thời gian" của Gaffer. Cập nhật trò chơi theo các bước cố định như trong tùy chọn 1, nhưng thực hiện nhiều lần trên mỗi khung hình - dựa trên thời gian đã trôi qua - để logic trò chơi theo kịp thời gian thực, trong khi vẫn ở các bước riêng biệt. Bằng cách này, dễ dàng thực hiện logic trò chơi như tích hợp Euler và phát hiện va chạm đơn giản vẫn hoạt động. Bạn cũng có tùy chọn nội suy hoạt ảnh đồ họa dựa trên thời gian delta, nhưng điều này chỉ dành cho hiệu ứng hình ảnh và không có gì ảnh hưởng đến logic trò chơi cốt lõi của bạn. Bạn có thể gặp rắc rối nếu các bản cập nhật của bạn rất chuyên sâu - nếu các bản cập nhật bị tụt lại phía sau, bạn sẽ cần nhiều hơn nữa để theo kịp, tiềm năng khiến trò chơi của bạn thậm chí ít phản hồi hơn.

Cá nhân, tôi thích Tùy chọn 1 khi tôi có thể thoát khỏi nó và Tùy chọn 3 khi tôi cần đồng bộ hóa với thời gian thực. Tôi tôn trọng Lựa chọn 2 có thể là một lựa chọn tốt khi bạn biết bạn đang làm gì, nhưng tôi biết rõ những hạn chế của mình đủ để tránh xa nó.


liên quan đến tùy chọn 2: Tôi không chắc chắn rằng một raycast có thể nhanh hơn kiểm tra khoảng cách pythagoras, ngoại trừ nếu bạn rất mạnh mẽ trong việc áp dụng pythagoras, nhưng một raycast cũng sẽ rất tốn kém nếu bạn không thêm một broadphase.
Kaj

4
Nếu bạn sử dụng Verlet với các bước thời gian không đồng đều, bạn sẽ ném em bé ra ngoài bằng nước tắm. Lý do Verlet ổn định như vậy là vì lỗi hủy bỏ trong các bước thời gian tiếp theo. Nếu các bước thời gian không bằng nhau, điều này không xảy ra và bạn quay lại vùng đất vật lý bùng nổ.
drxzcl

Tùy chọn 3 - nghe giống như mô tả của Joel Martinez về cách tiếp cận XNA.
topright

1
Đây là một câu trả lời thực sự tốt. Tất cả ba tùy chọn đều có vị trí của chúng và điều quan trọng là phải hiểu khi nào chúng phù hợp.
Adam Naylor

Tất cả các MMO tôi đã làm việc (EQ, Landmark / EQNext [khóc], PS2 [ngắn gọn] và ESO), chúng tôi luôn sử dụng thời gian khung thay đổi. Tôi chưa bao giờ là một bên của quyết định cụ thể đó, chỉ xuất hiện sau khi thực tế và sử dụng những gì người khác đã quyết định.
Mark Storer

25

Tôi thực sự thích cách XNA Framework thực hiện bước thời gian cố định. Nếu một cuộc gọi bốc thăm nhất định mất quá nhiều thời gian, nó sẽ gọi cập nhật liên tục cho đến khi "bắt kịp". Shawn Hargreaves mô tả nó ở đây:
http://bloss.msdn.com/b/shawnhar/archive/2007/11/23/game-timing-in-xna-game-studio-2-0.aspx

Trong 2.0, hành vi Draw đã thay đổi:

  • Cập nhật cuộc gọi nhiều lần nếu cần để theo kịp thời điểm hiện tại
  • Gọi Draw một lần
  • Đợi đến lúc cập nhật tiếp theo

Theo tôi, chuyên gia lớn nhất theo quan điểm của tôi là một điều mà bạn đã đề cập, nó làm cho tất cả các phép tính mã trò chơi của bạn trở nên đơn giản hơn rất nhiều vì bạn không phải đưa biến thời gian đó đi khắp nơi.

lưu ý: xna cũng hỗ trợ dấu thời gian thay đổi, đó chỉ là một cài đặt.


Đây là cách phổ biến nhất để thực hiện một vòng lặp trò chơi. Tuy nhiên, nó không tuyệt vời cho thời lượng pin khi làm việc với các thiết bị di động.
hiệp sĩ666

1
@ hiệp sĩ666; Bạn có gợi ý rằng sử dụng dấu thời gian dài hơn, số lần lặp giảm sẽ tiết kiệm được batterylife?
falstro

Đó vẫn là một bản cập nhật thay đổi - delta cập nhật thay đổi dựa trên thời gian khung hình được hiển thị thay vì một số giá trị cố định (nghĩa là 1/30 giây).
Dennis Munsie

1
@Dennis: theo tôi hiểu, chức năng Cập nhật được gọi với một delta cố định ...
RCIX

3
@ Knight666 Uh - Làm thế nào để bạn tìm ra điều đó? Nếu bạn bật vsync và không nói lắp - các phương thức này phải giống hệt nhau! Và nếu bạn có Vsync tắt bạn đang cập nhật hơn thường xuyên hơn bạn cần phải và có lẽ lãng phí CPU (và do đó pin) bằng cách không để cho nó nhàn rỗi!
Andrew Russell

12

Có một lựa chọn khác - cập nhật trò chơi và cập nhật vật lý. Việc cố gắng điều chỉnh công cụ vật lý theo dấu thời gian của trò chơi sẽ dẫn đến sự cố nếu bạn khắc phục dấu thời gian của mình (vấn đề mất kiểm soát vì tích hợp cần nhiều dấu thời gian hơn, cần nhiều thời gian hơn), hoặc biến nó thành vật lý mạnh mẽ.

Giải pháp mà tôi thấy rất nhiều là để vật lý chạy trên dấu thời gian cố định, trong một luồng khác (trên lõi khác). Trò chơi nội suy hoặc ngoại suy với hai khung hợp lệ gần đây nhất mà nó có thể lấy. Nội suy thêm một số độ trễ, ngoại suy thêm một số điểm không chắc chắn, nhưng vật lý của bạn sẽ ổn định và không làm mất thời gian của bạn ngoài tầm kiểm soát.

Điều này không phải là nhỏ để thực hiện, nhưng có thể chứng minh bản thân bằng chứng trong tương lai.


8

Cá nhân, tôi sử dụng một biến thể của bước thời gian thay đổi (đó là một loại lai giữa cố định và biến tôi nghĩ). Tôi nhấn mạnh đã thử nghiệm hệ thống thời gian này theo nhiều cách và tôi thấy mình đang sử dụng nó cho nhiều dự án. Tôi có giới thiệu nó cho tất cả mọi thứ? Chắc là không.

Các vòng lặp trò chơi của tôi tính toán số lượng khung hình để cập nhật bằng cách (hãy gọi F này) và sau đó thực hiện các cập nhật logic rời rạc F. Mỗi bản cập nhật logic giả định một đơn vị thời gian không đổi (thường là 1/100 giây trong các trò chơi của tôi). Mỗi bản cập nhật được thực hiện theo trình tự cho đến khi tất cả các cập nhật logic rời rạc F được thực hiện.

Tại sao cập nhật rời rạc trong các bước logic? Chà, nếu bạn cố gắng và sử dụng các bước liên tục, và đột nhiên bạn gặp trục trặc vật lý vì tốc độ và khoảng cách tính toán để di chuyển được nhân với một giá trị rất lớn của F.

Việc thực hiện kém điều này sẽ chỉ thực hiện F = thời gian hiện tại - cập nhật thời gian khung hình cuối cùng. Nhưng nếu các tính toán bị bỏ lại quá xa (đôi khi do hoàn cảnh nằm ngoài tầm kiểm soát của bạn như một quá trình khác đánh cắp thời gian của CPU), bạn sẽ nhanh chóng thấy việc bỏ qua khủng khiếp. Nhanh chóng, FPS ổn định mà bạn đã cố gắng duy trì trở thành SPF.

Trong trò chơi của mình, tôi cho phép làm chậm "trơn tru" (loại) để hạn chế lượng bắt logic có thể có giữa hai lần rút. Tôi làm điều này bằng cách kẹp: F = min (F, MAX_FRAME_DELTA) thường có MAX_FRAME_DELTA = 2/100 * s hoặc 3/100 * s. Vì vậy, thay vì bỏ qua các khung hình khi quá xa logic của trò chơi, hãy loại bỏ bất kỳ mất khung lớn nào (làm chậm mọi thứ), khôi phục một vài khung hình, vẽ và thử lại.

Bằng cách này, tôi cũng đảm bảo rằng các điều khiển trình phát giữ đồng bộ chặt chẽ hơn với những gì thực sự được hiển thị trên màn hình.

Mã giả sản phẩm cuối cùng là một cái gì đó như thế này (delta là F đã đề cập trước đó):

// 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()

Kiểu cập nhật này không phù hợp với mọi thứ, nhưng đối với các trò chơi theo phong cách arcade, tôi thà thấy trò chơi bị chậm lại vì có nhiều thứ đang diễn ra hơn là bỏ lỡ khung hình và mất kiểm soát người chơi. Tôi cũng thích điều này hơn các cách tiếp cận bước thời gian khác nhau mà cuối cùng có những trục trặc không thể khắc phục được do mất khung.


Rất đồng ý với điểm cuối cùng đó; trong hầu hết các trò chơi, đầu vào sẽ 'chậm lại' khi tốc độ khung hình giảm xuống. Mặc dù điều này không thể thực hiện được trong một số trò chơi (ví dụ như nhiều người chơi), nó vẫn sẽ tốt hơn nếu có thể. : P Đơn giản là cảm thấy tốt hơn là có một khung hình dài và sau đó có thế giới trò chơi 'nhảy' đến trạng thái 'chính xác'.
Ipsquiggle

Không có phần cứng cố định như máy arcade, việc có các game arcade làm chậm quá trình mô phỏng khi phần cứng không thể theo kịp khiến cho việc chơi trên máy bị chậm hơn.

Joe chỉ quan trọng nếu chúng ta quan tâm đến "gian lận". Hầu hết các trò chơi hiện đại không thực sự về sự cạnh tranh giữa những người chơi, chỉ tạo ra một trải nghiệm thú vị.
Iain

1
Iain, chúng ta đang nói cụ thể về các trò chơi kiểu arcade ở đây, theo truyền thống có danh sách / bảng xếp hạng cao theo truyền thống. Tôi chơi rất nhiều shmup, và tôi biết nếu tôi tìm thấy ai đó đang đăng điểm với sự chậm chạp giả tạo lên bảng xếp hạng tôi muốn điểm số của họ bị xóa sạch.

Không cố làm giảm câu trả lời của bạn, nhưng tôi sẽ hiểu đây là bước cố định trong đó kết xuất không được gắn trực tiếp với tốc độ cập nhật vật lý, ngoại trừ việc bắt kịp vật lý được ưu tiên hơn kết xuất. Nó chắc chắn có phẩm chất tốt.
AaronLS

6

Giải pháp này không áp dụng cho mọi thứ, nhưng có một mức dấu thời gian khác - dấu thời gian biến cho từng đối tượng trên thế giới.

Điều này có vẻ phức tạp, và nó có thể, nhưng hãy nghĩ về nó như mô hình hóa trò chơi của bạn như một mô phỏng sự kiện riêng biệt. Mỗi chuyển động của người chơi có thể được biểu diễn dưới dạng một sự kiện bắt đầu khi chuyển động bắt đầu và kết thúc khi chuyển động kết thúc. Nếu có bất kỳ tương tác nào yêu cầu phân tách sự kiện (ví dụ va chạm) thì sự kiện sẽ bị hủy và một sự kiện khác được đẩy lên hàng đợi sự kiện (có thể là hàng đợi ưu tiên được sắp xếp theo thời gian kết thúc sự kiện).

Kết xuất hoàn toàn tách rời khỏi hàng đợi sự kiện. Công cụ hiển thị sẽ nội suy các điểm giữa thời gian bắt đầu / kết thúc sự kiện khi cần thiết và có thể chính xác hoặc cẩu thả trong ước tính này khi cần.

Để xem triển khai phức tạp của mô hình này, hãy xem trình mô phỏng không gian EXOFLIGHT . Nó sử dụng một mô hình thực hiện khác với hầu hết các trình mô phỏng chuyến bay - một mô hình dựa trên sự kiện, thay vì mô hình cắt thời gian cố định truyền thống. Vòng lặp chính cơ bản của loại mô phỏng này trông như thế này, trong mã giả:

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

Lý do chính để sử dụng một trong một mô phỏng không gian là sự cần thiết của việc cung cấp thời gian tăng tốc tùy ý mà không mất độ chính xác. Một số nhiệm vụ trong EXOFLIGHT có thể mất vài năm để hoàn thành trò chơi và thậm chí tùy chọn tăng tốc 32 lần cũng không đủ. Bạn cần tăng tốc hơn 1.000.000 lần cho một sim có thể sử dụng, điều này rất khó thực hiện trong mô hình cắt thời gian. Với mô hình dựa trên sự kiện, chúng ta có được tốc độ thời gian tùy ý, từ 1 s = 7 ms đến 1 s = 1 năm.

Thay đổi tốc độ thời gian không thay đổi hành vi của sim, đây là một tính năng quan trọng. Nếu không có đủ năng lượng CPU để chạy trình giả lập ở tốc độ mong muốn, các sự kiện sẽ chồng lên và chúng tôi có thể hạn chế làm mới UI cho đến khi hàng đợi sự kiện bị xóa. Tương tự như vậy, chúng ta có thể chuyển tiếp nhanh sim nhiều như chúng ta muốn và chắc chắn rằng chúng ta sẽ không lãng phí CPU cũng như không hy sinh độ chính xác.

Vì vậy, tóm tắt: Chúng ta có thể mô hình một chiếc xe theo quỹ đạo dài, nhàn nhã (sử dụng tích hợp Runge-Kutta) và một phương tiện khác đồng loạt nảy dọc theo mặt đất - cả hai phương tiện sẽ được mô phỏng với độ chính xác phù hợp vì chúng ta không có dấu thời gian toàn cầu.

Nhược điểm: Độ phức tạp và thiếu bất kỳ động cơ vật lý ngoài luồng nào hỗ trợ mô hình này :)


5

Bước thời gian cố định rất hữu ích khi tính đến độ chính xác của dấu phẩy động và để cập nhật nhất quán.

Đây là một đoạn mã đơn giản nên sẽ rất hữu ích khi dùng thử và xem nó có hoạt động cho trò chơi của bạn không.

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()

Vấn đề chính khi sử dụng bước thời gian cố định là người chơi có máy tính nhanh sẽ không thể sử dụng tốc độ. Kết xuất ở tốc độ 100 khung hình / giây khi trò chơi chỉ được cập nhật ở tốc độ 30 khung hình / giây giống như chỉ hiển thị ở tốc độ 30 khung hình / giây.

Điều đó đang được nói, có thể sử dụng nhiều hơn một bước thời gian cố định. 60fps có thể được sử dụng để cập nhật các đối tượng tầm thường (như UI hoặc các họa tiết hoạt hình) và 30fps để cập nhật các hệ thống không tầm thường (như vật lý và) và thậm chí cả bộ đếm thời gian chậm hơn để thực hiện quản lý cảnh như sử dụng các đối tượng không sử dụng, tài nguyên, v.v.


2
Nếu trò chơi được thực hiện cẩn thận, phương thức kết xuất có thể thực hiện phép nội suy để thực hiện cập nhật 30 khung hình / giây không giống như kết xuất ở tốc độ 30 khung hình / giây.
Ricket

3

Trên hết những gì bạn đã nêu, nó có thể đi xuống cảm giác bạn muốn trò chơi của mình có. Trừ khi bạn có thể đảm bảo rằng bạn sẽ luôn có tốc độ khung hình không đổi thì bạn có thể bị chậm lại ở đâu đó và các bước thời gian cố định và thay đổi sẽ trông rất khác nhau. Đã sửa sẽ có hiệu ứng trò chơi của bạn chuyển động chậm trong một thời gian, đôi khi có thể là hiệu ứng mong muốn (nhìn vào một game bắn súng kiểu cũ như Ikaruga, nơi vụ nổ lớn gây ra chậm lại sau khi đánh trùm). Dấu thời gian thay đổi sẽ giữ cho mọi thứ chuyển động với tốc độ chính xác theo thời gian nhưng bạn có thể thấy những thay đổi đột ngột về vị trí, v.v ... điều này có thể khiến người chơi khó thực hiện hành động chính xác.

Tôi thực sự không thể thấy rằng một bước thời gian cố định sẽ giúp mọi thứ dễ dàng hơn qua mạng, tất cả chúng sẽ không đồng bộ một chút để bắt đầu và làm chậm trên một máy nhưng không phải là một thứ khác sẽ đẩy mọi thứ không đồng bộ hơn.

Tôi luôn luôn hướng tới cách tiếp cận khác nhau nhưng những bài viết đó có một số điều thú vị để suy nghĩ. Mặc dù vậy, tôi vẫn thấy các bước cố định khá phổ biến, đặc biệt là trên các bảng điều khiển nơi mọi người nghĩ rằng tốc độ khung hình là 60fps không đổi so với tốc độ rất cao có thể đạt được trên PC.


5
Bạn chắc chắn nên đọc liên kết Gaffer trên các trò chơi trong bài viết gốc. Tôi không nghĩ rằng đây là một câu trả lời tồi, vì vậy tôi sẽ không bỏ phiếu, nhưng tôi không đồng ý với bất kỳ lý lẽ nào của bạn .
falstro

Tôi không nghĩ việc chậm lại trong một trò chơi là kết quả của dấu thời gian cố định có thể là cố ý, bởi vì đó là do thiếu kiểm soát. Thiếu kiểm soát là theo định nghĩa đầu hàng cơ hội và do đó không thể có chủ ý. Nó có thể là những gì bạn có trong tâm trí, nhưng đó là tất cả những gì tôi muốn tiếp tục. Đối với dấu thời gian cố định trong kết nối mạng, có một điểm cộng nhất định ở đó, vì việc giữ các động cơ vật lý trên hai máy khác nhau đồng bộ mà không có cùng dấu thời gian là điều không thể. Vì tùy chọn duy nhất để đồng bộ hóa sau đó sẽ là gửi tất cả các biến đổi thực thể, điều đó sẽ khiến băng thông quá nặng.
Kaj

0

Sử dụng phương pháp "sửa bước thời gian" của Gaffer. Cập nhật trò chơi theo các bước cố định như trong tùy chọn 1, nhưng thực hiện nhiều lần trên mỗi khung hình - dựa trên thời gian đã trôi qua - để logic trò chơi theo kịp thời gian thực, trong khi vẫn ở các bước riêng biệt. Bằng cách này, dễ dàng thực hiện logic trò chơi như tích hợp Euler và phát hiện va chạm đơn giản vẫn hoạt động. Bạn cũng có tùy chọn nội suy hoạt ảnh đồ họa dựa trên thời gian delta, nhưng điều này chỉ dành cho hiệu ứng hình ảnh và không có gì ảnh hưởng đến logic trò chơi cốt lõi của bạn. Bạn có thể gặp rắc rối nếu các bản cập nhật của bạn rất chuyên sâu - nếu các bản cập nhật bị tụt lại phía sau, bạn sẽ cần nhiều hơn nữa để theo kịp, tiềm năng khiến trò chơi của bạn thậm chí ít phản hồi hơn.

Cá nhân, tôi thích Tùy chọn 1 khi tôi có thể thoát khỏi nó và Tùy chọn 3 khi tôi cần đồng bộ hóa với thời gian thực. Tôi tôn trọng Lựa chọn 2 có thể là một lựa chọn tốt khi bạn biết bạn đang làm gì, nhưng tôi biết rõ những hạn chế của mình đủ để tránh xa nó


Nếu bạn sẽ ăn cắp câu trả lời ít nhất là tín dụng người đó!
PrimRock

0

Tôi đã thấy rằng các dấu thời gian cố định được đồng bộ hóa với 60fps cho phép hoạt hình mượt mà. Điều này đặc biệt quan trọng đối với các ứng dụng VR. Bất cứ điều gì khác là buồn nôn về thể chất.

Dấu thời gian biến không được sử dụng cho VR. Hãy xem một số ví dụ về Unity VR sử dụng dấu thời gian thay đổi. Thật là khó chịu.

Nguyên tắc là nếu trò chơi 3D của bạn mượt mà ở chế độ VR, nó sẽ xuất sắc ở chế độ không VR.

So sánh hai (ứng dụng Cardboard VR)

(Dấu thời gian biến)

(Dấu thời gian cố định)

Trò chơi của bạn phải được đa luồng để đạt được dấu thời gian / khung hình nhất quán. Vật lý, giao diện người dùng và kết xuất phải được tách thành các luồng chuyên dụng. PITA gớm ghiếc để đồng bộ hóa chúng, nhưng kết quả là phản chiếu mượt mà mà bạn muốn (đặc biệt là cho VR).

Trò chơi di động là đặc biệt. đầy thách thức vì các CPU và GPU nhúng có hiệu năng hạn chế. Sử dụng GLSL (tiếng lóng) một cách tiết kiệm để giảm tải càng nhiều công việc từ CPU càng tốt. Hãy lưu ý hơn việc truyền tham số cho GPU sẽ tiêu tốn tài nguyên xe buýt.

Luôn luôn giữ tốc độ khung hình của bạn được hiển thị trong quá trình phát triển. Trò chơi thực sự là giữ cho nó cố định ở 60fps. Đây là tỷ lệ đồng bộ hóa riêng cho hầu hết các màn hình và cho hầu hết các nhãn cầu.

Khung bạn đang sử dụng có thể thông báo cho bạn về yêu cầu đồng bộ hóa hoặc sử dụng bộ hẹn giờ. Không chèn một giấc ngủ / chờ trì hoãn để đạt được điều này - ngay cả những thay đổi nhỏ cũng đáng chú ý.


0

Các bước thời gian thay đổi là dành cho các quy trình nên được chạy thường xuyên nhất có thể: Kết xuất chu kỳ, xử lý sự kiện, công cụ mạng, v.v.

Các bước thời gian cố định là khi bạn cần một cái gì đó để có thể dự đoán và ổn định. Điều này bao gồm, nhưng không giới hạn trong phát hiện va chạm vật lý.

Trong điều kiện thực tế, vật lý và phát hiện va chạm nên được tách rời khỏi mọi thứ khác, trên bước thời gian riêng của nó. Lý do để thực hiện các quy trình như thế này trong một bước thời gian cố định nhỏ, là để giữ cho chúng chính xác. Độ lớn của xung lực phụ thuộc rất nhiều vào thời gian và nếu khoảng thời gian quá lớn, mô phỏng trở nên không ổn định và những thứ điên rồ xảy ra như một quả bóng nảy trên mặt đất, hoặc bật ra khỏi thế giới trò chơi, cả hai đều không mong muốn.

Mọi thứ khác có thể chạy trên một bước thời gian khác nhau (mặc dù nói một cách chuyên nghiệp, đó thường là một ý tưởng tốt để cho phép khóa kết xuất thành một bước thời gian cố định). Để công cụ trò chơi phản ứng nhanh, những thứ như thông điệp mạng và đầu vào của người dùng nên được xử lý càng sớm càng tốt, điều đó có nghĩa là khoảng thời gian giữa các lần bỏ phiếu nên càng ngắn càng tốt. Điều này thường có nghĩa là biến.

Mọi thứ khác có thể được xử lý không đồng bộ, làm cho thời gian là một điểm cần thiết.

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.