網絡游戲的客戶端同步問題 .

?

有關位置同步的方案實際上已經比較成熟,網上也有比較多的資料可供參考。在《帶寬限制下的視覺實體屬性傳播》一文中,作者也簡單提到了位置同步方案的構造過程,但涉及到細節的地方沒有深入,這里專門針對這一主題做些回顧。

?

最直接的同步方案就是客戶端在每次發生位置改變時都向服務器報告 ,服務器再轉發給周圍的其他玩家,其他客戶端將對應的游戲實體移動到新的位置上。

?

但是這樣存在一個問題,每個玩家的位置都是自己先開始移動,一段時間之后才在其他玩家的客戶端上表現出來。如果只是希望每個客戶端上看到的游戲對象都同時開始移動,那可以讓玩家的每一步操作都由服務器確認之后再執行,這樣誤差將縮減到不同客戶端之間的網絡延時差。但是顯然的,這樣的做法不可能真正被采用,因為這將使得玩家的游戲體驗非常的糟糕。有誰能忍受連每走一步路都要卡一下的游戲呢?

?

既然一定存在先后時間差,那需要一種方法來讓不同客戶端上看到的玩家位置不至于有太大的誤差,尤其是不能有影響到游戲公平性的誤差存在。根據誤差出現的直接原因:時間差,我們應該能夠想到一個解決方案,那就是讓其他客戶端設法彌補掉這段時間差內少走的距離。這樣的話也就要求我們的消息包中多帶一個開始移動的時間數據,用于其他客戶端在收到這個消息包時計算對應的玩家實體已經移動過的時間和距離。

?

我們以一個實際的例子來說明如何減少這種誤差的影響。假設玩家A以速度V從P1點去到P2點,A的網絡延時為T1,在A旁邊有個玩家B,他的網絡延時為T2。B收到服務器轉發過來的移動包時,A在其自己的客戶端上已經移動了T1+T2的時間,在這段時間內他自己已經走過了V*(T1+T2)的距離。如果這時在B的客戶端上開始將實體A從P1移動到P2,那顯然兩個客戶端上看到的A的位置始終存在V*(T1+T2)的誤差。

?

為了使A在B客戶端上顯示的位置與其實際位置的誤差盡可能的縮小,一個簡單的做法是直接將A的位置向前拖V*(T1+T2)然后開始移動,這樣兩者之間的誤差便消除了。但這樣會使得客戶端的顯示太魯莽,要讓其看起來平滑一些,我們可以考慮使用一些算法,比如計算出A從當前位置走到P2點還需要的時間,然后加快其速度使其在規定的時間內到達P2點,這樣A和B看到的最終時間是相同的,但中間過程還是存在較多誤差。另一種較好的做法是先讓A以一個可接受的較快速度移動到其當前應該所在的位置稍前一點的地方,然后以正常速度移動到P2點,這樣后面的移動情況與其實際移動情況基本吻合了。

?

看起來這個方案很完美,但是這里卻忽略了一個問題:我們假設的是每次移動時都知道玩家要去的確切位置。這在靠鼠標點擊來移動的2D游戲中是正好合適的,但是在WOW一類的靠鍵盤來移動的3D游戲中卻沒有辦法采用。WOW中的移動消息都只能向服務器報告當前的坐標及朝向信息。

?

這類移動的位置同步其實也可以采用類似方案,服務器將移動玩家的當前位置信息廣播給周圍的其他玩家,當然其中也包含了時間戳。當其他玩家收到這個移動包后,表示的是在過去的某個時間里該玩家移動到了這個位置。如果只是簡單地將其對應的實體移動到這個位置,那同樣的,也存在位置誤差。

?

與上一種情況類似,如果我們知道該玩家的移動速度,再通過數據包中的時間戳,假設該玩家還在以相同的速度朝相同的方向移動,那我們也可以預測出該玩家從開始移動到現在這段時間內他走了多遠了距離。我們也可以將其位置做適當的修正,并使其繼續移動下去。

?

我們需要先停下來考慮一下這些算法的部分細節。其中出現了一些數據是否應該包含在我們的每個消息包中,也就是我們需要考慮的另外一個問題:移動同步的消息中應該包含哪些數據,以及這些數據到底應該向哪些玩家廣播。

?

對于2D游戲的情況來說,我們的算法需要的數據有:玩家的速度V,玩家開始移動的時間T0,收到數據包的時間T1,玩家當前位置P1和玩家要去的位置P2。T1和P1從當前客戶端上都可以取到,而速度V一般來說不會經常改變,至少不是每次移動時都不一樣,所以我們可以為速度的改變設計單獨的消息碼,這樣V值也是可以在客戶端上取到的。最后,每個移動消息中包含的數據只需要有移動到的位置P2和開始移動的時間T0。

?

其他客戶端在使用特定算法將玩家移動到P2后會將其停在此處,直到收到下一個移動包時再開始移動。而對于在移動過程中又收到了新的移動包的處理過程基本類似,不做過多描述。

?

對于3D游戲的情況,算法是基本相同的,但是沒有目標點,替換為移動方向,比如是向正前方移動,還是向左或向右移動等。在這種情況下,只要沒有收到玩家停止移動的消息,其他客戶端上都會以最后一次收到的移動包的狀態來繼續模擬移動。

?

所以,在網絡偶爾卡一下的時候也會出現一些奇怪的現象。比如WOW中,看到隊友直沖沖地走下了懸崖,你剛喊了句“怎么掉下去了?”只見隊友又從身后走出來,還冒出一句:“沒啊,我就在你旁邊!”

?

關于數據要向哪些人廣播的問題,其實很簡單,哪些人會看到這個玩家就需要向哪些人廣播。不管是直接在主屏幕上看到還是在大地圖上看到的代表其位置的一個點。但是,針對不同的人使用的廣播策略還是存在差異。

?

在《帶寬限制下的視覺實體屬性傳播》一文中提出了一個方案很值得參考。該方案提出的基礎是因為3D空間透視的原因,離你很遠的一個玩家移動了10米,最終在你的顯示器上看到的位移可能只有一個象素;而離你不到一米的一個玩家雖然只移動了一米,但最終顯示出來的位移可能會有幾十個象素。所以,遠處玩家的移動并不需要非常嚴格的關注,但近處玩家的移動同步需要非常高的優先級。

?

這個方案的實現還依賴于另一項技術要求,玩家的屬性更新以一定的頻率來進行,更新時比較一下當前屬性值與上次更新時的屬性值,如果存在差異則通知客戶端更新,另外如果中間跳過了某次更新也不會對客戶端表現及游戲公平性造成什么影響。比如這里要處理的玩家坐標,第一次移動到A點,第二次從A點又移動到B點,如果移動到A點的更新包沒有發送,直接發送了移動到B點的更新包,這將不會對游戲邏輯產生大的影響。

?

這套方案基本上是為3D游戲的實體屬性廣播優化而設計的,在2D游戲中很難使用。一是斜45度視角的2D游戲中屏幕頂端、中間和底部任何一個位置上的玩家移動,其距離和象素比是完全相同的,因為畫面不存在透視,所以也就沒有遠處對象更新頻率低這一可能。另外2D游戲中的移動與3D游戲也存在差異,具體情況前面有詳細描述,2D游戲中基本上每一次移動都需要廣播,不能跳過哪一個,否則玩家看到的現象就是在亂跑,這也必將影響到技能的使用等游戲邏輯。

?

有關位置同步所涉及到的一些技術細節及優化方案上面描述了一部分,但是在實際的應用中是否會使用還是要看具體游戲的需求。比如大話類型的游戲,其本身對位置的精確同步就沒有要求,兩個客戶端上出現一前一后的移動也不會影響任何的游戲邏輯,所以前面提到的同步方案可能都用不上。

?

而對于一些同步要求很高的游戲,如WOW中盜賊這類職業的需求,上面的方案可能還不夠細致,還需要設計更加有效的同步方案。

?

另外,在位置同步過程中還有一個不容忽視的問題是外掛。我們不能像WOW那樣完全依賴客戶端,如果沒有暴雪那樣強硬的封號措施,游戲也就成為了外掛們的溫床。所以,如何在服務器端模擬每個客戶端的移動,如何檢測出客戶端是否存在作弊行為,也是需要重點關注的一個問題。

小談網絡游戲同步

 
  同步在網絡游戲中是非常重要的,它保證了每個玩家在屏幕上看到的東西大體是一樣的。其實呢,解決同步問題的最簡單的方法就是把每個玩家的動作都向其他玩家廣播一遍,這里其實就存在兩個問題:1,向哪些玩家廣播,廣播哪些消息。2,如果網絡延遲怎么辦。事實上呢,第一個問題是個非常簡單的問題,不過之所以我提出這個問題來,是提醒大家在設計自己的消息結構的時候,需要把這個因素考慮進去。而對于第二個問題,則是一個挺麻煩的問題,大家可以來看這么個例子:

  比如有一個玩家A向服務器發了條指令,說我現在在P1點,要去P2點。指令發出的時間是T0,服務器收到指令的時間是T1,然后向周圍的玩家廣播這條消息,消息的內容是“玩家A從P1到P2”有一個在A附近的玩家B,收到服務器的這則廣播的消息的時間是T2,然后開始在客戶端上畫圖,A從P1到P2點。這個時候就存在一個不同步的問題,玩家A和玩家B的屏幕上顯示的畫面相差了T2-T1的時間。這個時候怎么辦呢?

  有個解決方案,我給它取名叫 預測拉扯,雖然有些怪異了點,不過基本上大家也能從字面上來理解它的意思。要解決這個問題,首先要定義一個值叫:預測誤差。然后需要在服務器端每個玩家連接的類里面加一項屬性,叫TimeModified,然后在玩家登陸的時候,對客戶端的時間和服務器的時間進行比較,得出來的差值保存在TimeModified里面。還是上面的那個例子,服務器廣播消息的時候,就根據要廣播對象的TimeModified,計算出一個客戶端的CurrentTime,然后在消息頭里面包含這個CurrentTime,然后再進行廣播。并且同時在玩家A的客戶端本地建立一個隊列,保存該條消息,只到獲得服務器驗證就從未被驗證的消息隊列里面將該消息刪除,如果驗證失敗,則會被拉扯回P1點。然后當玩家B收到了服務器發過來的消息“玩家A從P1到P2”這個時候就檢查消息里面服務器發出的時間和本地時間做比較,如果大于定義的預測誤差,就算出在T2這個時間,玩家A的屏幕上走到的地點P3,然后把玩家B屏幕上的玩家A直接拉扯到P3,再繼續走下去,這樣就能保證同步。更進一步,為了保證客戶端運行起來更加smooth,我并不推薦直接把玩家拉扯過去,而是算出P3偏后的一點P4,然后用(P4-P1)/T(P4-P3)來算出一個很快的速度S,然后讓玩家A用速度S快速移動到P4,這樣的處理方法是比較合理的,這種解決方案的原形在國際上被稱為(Full plesiochronous),當然,該原形被我篡改了很多來適應網絡游戲的同步,所以而變成所謂的:預測拉扯。

  另外一個解決方案,我給它取名叫 驗證同步,聽名字也知道,大體的意思就是每條指令在經過服務器驗證通過了以后再執行動作。具體的思路如下:首先也需要在每個玩家連接類型里面定義一個TimeModified,然后在客戶端響應玩家鼠標行走的同時,客戶端并不會先行走動,而是發一條走路的指令給服務器,然后等待服務器的驗證。服務器接受到這條消息以后,進行邏輯層的驗證,然后計算出需要廣播的范圍,包括玩家A在內,根據各個客戶端不同的TimeModified生成不同的消息頭,開始廣播,這個時候這個玩家的走路信息就是完全同步的了。這個方法的優點是能保證各個客戶端之間絕對的同步,缺點是當網絡延遲比較大的時候,玩家的客戶端的行為會變得比較不流暢,給玩家帶來很不爽的感覺。該種解決方案的原形在國際上被稱為(Hierarchical master-slave synchronization),80年代以后被廣泛應用于網絡的各個領域。

  最后一種解決方案是一種理想化的解決方案,在國際上被稱為Mutual synchronization,是一種對未來網絡的前景的良好預測出來的解決方案。這里之所以要提這個方案,并不是說我們已經完全的實現了這種方案,而只是在網絡游戲領域的某些方面應用到這種方案的某些思想。我對該種方案取名為:半服務器同步。大體的設計思路如下:

  首先客戶端需要在登陸世界的時候建立很多張廣播列表,這些列表在客戶端后臺和服務器要進行不及時同步,之所以要建立多張列表,是因為要廣播的類型是不止一種的,比如說有local message,有remote message,還有global message 等等,這些列表都需要在客戶端登陸的時候根據服務器發過來的消息建立好。在建立列表的同時,還需要獲得每個列表中廣播對象的TimeModified,并且要維護一張完整的用戶狀態列表在后臺,也是不及時的和服務器進行同步,根據本地的用戶狀態表,可以做到一部分決策由客戶端自己來決定,當客戶端發送這部分決策的時候,則直接將最終決策發送到各個廣播列表里面的客戶端,并對其時間進行校對,保證每個客戶端在收到的消息的時間是和根據本地時間進行校對過的。那么再采用預測拉扯中提到過的計算提前量,提高速度行走過去的方法,將會使同步變得非常的smooth。該方案的優點是不通過服務器,客戶端自己之間進行同步,大大的降低了由于網絡延遲而帶來的誤差,并且由于大部分決策都可以由客戶端來做,也大大的降低了服務器的資源。由此帶來的弊端就是由于消息和決策權都放在客戶端本地,所以給外掛提供了很大的可乘之機。

  綜合以上三種關于網絡同步派系的優缺點,綜合出一套關于網絡游戲傳輸同步的較完整的解決方案,我稱它為綜合同步法(colligate synchronization)。大體設計思路如下:

  首先將服務器需要同步的所有消息從劃分一個優先等級,然后按照3/4的比例劃分出重要消息和非重要消息,對于非重要消息,把決策權放在客戶端,在客戶端邏輯上建立相關的決策機構和各種消息緩存區,以及相關的消息緩存區管理機構,如下圖所示:

  上圖簡單說明了對于非重要消息,客戶端的大體處理流程,其中有一個客戶端被動行為值得大家注意,其中包括對服務器發過來的某些驗證代碼做返回,來確保消息緩存中的消息和服務器端是一致的,從而有效的防止外掛來篡改本地消息緩存。其中的消息來源是包括本地的客戶端響應玩家的消息以及遠程服務器傳遞過來的消息。

  對于重要消息,比如說戰斗或者是某些牽扯到玩家一些比較敏感數據的操作,則采用另外一套方案,該方案首先需要在服務器和客戶端之間建立一套Ping System,然后服務器保存和用戶的及時的ping值,當ping比較小的時候,響應玩家消息的同時先不進行動作,而是先把該消息反饋給服務器,并且阻塞,服務器收到該消息,進行邏輯驗證之后向所有該詳細廣播的有效對象進行廣播(包括消息發起者),然后客戶端收到該消息的驗證,才開始執行動作。而當ping比較大的時候,客戶端響應玩家消息的同時立刻進行動作,并且同時把該消息反饋給服務器,值得注意的是這個時候還需要在本地建立一個無驗證消息的隊列,把該消息入隊,執行動作的同時等待服務器的驗證,還需要保存當前狀態。服務器收到客戶端的請求后,進行邏輯驗證,并把消息反饋到各個客戶端,帶上各個客戶端校對過的本地時間。如果驗證通過不過,則通知消息發起者,該消息驗證失敗,然后客戶端自動把已經在進行中的動作取消,恢復原來狀態。如果驗證通過,則廣播到的各個客戶端根據從服務器獲得校對時間進行對其進行拉扯,保證在該行為完成之前完成同步。

  至此,一個比較成熟的網絡游戲的同步機制已經初步建立起來了,接下來的邏輯代碼就根據各自不同的游戲風格以及側重點來寫了。

  同步是網絡游戲最重要的問題,如何同步也牽扯到各個方面的問題,比如說游戲的規模,游戲的類型以及各種各樣的方面,對于規模比較大的游戲,在同步方面可以下很多的工夫,把消息分得十分的細膩,對于不同的消息采用不同的同步機制,而對于規模比較小的游戲,則可以采用大體上一樣的同步機制,究竟怎么樣同步,沒有個定式,是需要根據自己的不同情況來做出不同的同步決策的



網游同步算法之導航推測(Dead Reckoning)算法:


  在了解該算法前,我們先來談談該算法的一些背景資料。大家都知道,在網絡傳輸的時候,延遲現象是很普遍的,而在基于Server/Client結構下的網絡游戲的同步也就成了很頭疼的問題,在保證客戶端響應用戶本地指令流暢的情況下,沒法有效的保證的同步的及時性。同樣,在軍方也有類似的事情發生,即使是同一LAN里面的機器,也會因為傳輸的延遲,導致一些運算的失誤,介于此,美國國防部投入了大量的資金用于研究一種比較的好的方案來解決分布式系統中的延遲問題,特別是一個叫分布式模擬運動(Distributed Interactive Simulation)的系統,這套系統呢,其中就提出了一套號稱是Latency Hiding & Bandwidth Reduction的方案,命名為Dead Reckoning。呵呵,來頭很大吧,恩,那么我們下面就來看看這套系統的一些觀點,以及我們如何把它運用到我們的網絡游戲的同步中。

  首先,這套同步方案是基于我那篇《網絡游戲的同步》一文中的Mutual Synchronization同步方案的,也就是說,它并不是Server/Client結構的,而是基于客戶端之間的同步的。下面我們先來說一些本文中將用到的名詞概念:
  網狀網絡:客戶端之間構成的網絡
  節點:網狀網絡中的每個客戶端
  極限誤差:進行同步的時候可能產生的誤差的極值

  恩,在探討其原理的之前,我們先來看看我們需要一個什么樣的環境。首先,需要一個網狀網絡,網狀網絡如何構成呢?當有新節點進入的時候,通知該網絡里面的所有節點,各節點為該客戶端在本地創建一個副本,登出的時候,則通知所有節點銷毀本地關于該節點的副本。然后每個節點該保存一些什么數據呢?首先有一個很重要的包需要保存,叫做協議數據包(PDU Protocol Data Unit),PDU包含節點的一些相關的運動信息,比如當前位置,速度,運動方向,或者還有加速度等一些信息。除PDU之外,還有其他信息需要保存,比如說節點客戶端人物的HP,MP之類的。然后,保證每個節點在最少8秒之內要向其它節點廣播一次PDU信息。最后,設置一個極限誤差值。到此,其環境就算搭建完成了。下面,我們就來看看相關的具體算法:

  假設在節點A有一個小人(路人甲),開始跑路了,這個時候,就像所有的節點廣播一次他的PDU信息,包括:速度(S),方向(O),加速度(A)。那么所有的節點就開始模擬路人甲的運動軌跡和路線,包括節點A本身(這點很重要),同時,路人甲在某某玩家的控制下,會不時的改變一下方向,讓其跑路的路線變得不是那么正規。在跑路的過程中,節點A有一個值在不停的記錄著其真實坐標和在后臺模擬運動的坐標的差值,當差值大于極限誤差的時候,則計算出當前的速度S,方向O和速度A(算法將在后面介紹),并廣播給網絡中其他所有節點。其他節點在收到這條消息之后呢,就可以用一些很平滑的移動把路人甲拉扯過去,然后重新調整模擬跑路的數據,讓其繼續在后臺模擬跑路。

  很顯然,如果極限誤差定義得大了,其他節點看到的偏差就會過大,如果極限偏差定義得小了,網絡帶寬就會增大。如果定義這個極限誤差,就該根據各種數據的重要性來設計了。如果是回合制的網絡游戲,那么在走路上把極限誤差定義得大些無所謂,可以減少帶寬。但是如果是及時打斗的網絡游戲,那么就得把極限誤差定義得小一些,否則會出現某人看到某人老遠把自己給砍死的情況。

  Dead Reckoning的主要算法有9種,但是只有兩種是解決主要問題的,其他的基本上只是針對不同的坐標系的一些不同的算法,這里就不一一介紹了。好,那么我們下面來看傳說中的最主要的兩種算法:
    第一:目標點 = 原點 + 速度 * 時間差
    第二:目標點 = 原點 + 速度 * 時間差 + 1/2 * 加速度 * 時間差
呵呵,傳說中的算法都是很經典的,雖然我們早在初中物理的時候就學過。

  該算法的好處呢,正如它開始所說的,Latency Hiding & Bandwidth Reduction,從原則上解決了網絡延遲導致的不同步的問題,并且有效的減少了帶寬,不好的地方就是該算法基本上只能使用于移動中的同步,當然,移動的同步是網絡游戲中同步的最大的問題。

  該方法結合我在《網絡游戲的同步》一文中提出的綜合同步法的構架可以基本上解決掉網絡游戲中走路同步的問題。相關問題歡迎大家一起討論。


有關導航推測算法(Dead Reckoning)中的平滑處理:

  根據我上篇文章所介紹的,在節點A收到節點B新的PDU包時,如果和A本地的關于B的模擬運動的坐標不一致時,怎么樣在A的屏幕上把B拽到新的PDU包所描敘的點上面去呢,上文中只提了用“很平滑的移動”把B“拉扯”過去,那么實際中應該怎么操作呢?這里介紹四種方法。

  第一種方法,我取名叫直接拉扯法,大家聽名字也知道,就是直接把B硬生生的拽到新的PDU包所描敘的坐標上去,該方法的好處是:簡單。壞處是:看了以下三種方法之后你就不會用這種方法了。

  第二種方法,叫直線行走(Linear),即讓B從它的當前坐標走直線到新的PDU包所描敘的坐標,行走速度用上文中所介紹的經典算法:
    目標點 = 原點 + 速度 * 時間差 + 1/2 * 加速度 * 時間差算出:
  首先算出從當前坐標到PDU包中描敘的坐標所需要的時間:
    T = Dest( TargetB – OriginB ) / Speed
  然后根據新PDU包中所描敘的坐標信息模擬計算出在時間T之后,按照新的PDU包中的運動信息所應該達到的位置:
    _TargetB = NewPDU.Speed * T
  然后根據當前模擬行動中的B和_TargetB的距離配合時間T算出一個修正過的速度_S:
    _S = Dest( _TargetB – OriginB ) / T
  然后在畫面上讓B以速度_S走直線到Target_B,并且在走到之后調整其速度,方向,加速度等信息為新的PDU包中所描敘的。

  這種方法呢,非常的土,會讓物體在畫面上移動起來變得非常的不現實,經常會出現很生硬的拐角,而且對于經常要修改的速度_S,在玩家A的畫面上,玩家B的行動會變得非常的詭異。其好處是:比第一種方法要好。

  第三種方法,叫二次方程行走(Quadratic),該方法的原理呢,就是在直線行走的過程中,加入二次方程來計算一條曲線路徑,讓Dest( _TargetB – OriginB )的過程是一條曲線,而不是一條直線,恩,具體的實現方法,就是在Linear方法的計算中,設定一個二次方程,在Dest函數計算距離的時候根據設定的二次方程來計算,這樣一來,可以使B在玩家A屏幕上的移動變得比較的有人性化一些。但是該方法的考慮也是不周全的,僅僅只考慮了TargetB到_TargetB的方向,而沒有考慮新的PDU包中的方向描敘,那么從_TargetB開始模擬行走的時候,仍然是會出現比較生硬的拐角,那么下面提出的最終解決方案,將徹底解決這個問題。

  最后一種方法叫:立方體抖動(Cubic Splines),這個東東比較復雜,它需要四個坐標信息作為它的參數來進行運算,第一個參數Pos1是OriginB,第二個參數Pos2是OriginB在模擬運行一秒以后的位置,第三個參數Pos3是到達_TargetB前一秒的位置,第四個參數pos4是_TargetB的位置。

Struct pos {
??? Coordinate X;
??? Coordinate Y;
}


   Pos1 = OriginB
   Pos2 = OriginB + V
   Pos3 = _TargetB – V
   Pos4 = _TargetB

運動軌跡中(x, y)的坐標。
   x = At^3 + Bt^2 + Ct + D
   y = Et^3 + Ft^2 + Gt + H

(其中時間t的取值范圍為0-1,在Pos1的時候為0,在Pos4的時候為1)

x(0-3)代表Pos1-Pos4中x的值,y(0-3)代表Pos1-Pos4中y的值
   A = x3 – 3 * x2 +3 * x1 – x0
   B = 3 * x2 – 6 * x1 + 3 * x0
   C = 3 * x1 – 3 * x0
   D = x0

   E = y3 – 3 * y2 +3 * y1 – y0
   F = 3 * y2 – 6 * y1 + 3 * y0
   G = 3 * y1 – 3 * y0
   H = y0


  上面是公式,那么下面我們來看看如何獲得Pos1-Pos4:首先,Pos1和 Pos2的取值會比較容易獲得,根據OriginB配合當前的速度和方向可以獲得,然而Pos3和Pos4呢,怎么獲得呢?如果在從Pos1到Pos4的過程中有新的PDU到達,那么我們定義它為NewPackage。

   Pos3 = NewPackage.X + NewPackage.Y * t + 1/2 * NewPackage.a * t^2
   Pos4 = Pos3 – (NewPackage.V + NewPackage.a * t)


如果沒有NewPackage的情況下,則Pos3和Pos4按照開始所規定的方法獲得。

至此,關于導航推測的算法大致介紹完畢。

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/444962.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/444962.shtml
英文地址,請注明出處:http://en.pswp.cn/news/444962.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

leetcode319 燈泡的開關

初始時有 n 個燈泡關閉。 第 1 輪,你打開所有的燈泡。 第 2 輪,每兩個燈泡你關閉一次。 第 3 輪,每三個燈泡切換一次開關(如果關閉則開啟,如果開啟則關閉)。第 i 輪,每 i 個燈泡切換一次開關。 …

網游服務器端設計思考:心跳設計

網絡游戲服務器的主要作用是模擬整個游戲世界,客戶端用過網絡連接把一些信息數據發給服務器,在操作合法的情況下,更新服務器上該客戶端對應的player實體、所在場景等,并把這些操作及其影響廣播出去。讓別的客戶端能顯示這些操作。…

算法(25)-括號

各種括號1.LeetCode-22 括號生成--各種括號排列組合2.LeetCode-20 有效括號(是否)--堆棧3.LeetCode-32 最長有效括號(長度)--dp4.LeetCode-301刪除無效括號 --多種刪除方式1.LeetCode-22 括號生成–各種括號排列組合 數字 n 代表生成括號的對數,請你設計一個函數&a…

(二十)深入淺出TCPIP之epoll的一些思考

Epoll基本介紹 在linux的網絡編程中,很長的時間都在使用select來做事件觸發。在linux新的內核中,有了一種替換它的機制,就是epoll。相比于 select,epoll最大的好處在于它不會隨著監聽fd數目的增長而降低效率。因為在內核中的select實現中,它是采用輪詢來處理的,輪詢的fd…

leetcode542 01矩陣

給定一個由 0 和 1 組成的矩陣,找出每個元素到最近的 0 的距離。 兩個相鄰元素間的距離為 1 。 示例 1: 輸入: 0 0 0 0 1 0 0 0 0 輸出: 0 0 0 0 1 0 0 0 0 示例 2: 輸入: 0 0 0 0 1 0 1 1 1 輸出: 0 0 0 0 1 0 1 2 1 注意: 給定矩陣的元素個數不超過 10000。…

RPC、RMI與MOM與組播 通信原理 .

遠程過程調用(RPC): 即對遠程站點機上的過程進行調用。當站點機A上的一個進程調用另一個站點機上的過程時,A上的調用進程掛起,B上的被調用過程執行,并將結果返回給調用進程,使調用進程繼續執行【…

網關服務器 .

之前想著要把什么什么給寫一下,每次都太懶了,都是想起了才來寫一下。今天只討論游戲服務器的網關服務器。 1.轉發 轉發客戶端和服務器間的消息,網關將場景、會話、數據、名字、平臺等服務器的數據轉發給客戶端,接收客戶端的數據&a…

算法(26)-最長系列

最長系列1.LeetCode-32 最長有效括號--子串2.LeetCode-300 最長上升子序列--長度3.LeetCode-32 最長回文子串--是什么5.LeetCode-512 最長回文子序列--長度6.LeetCode-1143 最長公共子序列--長度6.LeetCode-128 最長連續序列--長度7.LeetCode-14 最長公共前綴-字符串8.劍指offe…

一個簡單的游戲服務器框架 .

最近一段時間不是很忙,就寫了一個自己的游戲服務器框架雛形,很多地方還不夠完善,但是基本上也算是能夠跑起來了。我先從上層結構說起,一直到實現細節吧,想起什么就寫什么。 第一部分 服務器邏輯 服務器這邊簡單的分為三…

游戲登陸流程 .

當公司有很多游戲的時候,那么公司往往會有一個統一的賬號管理平臺,就就像盛大通行證、網易通行證,戰網平臺,這些平臺統一管理游戲的賬號數據。 打個比方,現在我們玩星辰變,那么玩家登陸游戲的時候…

leetcode97 交錯字符串

給定三個字符串 s1, s2, s3, 驗證 s3 是否是由 s1 和 s2 交錯組成的。 示例 1: 輸入: s1 "aabcc", s2 "dbbca", s3 "aadbbcbcac" 輸出: true 示例 2: 輸入: s1 "aabcc", s2 "dbbca", s3 "aadbbbaccc" 輸…

算法(27)-最大系列

最大系列1.LeetCode-239 滑動窗口的最大值2.LeetCode-53 連續子數組的最大和3.LeetCode-152 乘積最大的子數組。4.劍指 Offer 14- I. 剪繩子為k個整數段,使各個段成績最大1.dp數學推導1.LeetCode-239 滑動窗口的最大值 窗口由左往右最大值數組Left,和由…

mysql數據庫表的導入導出

MySQL寫入數據通常用insert語句,如 復制代碼 代碼如下: insert into person values(張三,20),(李四,21),(王五,70)…; 但有時為了更快速地插入大批量數據或…

leetcode 33 搜索旋轉排序數組 到處是細節的好題

這個題想了想就會做,只是細節真的能卡死人,找了好久的bug。甚至我懷疑我現在的代碼可能還有錯,只是沒例子測出來。 假設按照升序排序的數組在預先未知的某個點上進行了旋轉。 ( 例如,數組 [0,1,2,4,5,6,7] 可能變為 [4,5,6,7,0,1…

多線程中局部靜態變量初始化的陷阱

C當中常常需要一個全局唯一的對象實例,這時候,我們就會想到單件模式。如何實現這一模式?全局變量當然是一個簡單可行的方法,然而,這太丑陋。嗯,其實,丑陋倒也罷了,最嚴重的是它將引誘…

MachineLearning(8)-PCA,LDA基礎+sklearn 簡單實踐

PCA,LDA基礎sklearn 簡單實踐1.PCAsklearn.decomposition.PCA1.PCA理論基礎2.sklearn.decomposition.PCA簡單實踐2.LDAsklearn.discriminant_analysis.LinearDiscriminantAnalysis2.1 LDA理論基礎2.2 sklearn LDA簡單實踐1.PCAsklearn.decomposition.PCA 1.PCA理論基礎 PCA:&…

引用變量和引用數組

前兩天沒事干,重拾C++的一些書籍,翻到引用這,無意寫了些DD: 其實引用和指針有很多相似的地方,又有不同的(太多了,不過說到效率上,比如函數傳參數,我們可以用引用,指針,哪種好呢,引用不必為站再分配空間了,而指針還學要分配4字節的空間給指針變量) 我們知道如何…

leetcode198 打家劫舍

你是一個專業的小偷,計劃偷竊沿街的房屋。每間房內都藏有一定的現金,影響你偷竊的唯一制約因素就是相鄰的房屋裝有相互連通的防盜系統,如果兩間相鄰的房屋在同一晚上被小偷闖入,系統會自動報警。 給定一個代表每個房屋存放金額的…

linux下的RPC

一、概述 在傳統的編程概念中,過程是由程序員在本地編譯完成,并只能局限在本地運行的一段代碼,也即其主程序和過程之間的運行關系是本地調用關系。因此這種結構在網絡日益發展的今天已無法適應實際需求。總而言之,傳統過程調用模式…

算法(28)--矩陣搜索系列

矩陣搜索1.leetcode-200. 島嶼數量2.leetcode-695. 島嶼的最大面積3.leetcode-463. 島嶼的周長4.劍指 Offer 12. 矩陣中的路徑5.leetcode-329. 矩陣中的最長遞增路徑6.leetcode-1091. 二進制矩陣中的最短路徑1.leetcode-200. 島嶼數量 給你一個由 ‘1’(陸地&#…