24 让画面跟游戏联动

用 PubSub 更新游戏状态

现在我们要让玩家订阅游戏的状态
并让游戏在状态更新的时候,广播到双方的画面

先来弄订阅,我们在邀请页面已经用过 id 来当作订阅的频道名称了,
我们来改一下好了,帮 id 前面加个 invite_,id 留给游戏用

# lib/card/room.ex 档案

  def subscribe(id) do
    Phoenix.PubSub.subscribe(Card.PubSub, "invite" <> id)
  end

  def broadcast(id, room) do
    Phoenix.PubSub.broadcast(Card.PubSub, "invite" <> id, room)
  end

帮他们前面加invite

接着在 lib/card/game.ex 加一下类似的方法

  def subscribe(id) do
    Phoenix.PubSub.subscribe(Card.PubSub, id)
  end

  def broadcast(id, game) do
    Phoenix.PubSub.broadcast(Card.PubSub, id, game)
  end

在 game 的 mount 方法订阅,就像我们在邀请页面做的一样

  def mount(%{"id" => id} = _params, _session, socket) do
    # 订阅
    if connected?(socket), do: Card.Game.subscribe(id)

    pid = Card.Dealer.find_or_create_game(id)
    game = Game.status(pid)
    {:ok, assign(socket, %{pid: pid, id: id, game: game})}
  end

与相对应的 handle_info 方法

  def handle_info(game, socket) do
    {:noreply, assign(socket, :game, game)}
  end

接着我们要回到原本的游戏程序 lib/card/game.ex
在有更新游戏状态的时候 也广播状态到目前id

首先 game 在执行的时候要先知道他的 id 是什麽
我们也加在 game struct 好了

  defstruct host: %{desk: [], hand: initial_hand, wins: 0},
            guest: %{desk: [], hand: initial_hand, wins: 0},
            turn: 1,
            round: 1,
            status: :start,
            id: nil

并在开始游戏的时候帮他加上

  def start(id) do
    GenServer.start_link(__MODULE__, %__MODULE__{id: id})
  end

接着是 发牌员 建立游戏的时候要把 id 带给他

defmodule Card.Dealer do
  use GenServer

  def init(_) do
    {:ok, []}
  end

  def handle_call(id, _from, games) do
    case :ets.lookup(:games, id) do
      [{^id, pid}] -> {:reply, pid, games}
      [] ->
        {:ok, pid} = Card.Game.start(id)
        :ets.insert(:games, {id, pid})
        {:reply, pid, [id | games]}
    end
  end

最後在游戏里面,有改变 game 的时候,像是成功出牌
就要广播给大家知道,
这边我偷吃步直接加在出牌的事件串

  def play_card_with_checks(%{turn: current_turn} = game, player, card) do
    game
    |> play_card_for(player, card)
    |> end_turn()
    |> add_wins()
    |> end_round()
    |> end_game()
    |> start_turn_timer(current_turn)
    |> maybe_broadcast(game)
  end

  defp maybe_broadcast(game, old_game) when game == old_game, do: game

  defp maybe_broadcast(game, _old_game) do
    broadcast(game.id, game)
    game
  end

完成了,游戏开始的时候
会自动照着游戏的状态反应

https://ppt.cc/fvu2Ex@.gif


<<:  Day 25:动态规划(dynamic programming)

>>:  [Day_24]函式与递回_(3)

Day2 基础安装 + 加码:nvm

今天正式进入主题~ 在开始前我们必须先把环境建立起来,我知道很多人会使用webpack,但这边我是使...

【Day 20】Google Apps Script - API 篇回顾整理

停留回想:要进入下一篇前,整理回顾一下 API 篇的笔记思绪。 今日要点: 》API 篇回顾整理 ...

DBA 训练营 - SQL Server 资料库管理入门

数据资料与 Azure SQL 热潮来袭 升级资料库专业技能 Are You Ready? DBA ...

【第21天】训练模型-模型组合与辨识isnull(二)

摘要 作业流程 设定资料集路径 找出每个中文字的阈值 任意选择奇数个模型组合後,产生模型权重表与利用...

30天程序语言研究

今天是30天程序语言研究的第十五天,由於深度学习老师多让我们上了python的进阶课程里面包括之前没...