Làm thế nào một hệ thống chụp nhanh trạng thái trò chơi sẽ được triển khai cho các trò chơi thời gian thực được nối mạng?


12

Tôi muốn tạo một trò chơi nhiều người chơi máy chủ thời gian thực đơn giản như một dự án cho lớp kết nối mạng của tôi.

Tôi đã đọc rất nhiều về các mô hình mạng nhiều người chơi trong thời gian thực và tôi hiểu mối quan hệ giữa máy khách và máy chủ và các kỹ thuật bù trễ.

Những gì tôi muốn làm là một cái gì đó tương tự như mô hình mạng Quake 3: về cơ bản, máy chủ lưu trữ một ảnh chụp nhanh của toàn bộ trạng thái trò chơi; khi nhận được đầu vào từ máy khách, máy chủ sẽ tạo một ảnh chụp nhanh mới phản ánh các thay đổi. Sau đó, nó tính toán sự khác biệt giữa ảnh chụp nhanh mới và ảnh chụp cuối cùng và gửi chúng cho khách hàng, để chúng có thể được đồng bộ hóa.

Cách tiếp cận này có vẻ rất chắc chắn đối với tôi - nếu máy khách và máy chủ có kết nối ổn định, chỉ có lượng dữ liệu cần thiết tối thiểu sẽ được gửi để giữ chúng đồng bộ. Nếu khách hàng không đồng bộ, cũng có thể yêu cầu một ảnh chụp nhanh đầy đủ.

Tuy nhiên, tôi không thể tìm thấy một cách tốt để thực hiện hệ thống chụp nhanh. Tôi thấy thực sự khó khăn khi di chuyển khỏi kiến ​​trúc lập trình một người chơi và suy nghĩ về cách tôi có thể lưu trữ trạng thái trò chơi theo cách:

  • Tất cả dữ liệu được tách ra khỏi logic
  • Sự khác biệt có thể được tính giữa ảnh chụp nhanh của trạng thái trò chơi
  • Các thực thể trò chơi vẫn có thể dễ dàng thao tác thông qua mã

Làm thế nào là một lớp chụp nhanh được thực hiện? Làm thế nào là các thực thể và dữ liệu của họ được lưu trữ? Có phải mọi thực thể khách hàng đều có ID khớp với ID trên máy chủ không?

Sự khác biệt ảnh chụp được tính như thế nào?

Nói chung: làm thế nào một hệ thống chụp nhanh trạng thái trò chơi sẽ được thực hiện?


4
+1. Đây là một chút quá rộng cho một câu hỏi, nhưng IMO nó là một chủ đề thú vị có thể được trình bày đại khái trong một câu trả lời.
Kromster nói hỗ trợ Monica

Tại sao bạn không lưu trữ 1 Ảnh chụp nhanh (thế giới thực), lưu mọi thay đổi đến vào trạng thái thế giới thông thường này VÀ lưu trữ thay đổi trong danh sách hoặc nội dung nào đó. Sau đó, khi đến lúc gửi các thay đổi cho tất cả các khách hàng, chỉ cần gửi nội dung của danh sách cho tất cả họ và xóa danh sách, bắt đầu từ số không (thay đổi). Có thể điều này không tốt bằng việc lưu trữ 2 ảnh chụp nhanh nhưng với cách tiếp cận này, bạn không cần phải lo lắng về thuật toán về cách nhanh chóng chụp 2 ảnh chụp nhanh.
tkausl

Bạn đã đọc cái này chưa: fabiensanglard.net/quake3/network.php - đánh giá mô hình mạng động đất 3 bao gồm thảo luận về việc triển khai.
Steven

Những loại trò chơi đang cố gắng để xây dựng? Việc thiết lập mạng phụ thuộc rất nhiều vào loại trò chơi bạn đang thực hiện. RTS không hoạt động như FPS về mặt mạng.
AturSams

Câu trả lời:


3

Bạn có thể tính toán delta snapshot (thay đổi trạng thái được đồng bộ hóa trước đó) bằng cách giữ hai trường hợp snapshot: hiện tại và lần cuối được đồng bộ hóa.

Khi khách hàng đến, bạn sửa đổi ảnh chụp nhanh hiện tại. Sau đó, khi đến lúc gửi delta cho khách hàng, bạn tính toán ảnh chụp nhanh được đồng bộ hóa cuối cùng với một trường hiện tại (theo đệ quy) và tính toán và xê-ri hóa delta. Để tuần tự hóa, bạn có thể gán ID duy nhất cho từng trường trong phạm vi của lớp (trái ngược với phạm vi trạng thái toàn cầu). Máy khách và máy chủ phải chia sẻ cùng một cấu trúc dữ liệu cho trạng thái toàn cầu để khách hàng hiểu được ID cụ thể được áp dụng cho cái gì.

Sau đó, khi delta được tính, bạn sao chép trạng thái hiện tại và biến nó thành trạng thái được đồng bộ hóa cuối cùng, vì vậy bây giờ bạn có trạng thái được đồng bộ hóa hiện tại và cuối cùng nhưng các trường hợp khác nhau để bạn có thể sửa đổi trạng thái hiện tại và không ảnh hưởng đến trạng thái khác.

Cách tiếp cận này có thể dễ thực hiện hơn, đặc biệt là với sự trợ giúp của phản xạ (nếu bạn có một sự xa xỉ như vậy), nhưng có thể chậm, ngay cả khi bạn đánh giá cao phần phản chiếu (bằng cách xây dựng lược đồ dữ liệu của bạn để lưu trữ hầu hết các cuộc gọi phản chiếu). Chủ yếu là vì bạn cần so sánh hai bản sao của trạng thái tiềm năng lớn. Tất nhiên nó phụ thuộc vào cách bạn thực hiện so sánh và ngôn ngữ của bạn. Nó có thể nhanh trong C ++ với bộ so sánh được mã hóa cứng nhưng không linh hoạt: mọi thay đổi cấu trúc trạng thái toàn cầu của bạn đều yêu cầu sửa đổi bộ so sánh này và những thay đổi này rất thường xuyên ở các giai đoạn dự án ban đầu.

Một cách tiếp cận khác là sử dụng cờ bẩn. Mỗi lần đầu vào của máy khách đến, bạn áp dụng nó cho một bản sao trạng thái toàn cầu và gắn cờ trường tương ứng là bẩn. Sau đó, đã đến lúc đồng bộ hóa máy khách, bạn tuần tự hóa các trường bẩn (đệ quy) bằng cách sử dụng cùng một ID duy nhất. Hạn chế (nhỏ) là đôi khi bạn gửi nhiều dữ liệu hơn mức yêu cầu nghiêm ngặt: ví dụ int field1ban đầu là 0, sau đó được gán 1 (và bị gắn cờ bẩn) và sau đó được gán lại 0 (nhưng vẫn bẩn). Lợi ích là có cấu trúc dữ liệu phân cấp rất lớn, bạn không cần phải phân tích nó hoàn toàn để tính toán delta, chỉ các đường dẫn bẩn.

Nói chung, nhiệm vụ này có thể khá phức tạp, phụ thuộc vào mức độ linh hoạt nên là giải pháp cuối cùng. Ví dụ: Unity3D 5 (sắp tới) sẽ sử dụng các thuộc tính để chỉ định dữ liệu nên được tự động đồng bộ hóa với máy khách (cách tiếp cận rất linh hoạt, bạn không cần làm gì ngoại trừ thêm một thuộc tính vào trường của mình) bước hậu xây dựng. Thêm chi tiết tại đây.


2

Trước tiên, bạn cần biết cách thể hiện dữ liệu liên quan của mình theo cách tuân thủ giao thức. Điều này phụ thuộc vào dữ liệu liên quan đến trò chơi. Tôi sẽ sử dụng một trò chơi RTS làm ví dụ.

Đối với mục đích kết nối mạng, tất cả các thực thể trong trò chơi được liệt kê (ví dụ: xe bán tải, đơn vị, tòa nhà, tài nguyên thiên nhiên, vật hủy diệt).

Người chơi cần có dữ liệu liên quan đến họ (ví dụ: tất cả các đơn vị hiển thị):

  • Họ còn sống hay đã chết?
  • Họ thuộc loại nào?
  • Họ còn lại bao nhiêu sức khỏe?
  • Vị trí hiện tại, vòng quay, vận tốc (tốc độ + hướng), đường dẫn trong tương lai gần ...
  • Hoạt động: Tấn công, đi bộ, xây dựng, sửa chữa, chữa bệnh, v.v ...
  • hiệu ứng trạng thái buff / debuff
  • và có thể các chỉ số khác như mana, khiên và những gì không?

Đầu tiên, người chơi phải nhận được trạng thái đầy đủ trước khi cô ấy có thể vào trò chơi (hoặc thay vào đó là tất cả thông tin liên quan đến người chơi đó).

Mỗi đơn vị có một ID số nguyên. Các thuộc tính được liệt kê và do đó cũng có các định danh tích phân. ID đơn vị không phải dài 32 bit (có thể là nếu chúng ta không tiết kiệm). Nó rất có thể là 20 bit (để lại 10 bit cho các thuộc tính). ID của đơn vị phải là duy nhất, rất có thể được chỉ định bởi một bộ đếm khi đơn vị được khởi tạo và / hoặc thêm vào thế giới trò chơi (các tòa nhà và tài nguyên được coi là một đơn vị bất động và tài nguyên có thể được gán ID khi bản đồ Nó đã nạp đầy).

Máy chủ lưu trữ trạng thái toàn cầu hiện tại. Trạng thái cập nhật gần đây nhất của mỗi người chơi được biểu thị bằng một con trỏ tới một listtrong những thay đổi gần đây (tất cả các thay đổi sau khi con trỏ chưa được gửi đến người chơi đó). Thay đổi được thêm vào listkhi chúng xảy ra. Khi máy chủ hoàn tất việc gửi bản cập nhật cuối cùng, nó có thể bắt đầu lặp lại danh sách: máy chủ di chuyển con trỏ của người chơi dọc theo danh sách đến đuôi của nó, thu thập tất cả các thay đổi trên đường đi và đặt chúng vào bộ đệm sẽ được gửi đến trình phát (tức là định dạng của giao thức có thể giống như thế này: unit_id; attr_id; new_value) Các đơn vị mới cũng được coi là thay đổi và được gửi với tất cả các giá trị thuộc tính của chúng cho người chơi nhận.

Nếu bạn không sử dụng ngôn ngữ với trình thu gom rác, bạn sẽ cần thiết lập một con trỏ lười biếng sẽ bị tụt lại phía sau và sau đó bắt kịp con trỏ trình phát lỗi thời nhất trong danh sách, giải phóng các đối tượng trên đường đi. Bạn có thể nhớ người chơi nào là lỗi thời nhất trong một đống ưu tiên hoặc chỉ đơn giản là lặp đi lặp lại và miễn phí cho đến khi con trỏ lười bằng (nghĩa là trỏ đến cùng một mục với một trong những con trỏ của người chơi).

Một số câu hỏi bạn không nêu ra và tôi nghĩ là thú vị là:

  1. Khách hàng có nên nhận một ảnh chụp nhanh với tất cả dữ liệu ở vị trí đầu tiên không? Còn những món đồ nằm ngoài tầm nhìn của họ thì sao? Còn sương mù chiến tranh trong game RTS thì sao? Nếu bạn gửi tất cả dữ liệu, máy khách có thể bị hack để hiển thị dữ liệu không có sẵn cho người chơi (tùy thuộc vào các biện pháp bảo mật khác mà bạn thực hiện). Nếu bạn chỉ gửi dữ liệu liên quan, vấn đề được giải quyết.
  2. Khi nào cần gửi thay đổi thay vì gửi tất cả thông tin? Xem xét băng thông có sẵn trên các máy hiện đại, chúng ta có thu được gì từ việc gửi "delta" thay vì gửi tất cả thông tin, nếu vậy thì khi nào?
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.