C++實現的手機遊戲區域網路聯機對戰庫

來源:互聯網
上載者:User

標籤:

前言

  我一直想做一個可以區域網路聯機對戰的遊戲,但是無論是使用還是藍芽的方式進行開發都要學習相關平台的知識。其實我去年瞭解過這方面的知識,據不可靠的資料顯示我會遇到這些問題:

  1. IOS的藍芽不可串連其它廠商的藍牙裝置;
  2. WIFI好像也是和第一條一樣;
  3. 如何知道某個藍芽或者wifi裝置所在的手機上啟動了我的遊戲?

  由於涉及到不同平台,問題還有很多,我也懶得去解決這些問題。於是我就選擇了一個懶辦法,使用TCP協議來進行區域網路聯機對戰,這樣有一個前提就是多台裝置必須要在一個區域網路內。但是可以做到跨平台,而且也不用那麼麻煩。於是 Buddy 庫誕生了,這個名字用於紀念童年一起玩小霸王遊戲機的小夥伴們。

實現原理

  實現原理很簡單,首先主機玩家開一個遊戲房間,向區域網路內廣播主機玩家的地址連接埠等資訊,並啟動遊戲伺服器。其它玩家收到主機玩家廣播的訊息後(廣播資訊裡麵包含了遊戲伺服器的地址和連接埠資訊),就串連到遊戲伺服器,從而達到聯機對戰的目的。這些步驟 Buddy 庫已經封裝好啦,我們可以直接使用。

使用說明

  使用上也是比較簡單的,這裡把服務端和用戶端的使用分開來講解,其實它們是非常相似的。

服務端

範例程式碼:

 1 #include <iostream> 2 #include "Classes/Buddy.h" 3  4 enum eMessageDelegate 5 { 6     BuddyServiceID = (int)ReservedDelegateID::UserCustom + 1, 7 }; 8  9 class SessionManage : public ServiceDelegate10 {11 public:12     virtual void OnPlayerJoin(SOCKET session, const Address &address) override13     {14         std::cout << "OnPlayerJoin" << std::endl;15 16         char buffer[] = "hello";17         SendData(session, buffer, sizeof(buffer));18     }19 20     virtual void OnPlayerLeave(SOCKET session, const Address &address) override21     {22         std::cout << "OnPlayerLeave" << std::endl;23     }24 25     virtual void OnMessageReceive(SOCKET session, void *data, size_t size) override26     {27         std::cout << "OnMessageReceive" << std::endl;28     }29 };30 31 int main(int argc, char **argv)32 {33     InitBuddy();34 35     SessionManage manage;36     BuddyService server(Address(kHostPort), 10, BuddyServiceID, &manage);37     server.Accept();38 39     while (true)40     {41         std::this_thread::sleep_for(std::chrono::milliseconds(kFrameDeltaTime));42         MessageManager::GetInstance()->Update(0);43         server.Broadcast();44     }45 46     return 0;47 }

  首先,第4行聲明一個枚舉類型,用來表示訊息代理的ID。Buddy 庫內部實現了一個訊息佇列,需要遊戲主迴圈來更新它。我們可以為一個對象(對象的類類型必須繼承自MessageDelegate)指定一個ID,這樣向這個ID發送訊息後,這個對象的OnMessageReceive函數就會被調用。

  在第9行實現一個類SessionManage,繼承自ServiceDelegate。實際上這個類是對所有會話的管理類,當玩家進入或離開或收到玩家發送的資料時,ServiceDelegate類的虛函數將被調用。另外ServiceDelegate類還有提供了其它幾個函數來管理玩家。

  第33行是對庫進行初始化,這個必須在主線程中調用。

  第36行建立了一個遊戲伺服器,建構函式的參數分別是伺服器的地址、訊息代理的ID和服務代理的指標。服務代理其實就是前面說的會話管理類的執行個體。

  第37行調用Accept後,將會接受區域網路內的串連請求,並不會阻塞線程。

  第39行其實是在類比遊戲的主迴圈,一般是每秒60幀,一幀耗時就是16毫秒。

  第42行是在遊戲主迴圈中更新訊息佇列。

  第43行是在區域網路內廣播訊息,這樣區域網路裡的玩家才能夠探索服務器。

用戶端

範例程式碼:

 1 1 #include <iostream> 2 2 #include "Classes/Buddy.h" 3  4 enum eMessageDelegate 5 { 6     BuddyClientID = (int)ReservedDelegateID::UserCustom + 1, 7 }; 8  9 class ConnectManage : public ClientDelegate10 {11 public:12     virtual void OnFoundHost(const Address &address, int number)13     {14         std::cout << "FoundHost: " << address.ToString() << std::endl;15         std::cout << "線上人數: " << number << std::endl;16         client_->Connect(address);17     }18 19     virtual void OnNotFoundHost()20     {21         std::cout << "OnNotFoundHost" << std::endl;22     }23 24     virtual void OnConnectSuccess()25     {26         std::cout << "OnConnectSuccess" << std::endl;27     }28 29     virtual void OnConnectFail()30     {31         std::cout << "OnConnectFail" << std::endl;32     }33 34     virtual void OnDisconnect()35     {36         std::cout << "OnDisconnect" << std::endl;37     }38 39     virtual void OnMessageReceive(void *data, size_t size)40     {41         std::cout << "OnMessageReceive" << std::endl;42         std::cout << (char *)data << std::endl;43     }44 45 public:46     void SetBuddyClient(BuddyClient *client)47     {48         client_ = client;49     }50 51 public:52     BuddyClient* client_ = { nullptr };53 };54 55 int main(int argc, char **argv)56 {57     init_sockets();58     MessageManager::GetInstance();59 60     ConnectManage manage;61     BuddyClient client(BuddyClientID, &manage);62     manage.SetBuddyClient(&client);63     client.SearchHost(60);64 65     while (true)66     {67         std::this_thread::sleep_for(std::chrono::milliseconds(16));68         MessageManager::GetInstance()->Update(0);69     }70 71     return 0;72 }

  你會發現跟服務端的用法很相似對吧?下面來說說不同的地方。

  在第9行實現一個類ConnectManage,這是一個串連管理類(永遠只有一個串連)。

  第61行跟服務端的用法類似,建立了一個用戶端,建構函式傳入訊息代理的ID和管理類的指標。

  第63行調用SearchHost函數將會在區域網路內搜尋有無遊戲服務端,參數是逾時時間,單位為秒。這個操作不會阻塞主線程。

  第65行也是在類比遊戲主線程,在主線程中更新訊息佇列。

 

  值得注意的是,遊戲的邏輯通常在會話管理類或者串連管理類裡面實現。遊戲主線程中每幀只需更新一次訊息佇列。訊息的代理ID必須每個對象都是唯一的,意思就是說兩個不同的對象不能擁有同一個訊息代理ID。

源碼下載

https://github.com/zhangpanyi/Buddy

C++實現的手機遊戲區域網路聯機對戰庫

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.