到目前為止我們已經能讓遊戲的操作跟伺服器連結起來,可以透過伺服器去管理一些行為的操作。不過要讓其他玩家能夠出現在地圖上,我們就必須調整現階段的程式碼讓伺服器能夠管理「線上玩家」的資訊。
WebSocket 的連線是由我們使用的套件所管理,但是我們需要一個已經抽象成方便我們處理的 Connection 物件列表,因此我們要來實作「連線池」這個物件來幫助我們管理。
# app/network/connection_pool.rb
# frozen_string_literal: true
class ConnectionPool
include Enumerable
def initialize
@mutex = Mutex.new
@connections = []
end
def each(&block)
@connections.each(&block)
end
def add(conn)
@mutex.synchronize do
@connections.push(conn)
end
end
def remove(conn)
@mutex.synchronize do
@connections.delete(conn)
end
end
end
這是一個很簡單的物件封裝,實際上只是利用一個陣列將物件儲存起來。不過因為我們無法確定使用者會不會在某個時間點同時加入,因此為了避免這樣的情況我們利用 Mutex
的機制確保一次只會有一個人可以同時操作我們的陣列。
因為我們使用的 Puma 是多執行緒的所以使用者是有很大的機率同時連上並且開始登記,因此需要將操作進行一個上鎖的動作確保一次只能有一位玩家登記到連線列表中。
這個物件其實也能設計成 Singleton 的形式,不過在處理資料庫的連線或者其他地方都是可以使用的為了保有未來的擴充性就先以普通物件的方式設計。
接下來要稍微改動 Connection 透過靜態方法的方式讓他增加一個連線池,並且將玩家登記進去。
# app/network/connection.rb
class Connection
class << self
def pool
@pool ||= ConnectionPool.new
end
end
def open(_event)
Connection.pool.add(self)
end
def close(_event)
Connection.pool.remove(self)
end
# ...
end
在這邊我們對連線增加了 #open
和 #close
兩個行為來對連線池增加或者刪除連線,如此一來只要調整 Protocol::WebSocket 針對開啟跟關閉連線時間呼叫,就能夠自動做到調整連線池跟線上玩家一致的狀態。
這邊其實有一個需要評估的地方是
@pool || ConnectionPool.new
這個處理是否恰當,在 Ruby 中 Singleton 物件是會自動使用 Mutex 確保不會重複性的初始化,那麼在這裡的@pool
是否也需要加入相關的設計來避免重複初始化呢?
接下來再對 app/network/protocol/websocket.rb
做調整,將 open 和 close 的事件註冊給 @conn
物件。
# app/network/protocol/websocket.rb
module Protocol
class WebSocket
# ...
def setup
raise InvalidRequest unless websocket?
@ws = Faye::WebSocket.new(@env)
@ws.on :open, @conn.method(:open)
@ws.on :message, method(:receive)
@ws.on :close, @conn.method(:close)
end
end
end
在我們知道全部上線玩家的列表之後,就能夠實作廣播這個動作。依照不同類型的遊戲會需要通知的玩家數量不太一樣,以我們這次目標要製作的多玩家在地圖上互動的類型來看,大多數操作都是需要「廣播」給其他玩家知道的。
# app/network/connection.rb
class Connection
# ...
def broadcast(data)
Connection.pool.each do |conn|
conn.write(data)
end
end
end
實作上也相對的簡單,只需要將連線列表抓取出來後對每一個連線都進行發送資料的指令即可。
這邊的 ConnectionPool 透過
#each
方法實作了迭代器,並利用 Enumerable 模組將迭代器相關的行為都實作到裡面,因此可以向陣列一樣使用#take
#map
等方法。
我的個人部落格是弦而時習之平常會把自己發現的一些新技巧紀錄在上面,也歡迎大家來逛逛。