iT邦幫忙

第 11 屆 iT 邦幫忙鐵人賽

0

到目前為止我們已經將遊戲的狀態保存機制處理完畢,接下來只要調整客戶端支援前幾天實作新版本伺服器就能夠透過玩家的暱稱登入遊戲,並且取回上一次進入的狀態。

登入機制

因為我們使用 prompt 的方式來詢問玩家,所以必定會需要有一個地方能夠使用。基本上最理想的是起始畫面去修改開始選單,不過為了方便起見我們直接在 SimpleRPG_Map 上面處理,讓我們在地圖載入的時候詢問玩家的名稱,如果正確驗證的話就在繼續後續的行為。

// js/Plugins/SimpleRPG_Map.js

// ...
(function() {
  // ...

  var _Scene_Map_onMapLoaded = Scene_Map.prototype.onMapLoaded;
  Scene_Map.prototype.onMapLoaded = function() {
    _Scene_Map_onMapLoaded.call(this);

    SimpleRPG.Servers.Map.setCurrentMap(this);
    SimpleRPG.Servers.Map.send('negotiate', [prompt('What is your name?')]);
    SimpleRPG.Servers.Map.send('join', []);
    SimpleRPG.Servers.Map.send('player_list', []);

    // Hide Default Player
    $gamePlayer.setOpacity(0);
  }
  
  // ...
}());

這次我們在 join 前加入了 SimpleRPG.Servers.Map.send('negotiate', [prompt('What is your name?')]); 這行,因為 prompt 會暫停後面的腳本執行,因此我們可以安心的判斷後續的步驟會再輸入後開始運行。

完成之後,因為伺服器會發送座標過來,因此我們還需要到 Controller 上面修改程式將寫死的座標改為伺服器回傳的位置。

// js/Plugins/SimpleRPG_Controllers_Map.js

(function() {
  // ...

  MapController.prototype.join = function(id, x, y) {
    var player = this.map.addPlayer(id);
    player.setImage('Actor2', 1);
    player.locate(x, y);
  };
  
 // ...
}());

我們將 join 指令接收改為 id, x, y 三個資訊,並且修改 .locate 方法為 player.locate(x, y); 如此一來我們就能正確的抓取到上一次連線的資訊並且將玩家上一次的位置顯示出來。

離開遊戲

遊戲整體的雛型大致上都做出來了,之後就可以替換成其他引擎或者套件開始正式設計。不過似乎還漏了什麼?

當其他玩家離線時必須確實告訴其他玩家離線了,不然就會存在很多幽靈玩家在上面,我們可以利用 close 事件來處理。

# app/network/connection.rb

# frozen_string_literal: true

require 'json'

class Connection
  # ...

  def close(_event)
    Connection.pool.remove(self)
    broadcast({ command: 'exit', parameters: [player.id] })
  end
  
  # ...
end

我們很簡單的在連線斷開的時候對其他玩家發送一個「離開」的指令,並且告知是哪個玩家斷線。

接下來到客戶端的 Controller 上面實作 exit 指令的處理。

// js/Plugins/SimpleRPG_Controllers_Map.js

(function() {
  // ...
  
  MapController.prototype.exit = function(id) {
    this.map.removePlayer(id);
  };
  
  // ...
}());

因為地圖上還沒有 removePlayer 這個指令,所以我們再到 SimpleRPG_Map.js 上面增加相關的方法。

// js/Plugins/SimpleRPG_Map.js

// ...
(function() {
  // ...

  Scene_Map.prototype.removePlayer = function(id) {
    this._spriteset._tilemap.removeChild(this._remotePlayerSprites[id]);
    delete this._remotePlayerSprites[id];
    delete this._remotePlayers[id];
  };
  
  // ...
}());

這樣我們就可以在玩家離線的時候在其他玩家的畫面上將離線的玩家移除,到這邊為止我們就完成了最簡單的連線遊戲地圖伺服器。

前面的保存狀態兩篇文章在伺服器的設定上有缺少一些修改跟程式碼已經補上,在實作完這段進行測試前麻煩先修正以免發生錯誤。

我的個人部落格是弦而時習之平常會把自己發現的一些新技巧紀錄在上面,也歡迎大家來逛逛。


上一篇
Day 31 - 實作練習 - 保存狀態(二)
下一篇
Day. 33 - 後記
系列文
從讀遊戲原始碼學做連線遊戲33

尚未有邦友留言

立即登入留言