Giao thức trò chơi RTS


18

Tôi đã suy nghĩ về một trò chơi RTS nhiều người chơi. Phần mà tôi dường như không thể đi xung quanh là giữ cho chuyển động của đơn vị được đồng bộ hóa. Nếu tôi di chuyển đơn vị A để phát hiện XY, tôi phải liên lạc trở lại máy chủ chuyển tiếp đến máy khách khác.

Tôi tò mò không biết giao tiếp sẽ như thế nào. Bạn có thể liên lạc với máy chủ mà tôi đang chuyển đơn vị A sang XY từ JZ không? Có lẽ bạn cần phải giao tiếp phối hợp chuyển động bằng cách phối hợp thay thế? Phương pháp hiệu quả nhất để truyền đạt sự di chuyển của các đơn vị từ khách hàng này sang khách hàng khác là gì?

CHỈNH SỬA

Đây là một câu hỏi được đăng lại từ stackoverflow . Tôi thấy rằng trang web này có lẽ là một nơi tốt hơn cho câu hỏi.

Một trong những câu trả lời tốt hơn từ bài đăng đó:

Tôi cho rằng bạn đang có ý định sử dụng mô hình mạng Client-Server? Trong trường hợp bạn không thể tin tưởng các máy khách để xử lý việc định vị thực tế của các đơn vị, bạn phải ủy thác nhiệm vụ đó cho máy chủ. Sau đó, bạn lấy danh sách lệnh từ mỗi máy khách mỗi lần đánh dấu và tính toán chuyển động của từng đơn vị, sau khi hoàn thành việc này, đánh dấu tiếp theo bạn chuyển tiếp vị trí của từng đơn vị có liên quan đến từng khách hàng (trên cơ sở toàn bản đồ hoặc cơ sở theo quan điểm) và bắt đầu lại quá trình.


2
Câu trả lời thực sự phụ thuộc vào phương pháp bạn muốn sử dụng. Khách hàng - khách hàng hoặc khách hàng - máy chủ. Máy khách đến máy chủ dễ dàng hơn nhưng nó đòi hỏi một máy chủ đáng tin cậy
Cem Kalyoncu

Câu trả lời:


25

Bạn không muốn đồng bộ hóa vị trí của tất cả các đơn vị từ máy chủ đến từng máy khách; rằng sẽ mất cách nhiều băng thông hơn bạn cần. Bạn cũng sẽ phải đối phó với các vị trí đơn vị nội suy / ngoại suy, v.v. Hầu như không có ứng dụng khách / máy chủ chuyên nghiệp nào của RTS!

Thay vào đó, bạn muốn chỉ gửi lệnh của người chơi. Thay vì di chuyển các đơn vị ngay lập tức khi người chơi nhấp vào, bạn sẽ xếp hàng lệnh di chuyển sẽ được thực hiện tại một số điểm trong tương lai - thường chỉ là một vài khung. Mọi người gửi lệnh của mình cho mọi người. Một vài khung hình sau đó, mọi người thực hiện tất cả các lệnh và bởi vì trò chơi mang tính quyết định, tất cả đều thấy kết quả giống nhau.

Nhược điểm là mọi người chơi đều chậm như người chơi chậm nhất - nếu có ai bị tụt lại trong việc gửi lệnh, mọi người phải chậm lại và chờ anh ta bắt kịp (trong Starcraft 2, đây là "XXX đang làm chậm trò chơi " Hộp thoại).


Trong thực tế, có một điều nữa thường được thực hiện: loại bỏ hoàn toàn máy chủ . Có mọi khách hàng gửi lệnh của họ cho mọi khách hàng khác. Điều này giúp giảm độ trễ (thay vì lệnh đi từ bạn -> máy chủ -> đối thủ, nó chỉ đi từ bạn -> đối thủ) giúp mã hóa dễ dàng hơn, vì bạn không còn cần phải mã hóa một máy chủ riêng biệt. Kiểu kiến ​​trúc này được gọi là ngang hàng (P2P).

Nhược điểm là bây giờ bạn cần một cách giải quyết xung đột, nhưng vì các lệnh của người chơi độc lập với nhau trong hầu hết các RTS, nên điều này thường không thành vấn đề. Ngoài ra, nó không có quy mô tốt - mỗi khi bạn thêm một người chơi mới, mọi người chơi cần gửi cho anh ta các lệnh của họ. Bạn sẽ không tạo ra MMO RTS bằng P2P.


Thiết lập này (chỉ gửi các lệnh sử dụng P2P) là cách mà hầu hết các RTS, bao gồm Starcraft, C & C và AoE hoạt động, và là cách duy nhất AoE có thể hỗ trợ 1500 đơn vị trên kết nối 28,8kbps .

(hình ảnh của mạng trong AoE)

Dưới đây là một vài mẹo để viết RTS P2P:

  • Vì các lý do rõ ràng, thiết lập này chỉ có thể hoạt động nếu trò chơi của bạn sử dụng thời gian bước cố định - bạn không muốn kết quả của phép tính phụ thuộc vào tốc độ khung hình! Bước cố định dễ dàng hơn để làm việc với hầu hết mọi thứ, vì vậy đây không phải là vấn đề.
  • Để làm việc này, kết quả của mọi lệnh phải hoàn toàn xác định .
    • Điều này thường khá dễ dàng nếu bạn giới hạn bản thân trong một hệ thống (chẳng hạn như Windows 32 bit) và buộc tất cả các máy khách sử dụng cùng một tệp thực thi: đảm bảo mọi trình tạo số ngẫu nhiên có cùng một hạt giống và luôn được gọi theo cùng một thứ tự; cực kỳ cẩn thận khi lặp qua các bộ sưu tập không có thứ tự ; v.v.
    • Điều này cực kỳ khó khăn nếu bạn có kế hoạch làm cho trò chơi có thể chơi được trên các nền tảng khác nhau hoặc (như thường thấy với Linux) cho phép khách hàng tự biên dịch mã. Không chỉ các thư viện hệ thống khác nhau được đảm bảo khá nhiều để sử dụng các triển khai khác nhau rand(), cos()v.v., mà gần như tất cả các phép toán dấu phẩy động đều nằm ngoài câu hỏi (xem tại đây , tại đâytại đây ) ! Trong trường hợp đó, bạn có thể sử dụng máy khách-máy chủ tốt hơn.
  • Thỉnh thoảng bạn sẽ muốn gửi tất cả các vị trí đơn vị, ít nhất là trong khi gỡ lỗi, để phát hiện các lỗi desync (mà, tin tôi đi, bạn sẽ có). Cho dù bạn giữ điều đó trong trò chơi cuối cùng là tùy thuộc vào bạn - tôi sẽ đồng bộ hóa ít nhất một số đơn vị (hoặc sử dụng một số loại tổng kiểm tra), để phát hiện hack đã cố gắng.

Bài đăng tốt. Thêm một điều nhỏ, ngay cả các trình biên dịch tương tự tối ưu hóa, gỡ lỗi / phát hành và các cờ khác có thể thay đổi kết quả. Hãy cẩn thận!
Peter lsted

14

Tôi đã tạo ra một RTS nối mạng TCP, trong đó tôi đã tự truyền các lệnh, thay vì kết quả của các lệnh . Chẳng hạn, một người chơi đưa ra một lệnh di chuyển. Nếu lệnh di chuyển hợp lệ theo máy khách đó, nó sẽ được gửi đến máy chủ. Sau đó, máy chủ sẽ gửi lại cho tất cả các máy khách, những người xác nhận và thực hiện nó.

Vì vậy, tất cả các máy khách tự chạy trò chơi, mã máy chủ chấp nhận tin nhắn và gửi lại cho tất cả các máy khách. Nếu một khách hàng đưa ra một lệnh di chuyển, nó sẽ không bắt đầu thực hiện nó cho đến khi nó được nhận lại từ máy chủ.

Máy chủ cũng gửi một số 'tick' để thực thi lệnh, đó là một vài đánh dấu trước dấu tick 'hiện tại'. Bằng cách này, tất cả các lệnh có thể được thực thi tại cùng một 'tick' trên tất cả các máy.

Một lợi ích của phương pháp này là nó không phụ thuộc vào bất kỳ máy khách cá nhân nào để xác thực lệnh. Nếu tôi vượt qua kết quả di chuyển, tôi có thể hack nó để di chuyển các đơn vị của mình nhanh hơn. Tất cả các máy khách phải thực hiện cùng một lệnh và nếu một máy thực thi nó khác nhau, điều đó sẽ rõ ràng.

Xác thực lệnh phía máy khách trước khi gửi nó đến máy chủ là không cần thiết, nhưng về lý thuyết, nó sẽ tiết kiệm lưu lượng mạng. Tôi đã sử dụng cùng một mã xác nhận để nói với UI rằng việc di chuyển là có thể, vì vậy nó không yêu cầu viết thêm mã.

Đối với những gì các tin nhắn có thể trông như thế nào. Tôi không quan tâm đến hiệu quả cao vì đây là trò chơi nối mạng đầu tiên của tôi. Tôi đã truyền lệnh dưới dạng chuỗi. Các lệnh sẽ được định dạng như thế này:"<player_id>:<command>:<parameters>"

Đối với một ví dụ giả định, một lệnh di chuyển có thể trông như thế này : "3:move:522:100:200". Điều này có nghĩa là Người chơi 3muốn moveđơn vị 522( 100, 200).

Máy chủ chuyển lệnh cho tất cả các máy khách, bao gồm cả người đã gửi nó, với một số đánh dấu được đính kèm như thế này : "153238:3:move:522:100:200".

Sau đó, tất cả các máy khách sẽ thực thi lệnh này khi đánh dấu 153238.


Tôi đã thêm một chút thông tin cho câu hỏi. Câu trả lời từ SO dường như trái ngược với những gì bạn nói và tôi muốn thảo luận về các chi tiết tốt hơn.
Darthg8r

Vâng, đó là một cách khác để làm điều đó, nhưng đối với tôi, có vẻ như sẽ có nhiều công việc hơn để vượt qua rất nhiều trạng thái trò chơi xung quanh, thay vì chỉ là các lệnh. Trò chơi của tôi đủ đơn giản để toàn bộ mọi thứ có thể chạy trên mỗi máy khách. Đối với MMO hoặc đối với một cái gì đó như Minecraft, bạn không có toàn bộ mô phỏng chạy ở phía máy khách, do đó bạn chỉ truyền thông tin liên quan đến từng khách hàng.
Philip
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.