AMP
  • 网站

井字游戏

简介

这是一个展示如何实现井字游戏的示例。这包括

  • 如何使用 amp-state 来维护游戏状态。

  • 如何使用表达式来检测获胜的移动。

  • 如何使用动作事件来创建交互式游戏玩法。

设置

交互式游戏玩法需要 amp-bind

<script async custom-element="amp-bind" src="https://cdn.ampproject.org/v0/amp-bind-0.1.js"></script>

初始游戏状态

我们使用名为 gameStateamp-state 来保存游戏状态。此外,一些状态值未初始化,但将在下面解释

  • currentPlayer:可以为 1 或 -1,分别表示 ⚡ 和 O。
  • board:存储棋盘的状态。此对象有 9 个属性,从 ai,表示从左上角到右下角的方格。
  • trmrbrlcmcrcfdbd:读取为行、行等等,这 8 个值保存每个可能的获胜状态的计分
<amp-state id="gameState">
  <script type="application/json">
    {
      "currentPlayer": 1,
      "displayValues": {
        "-1": "O",
        "1": "⚡"
      }
    }
  </script>
</amp-state>

显示获胜

要检测获胜,我们会检查是否有任何计分达到正 3 或负 3。

开始玩吧!

⚡ 赢了!!!

O 赢了!!!

<div class="results-component">
  <h1 [class]="max(abs(tr),abs(br),abs(lc),abs(rc),abs(fd),abs(bd),abs(mc),abs(mr)) == 3 ? 'hide' : 'show'">Let's play!</h1>
  <h1 [class]="max(tr,br,lc,rc,fd,bd,mc,mr) == 3 ? 'show' : 'hide'" class="hide">⚡ wins!!!</h1>
  <h1 [class]="min(tr,br,lc,rc,fd,bd,mc,mr) == -3 ? 'show' : 'hide'" class="hide">O wins!!!</h1>
</div>

处理玩家的回合

游戏板的每个方格都是一个按钮。当进行移动时,状态会更新

  • 适当的计分会增加或减少。例如,在左上角进行移动会更改 3 个可能的获胜状态的计分:trlcbd(顶行、左列和向后对角线)。

  • board 的状态已更新,以记录此方格已填充。

  • 通过将当前玩家乘以 -1,游戏玩法切换到另一位玩家。

每个方格的显示属性会根据状态的这种变化而更新

  • [text]:每个方格要么不包含任何内容,要么包含 board 中的相应值。

  • [class]:如果已达到此方格的任何获胜状态,则会相应地更改背景。

  • [disabled]:如果已发生获胜或已移动此方格,则必须禁用此按钮。

<div class="board-component">
  <table>
    <tr>
      <td class="cell">
        <button on="tap:AMP.setState({
                      tr: tr + gameState.currentPlayer,
                      lc: lc + gameState.currentPlayer,
                      bd: bd + gameState.currentPlayer,
                      board: {
                        a: gameState.displayValues[gameState.currentPlayer]
                      },
                      gameState: {
                        currentPlayer: gameState.currentPlayer * -1
                      }
                    })" [text]="board.a ? board.a : ''" [class]="max(abs(tr),abs(lc),abs(bd)) == 3 ? 'grid-button win' : 'grid-button in-play'" [disabled]="board.a || max(abs(tr),abs(br),abs(lc),abs(rc),abs(fd),abs(bd),abs(mc),abs(mr)) == 3" class="grid-button in-play">
        </button>
      </td>
      <td class="cell cell-vert">
        <button on="tap:AMP.setState({
                      tr: tr + gameState.currentPlayer,
                      mc: mc + gameState.currentPlayer,
                      board: {
                        b: gameState.displayValues[gameState.currentPlayer]
                      },
                      gameState: {
                        currentPlayer: gameState.currentPlayer * -1
                      }
                    })" [text]="board.b ? board.b : ''" [class]="max(abs(tr),abs(mc)) == 3 ? 'grid-button win' : 'grid-button in-play'" [disabled]="board.b || max(abs(tr),abs(br),abs(lc),abs(rc),abs(fd),abs(bd),abs(mc),abs(mr)) == 3" class="grid-button in-play">
        </button>
      </td>
      <td class="cell">
        <button on="tap:AMP.setState({
                      tr: tr + gameState.currentPlayer,
                      rc: rc + gameState.currentPlayer,
                      fd: fd + gameState.currentPlayer,
                      board: {
                        c: gameState.displayValues[gameState.currentPlayer]
                      },
                      gameState: {
                        currentPlayer: gameState.currentPlayer * -1
                      }
                    })" [text]="board.c ? board.c : ''" [class]="max(abs(tr),abs(rc),abs(fd)) == 3 ? 'grid-button win' : 'grid-button in-play'" [disabled]="board.c || max(abs(tr),abs(br),abs(lc),abs(rc),abs(fd),abs(bd),abs(mc),abs(mr)) == 3" class="grid-button in-play">
        </button>
      </td>
    </tr>
    <tr>
      <td class="cell cell-horiz">
        <button on="tap:AMP.setState({
                      mr: mr + gameState.currentPlayer,
                      lc: lc + gameState.currentPlayer,
                      board: {
                        d: gameState.displayValues[gameState.currentPlayer]
                      },
                      gameState: {
                        currentPlayer: gameState.currentPlayer * -1
                      }
                    })" [text]="board.d ? board.d : ''" [class]="max(abs(mr),abs(lc)) == 3 ? 'grid-button win' : 'grid-button in-play'" [disabled]="board.d || max(abs(tr),abs(br),abs(lc),abs(rc),abs(fd),abs(bd),abs(mc),abs(mr)) == 3" class="grid-button in-play">
        </button>
      </td>
      <td class="cell cell-horiz cell-vert">
        <button on="tap:AMP.setState({
                      mr: mr + gameState.currentPlayer,
                      mc: mc + gameState.currentPlayer,
                      fd: fd + gameState.currentPlayer,bd: bd + gameState.currentPlayer,
                      board: {
                        e: gameState.displayValues[gameState.currentPlayer]
                      },
                      gameState: {
                        currentPlayer: gameState.currentPlayer * -1
                      }
                    })" [text]="board.e ? board.e : ''" [class]="max(abs(mr),abs(mc),abs(fd),abs(bd)) == 3 ? 'grid-button win' : 'grid-button in-play'" [disabled]="board.e || max(abs(tr),abs(br),abs(lc),abs(rc),abs(fd),abs(bd),abs(mc),abs(mr)) == 3" class="grid-button in-play">
        </button>
      </td>
      <td class="cell cell-horiz">
        <button on="tap:AMP.setState({
                      mr: mr + gameState.currentPlayer,
                      rc: rc + gameState.currentPlayer,
                      board: {
                        f: gameState.displayValues[gameState.currentPlayer]
                      },
                      gameState: {
                        currentPlayer: gameState.currentPlayer * -1
                      }
                    })" [text]="board.f ? board.f : ''" [class]="max(abs(mr),abs(rc)) == 3 ? 'grid-button win' : 'grid-button in-play'" [disabled]="board.f || max(abs(tr),abs(br),abs(lc),abs(rc),abs(fd),abs(bd),abs(mc),abs(mr)) == 3" class="grid-button in-play">
        </button>
      </td>
    </tr>
    <tr>
      <td class="cell">
        <button on="tap:AMP.setState({
                      br: br + gameState.currentPlayer,
                      lc: lc + gameState.currentPlayer,
                      fd: fd + gameState.currentPlayer,
                      board: {
                        g: gameState.displayValues[gameState.currentPlayer]
                      },
                      gameState: {
                        currentPlayer: gameState.currentPlayer * -1
                      }
                    })" [text]="board.g ? board.g : ''" [class]="max(abs(br),abs(lc),abs(fd)) == 3 ? 'grid-button win' : 'grid-button in-play'" [disabled]="board.g || max(abs(tr),abs(br),abs(lc),abs(rc),abs(fd),abs(bd),abs(mc),abs(mr)) == 3" class="grid-button in-play">
        </button>
      </td>
      <td class="cell cell-vert">
        <button on="tap:AMP.setState({
                      br: br + gameState.currentPlayer,
                      mc: mc + gameState.currentPlayer,
                      board: {
                        h: gameState.displayValues[gameState.currentPlayer]
                      },
                      gameState: {
                        currentPlayer: gameState.currentPlayer * -1
                      }
                    })" [text]="board.h ? board.h : ''" [class]="max(abs(br),abs(mc)) == 3 ? 'grid-button win' : 'grid-button in-play'" [disabled]="board.h || max(abs(tr),abs(br),abs(lc),abs(rc),abs(fd),abs(bd),abs(mc),abs(mr)) == 3" class="grid-button in-play">
        </button>
      </td>
      <td class="cell">
        <button on="tap:AMP.setState({
                      br: br + gameState.currentPlayer,
                      rc: rc + gameState.currentPlayer,
                      bd: bd + gameState.currentPlayer,
                      board: {
                        i: gameState.displayValues[gameState.currentPlayer]
                      },
                      gameState: {
                        currentPlayer: gameState.currentPlayer * -1
                      }
                    })" [text]="board.i ? board.i : ''" [class]="max(abs(br),abs(rc), abs(bd)) == 3 ? 'grid-button win' : 'grid-button in-play'" [disabled]="board.i || max(abs(tr),abs(br),abs(lc),abs(rc),abs(fd),abs(bd),abs(mc),abs(mr)) == 3" class="grid-button in-play">
        </button>
      </td>
    </tr>
  </table>
</div>

重置游戏状态

要开始新游戏,board 和 8 个计分会重置为 null,并且 currentPlayer 重置为

<div class="reset-component">
  <button class="reset-button" on="tap:AMP.setState({
              gameState: {
                currentPlayer: 1,
                displayValues: {
                  '-1': 'O',
                  '1': '⚡'
                }
              },
              tr: null,
              mr: null,
              br: null,
              lc: null,
              mc: null,
              rc: null,
              fd: null,
              bd: null,
              board: null
            })">
    Restart game
  </button>
</div>

提示

将 ⚡ 放在中心方格中!

需要进一步解释吗?

如果此页面上的解释不能涵盖您的所有问题,请随时与其他 AMP 用户联系,讨论您的确切用例。

转到 Stack Overflow
一个未解释的功能?

AMP 项目强烈鼓励您的参与和贡献!我们希望您成为我们开源社区的持续参与者,但我们也欢迎您对您特别感兴趣的问题进行一次性贡献。

在 GitHub 上编辑示例