Ghost replay - lưu trữ và thời gian


11

Tôi đang làm việc trên một trò chơi đua xe và chỉ thực hiện một sprite ma để phát lại các cuộc đua trong quá khứ. Tôi sử dụng một công cụ vật lý và sau khi đọc nhiều, tôi đã đi đến kết luận rằng cách tốt nhất để lưu trữ dữ liệu ma để phát lại là ghi lại vị trí và vòng quay của ô tô tại các mốc thời gian đã cho, như ví dụ được mô tả ở đây: https: // gamedev. stackexchange.com/a/8380/26261 .

Nhưng điều gì sẽ là một cách tốt để tìm thấy những dấu thời gian trong khi phát lại? Một ví dụ sẽ là một bản ghi với dữ liệu này:

time: +3.19932 (seconds since race start)
position:  180,40 (position at that time)
rotation: 30.4 (rotation at that time)

Nhưng tôi có một số vấn đề với điều đó:

  1. Khi tôi phát lại, không chắc là tôi đạt được mốc thời gian chính xác ở 3.19932 một lần nữa - nhiều khả năng, tôi sẽ có một mốc thời gian khoảng 3.1 và phải tìm bản ghi khớp gần nhất. Khi nội suy, thậm chí khớp gần nhất ở trên và dưới. Điều này nghe có vẻ rất không hiệu quả và tốn thời gian?

  2. Trong cấu trúc danh sách nào tôi có thể lưu trữ các bản ghi này cho lần phát lại sau? Một mảng? Điều đó không có nghĩa là thời gian tìm kiếm hồ sơ phù hợp với một thời gian nhất định sẽ tăng thời gian cuộc đua dài hơn?

  3. Tôi nên sử dụng tần số nào cho các mốc thời gian? Mỗi khung hình sẽ là - Tôi đoán quá mức cần thiết, thay vào đó tôi nên lưu tức là mọi khung hình thứ n và nội suy ở giữa, điều này làm cho các câu hỏi lưu trữ trong 2. thậm chí còn khó khăn hơn.

Vì vậy, ý tưởng này thậm chí là phương pháp đúng? Nếu có, làm thế nào tôi có thể lưu trữ và lấy dữ liệu một cách hiệu quả? Xin lưu ý rằng tôi thường muốn sử dụng cấu trúc dữ liệu ở trên, không phải các trò chơi xác định và ghi lại đầu vào của người dùng, v.v.

Cảm ơn vì bất kì sự giúp đỡ!

EDIT: Tôi nhận ra rằng tôi nên mô tả môi trường tôi sử dụng: Cocos2D cho iPhone. Có một phương pháp update:(ccTime)delta. Lý tưởng nhất là phương pháp này sẽ được gọi cứ sau 1/60 giây, nhưng không có gì đảm bảo - deltalà thời gian thực tế đã trôi qua kể từ lần giao tử cuối cùng và có thể nhiều hơn hoặc ít hơn 1/60. Đó là trong phương pháp này, nơi tôi muốn lưu trữ các gamestate hiện tại.


2
Câu hỏi tuyệt vời. Như điều này cho thấy, một phát lại chính xác phức tạp hơn bạn nghĩ lúc đầu, và tôi tò mò muốn xem những giải pháp nào mọi người đã đưa ra ở đây.
Christian

Câu trả lời:


8

Điều đó không có nghĩa là thời gian tìm kiếm hồ sơ phù hợp với một thời gian nhất định sẽ tăng thời gian cuộc đua dài hơn?

Không :)

Giả sử bạn lưu trữ nó dưới dạng một mảng (lưu ý các ảnh chụp nhanh theo thứ tự thời gian, nhưng không cách đều nhau):

snapshots = [
    {time: 0.0, position: {x,y,z}},
    {time: 0.41,    position: {x,y,z}},
    {time: 0.57,    position: {x,y,z}},
    {time: 1.10,    position: {x,y,z}},
    {time: 1.67,    position: {x,y,z}},
    {time: 2.05,    position: {x,y,z}},
    {time: 3.24,    position: {x,y,z}},
    {time: 3.86,    position: {x,y,z}},
    {time: 3.91,    position: {x,y,z}},
    {time: 5.42,    position: {x,y,z}},
    ...]

Sau đó, khi phát lại / trò chơi bắt đầu, bạn nhận được phần tử thứ nhất và thứ hai từ mảng:

nextIdx = 1
previousSnapshot = snapshots[nextIdx-1]
nextSnapshot = snapshots[nextIdx]

Sau đó, trong mỗi khung hình ( currentTimelà thời gian hiện tại trong trò chơi mới này):

if currentTime > nextSnapshot.time
    nextIdx++
    previousSnapshot = snapshots[nextIdx-1]
    nextSnapshot = snapshots[nextIdx]

# Do your magic here, e.g.:
snapshotPairGap = nextSnapshot.time - previousSnapshot.time
ratio = (currentTime - previousSnapshot.time) / snapshotPairGap
ghostPosition = {
    x: previousSnapshot.position.x + ratio*(nextSnapshot.position.x - previousSnapshot.position.x)
    y: previousSnapshot.position.y + ratio*(nextSnapshot.position.y - previousSnapshot.position.y)
    z: previousSnapshot.position.z + ratio*(nextSnapshot.position.z - previousSnapshot.position.z)
}

Tất nhiên điều này có thể được tối ưu hóa bằng cách lưu trữ một số tính toán. Không có tìm kiếm thông qua các mảng, chỉ tìm kiếm các chỉ số cụ thể.


ĐÚNG! Tôi phải thử nó sau, nhưng đây dường như là thứ tôi đang tìm kiếm. Cảm ơn!!
marimba

15

Nó không quá khó. Bạn có thể lưu trữ dữ liệu của mình tại các thời điểm tùy ý (càng nhiều, càng tốt) và bạn có thể nội suy các giá trị của dữ liệu dựa trên dấu thời gian bạn đang tìm và dữ liệu từ hai dấu thời gian được ghi gần nhất, ví dụ:

N | Time | Position | Rotation
1 | 0.05 | 1, 1, 1  | 0
2 | 0.15 | 1, 2, 1  | 0
3 | 0.25 | 1, 3, 2  | 30

Bây giờ hãy tưởng tượng bạn muốn có được vị trí và xoay tại thời điểm 0.10. Vì 0.10 nằm giữa các điểm '1' (có nghĩa là 0,05 thời gian) và '2' (có nghĩa là 0,15 thời gian), bạn cần phải nội suy các điểm này.

timestamp = 0.10
factor = (timestamp - Time[1]) / (Time[2] - Time[1])
position = Lerp(Position[1], Position[2], factor)
rotation = Lerp(Rotation[1], Rotation[2], factor)

Lerpchỉ là nội suy tuyến tính .

Vì vậy, hãy lấp đầy khoảng trống bằng một số ví dụ (*).

N | Time  | Position    | Rotation
1 | 0.05  | 1, 1,    1  | 0
* | 0.075 | 1, 1.25, 1  | 0
* | 0.10  | 1, 1.5,  1  | 0
2 | 0.15  | 1, 2,    1  | 0
* | 0.20  | 1, 2.5,  2  | 15
3 | 0.25  | 1, 3,    2  | 30

HTH.


5
+1. Nội suy là câu trả lời đơn giản và hiệu quả ở đây. Có thể đúng là phép nội suy bậc ba có thể cho kết quả tốt hơn một chút khi xe đang rẽ nhưng tuyến tính sẽ hoạt động tốt nếu các khoảng thời gian đủ nhỏ.
Kylotan

Cảm ơn đã chỉ ra cách nội suy! Điều này sẽ rất hữu ích cho trò chơi của tôi. Nhưng hãy nói rằng tôi muốn truy xuất tại thời điểm 41,15, sâu bên trong mảng. Bạn có bắt đầu tìm kiếm trong toàn bộ mảng cho đến khi bạn tìm thấy một bản ghi> 41,15 không?
marimba

1
Một tìm kiếm tuyến tính đơn giản có thể phù hợp với bạn, nhưng tìm kiếm nhị phân sẽ tốt hơn, khi bạn có một mảng được sắp xếp: en.wikipedia.org/wiki/Binary_search_alacticm
Marcin Seredynski
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.