我正在菲尼克斯创建一个使用Phoenix频道和GenServer的2名玩家的纸牌游戏。这就是我的Game Struct的样子:
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,然后让GameServer使用GenServer来管理玩家的手。
答案 0 :(得分:0)
这将是一个伪答案,因为你也提出了一个伪问题;一种方法:
假设您有一个用户频道,您可以通过该频道向每个玩家发送套接字事件(或任何其他单独到达玩家的方式)
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}”的游戏,你发起一个名为global
的新gen_server,传递给{{1} }播放器邀请id和被邀请者id。
在gen_server init上,您向player_2广播一条消息,询问他是否想要使用您之前设置的全局ID加入游戏,并将其初始状态设置为,例如:
start
并且你通过从%{ player_1: player_1_id, player_2: invitee_id, game_id: "#{player_1_id}#{player_2_id}", started: false }
函数返回来为这个genserver设置一个合理的超时来接收回复,比如25秒。
init
现在在播放器2的前端,你需要接收这个收到的广播,说明他被邀请并把它变成一个可操作的东西,它将向大厅频道发送一条消息,如{:ok, state, 25_000}
。你做了所有的检查以确定它是否有效,这个玩家还没有游戏,如果这样设置在他的套接字中,他现在有一个游戏,那么调用之前发起的gen_server,例如, %{action: "accept", game_id: "player_1_idplayer_2_id"}
然后在gen_server上你有一个handle_call
GenServer.call(game_id,{:accept_game, player_2_id})
你需要至少创建一个handle_info来处理邀请过期 - 这应该干净地终止gen_server,并触发清除player_1的套接字等等......