1

我正在使用 Phoenix 频道和 GenServer 在 Phoenix 创建一个有 2 名玩家的纸牌游戏。这是我的游戏结构的样子:

  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 来管理玩家的手。

4

1 回答 1

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}”,然后您启动一个名为该 id 的新 gen_server ,将玩家邀请 id 和被邀请者 idglobal传递给函数。start

在 gen_server init 上,您向 player_2 广播一条消息,询问他是否想使用您之前设置的全局 id 加入游戏,并将其初始状态设置为,例如: %{ player_1: player_1_id, player_2: invitee_id, game_id: "#{player_1_id}#{player_2_id}", started: false } 并且您为此 genserver 设置了合理的超时以接收回复,比如 25 秒,通过从init函数返回: {: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 的套接字等...

于 2018-01-05T10:29:37.543 回答