2020年9月1日
ゲーム作りで学ぶVue.js (2) ゲームのレイアウト

背景画像

ゲームのレイアウトを作成していきます。

まずは使用する画像をGithubからダウンロードしてください。
右上のDownloadボタンからダウンロードできます。

背景の畳の画像をsrc/assetsの中にtatami.jpegで、将棋盤の木目をsrc/assetsの中にmokume.jpegで保存してください。

ファビコンはpublicにfavicon.icoで保存してください。
元のfavicon.icoを上書きして問題ないです。

タイトルと全体レイアウト

タイトルと全体のCSSを調整するためにpublic/index.htmlを少しだけ編集します。
<title>を将棋ポーカーに変えて、下にスタイルを追加してください。

public/index.html

<head>
  ...
  <title>将棋ポーカー</title>
  <style>
    html {
      height: 100%;
    }
    body {
      margin: 0;
      height: 100%;
    }
  </style>
</head>

サイトのタイトルがこのように変わっていると思います。

02-005title

将棋盤を作成

画面の大元になるShogiPoker.vuesrc/componentsに作成します。

src/components/ShogiPoker.vue

<template>
  <div>
    <h1>将棋ポーカー</h1>
    <div class="wrapper">
      <div class="com-komadai"></div>
      <div class="shogi-ban"></div>
      <div class="player-komadai"></div>
    </div>
  </div>
</template>

<script></script>

<style scoped>
h1 {
  text-align: center;
  margin: 0;
  padding: 20px 0;
}
.wrapper {
  display: flex;
  justify-content: center;
  min-width: 800px;
}
.player-komadai {
  display: flex;
  flex-direction: column-reverse;
}
table {
  margin: 0 15px;
  border: solid 2px black;
  border-collapse: collapse;
  background-image: url("../assets/mokume.jpeg");
  background-repeat: repeat;
}
td {
  width: 60px;
  height: 60px;
  text-align: center;
  font-size: 35px;
  font-weight: bold;
  border: solid 2px black;
}
.result {
  font-size: 17px;
  font-weight: bold;
}
.phase {
  font-size: 18px;
  background: #e7b87a;
  cursor: pointer;
}
.phase:hover {
  opacity: 0.7;
}
.player-select,
.com-select {
  font-weight: bold;
  background: #e7b87a;
}
.com-select {
  transform: rotate(0.5turn);
  -webkit-transform: rotate(0.5turn);
}
</style>

テンプレートには3つの<div>を用意しました。

  • 対戦相手の駒台とポイント
  • 将棋盤
  • ルールとリセットボタンとプレイヤーの駒台とポイント

JSはまだ空です。

CSSは今後使用するスタイルを全て最初に記載することにします。
scopedがついているので他のコンポーネントには影響しません。

プレイヤーと対戦相手の概念は至る所で登場しますので、それぞれPlayer、Comという名前を使っていきます。

  • プレイヤー:Player
  • 対戦相手(コンピュータ):Com

ShogiPoker.vueを描画

App.vueShogiPoker.vueを読み込んで描画します。

src/App.vue

<template>
  <div id="app">
    <shogi-poker />
  </div>
</template>

<script>
import ShogiPoker from "./components/ShogiPoker"

export default {
  name: "App",
  components: {
    ShogiPoker
  }
}
</script>

<style>
#app {
  height: 100%;
  background-image: url("./assets/tatami.jpeg");
  background-repeat: repeat;
  overflow: auto;
}
</style>

JSでは読み込みをHelloWorld.vueからShogiPoker.vueに変えました。
読み込むときは.vueはなくても構いません。
さらにexport defaultの中のcomponentsでShogiPokerを使用することを定義します。

テンプレートはロゴとHelloWorldを削除して、ShogiPokerを描画します。
書き方としては以下の4通りがあります。
<shogi-poker />
<ShogiPoker />
<shogi-poker></shogi-poker>
<ShogiPoker></ShogiPoker>

Vueのガイドラインでテンプレート内ではケバブケースのshogi-pokerが推奨されているのでこちらを採用します。
閉じタグについては中に要素がなければ<shogi-poker />のように自己終了形式で書くことが推奨されています。
通常のHTMLでも<img>は中身がないので、閉じタグの</img>は書きません。
それと同じです。

CSSでは背景を畳の画像にしています。
2

<div class="shogi-ban">の中に将棋盤を<table>で作成していきます。

src/components/ShogiPoker.vue

<div class="shogi-ban">
  <table>
    <tbody>
      <tr class="com-row">
        <td>歩</td>
        <td>香</td>
        <td>桂</td>
        <td>銀</td>
        <td>金</td>
        <td>角</td>
        <td>飛</td>
      </tr>
      <tr>
        <td v-for="n in 7" :key="n"></td>
      </tr>
      <tr>
        <td></td><td></td><td></td>
        <td class="com-select"></td>
        <td></td><td></td><td></td>
      </tr>
      <tr>
        <td></td><td></td><td></td>
        <td class="result"></td>
        <td></td>
        <td class="phase"></td>
        <td></td>
      </tr>
      <tr>
        <td></td><td></td><td></td>
        <td class="player-select"></td>
        <td></td><td></td><td></td>
      </tr>
      <tr>
        <td v-for="n in 7" :key="n"></td>
      </tr>
      <tr class="player-row">
        <td>歩</td>
        <td>香</td>
        <td>桂</td>
        <td>銀</td>
        <td>金</td>
        <td>角</td>
        <td>飛</td>
      </tr>
    </tbody>
  </table>
</div>

ゲームで使用するセルには何らかのクラス名がついています。

1段目と7段目には駒が入ります。

2段目と6段目は全て空なので<td></td>を7回書けば良いのですが、面倒なので違った書き方をしています。
2段目と6段目の<td v-for="n in 7" :key="n"></td>はリストレンダリングというもので、v-forでタグを繰り返すことができます。
v-forを使うときは:key=を設定する必要があります。
nに1から7まで順に代入されてループします。
ここでは<td></td>が7回繰り返されます。

実際にはitemsという配列があって、それをループして各itemの要素を表示するような使い方が一般的です。
<td v-for="item in items" :key="item.key">{{ item.value }}</td>

itemsはこのような配列です。

items = [
  {key: "en", value: "英語"},
  {key: "ja", value: "日本語"}
]

画面はそれっぽくなってきたと思います。

02-020first-table

ルールの作成

続いて右上のルール部分を作ります。

ShogiPoker.vueに直接書かず、GameRule.vueを作ってそれを読み込む方法を取ります。
GameRule.vueをsrc/componentsに作成します。

src/components/GameRule.vue

<template>
  <div class="rule">
    <h2>ルール</h2>
    <ul>
      <li>駒を選択して○手目をクリック</li>
      <li>相手の駒より強ければ勝ち</li>
      <li>相手の駒の点数が獲得ポイント</li>
      <li>駒の点数はこちら<br />歩:1 香:3 桂:4 銀:6 金:7 角:9 飛:10</li>
    </ul>
  </div>
</template>

<style scoped>
.rule {
  margin: 0 0 5px 0;
}
h2 {
  margin: 0;
  text-align: center;
}
li {
  margin: 5px 0;
  font-size: 17px;
}
</style>

これをShogiPoker.vueで読み込んで描画します

src/components/ShogiPoker.vue

...
      <div class="player-komadai">
        <game-rule /> <!-- 追加 -->
      </div>
    </div>
  </div>
</template>

<script>
import GameRule from "./GameRule"

export default {
  components: {
    GameRule
  }
}
</script>

これでルール部分のコンポーネントを作り、ShogiPoker.vueで使用することができました。
表示位置はプレイヤーの駒台ができたら丁度良い位置にきます。

02-030rule

駒台を作成

次は駒台を作ります。
まずはCom側から。

ComKomadai.vueをsrc/componentsに作成します。

src/components/ComKomadai.vue

<template>
  <div>
    <table>
      <tbody>
        <tr>
          <td></td>
          <td></td>
          <td></td>
        </tr>
        <tr>
          <td></td>
          <td></td>
          <td></td>
        </tr>
      </tbody>
    </table>
    <div class="com-point"></div>
  </div>
</template>

<script></script>

<style scoped>
table {
  border: 2px solid black;
  border-collapse: collapse;
  background-image: url("../assets/mokume.jpeg");
  background-repeat: repeat;
}

td {
  width: 42px;
  height: 48px;
  text-align: center;
  font-size: 28px;
  font-weight: bold;
  border-width: 0px;
  transform: rotate(0.5turn);
  -webkit-transform: rotate(0.5turn);
}

.com-point {
  width: 50px;
  height: 50px;
  text-align: center;
  line-height: 50px;
  font-size: 22px;
  font-weight: bold;
  border: 2px black solid;
  background: #e7b87a;
  float: right;
  margin-top: 10px;
}
</style>

レイアウトだけなので駒の表示はまだ行いません。

これをShogiPoker.vueで使用します。

src/components/ShogiPoker.vue

<template>
  <div>
    <h1>将棋ポーカー</h1>
    <div class="wrapper">
      <div class="com-komadai">
        <com-komadai /> <!-- 追加 -->
      </div>

...

<script>
import GameRule from "./GameRule"
import ComKomadai from "./ComKomadai" // 追加

export default {
  components: {
    GameRule,
    ComKomadai // 追加
  }
}
</script>

次はPlayer側の駒台を作ります。

src/components/PlayerKomadai.vue

<template>
  <div>
    <div class="player-point"></div>
    <table>
      <tbody>
        <tr>
          <td></td>
          <td></td>
          <td></td>
        </tr>
        <tr>
          <td></td>
          <td></td>
          <td></td>
        </tr>
      </tbody>
    </table>
  </div>
</template>

<script></script>

<style scoped>
table {
  border: 2px solid black;
  border-collapse: collapse;
  background-image: url("../assets/mokume.jpeg");
  background-repeat: repeat;
}

td {
  width: 42px;
  height: 48px;
  text-align: center;
  font-size: 28px;
  font-weight: bold;
  border-width: 0px;
}

.player-point {
  width: 50px;
  height: 50px;
  text-align: center;
  line-height: 50px;
  font-size: 22px;
  font-weight: bold;
  border: 2px black solid;
  background: #e7b87a;
  margin-bottom: 10px;
}
</style>
src/components/ShogiPoker.vue

...
      <div class="player-komadai">
        <player-komadai /> <!-- 追加 -->
        <game-rule />
      </div>
    </div>
  </div>
</template>

<script>
import GameRule from "./GameRule"
import ComKomadai from "./ComKomadai"
import PlayerKomadai from "./PlayerKomadai" // 追加

export default {
  components: {
    GameRule,
    ComKomadai,
    PlayerKomadai // 追加
  }
}
</script>

Playerの駒台とルールの順番がHTMLと画面で逆になっているのは、CSSでplayer-komadaiflex-direction: column-reverseが指定されているからです。
column-reverseで縦向きで逆順にできます。
Playerの駒台を下揃えにするためです。
https://developer.mozilla.org/ja/docs/Web/CSS/flex-direction

02-040komadai

リセットボタン

最後にリセットボタンを作ります。

src/components/ResetBtn.vue

<template>
  <div class="reset-btn">リセット</div>
</template>

<script></script>

<style scoped>
.reset-btn {
  width: 90px;
  height: 36px;
  text-align: center;
  border: solid 2px black;
  font-size: 16px;
  font-weight: bold;
  margin-bottom: 20px;
  line-height: 36px;
  background-image: url("../assets/mokume.jpeg");
  background-repeat: repeat;
  cursor: pointer;
}
</style>
src/components/ShogiPoker.vue

...
      <div class="player-komadai">
        <player-komadai />
        <reset-btn /> <!-- 追加 -->
        <game-rule />
      </div>
    </div>
  </div>
</template>

<script>
import GameRule from "./GameRule"
import ComKomadai from "./ComKomadai"
import PlayerKomadai from "./PlayerKomadai"
import ResetBtn from "./ResetBtn" // 追加

export default {
  components: {
    GameRule,
    ComKomadai,
    PlayerKomadai,
    ResetBtn // 追加
  }
}
</script>

これでレイアウトはほぼ出来上がりました。

02-050resetbtn

ここまでのコードはこちらにあります。

次章 からはゲームのロジックを作っていきます。

連載記事