iT邦幫忙

2021 iThome 鐵人賽

DAY 28
0
Modern Web

連線網頁卡牌遊戲(Elixir, Phoenix, Liveview)系列 第 28

28 遊戲狀態欄

遊戲狀態

是時候把 inspect game 拿掉,換成好看的介面了,啊更正!相對好看的介面哈哈
主要有兩小區

  1. 勝場數(先到二的贏)
  2. 目前回合

東西都已經在 game 裡面了,所以我們直接用 live component
把他們用 tailwind 勾出來就行了

先把 原本暫時寫的 inspect game 改成呼叫 status component

  def render(assigns) do
    ~H"""
    <div class="flex flex-col items-center h-screen">
      <.logo />
      <.status game={@game} opponent={@opponent} current_player={@current_player}/>
      <.desk player={Map.get(@game, @opponent)}/>
      <.desk player={Map.get(@game, @current_player)}/>
      <.hand player={Map.get(@game, @current_player)}/>
    </div>
    """
  end

接著定義 status component

  def status(assigns) do
    ~H"""
    <div class="flex flex-col items-center">
      <.wins game={@game} opponent={@opponent} current_player={@current_player}/>
      <.game_round round={@game.round}/>
    </div>
    """
  end

這個裡面包的分別是

wins

  def wins(assigns) do
    ~H"""
    <div class="flex h-6 items-center justify-between text-gray-600 m-4">
      <div class="bg-blue-300 w-4 h-3 rounded-xl transform skew-x-12 -rotate-12 translate-x-8"></div>
      <h2 class="transform mr-8 text-xl font-serif"> Wins:</h2>
      <.player_wins player={"You"} wins={Map.get(@game, @current_player).wins}/>
      <div class="ml-8"></div>
      <.player_wins player={"Opponent"} wins={Map.get(@game, @opponent).wins}/>
    </div>
    """
  end

  # wins 裡面有重複的地方再拉出來一次
  def player_wins(assigns) do
    ~H"""
    <h3 class="block"><%= @player %>:</h3>
    <%= for x <- 0..(@wins), x > 0 do %>
      <div class={"ml-4 bg-green-300 w-4 h-4 rounded-3xl transform -skew-x-3 rotate-12"}></div>
    <% end %>
    <%= for x <- 0..(2 - @wins), x > 0 do %>
      <div class={"ml-4 bg-gray-300 w-4 h-4 rounded-3xl transform -skew-x-3 rotate-12"}></div>
    <% end %>
    """
  end

回合的部分

  def game_round(assigns) do
    ~H"""
    <div class="mt-2 text-gray-600 flex m-4">
      <div class="bg-blue-300 w-9 h-2 rounded-xl transform -skew-x-12 rotate-6 translate-x-10 translate-y-4"></div>
      <h2 class="transform mr-8 text-xl font-serif block">Round:</h2>
      <div class="ml-2 text-lg"><%= @round %></div>
    </div>
    """
  end

這邊用game_round是因為round會撞到是內建的Kernel.round/1方法

改一下 desk

看起來可能沒有時間做成只顯示當下回合的卡
不過還是可以加上分隔線讓他看起來舒服一些

  def desk(assigns) do
    ~H"""
    <div class="flex w-full justify-center items-center h-32">
      <%= for {card, i} <- Enum.with_index(@player.desk, 1) do %>
        <%= if Enum.member?([4,7], i) do %>
          <div class="w-1 h-20 bg-gray-200 mx-2 rounded"></div>
        <% end %>
        <.card name={card}/>
      <% end %>
    </div>
    """
  end

使用了 Enum.with_index 後,我就可以得知目前正準備要顯示的卡是第幾張
在顯示第 4, 7 張卡的時候,在前面加一個小分隔

遊戲都要有提示

儘管規則已經盡量簡單了
還是需要有很多說明,因為篇幅的關西
我們就在第一個回合 畫面上只有手牌的時候
提醒一下玩家出牌好了

做一個notice元件

  def notice(%{game: %{round: 1, turn: 1}} = assigns) do
    ~H"""
    <div class="mt-4 h-4 text-gray-600">? Pick a card</div>
    """
  end

  def notice(assigns) do 
    ~H"""
    <div class="mt-4 h-4"></div>
    """
  end

放在 hand 上面

  def render(assigns) do
    ~H"""
    <div class="flex flex-col items-center h-screen">
      <.logo />
      <.status game={@game} opponent={@opponent} current_player={@current_player}/>
      <div class="border-t border-b m-4">
        <.desk player={Map.get(@game, @opponent)}/>
        <.desk player={Map.get(@game, @current_player)}/>
      </div>
      <.notice game={@game}/>
      <.hand player={Map.get(@game, @current_player)}/>
    </div>
    """
  end

完成之後就變成這樣,算是相對好看的狀態了
https://ithelp.ithome.com.tw/upload/images/20211011/20141054rYbIx2pdJ1.png


hotfix

超嚴重bug

在 card/game.ex 的 host_win_this_round? 方法

  if reverse?(host_desk ++ guest_desk) do
    host_win
  else
    !host_win
  end

那個 ! 加錯地方了拉,難怪有的時候遊戲結果很奇怪

這樣才對

  if reverse?(host_desk ++ guest_desk) do
    !host_win
  else
    host_win
  end

上一篇
27 顯示覆蓋的牌
下一篇
29 勝利與失敗畫面
系列文
連線網頁卡牌遊戲(Elixir, Phoenix, Liveview)32

尚未有邦友留言

立即登入留言