1. 肯定本局隨機種子服務器
因爲即時對戰遊戲中有不少隨機的事件,同一個隨機事件(好比MOBA中的暴擊)不能由於是不一樣的機器就得出不一樣的結果。因此在某一局的開始時就肯定一個固定的時間種子,可使用當前的時間戳做爲種子(通常以服務器時間)。dom
TimeSpan ts = DateTime.UtcNow - new DateTime(1970, 1, 1, 0, 0, 0, 0); System.Random random = new System.Random((int)ts.TotalSeconds); for (int i = 0; i < 10; i++) { Debug.Log(random.Next(1, 1000)); //從1-999中隨機一個數 }
由服務器將服務器時間戳發送到各個客戶端(果如以爲太大能夠用65536取個餘),若是須要回放功能只要保存服務器發送的時間戳便可。oop
2. 遊戲循環和插值計算code
咱們假設作一個物體移動的功能,如下是核心邏輯代碼:orm
private bool m_bIsLoop = false; //是否循環 private int m_iLogicFrameCount; //邏輯幀數計數 private const int m_kFRAME_UPDATE_MS = 50; //正常邏輯中更新間隔(毫秒),設50毫秒由於MOBA通常設的是50 private const int m_kFRAME_UPDATE_MS_SLOW = 500; //慢速邏輯中更新間隔(毫秒) private int m_iFrameUpdateMS; //實際邏輯中更新間隔(毫秒) private int m_iLag; //據上一個邏輯幀的間隔(毫秒) private float m_fInterpolation; //插值百分比 [SerializeField] private GameObject g; //模擬移動的物體 private Vector3 m_v3LogicPosition; //物體邏輯幀的位置 private const float m_kSpeed = 0.1f; //物體移動速度(每一個邏輯幀) void Loop() //邏輯幀計算 { m_v3LogicPosition = m_v3LogicPosition + Vector3.right * m_kSpeed; //物體邏輯幀的位置移動m_kSpeed的距離 g.transform.localPosition = m_v3LogicPosition; //物體的位置設爲邏輯幀計算獲得的位置 if(m_iLogicFrameCount >= 2) //兩秒以後進入慢速模式(子彈時間) { m_iFrameUpdateMS = m_kFRAME_UPDATE_MS_SLOW; } } void Interpolation() //插值計算 { //根據插值百分比計算插值位置 g.transform.localPosition = Vector3.Lerp(m_v3LogicPosition, m_v3LogicPosition + Vector3.right * m_kSpeed, m_fInterpolation); } void FixedUpdate() { if (!m_bIsLoop) return; if (m_iLag < m_iFrameUpdateMS) //據上一個邏輯幀的間隔小於固定更新間隔 { m_iLag += (int)(Time.fixedDeltaTime * 1000); m_fInterpolation = (float)m_iLag / m_iFrameUpdateMS; //計算插值百分比 Interpolation(); } else //據上一個邏輯幀的間隔大於固定更新間隔,執行一次邏輯幀計算 { m_iLogicFrameCount++; m_iLag -= m_iFrameUpdateMS; Loop(); } }
FixedUpdate裏只會寫物理運動和與遊戲相關的邏輯,另外一些與遊戲邏輯無關的能夠寫到Update裏面去(好比Dota裏面樹木的晃動,河道水流的運動等)。作到這裏我想到是否是能夠經過這段代碼實現子彈時間功能?因而我稍做修改添加了m_kFRAME_UPDATE_MS_SLOW這個常量,而且在兩個邏輯幀後將邏輯幀更新間隔設成這個慢速的,即可以看出物體的移動速度只有原來的十分之一(因此猜測咱們用m_kFRAME_UPDATE_MS來處理主角的邏輯是否是就能夠實現相似荒野大鏢客2裏的子彈時間功能,聯想Dota裏面暫停的時候樹木的晃動和河道的運動並無變化,因此進一步證實了他們的邏輯是在Update裏處理的)。遊戲
3. 遊戲裏輸入的處理事件
以上面的代碼爲基礎,假設咱們改變一下需求,按下鍵盤上的上下左右方向鍵能夠改變物體的移動方向,都不按時物體不移動,實現時要考慮到客戶端服務器間交互的延遲。猜測若是有多個客戶端估計還要給每一個客戶端一個ID,客戶端和服務器都要管理這個客戶端List。客戶端發送輸入時要帶上本身的ID信息,同時服務器通知各個客戶端時也要帶上每一個輸入是針對的哪一個客戶端的信息。it
再一個要着重考慮就是輸入順序的管理。io
首先是同一客戶端的輸入順序,假如客戶端5毫秒時發送了向左的輸入,10毫秒時發送了向右的輸入,按道理客戶端最終的狀態應該是向右,但是若是考慮到延遲,向左的輸入在45毫秒時被服務器收到,向右的輸入在40毫秒時被服務器收到,那麼服務器通知客戶端的方向就變成了向左,顯然這是錯誤的。form
再者就是不一樣客戶端的輸入順序,假若有兩個客戶端A和B,A在第5毫秒攻擊了B,B在第10毫秒攻擊了A,兩人都是一擊斃命。若是服務器通知各個客戶端輸入時沒有標註這兩個輸入誰先誰後,各個客戶端Update以後的結果可能都會不一樣。
遊戲裏輸入的處理之後有機會再補充吧。