Java 多玩家 libgdx 教程

jopen 10年前發布 | 25K 次閱讀 libgdx 游戲開發

Java 多玩家 libgdx 教程

我們如何去做?

  • 在 libgdx的主頁修改libgdx樣本“superjumper".

    </li>

  • 使用 AppWarp Cloud將它轉化為2個玩家的實時游戲.

    </li>

  • 本游戲將匹配玩家并且用戶需要到達城堡來贏得游戲的勝利.

    </li>

  •  用戶將獲得其他用戶成績的實時反饋以增加了游戲的刺激性。 

    </li> </ul>

    Eclipse 項目設置

     接下來,您需要從這個git repository下載libgdx游戲樣本(superjumper項目。.

    在Eclipse中打開下載的superjumper解決方案。你將看到項目如下:

    Java 多玩家 libgdx 教程為了創建多玩家,我使用了 AppWarp Java SDK (1.5 as of now)

    關于libgdx的依賴

    正如 libgdx的官網上提到的,這個示例依賴于libgbx。如果你試圖運行libgbx網站上的superjumper示例程序,你會得到關于gdx,gdx-backend-lwjgl, gdx-jnigen, gdx-openal的錯誤。你需要將這些工程設置為你的應用(superjumper)的依賴庫工程來解決這些錯誤。

    但我已經將這些庫包含在了superjumper git倉庫中的libs文件夾下。觀看這個視頻或閱讀這個教程來了解更多關于libgdx工程的安裝設置。

    取得你的AppWarp application keys

    如果你要與AppWarp云服務集成,你需要從ShepHertz開發者面板AppHq取得你的application keys.這些key能夠在ShepHertz云服務中識別的你應用空間,而且AppWarp云需要用它們隔離不同應用間的消息。

    AppWarp網站上按步驟注冊(免費)并取得你的application keys.

    現在打開superjumper示例工程中的 WarpController.java 文件并在其中添加這些值。例如:

    public static String AppKey = "14a611b4b3075972be364a7270d9b69a5d2b24898ac483e32d4dc72b2df039ef";
    public static String SecretKey = "55216a9a165b08d93f9390435c9be4739888d971a17170591979e5837f618059";

    運行多用戶sample

    既然你已經準備好了, 我們可以實際運行并觀察這個游戲了。因為這個游戲有單人或多人游戲的選項,為了玩多人游戲你需要在2個模擬器/設備上同時運行它。

    當你按了multiplayer按扭, 這個游戲會連接AppWarp并加入一個游戲房間。一旦進入這個游戲房間, 這個客戶端在游戲開始前會一直等待第二個玩家加入該房間。

    Java 多玩家 libgdx 教程

    現在你需要在第二個模擬器/設備上做同樣的操作,AppWarp的匹配API會將第二個玩家連接到相同的游戲房間,然后游戲開始。玩家需要到達城堡來完成這個游戲。同時用戶會發現他們的對手在實時地運動。這個游戲內實時通信正是AppWarp的強大之處。

    Java 多玩家 libgdx 教程

    游戲會在這三個條件下完成

    1. 用戶離開:當一個玩家離開游戲時,另一個玩家被判定為勝利者。因為他的對手已經離開的游戲。

      </li>

    2. 闖關成功:到達城堡的玩家成為勝利者

      </li>

    3. 游戲結束:如果玩家碰到了松鼠或者玩家掉了下來那另一個玩家會成為勝利者。

      </li> </ol>

      Java 多玩家 libgdx 教程

      怎樣與AppWarp集成

      開始游戲

      首先你需要用你的應用密鑰初始化Warpclient單例(WarpController.java).

      WarpClient.initialize(apiKey, secretKey);

      接下你需要連接到AppWarp云端并且加入一個游戲房間(WarpController.java)

      注意: AppWarp SDK 提供通過異步API提供它的功能。這意味著你只需簡單的將請求監聽器添加到WarpClient實例中區接受響應和通知即可。

      這個文件 (WarpController.java) 有我們這步所需的所有代碼。它創建連接請求,房間請求,區域請求(如果有必要創建一個房間)。因此我們添加相關監聽器到OnStart()方法中。

      public WarpController()
      {
          initAppwarp();
          warpClient.addConnectionRequestListener(new ConnectionListener(this));
          warpClient.addChatRequestListener(new ChatListener(this));
          warpClient.addZoneRequestListener(new ZoneListener(this));
          warpClient.addRoomRequestListener(new RoomListener(this));
          warpClient.addNotificationListener(new NotificationListener(this));
      }

      private void initAppwarp(){
          try {
              WarpClient.initialize(apiKey, secretKey);
              warpClient = WarpClient.getInstance();
          } catch (Exception e) {
              e.printStackTrace();
          }
      }

      設置好listener后我們可以繼續創建連接。用戶需要傳入一個惟一用戶名(username)以連接到AppWarp云。在示例中我只是使用了一個隨機字符串(你也可以從用戶或像非死book的第三方服務處取得來惟一標識用戶)。隨機字符串是在MainMenuScreen.java文件中生成的。

      WarpClient.connectWithUserName(userName);

      連接的結果會交給以下回調函數。

      public void onConnectDone(ConnectEvent e) {
          if(e.getResult()==WarpResponseResultCode.SUCCESS){
              callBack.onConnectDone(true);
          }else{
              callBack.onConnectDone(false);
          }
      }

      public void onConnectDone(boolean status){
          if(status){
              warpClient.initUDP();
              warpClient.joinRoomInRange(1, 1, false);
          }else{
              isConnected = false;
              handleError();
          }
      }

      如果連接成功,我們會試著加入一個房間。我們也可以選擇初始化UDP(稍后的游戲玩家會用到)。為了加入房間,我們使用JoinRoomInRange方法并傳入參數(1,1),它會請求服務器將客戶端加入只有一個用戶的房間。如果失敗我們會新建并加入一個容納兩個玩家的房間。

      public void onJoinRoomDone(RoomEvent event){
          if(event.getResult()==WarpResponseResultCode.SUCCESS){// success case
              this.roomId = event.getData().getId();
              warpClient.subscribeRoom(roomId);
          }else if(event.getResult()==WarpResponseResultCode.RESOURCE_NOT_FOUND){// no such room found
              HashMap data = new HashMap();
              data.put("result", "");
              warpClient.createRoom("superjumper", "shephertz", 2, data);
          }else{
              warpClient.disconnect();
              handleError();
          }
      }

      一旦加入某個房間(不管是現在還是創建新房間之后),客戶端需要訂閱這個房間來接收房間的通知(這在游戲中是必須的)。這里詳細解釋了這些概念。訂閱之后我們要調用getLiveRoomInfo來檢查房間是否有兩個玩家了,如果是我們就開始游戲,否則就等待其他玩家加入這個房間。

      WarpClient.getLiveRoomInfo(roomId);

      public void onGetLiveRoomInfo(String[] liveUsers){
          if(liveUsers!=null){
              if(liveUsers.length==2){
                  startGame();    
              }else{
                  waitForOtherUser();
              }
              }else{
                  warpClient.disconnect();
                  handleError();
          }
      }


      開始游戲

      進行游戲的代碼在MultiplayerGameScreen.java文件中。如果用戶進入了這個界面,那就意味著有兩個用戶在這個房間中且游戲開始了。玩家玩這個游戲,并且他也要更新其他玩家的狀態。其他玩家在你的界面上顯示成綠色小怪物。

      隨著玩家在界面上移動以完成游戲關卡,需要繪制它的移動軌跡,也要將位置更新發送給遠程玩家。參見WorldRenderer.java(multiplayer)

      private void renderBob () {
      {
      ...
      ...
          if (side < 0){
              batch.draw(keyFrame, world.local_bob.position.x + 0.5f, world.local_bob.position.y - 0.5f, side * 1, 1);
              sendLocation(world.local_bob.position.x + 0.5f, world.local_bob.position.y - 0.5f, side * 1, 1);
          }else{
              batch.draw(keyFrame, world.local_bob.position.x - 0.5f, world.local_bob.position.y - 0.5f, side * 1, 1);
              sendLocation(world.local_bob.position.x - 0.5f, world.local_bob.position.y - 0.5f, side * 1, 1);
          }
      }

      消息通過我們在這個示例中所寫的工具方法來發送。WarpClient允許客戶端將字節數組廣播給它所在的房間。可以使用TCP(默認)或UDP來發送。記住我們已經在成功連接到云服務后的第一個界面中初始化了UDP。

      private void sendLocation(float x, float y, float width, float height){
        try {
          JSONObject data = new JSONObject();
          data.put("x", x);
          data.put("y", y);
          data.put("width", width);
          data.put("height", height);
          WarpController.getInstance().sendGameUpdate(data.toString());
          } catch (Exception e) {
              // exception in sendLocation
          }
        }

      發送給房間的消息是通過onUpdatePeersReceived的回調方法提供的。在這個回調中我們要解析這個消息并識別發送者,消息類型和與此消息綁定的數據。我們根據這些消息做相應的處理。

      public void onUpdatePeersReceived(UpdateEvent event) {
          callBack.onGameUpdateReceived(new String(event.getUpdate()));
      }

      try {
          JSONObject data = new JSONObject(message);
          float x = (float)data.getDouble("x");
          float y = (float)data.getDouble("y");
          float width = (float)data.getDouble("width");
          float height = (float)data.getDouble("height");
          renderer.updateEnemyLocation(x, y, width, height);
      } catch (Exception e) {
          // exception 
      }

      游戲結束

      當游戲結束后我們只需要更新房間的屬性。其他玩家收到通知后需要根據此消息更新他們的UI。

      public void updateResult(int code, String msg){
          if(isConnected){
              STATE = COMPLETED;
              HashMap properties = new HashMap();
              properties.put("result", code);
              warpClient.lockProperties(properties);
          }
      }

      lockProperties

      當兩個遠程玩家同玩游戲時,他們有可能會同時結束游戲,而這會引起資源競爭。這種情況最好交由服務器解決,所以我們使用了lockProperties API。所以當游戲結束時用戶向服務器發送一個lockProperties請求將結果屬性鎖定。一旦這個結果被某個用戶鎖定,服務器會放棄處理后續對同一個屬性的lockProperties請求。點擊此處以了解更多此AppWarp仲裁方式。

      隨著游戲的結束,其他用戶得到通知,StartMultiplayerScreen.java根據以下代碼將游戲結束的原因顯示到界面上。

      public void onGameFinished (int code) {
          if(code==WarpController.GAME_WIN){
              this.msg = game_loose;
          }else if(code==WarpController.GAME_LOOSE){
              this.msg = game_win;
          }else if(code==WarpController.ENEMY_LEFT){
              this.msg = enemy_left;
          }
          update();
          game.setScreen(this);
      }

      我們也要離開并取消訂閱此房間,并且取消監聽器;如果游戲不在運行狀態我們也要刪除房間。由于在這個游戲中我們使用的是AppWarp 動態房間,在使用完后最好立即刪除(盡管空動態房間在60分鐘后都會被自動刪除)。

      public void handleLeave(){
          if(isConnected){
              warpClient.unsubscribeRoom(roomId);
              warpClient.leaveRoom(roomId);
              if(STATE!=STARTED){
                  warpClient.deleteRoom(roomId);
              }
              warpClient.disconnect();
          }
      }

      private void disconnect(){
          warpClient.removeConnectionRequestListener(new ConnectionListener(this));
          warpClient.removeChatRequestListener(new ChatListener(this));
          warpClient.removeZoneRequestListener(new ZoneListener(this));
          warpClient.removeRoomRequestListener(new RoomListener(this));
          warpClient.removeNotificationListener(new NotificationListener(this));
          warpClient.disconnect();
      }

      用戶可以在這里點擊并返回MainMenuScreen,然后我們可以重新進行這個過程。但這次我們只需要找到一個房間就可以開始了(因為我們已經連接到了服務器)。

      總結

      這篇文章中我們看到如何用AppWarp開發多人游戲。 我們在一個現成的libgdx超級跳躍例子基礎上用 AppWarp Cloud 特性進行拓展。我們同樣看到客戶端怎樣連接到AppWarp上,怎樣加入游戲房間。繼承概念不受libgdx的影響,并且可以應有與其他任何Java程序中。

      使用Robovm發布到iOS

      你可以使用 Robovm 來將超級跳躍游戲發布到iOS上. 下面是幾步是任何其它項目中都需要做的。另外你需要做如下改變。

      1. 將這些屬性添加到 robovm.xml  

         org.apache.harmony.xnet.provider.jsse.OpenSSLProvider   org.apache.harmony.security.provider.cert.DRLCertFactory   com.android.org.bouncycastle.jce.provider.BouncyCastleProvider   org.apache.harmony.security.provider.crypto.CryptoProvider   org.apache.harmony.xnet.provider.jsse.JSSEProvider   com.android.org.bouncycastle.jce.provider.JCEMac$SHA1 

      2. 使用如下代碼從背景中改變屏幕。

        Gdx.app.postRunnable(new Runnable() {
          @Override
          public void run () {
              game.setScreen(new MultiplayerGameScreen(game, StartMultiplayerScreen.this));
          }
        });

      這里另有要求, 我們得到如下錯誤,因為AppWarp的回調不在UI線程中。
          Exception in thread "MessageDispatchThread" java.lang.IllegalArgumentException:     Error compiling shader

      1. 超級跳躍中聲音不可用了,這是因為iOS中的聲音是使用RoboVm。</p>
 本文由用戶 jopen 自行上傳分享,僅供網友學習交流。所有權歸原作者,若您的權利被侵害,請聯系管理員。
 轉載本站原創文章,請注明出處,并保留原始鏈接、圖片水印。
 本站是一個以用戶分享為主的開源技術平臺,歡迎各類分享!