獲勝畫面我們做一個 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
趕快試試看
雖然我們的規模就算不關也不會塞爆
但沒用的時候還是關掉一下好了
在這次我覺得用 超過時間就關閉 的做法就行了
回到 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
這樣子就行了,遊戲開始後一小時,那個遊戲就會壞掉。