從 0 到 1,打造自己的遊戲後端服務
  • 簡介
  • 基礎服務
    • 架構介紹
    • Data 服務
    • API 服務
      • 在 Parse 服務架構簡易的 Cloud Code 部署機制
    • Notification 服務
      • Parse 推送服務設定與測試
    • Job 服務
      • 在 Parse 上透過 Cron 配置常用的 Scheduler
    • Email 服務
    • SMS 服務
    • Hosting 服務
    • Realtime 服務
      • Parse Live Query 設定
    • Information 服務
      • Parse Config 與 Firebase Remote Config 服務介紹
      • Connectivity 取得與監聽
      • Time 服務介紹與實作方法
      • IP 資料庫能獲得什麼資料
  • 遊戲服務
    • Achievement 成就系統
      • 設計簡易的成就系統 - 透過 Parse
    • Leaderboard 排行榜系統
      • 設計簡易的公開排行榜系統 - 透過 Parse
    • Pairing 配對系統
      • 設計簡易的 Dispatcherless 自動配對機制 - 透過 Firebase Realtime Database
    • Turn-based Multiplayer 回合制多人遊戲
      • 簡易的回合制多人遊戲系統 - 透過 Parse
    • Real-time Multiplayer 即時多人遊戲
      • 設計簡易的即時多人遊戲傳輸通道 - 透過 Firebase Realtime Database
  • 附錄 Self-Hosted Parse
    • Parse 服務架設
    • 建立 Parse 資料庫服務
    • 建立 Parse 服務
Powered by GitBook
On this page
  • 排隊結構
  • 遊戲結構
  1. 遊戲服務
  2. Pairing 配對系統

設計簡易的 Dispatcherless 自動配對機制 - 透過 Firebase Realtime Database

遊戲配對系統中,直接規劃 配對者(Dispatcher) 來執行配對任務是最直接的解決辦法,但耗費較高也比較繁瑣,以下的設計,透過使用者端發起 Transaction 機制來作動配對邏輯,再另外監聽單場遊戲節點來確認遊戲配對狀態與起始資料,可在不需而外 Dispatcher 的狀況下進行配對,適用在固定玩家數量的遊戲類型

排隊結構

  • 透過 子結點 實作 群組配對,並將玩家屬性寫入排隊資料,配對邏輯可以進行 屬性配對

根目錄

群組

資料

Queue /

Group ID /

[ Room ID: 已開啟的房間號碼 User[ ]: 已經報名的玩家,及其屬性 Create: 房間創立時間 ]

  • 玩家進行自動配對

其中 Queue/GroupA 為特定群組,以群組為節點存放等待資訊,也以此節點為 Transaction 執行的標的。其中 game_id, score, low, high 為玩家屬性,實際使用應為變化數值

FIRDatabaseReference* pair_ref = [[[FIRDatabase database] reference] child:@"Queue/GroupA"];
[pair_ref runTransactionBlock:^FIRTransactionResult* _Nonnull(FIRMutableData* _Nonnull currentData) {
    NSMutableArray* datas = currentData.value;

    if (!datas || [datas isEqual:[NSNull null]]) {
        // Queue 空白,將自己排入 Queue
        NSDictionary* data = @{
            @"game_id" : "UUID GAME ID",    // 新建遊戲房的 ID
            @"score" : 100,                 // 玩家目前積分
            @"low" : 80,                    // 配對玩家的積分下限
            @"high" : 120,                  // 配對玩家的積分上限
        };

        datas = [[NSMutableArray alloc] initWithObjects:data, nil];
    } else {
        BOOL pair = NO;

        for (NSDictionary* data in datas) {
            if ([[data objectForKey:@"score"] intValue] >= 80
                && [[data objectForKey:@"score"] intValue] <= 120
                && 100 >= [[data objectForKey:@"low"] intValue]
                && 100 <= [[data objectForKey:@"high"] intValue]) {
                // 配對成功 Pair,將等待訊息移除,目標前往加入 [data objectForKey:@"game_id"]
                [datas removeObject:data];
                break;
            }
        }

        if (!pair) {
            // 配對失敗,將自己排入 Queue
            NSDictionary* data = @{
                @"game_id" : "UUID GAME ID",
                @"score" : 100,
                @"low" : 80,
                @"high" : 120,
            };

            [datas addObject:data];
        }
    }
    [currentData setValue:datas];

    return [FIRTransactionResult successWithValue:currentData];
}
    andCompletionBlock:^(NSError* _Nullable error, BOOL committed, FIRDataSnapshot* _Nullable snapshot) {
        if (error || !committed) {
            // 配對失敗
        } else {
            // 成功配對,進入下個階段,前往 game
        }
    }
    withLocalEvents:NO];

遊戲結構

  • 透過 Player 來監聽整體的 配對狀態,滿員時即配對完成。Init 則是設計為開場預設資料,統一委由開局者或是關局者來寫入即可

根目錄

-

資料

Game ID / Player /

Player Id /

User Image ... // 遊戲中使用到的玩家基本資料

Game ID / Init /

RandomSeed ... // 遊戲中共同設定資料

  • 配對完成後,加入遊戲。可以相同方法寫入初始值

Player ID A 與 user_json_dic 為此玩家的專屬 ID 及其玩家資料,使用上應替換為玩家數值

FIRDatabaseReference* game_ref = [[[FIRDatabase database] reference] child:@"UUID GAME ID/Player"];

NSData* user_json_string = [[NSString stringWithUTF8String:user_json] dataUsingEncoding:NSUTF8StringEncoding];
NSDictionary* user_json_dic = [NSJSONSerialization JSONObjectWithData:user_json_string options:0 error:nil];

NSDictionary* player = @{
                         @"Player ID A" : user_json_dic,
                         };
[game_ref setValue:player];
  • 監聽遊戲的配對狀態

FIRDatabaseReference* listen_ref = [[[FIRDatabase database] reference] child:@"Game/UUID GAME ID"];
FIRDatabaseHandle handle = [listen_ref observeEventType:FIRDataEventTypeValue
                                              withBlock:^(FIRDataSnapshot* _Nonnull snapshot) {
                                                  if (snapshot.value != [NSNull null]) {
                                                      // 監聽遊戲房間副本
                                                  }
                                              }];
PreviousPairing 配對系統NextTurn-based Multiplayer 回合制多人遊戲

Last updated 6 years ago