20 等待对手页面

昨天用 tailwind 画好首页
现在要做开始游戏前的等待对手页面

把游戏放进去 phoenix 里面

在这之前,我觉得差不多可以把 game 搬到 phoenix 里面了
就..把他移动到 lib/card/game.ex
但我们还是要调整一下 module 名称
Game 变成 Card.Game,同时里面有一些用 %Game{} 的地方,
也要改,不过既然是在里面用的 我们可以写 %__MODULE__{} 就好

房间状态

接着我们需要另一个 struct 来储存房间状态

这个也是 lib/card/room.ex

defmodule Card.Room do
  defstruct id: nil, game: nil, game_pid: nil, host_ready: false, guest_ready: false
end

这个 struct 就可以替换掉我们昨天暂时写的 "房间状态"
在昨天的 lib/card_web/live/page_live/index.ex 最後两个方法

  def handle_event("start_game", _params, socket) do
    room_id = random_room_id()
    :ets.insert_new(:rooms, {room_id, %Card.Room{id: room_id}})

    {:noreply, push_redirect(socket, to: "/#{room_id}")}
  end

  # 这个跟昨天比少了 "room_" 我发现那个好像有点没意义
  defp random_room_id(), do: String.trim(to_string(:rand.uniform), "0.")

打点好之後我们就可以来 router 帮路径补上

scope "/", CardWeb do
  pipe_through :browser

  live "/", PageLive.Index, :index
  live "/:id/host", GameLive.Invite, :host
  live "/:id/guest", GameLive.Invite, :guest
end

这边会分成两个,host 结尾的是我们要从 page index 导出去的连结
guest 是给我们复制贴给对手用的

写好之後在终端机打 mix phx.routes
他就会回传我们现在设定好的连结,跟 router helper 名称

    page_index_path  GET  /                                      Phoenix.LiveView.Plug :index
   game_invite_path  GET  /:id/host                              Phoenix.LiveView.Plug :host
   game_invite_path  GET  /:id/guest                             Phoenix.LiveView.Plug :guest
   下略...

我们在 page index 按下开始游戏按钮後,就可以使用 Routes.game_invite_path(socket, :host, room_id)
这样:

  def handle_event("start_game", _params, socket) do
    room_id = random_room_id()
    :ets.insert_new(:rooms, {room_id, %Card.Room{id: room_id}})

    {:noreply, push_redirect(socket, to: Routes.game_invite_path(socket, :host, room_id))}
  end

有了连结接着就是做出等待邀请的页面了
lib/card_web/live/game_live/invite.ex

等待页面

一不注意就一次打完了... 只好加说明在里面

defmodule CardWeb.GameLive.Invite do
  use CardWeb, :live_view

  def mount(%{"id" => id} = params, session, socket) do
    # 这边是拿网址里面的 id 去 ETS 的 rooms 表格找找看有没有纪录,没有的话就转到首页
    # 有的话就在 socket 的 assigns 里面加入 room, player, invite_path(要邀请 guest 的连结)
    case :ets.lookup(:rooms, id) do
    [{_, room}] ->
      {:ok, assign(socket, %{room: room, player: socket.assigns.live_action, invite_path: Routes.game_invite_url(socket, :guest, id)})}
    _ ->
      {:ok, push_redirect(socket, to: "/")}
    end
  end

  def render(assigns) do
    # 因为刚刚已经有把要用的东西加进 assigns 里面,这边就可以直接用 @ 取值
    ~H"""
    <div class="flex flex-col items-center h-screen">
      <header class="text-blue-500 m-4">
        <a href="/" class="text-5xl font-serif">
          ? CardyTotala
        </a>
      </header>
      <div class="flex-grow flex flex-col items-center justify-center">
        <%=# 如果玩家是 host 而且 guest 还没准备好的话 显示邀请连结 %>
        <%= if @player == :host && [email protected]_ready do %>
          <.invite path={@invite_path}/>
        <% end %>
      </div>
    </div>
    """
  end

  def invite(assigns) do
    ~H"""
    <div class="flex flex-col p-4 bg-grey-50 shadow-lg text-center mt-8">
      <div class="bg-blue-300 w-40 h-8 rounded-xl transform skew-x-12 rotate-6 translate-y-6 translate-x-40"></div>
      <div class="transform">
        <label for="invite_url" class="text-2xl font-serif">Guest Link</label><br>
        <input id="invite_url" class="w-96 text-center text-gray-500" type="text" value={@path} readonly>
      </div>
      <p class="text-lg text-gray-600">To begin the game, send this link to your component.</p>
    </div>
    """
  end
end

刚刚上面有 <.invite /> 这种东西,这个是 heex 专用的 component 写法,不是 html
是 phoenix 1.6 刚加进去的,我们看到另一个方法叫 invite(assigns) 就可以猜到
他就是去执行并 render 里面的东西取代掉 <.invite />

另外在 heex 里面不能在html tag 上使用 #{}
以前是这样

# text_color = "text-red-600"
~L"""
<p class="#{text_color}">
"""

但 heex 不行这样用

现在要改用

# text_color = "text-red-600"
~H"""
<p class={text_color}>
"""

所以现在邀请页面长这样

https://ithelp.ithome.com.tw/upload/images/20211003/201410543hJIXl3Mkz.png


<<:  D24 - 用 Swift 和公开资讯,打造投资理财的 Apps { 台股成交量实作.4 }

>>:  Day 22 活泼是为了不让人倦怠

【Day 04】CVE 哪有那麽萌 - 找漏洞经验分享

动机 这篇内容讲的是我在今年暑假参加 AIS3 暑期营队软件安全组所做的专题,队友分别为郑永泰、许智...

视觉化KBARS(2)-python api

上篇大概介绍一下我们所运用的js与方法, 今天我们要先来写python api的部分。 (1)首先新...

资料验证(golang)(Day23)

文章同步更新於个人官网 https://kevinyay945.com/smart-home-tut...

如何快速上手第三方套件

在现在这种讲求快速开发的开发模式,我们通常不太会自己将所有功能都自己硬刻出来,而是会去使用第三方的套...

[2021铁人赛 Day24] Forensics 监识学题目 01

小勘误: 前几天提到我们会把六大类都至少做过一题,但是 picoCTF 的 Misc 类 -- U...