我正在凤凰城创建一个纸牌游戏,有 2 名玩家使用凤凰城频道和 GenServer。这是我的游戏结构的样子:
schema "games" do
field :winner, :integer
field :player_1, :id, default: nil
field :player_2, :id, default: nil
field :status, :string
## VIRTUAL FIELDS ##
field :player_1_hand, :map, virtual: :true
field :player_2_hand, :map, virtual: :true
timestamps()
end
所以,正如你所看到的,我将用虚拟字段处理玩家的手,然后将玩家和获胜者保存到数据库中。
我现在设置了一个大厅频道,玩家可以在其中聊天。我有一个没有功能的游戏频道。如何允许玩家互相邀请玩游戏,接受或拒绝,然后将两个玩家一起放入游戏中?
这是我到目前为止在我的大厅频道中拥有的内容(关于游戏):
def handle_in("game_invite", %{"username" => username}, socket) do
data = %{"username" => username, "sender" => socket.assigns.current_player.username }
broadcast! socket, "game_invite", data
{:noreply, socket}
end
intercept ["game_invite"]
def handle_out("game_invite", %{"username" => username, "sender" => sender}, socket) do
if socket.assigns.current_player.username == username do
push socket, "game_invite", %{ username: sender}
end
{:noreply, socket}
end
我不知道我是否问了正确的问题。我正在尝试生成一个新的游戏ID(来自postgres),将两个玩家ID放入游戏中,然后让游戏服务器使用GenServer来管理玩家的手。
这将是一个伪答案,因为你也提出了一个伪问题; 一种方法是:
假设您有一个用户通道,您可以通过该通道将套接字事件发送给每个单独的玩家(或任何其他单独访问玩家的方式)
Player_1从列表中选择一个Player_2,这将发送一个套接字事件,表示,如{ action: 'create_invitation', invitee: 'player_2' }
,那么你有一个handle_in(%{'action' => 'create_invitation', 'invitee': invitee})
在这个handle_in
,你检查发出邀请的玩家是否还没有任何打开的游戏,也没有在玩游戏,如果是这样,首先你给它的套接字分配他现在有一个ID的游戏的信息,例如,"#{socket.current_player}#{invitee.id}",然后你启动一个新的gen_server,global
名称是那个id, 将玩家邀请 ID 和受邀者 ID 传递给start
函数。
在 init gen_server,您向 player_2 广播一条消息,询问他是否要使用您之前设置的全局 id 加入游戏,并将其初始状态设置为,例如:%{ player_1: player_1_id, player_2: invitee_id, game_id: "#{player_1_id}#{player_2_id}", started: false }
你为这个genserver设置了一个合理的超时,通过从init
函数返回来接收回复,比如25秒:{:ok, state, 25_000}
现在在player_2的前端,您需要将收到的广播说明他被邀请并将其转换为可操作的东西,这将向大厅频道发送消息,例如%{action: "accept", game_id: "player_1_idplayer_2_id"}
。您进行所有检查以查看它是否有效,该玩家还没有游戏,如果在他的套接字中设置了他现在有游戏,然后调用之前启动的gen_server,例如GenServer.call(game_id,{:accept_game, player_2_id})
然后在gen_server你有一个handle_call
def handle_call({:accept_game, player_2_id}, _from, %{started: false, player_2: p2_id} = state) when player_2_id == p2_id do
#create game hands, broadcasts, etc
{:reply, :ok, Map.put(state, :started, true)}
end
您至少需要创建一个handle_info来处理即将到期的邀请 - 这应该干净地终止gen_server,并触发player_1套接字的清理等......