Tôi đang làm việc trên một trò chơi 2D isometric với nhiều người chơi ở quy mô vừa phải, khoảng 20-30 người chơi được kết nối cùng một lúc với một máy chủ liên tục. Tôi đã gặp một số khó khăn khi triển khai dự đoán chuyển động tốt.
Vật lý / Chuyển động
Trò chơi không có triển khai vật lý thực sự, nhưng sử dụng các nguyên tắc cơ bản để thực hiện chuyển động. Thay vì liên tục bỏ phiếu đầu vào, các thay đổi trạng thái (tức là / chuột xuống / lên / di chuyển sự kiện) được sử dụng để thay đổi trạng thái của thực thể nhân vật mà người chơi đang điều khiển. Hướng của người chơi (tức là / đông bắc) được kết hợp với tốc độ không đổi và biến thành một vectơ 3D thực sự - vận tốc của thực thể.
Trong vòng lặp trò chơi chính, "Cập nhật" được gọi trước khi "Vẽ". Logic cập nhật kích hoạt "nhiệm vụ cập nhật vật lý" theo dõi tất cả các thực thể với vận tốc khác không sử dụng tích hợp rất cơ bản để thay đổi vị trí thực thể. Ví dụ: entity.Pocation + = entity.Velocity.Scale (ElapsedTime.Seconds) (trong đó "Giây" là một giá trị dấu phẩy động, nhưng cách tiếp cận tương tự sẽ hoạt động với các giá trị số nguyên mili giây).
Điểm mấu chốt là không có phép nội suy nào được sử dụng cho chuyển động - động cơ vật lý thô sơ không có khái niệm về "trạng thái trước" hay "trạng thái hiện tại", chỉ có một vị trí và vận tốc.
Gói thay đổi và cập nhật trạng thái
Khi vận tốc của thực thể nhân vật mà người chơi đang kiểm soát thay đổi, gói "di chuyển avatar" sẽ được gửi đến máy chủ chứa loại hành động của thực thể (đứng, đi, chạy), hướng (đông bắc) và vị trí hiện tại. Điều này khác với cách trò chơi 3D người đầu tiên hoạt động. Trong trò chơi 3D, vận tốc (hướng) có thể thay đổi khung hình thành khung hình khi người chơi di chuyển xung quanh. Gửi mọi thay đổi trạng thái sẽ truyền tải hiệu quả một gói trên mỗi khung, quá tốn kém. Thay vào đó, các trò chơi 3D dường như bỏ qua các thay đổi trạng thái và gửi các gói "cập nhật trạng thái" trong một khoảng thời gian cố định - giả sử, cứ sau 80-150ms.
Vì cập nhật tốc độ và hướng xảy ra ít thường xuyên hơn trong trò chơi của tôi, tôi có thể thoát khỏi việc gửi mọi thay đổi trạng thái. Mặc dù tất cả các mô phỏng vật lý xảy ra ở cùng một tốc độ và mang tính quyết định, độ trễ vẫn là một vấn đề. Vì lý do đó, tôi gửi các gói cập nhật vị trí thường xuyên (tương tự như trò chơi 3D) nhưng ít thường xuyên hơn - ngay bây giờ cứ sau 250ms, nhưng tôi nghi ngờ với dự đoán tốt tôi có thể dễ dàng tăng tốc lên 500ms. Vấn đề lớn nhất là bây giờ tôi đã đi lệch khỏi định mức - tất cả các tài liệu, hướng dẫn và mẫu trực tuyến khác đều gửi các cập nhật thường xuyên và nội suy giữa hai trạng thái. Nó dường như không tương thích với kiến trúc của tôi và tôi cần đưa ra một thuật toán dự đoán chuyển động tốt hơn gần với kiến trúc "vật lý mạng" (rất cơ bản).
Sau đó, máy chủ sẽ nhận gói tin và xác định tốc độ của người chơi từ loại chuyển động dựa trên tập lệnh (Người chơi có thể chạy không? Lấy tốc độ chạy của người chơi). Khi nó có tốc độ, nó kết hợp nó với hướng để có được một vectơ - vận tốc của thực thể. Một số phát hiện gian lận và xác nhận cơ bản xảy ra và thực thể ở phía máy chủ được cập nhật với vận tốc, hướng và vị trí hiện tại. Điều chỉnh cơ bản cũng được thực hiện để ngăn người chơi tràn vào máy chủ với các yêu cầu di chuyển.
Sau khi cập nhật thực thể riêng của mình, máy chủ sẽ phát gói "cập nhật vị trí avatar" cho tất cả người chơi khác trong phạm vi. Gói cập nhật vị trí được sử dụng để cập nhật các mô phỏng vật lý phía máy khách (trạng thái thế giới) của các máy khách từ xa và thực hiện dự đoán và bù độ trễ.
Dự đoán và bồi thường Lag
Như đã đề cập ở trên, khách hàng có thẩm quyền cho vị trí riêng của họ. Ngoại trừ các trường hợp gian lận hoặc dị thường, hình đại diện của khách hàng sẽ không bao giờ được máy chủ định vị lại. Không ngoại suy ("di chuyển ngay bây giờ và sửa lại sau") là bắt buộc đối với hình đại diện của khách hàng - những gì người chơi thấy là chính xác. Tuy nhiên, một số loại ngoại suy hoặc nội suy là cần thiết cho tất cả các thực thể từ xa đang di chuyển. Một số loại dự đoán và / hoặc bù trễ rõ ràng là cần thiết trong công cụ mô phỏng / vật lý cục bộ của khách hàng.
Các vấn đề
Tôi đã vật lộn với các thuật toán khác nhau, và có một số câu hỏi và vấn đề:
Tôi nên ngoại suy, nội suy, hoặc cả hai? "Cảm giác ruột" của tôi là tôi nên sử dụng phép ngoại suy thuần túy dựa trên vận tốc. Khách hàng nhận được sự thay đổi trạng thái, khách hàng tính toán vận tốc "dự đoán" bù cho độ trễ và hệ thống vật lý thông thường làm phần còn lại. Tuy nhiên, nó cảm thấy mâu thuẫn với tất cả các mã và bài viết mẫu khác - tất cả chúng dường như lưu trữ một số trạng thái và thực hiện phép nội suy mà không cần động cơ vật lý.
Khi một gói đến, tôi đã thử nội suy vị trí của gói với vận tốc của gói trong một khoảng thời gian cố định (giả sử, 200ms). Sau đó, tôi lấy sự khác biệt giữa vị trí nội suy và vị trí "lỗi" hiện tại để tính toán một vectơ mới và đặt nó trên thực thể thay vì vận tốc được gửi. Tuy nhiên, giả định là một gói khác sẽ đến trong khoảng thời gian đó và rất khó để "đoán" khi gói tiếp theo sẽ đến - đặc biệt là vì chúng không đến vào các khoảng thời gian cố định (tức là cũng thay đổi trạng thái). Là khái niệm về cơ bản là thiếu sót, hoặc nó là chính xác nhưng cần một số sửa chữa / điều chỉnh?
Điều gì xảy ra khi một người chơi từ xa dừng lại? Tôi có thể ngay lập tức dừng thực thể, nhưng nó sẽ được đặt ở vị trí "sai" cho đến khi nó di chuyển trở lại. Nếu tôi ước tính một vectơ hoặc cố gắng nội suy, tôi có một vấn đề vì tôi không lưu trữ trạng thái trước đó - công cụ vật lý không có cách nào để nói "bạn cần dừng lại sau khi bạn đạt đến vị trí X". Nó chỉ đơn giản là hiểu một vận tốc, không có gì phức tạp hơn. Tôi miễn cưỡng thêm thông tin "trạng thái chuyển động gói" vào các thực thể hoặc công cụ vật lý, vì nó vi phạm các nguyên tắc thiết kế cơ bản và làm chảy mã mạng trên phần còn lại của công cụ trò chơi.
Điều gì sẽ xảy ra khi các thực thể va chạm? Có ba kịch bản - trình phát điều khiển va chạm cục bộ, hai thực thể va chạm trên máy chủ trong khi cập nhật vị trí hoặc cập nhật thực thể từ xa va chạm vào máy khách cục bộ. Trong mọi trường hợp, tôi không chắc chắn làm thế nào để xử lý vụ va chạm - ngoài việc gian lận, cả hai trạng thái đều "chính xác" nhưng ở các khoảng thời gian khác nhau. Trong trường hợp của một thực thể ở xa, sẽ không có ý nghĩa gì khi vẽ nó đi xuyên qua tường, vì vậy tôi thực hiện phát hiện va chạm trên máy khách cục bộ và khiến nó "dừng lại". Dựa trên điểm số 2 ở trên, tôi có thể tính toán một "vectơ đã sửa" liên tục cố gắng di chuyển thực thể "xuyên tường" sẽ không bao giờ thành công - hình đại diện từ xa bị kẹt ở đó cho đến khi lỗi quá cao và nó "chộp" vào Chức vụ. Làm thế nào để các trò chơi làm việc xung quanh này?