東方 project 聯機版開發日記(1)

touhou-project online

Intro

東方project是一個典型的2d射擊遊戲(STG),這裏我要實現的是一個簡單的雙人聯機版 東方project 遊戲,內容涵蓋客戶端的開發和服務端的開發,主要目的是實踐網絡遊戲的同步。git

源代碼倉庫託管於giteeweb

貼圖資源是來自網上下載的《東方地靈殿》圖集,而後本身用PS切了切,這裏給張地靈殿的遊戲截圖。typescript

截圖

服務器架構

登陸和房間

不須要嚴格意義上的帳戶系統,因此這方面的通訊操做僅僅是客戶端發出申請,服務器提供數據而已。服務器

服務器操做 客戶端操做
登記客戶端鏈接,返回玩家id 鏈接服務器,申請玩家id
檢查房間狀態,返回成功與否 退出/進入/建立/隨機 房間
是否全部玩家都已經申請開始遊戲,若是是則開始遊戲 申請開始遊戲

遊戲操做和網絡同步

採用幀鎖定同步機制,初步決定是使用嚴格幀鎖定,這裏是嚴格幀鎖定相關的參考資料websocket

對於這個流程,在開始實現服務端的時候會再作分析網絡

基本思路是這樣的,玩家操做先發送給服務器,等到收到服務器返回的關鍵幀後,再執行操做。架構

關鍵在於,若是不收到服務器提供的關鍵幀,則遊戲要暫停,等待服務器關鍵幀抵達後才繼續進行。socket

序號 服務器操做 客戶端操做
1 關鍵幀計時器開始執行 控制幀計時器開始執行
2 進入關鍵幀若是已經收到全部客戶端的控制幀,則繼續下一步,不然回到上一步 -
3 整合控制幀,向全部客戶端廣播關鍵幀,重啓關鍵幀計時 收到關鍵幀
4 - 播放遊戲,使用關鍵幀提供的控制幀做爲玩家輸入
5 - 進入客戶端控制幀
6 - 整合控制幀間的玩家輸入,鍵盤狀態,做爲控制幀發送給服務器
7 收到控制幀 若是沒有收到關鍵幀,發送完控制幀後繼續等待

遊戲的操做很簡單,這裏能夠給出全部的操做類型ui

操做 鍵位定義
上下左右八方向移動 方向鍵
射擊鍵 z
減速 x
符卡 c

客戶端須要傳遞的主要就是鍵盤的狀態,按下仍是鬆開,這樣子。code

服務器接口

有了流程,那麼能夠定義出服務器的接口了

接口 描述 參數 結果
login 申請玩家id,也能夠視做登陸 {token: string}
curr-room 當前所處的房間 {room_id: number}
join-room 加入房間,須要提供要加入的房間id room_id {result: boolean}
new-room 建立房間 {room_id: number}
rand-room 隨機加入房間,若是沒有房間,則返回空 {room_id: number or null}
quit-room 退出房間,理論上應該不會出現錯誤 {result:boolean}
start 申請開始遊戲,全部人都發出申請開始遊戲後,則遊戲開始 {result: true}
cancel-start 取消申請開始遊戲 {result: true}

控制幀結構

// typescript 編寫的示例
// 也能夠用其餘方式編寫,好比 protobuf 啊
// 而後拿 C++ 或者 rust 寫服務端也沒問題
// 不過爲了開發速度,因此先拿 typescript 和 websocket 寫個原型
interface ICtrlFrame {
    // 這是個 tuple
    // 第一個number表示在x軸上的移動,負數表示向左,正數表示向右
    // 第二個表示在y軸上的移動,負數表示向下,正數表示向上
    motion:[number,number]; 
    // 射擊鍵的按壓狀態
    fire: boolean;
    // 低速鍵的按壓狀態
    slow: boolean;
    // 符卡鍵的按壓狀態
    spell: boolean;
}

關鍵幀結構

interface IKeyFrame {
    // 關鍵幀的序號
    frameIndex: number;
    // 控制幀
    // {[index:number]: ICtrlFrame} 這個寫法是 ts 特有的
    // 用起來至關於其餘語言的 HashTable 之類的,舉個例子來講
    // 差很少像是 C++ 的 std::map<int, ICtrlFrame>
    // Python 的 dict 這樣
    // 順便一提 Python3 的 type annotation 能夠指定 Dict[int,ICtrlFrame] 這樣的類型
    // import typing
    // ctrl: Dict[int,ICtrlFrame] = {} # 像這樣
    // 可是沒有強類型檢查
    ctrl: {[index:number]: ICtrlFrame};
}
相關文章
相關標籤/搜索