23 搞半天终於在网页上启动游戏了

发牌员

我们的短期目标是,在网页上用纯文字的方式直接显示游戏状态
并会随着游戏更新的时候更新

原本想要把 游戏 存在房间里面,但是在这边已经不需要其他房间的功能了,多一层很烦
我就直接在 ETS 再开另一个表格 叫 games 然後用跟房间一样的 id 来储存游戏状态

lib/card/application.ex 里面加在之前的 rooms 表格後面

# 建立 rooms 与 games table 给大家用
:ets.new(:rooms, [:set, :public, :named_table])
:ets.new(:games, [:set, :public, :named_table])

开始写这一页的 mount 方法吧
要做的事情有

  1. 从网址捞出id
  2. 请发牌员建立新的游戏并把 pid 存在 games表格里面
  3. 用 pid 取得游戏目前状态
  4. 显示在 render

我们先把发牌员做好
新开一个档案/lib/card/dealer.ex

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, {id, pid}, games}
      [] ->
        {:ok, pid} = Card.Game.start()
        :ets.insert(:games, {id, pid})
        {:reply, {id, pid}, [id | games]}
    end
  end

  def start_link(_) do
    GenServer.start_link(__MODULE__, [], name: :dealer)
  end

  def maybe_create_game(id) do
    GenServer.call(:dealer, id)
  end
end

每次开始一个新的游戏,双方都会想要得到游戏的 pid
所以统一由一个发牌员来建立,来避免双方同时各自建立分开的游戏的情况

再将发牌员放到 lib/card/application.ex 的 start 方法的 children 里面

  def start(_type, _args) do
    children = [
      # Start the Telemetry supervisor
      CardWeb.Telemetry,
      # Start the PubSub system
      {Phoenix.PubSub, name: Card.PubSub},
      # Start the Endpoint (http/https)
      CardWeb.Endpoint,
      # Start a worker by calling: Card.Worker.start_link(arg)
      # {Card.Worker, arg}
      Card.Dealer # 加在这里
    ]

    # 建立 rooms 与 games table 给大家用
    :ets.new(:rooms, [:set, :public, :named_table])
    :ets.new(:games, [:set, :public, :named_table])

    # See https://hexdocs.pm/elixir/Supervisor.html
    # for other strategies and supported options
    opts = [strategy: :one_for_one, name: Card.Supervisor]
    Supervisor.start_link(children, opts)
  end

ok 之後就回来做 mount 方法

defmodule CardWeb.GameLive.Game do
  use CardWeb, :live_view
  import CardWeb.Component
  alias Card.Game

  def mount(%{"id" => id} = _params, _session, socket) do
    # 请 dealer 给我们一个游戏
    pid = Card.Dealer.find_or_create_game(id)

    # 用拿到的 pid 跟 查看游戏状态
    game = Game.status(pid)
    
    # 把这些资讯存进 assigns 里面
    {:ok, assign(socket, %{pid: pid, id: id, game: game})}
  end


  # 接着就可以在 画面上 用 inspect 方法 把原始的资料型态印在网页上
  def render(assigns) do
    ~H"""
    <div class="flex flex-col items-center h-screen">
      <.logo />
      <%= inspect @game %>
    </div>
    """
  end
end

建立游戏後,画面上会有游戏刚开始的状态
https://ithelp.ithome.com.tw/upload/images/20211007/20141054qCPaE4divS.png

如果重新整理,可以看到会依照自动出牌的进度,游戏状态有改变

但是我们不可能边玩边重新整理

明天来用 pubsub 自动更新游戏状态


<<:  Day22 - 悬浮视窗

>>:  What is Vuex?

Day10 Sync.WaitGroup & Sync.Map

Sync.WaitGroup A WaitGroup waits for a collection ...

[Vue2Leaflet系列二] Leaflet Plugins with Vue

本篇文章请参考 [Vue2Leaflet系列一] 从vue-cli安装到建置地图 之前介绍过Leaf...

写在前面-不要停止思考和学习

第一天的文章偏向一个前言或是导读的概念。 今年再次挑战iThone的铁人赛,带着比前两年更大的压力,...

菜鸡的学习笔记 终於开始了!

之前在学习上遇到问题的时候,会搜寻 iT 的文章来看 现在终於自己也办了帐号,准备记录自己的学习历程...

为什麽要学Python

如今,人人都在谈人工智慧,而程序语言百百种,我们到底要学习哪一种呢?如过现在想要学习一种好入门、好上...