2013-08-07 108 views
-1

我有一個關於編程網絡遊戲上的客戶端/服務器通信的一般問題。 我使用TCP作爲協議,並且通信...有效,但我不確定,如果這是一種有效的方式。GAMEPROGRAMMING通過....進行客戶端/服務器通信? (JAVA)

在一般情況下,在客戶端所發生的行爲會throught所有這些步驟:(例如火球正投)

  1. 一些行動
  2. [*]對於這個動作我定義了一個字符串(例如#F#270#130#,這意味着'F'表示它是一個火球,270是(例如)角度,130 - 火球的速度是射擊。)
  3. 字符串進入客戶端的輸出緩衝器&等待隊列
  4. 字符串被髮送
  5. 字符串被服務器接收
  6. [*]服務器需要一個可以檢測字符串含義的行解釋器(這裏:什麼意思是F?這是一個火球!)&增加了一個唯一的身份,基於,從哪個客戶端收到命令。
  7. [*]服務器需要根據發生的動作計算邏輯(火球對別人造成傷害,是否立即觸及某人或立即飛行)
  8. 服務器發送一個(更新的)字符串所有客戶都會採取的行動。 (例如,也許火球速度由於某種原因減速 - 這裏將是一個更新的字符串(#F#12345#270#90# - 12345是唯一的玩家身份)
  9. 客戶端接收字符串
  10. [* * ]客戶端將字符串解析爲命令+處理它(觸發動畫序列...)
  11. originaly發送命令的客戶端將收到的字符串與等待隊列中的字符串進行比較 - 當相等時,不執行任何操作(平滑某些操作,否則通過連接問題/延遲,一些動作會發生兩次或跳轉從一個位置到另一個位置,基於ping

真的有必要通過所有t這些步驟?在所有標有[*]的步驟中,我需要爲每個命令定義新的行解釋器/操作,因此我將每個操作編碼兩次,客戶端爲&服務器端。 我讀了一些關於發送可序列化對象的東西,但在genereal中,這個想法對我來說似乎是一樣的,我發送一個對象,該對象必須被解釋+處理,並且我發回一個對象...

任何提示?爲了解決整個溝通更優雅,用更少的代碼?或略偏分類 - 所有這些#樓##男尋找不同的動作##^h#標籤使它越來越複雜:)

(其實我確實有如下處理/操作:

- 移動 -Look /旋轉 -hpchange -firearrow -spawn /斷開 ...)

希望你明白我的意思 - 我知道,我可能只是繼續編碼一樣的是,它會以某種方式工作,但它似乎太複雜了,因爲它可能是。

謝謝!

+0

還有更多:)字符串被髮送,字節被轉移到服務器,字符串被服務器接收,其他100個步驟你沒有提到 – Tala

回答

0

在決定遊戲是否需要更改之前,您需要先看幾個因素。

首先,TCP是最好的通信渠道嗎?你有沒有比較它與UDP。使用UDP實現網絡會更好嗎?如果有幾個數據包丟失了,它會影響嗎?如果網絡速度慢,會發生什麼?

其次,看你投票/推送到服務器的頻率。這可以減少嗎?遊戲是否必須實時進行?遊戲的所有部分都必須實時進行。也許某些事情可能是非實時的。火球會繼續沿着直線前進,所以你不必更新服務器的位置,你可以直接告訴它的方向和速度。遊戲的其他方面可能不是實時的。唯一需要發送的是玩家位置和動作。大多數其他事情,如碰撞檢測可以卸載到客戶端。

第三,每個按鍵都需要發送到服務器嗎?如果用戶靠牆並希望進一步移動,則客戶端知道他們不能,因此不會將這些按鍵發送到服務器。如果用戶已移至新的有效位置,請更新服務器。某些事情可以一次性緩衝併發送到服務器,而不是向服務器發送多個查詢。也就是說,如果我向前邁進,跳起並投擲一個火球,這就是客戶端的3個按鍵,它們能夠在下一個500毫秒被緩衝併發送出去嗎?

如果您擔心網絡開銷,您應該在位級別工作。發送長度爲11個字節的長字符串「#F#270#130#」而不是發送3個連續字節(24位)是有意義的。

7位代表動作(127個不同的動作)。 9位將表示角度(1-512),但您只需要它直到0-360度。 8位代表力。

這個或任何其他字節格式在網絡上更短,更容易使用,並且產生更緊密的代碼。而且二進制比較速度更快,所以現在可以更輕鬆地在服務器上編寫動作解析器。即而不是尋找#F#的大型開關盒,你只需看看前7位,並將其與int進行比較。

您可以減少其他網絡開銷,而不是強制由客戶端決定,服務器是否可以決定這一點。即一個標準的力,或2個力的水平(好得多,因爲這可以用1位表示)。這阻止了客戶端和惡意用戶向服務器發送垃圾數​​據(例如999的強制),現在該力量可以是0或1,即10或20的速度,沒有什麼愚蠢的。

+0

好吧,謝謝,據我所知,這聽起來非常有用,最知名的多玩家遊戲(RealTimeStrategy ...星際爭霸?,不知道肯定,但魔獸世界?)使用UDP,但我無法想象如何處理缺失的信息,我的意思是,幾乎所有行動都很重要,或者可能很重要發送的每個對象都可能是一個接近死亡的治療。 我喜歡減少交通的部分,但我不認爲我會通過我的小遊戲達到沉重的交通狀況:D 它可以處理,不知道,也許多達5個玩家和〜50個其他移動物體。 此刻,動作緩存在50毫秒的堆棧中...... –

+0

也許你的消息可以用幾個字節來表示消息ID。每個客戶端都有自己的消息隊列 - 發送消息和消息,並且它們是連續的,所以00000001和00000010等等不斷增加(並最終重置),所以你可以保持一個軌道。如果服務器或客戶端看到的消息不是按順序排列的,則會知道消息在轉換中已經丟失。 – Husman

1

你可以做一個更面向對象的方式,如果你:

  1. 定義稱爲動作或類似的東西的對象,它具有上述所有參數的 - 動作的類型,動作的方向(或 目標),造成的傷害等。
  2. 創建這些Action對象爲您的遊戲正常執行
  3. ,使用ObjectOutputStream鏈接到你的TPC插座輸出整個Action對象到服務器/傳回給客戶端。
  4. 在服務器上,通過檢查ObjectInputStream中收到的對象來解釋發生了什麼。

我覺得這種方式會在情況更清潔和更靈活添加更多的邏輯,不僅僅是分析字符串,但沒有那麼快(因爲對象進入的ObjectOutputStream需要序列)。

+0

好吧,那聽起來就像我讀過的。但是,是的,這將更加優雅:) 我想我會編輯我的代碼到這個變體並且定義一個抽象操作類,以及許多將描述操作的子操作類......是否可以在類中定義方法,fe doLogic()然後被髮送到服務器並返回後,調用它們?例如。 action.doLogic()和這些會更新遊戲的一些參數?這將非常有幫助! ^^ –

+0

是的,它可以定義方法,基本上你可以傳遞任何普通的類,只要它沒有引用外部的東西 - 例如對文件或數據庫的引用等等。如果是這樣,那些代表引用的實例變量必須用修飾符transient標記,以便它們不會被序列化。你可以閱讀更多關於何時使用瞬態:http://stackoverflow.com/questions/5960280/what-is-the-use-of-transient-variables希望有所幫助,祝你好運! –