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

这样子就行了,游戏开始後一小时,那个游戏就会坏掉。


<<:  [访谈] APCS x 资讯科学班 tom1484

>>:  29.5 如果我要装 javascript 套件勒?

【Day28】企业数位治理议题1:系统因应企业商业模式变动弹性调整

#odoo #开源系统 #数位赋能 #E化自主 前言 在我们对於odoo社区版重要应用模组功能有简单...

[Day 14] Delete 删除资料

利用Day 13的collection public function getData(){ ret...

Day30 - Windows 提权(1)-Unquoted Service Paths、修改服务提权

假设我们取得受害主机的 shell (cmd.exe 或 powershell)可以根据自己的需求取...

[Day - 13] - Spring 依赖性注入元件管理运作与方法

Abstract 无论何种时候,每种系统的开发元件势必都有先後启动顺序,如何有效管控每项元件的启动流...

Day37 ( 游戏设计 ) 台湾地图拼图

台湾地图拼图 教学原文参考:台湾地图拼图 这篇文章延伸「形状配对拼图」的范例,在 Scratch 3...