iT邦幫忙

2021 iThome 鐵人賽

DAY 29
0
Modern Web

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

29 勝利與失敗畫面

獲勝畫面

獲勝畫面我們做一個 modal 好了

如果 遊戲狀態不是進行中 與 開啟modal 的話
就顯示 game_over_modal component

進行中的時候狀態是 :start
host 贏是 :host_win
guest 贏是 :guest_win

我們可以用 @current_player"_win" 組合起來看看是不是等於狀態來判斷目前玩家是否獲勝

@game.status == :"#{@current_player}_win"

  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)}/>
      <%= if (@game.status != :start) && @modal_on do %>
        <.game_over_modal win={@game.status == :"#{@current_player}_win"}/>
      <% end %>
    </div>
    """
  end

再來用 tailwind 做一個蓋版 modal
除了顯示輸贏之外
還要有一個可以關掉 modal 的按鈕
可以用 phx-click 來實作

  def game_over_modal(assigns) do
    ~H"""
    <div phx-capture-click="close_model" class="fixed w-full h-screen flex bg-black bg-opacity-20 justify-center items-center">
      <div class="flex flex-col p-4 bg-gray-50 shadow-lg text-center border w-60 h-70 rounded-xl">
        <div class="flex">

          # 關閉 modal 按鈕
          <button phx-click="close_model" class="-mt-6">
            <div class="bg-red-300 w-4 h-4 rounded-xl transform skew-x-12 -rotate-6 translate-y-6"></div>
            <h2 class="block transform text-xl">x</h2>
          </button>
        </div>


        # 依照輸贏顯示訊息
        <%= if @win do %>
          <div class="bg-yellow-300 w-12 h-8 rounded-xl transform skew-x-12 -rotate-12 translate-x-12 translate-y-12"></div>
          <h2 class="transform text-3xl font-serif mb-4">You Win</h2>
        <% else %>
          <div class="bg-gray-300 w-8 h-8 rounded-xl transform skew-x-12 -rotate-12 translate-x-12 translate-y-12"></div>
          <h2 class="transform text-3xl font-serif mb-4">You Lose</h2>
        <% end %>



        <div class="flex flex-col mt-8 justify-center">
          <%= link to: "/" do %>
            <div class="bg-green-300 w-24 h-6 rounded-xl transform -skew-x-12 rotate-6 translate-y-8 translate-x-16"></div>
            <h2 class="block transform text-xl font-serif">Back to Start Menu</h2>
          <% end %>
        </div>
      </div>
    </div>
    """
  end

加上 handle_event :close_modal

  def handle_event("close_model", _params, socket) do
    {:noreply, assign(socket, :modal_on, false)}
  end

別忘了要在 mount 最後加上我們用的 :modal_on

  def mount(
    # 略
       id: id,
       game: maybe_fold_last(game, current_player, opponent),
       current_player: current_player,
       opponent: opponent,
       modal_on: true
     })}
  end

趕快試試看

https://ithelp.ithome.com.tw/upload/images/20211011/20141054MKsp2muj3N.png

補一下關掉沒人的遊戲好了

雖然我們的規模就算不關也不會塞爆
但沒用的時候還是關掉一下好了

在這次我覺得用 超過時間就關閉 的做法就行了

回到 lib/card/game.ex

這次的做法是,
啟動遊戲的時候順便設定 1 小時後會發 GenServer.cast :times_up
handle_cast :times_up 裡面再去呼叫 GenServer.stop

啟動時定時

  def init(game) do
    Process.send_after(self(), :stop_timer, 60 * 60 * 1000)
    {:ok, start_turn_timer(game)}
  end

自我毀滅按鈕

  def handle_info(:stop_timer, _game) do
    GenServer.stop(self())
  end

GenServer stop 的時候會呼叫 terminate callback
我們可以在這邊把要關掉的 id 從 games 表格裡面拿掉

  def terminate(_reason, game) do
    :ets.delete(:games, game.id)
    :ok
  end

這樣子就行了,遊戲開始後一小時,那個遊戲就會壞掉。


上一篇
28 遊戲狀態欄
下一篇
29.5 如果我要裝 javascript 套件勒?
系列文
連線網頁卡牌遊戲(Elixir, Phoenix, Liveview)32

尚未有邦友留言

立即登入留言