2020年9月5日
ゲーム作りで学ぶVue.js (6) emitで駒選択

選択中の駒を表示

Playerが駒を選択して、○手目をクリックした時の挙動を実装していきます。

選択した駒の表示をcomputedで作ります。
Playerが選択した駒のラベルをplayerSelectingKomaLabel、Comが選択した駒のラベルをcomSelectingKomaLabelで定義します。

src/components/ShogiPoker.vue

computed: {
  ...mapState(["komaList"]),
  kyokumen() {
    return this.phase === 1 ? "初手" : this.phase + "手目"
  },
  displayResult() {
    return this.gameResult ? this.gameResult : this.phaseResult
  },
  playerSelectingKomaLabel () {  // 以下追加
    return this.playerSelectingKoma ? this.komaList[this.playerSelectingKoma].label : null
  },
  comSelectingKomaLabel () {
    return this.comSelectingKoma ? this.komaList[this.comSelectingKoma].label : null
  }
}

PlayerはplayerSelectingKomaに値が入っていればその駒のラベルを表示、値がなければ何も表示しません。
Comも同様です。

これをテンプレートで使います。

src/components/ShogiPoker.vue

<td class="com-select">
  {{ comSelectingKomaLabel }}
</td>

...

<td class="player-select">
  {{ playerSelectingKomaLabel }}
</td>

playerSelectingKomacomSelectingKomaはnullなのでまだ何も表示されません。

Playerの駒選択にemitを使う

Playerが駒を選択したらplayerSelectingKomaに値が入る処理をemitを使って実装します。

emitは子コンポーネントから親コンポーネントのイベント(主にmethods)を呼び出す仕組みのことです。
親から子へ変数を渡すpropsとは逆のイメージです。

これから実現したいのは下記の要件です。

子コンポーネントのPlayerKoma.vueで駒をクリックすると、親コンポーネントのShogiPoker.vueplayerSelectingKomaに値が入る。

この要件を満たすために親コンポーネントであるShogiPoker.vueplayerSelectingKomaに値を代入するmethodsを作ります。
Playerが駒を選択したということで関数名は単純にselectとします。

その準備として...mapStateに今後使用するstateを追加します。

src/components/ShogiPoker.vue

computed: {
  ...mapState([
    "komaList",
    "playerSelectable",  // 以下追加
    "comSelectable",
    "playerPoint",
    "comPoint"
  ]),
},
src/components/ShogiPoker.vue

computed: {
  // 省略
},
methods: {  // 以下追加
  // playerが駒を選択
  select(komaIndex) {
    if (this.playerSelectable.includes(komaIndex)) {
      this.playerSelectingKoma = komaIndex
    }
  }
}

引数のkomaIndexにはfuやkinなどが渡ってくる想定です。
ただ駒はなんでもいい訳では無く、選択可能な駒である必要があるのでplayerSelectableに含まれるかを条件にしています。

このselectを子コンポーネントであるPlayerKoma.vueからemitを使って呼び出せば良いことになります。

emitの実行にはイベントが必要なので、select-komaというイベントを用意します。
このselect-komaが親と子を繋ぐものになります。

実装は@select-koma="select"をコンポーネントを使う箇所で記載します。

src/components/ShogiPoker.vue

<player-koma
  v-for="(koma, index) in this.komaList"
  :key="index"
  :koma-index="index"
  :koma="koma"
  @select-koma="select"
/>

PlayerKoma.vueselect-komaが呼ばれたら、ShogiPoker.vueselectを実行するという意味です。
@v-onの省略記法です。

あとはこのselect-komaPlayerKoma.vueで駒がクリックされたときに呼び出せば実現できます。

PlayerKoma.vueに駒がクリックされたら呼ばれるclickKomaを作ります。

src/components/PlayerKoma.vue

methods: {
  getKomaClass() {
    if (!this.playerSelectable.includes(this.komaIndex)) {
      return "unselectable"
    }
  },
  clickKoma() {  // 以下追加
    this.$emit("select-koma", this.komaIndex)
  }
}

clickKomaの中でemitを使っています。
emit$emit(イベント名, 渡す値)のように書きます。

駒がクリックされたらclickKomaを実行したいので、td@clickで設定します。
@clickv-on:clickの省略記法です。

ShogiPoker.vue@select-komaはこちらで作ったイベント(カスタムイベント)で、@clickはVueに元々あるイベント(ネイティブイベント)です。
ここら辺はややこしいので混同しないようにしましょう。

src/components/PlayerKoma.vue

<td @click="clickKoma()" :class="getKomaClass()">{{ koma.label }}</td>

これでクリックしたら駒が表示されるようになったと思います。

06-010clickKoma

○手目クリック処理

次は○手目をクリックしたときの処理を作っていきます。

○手目をクリックしたら起きることは以下になります。

  • Comの駒をランダムに選択
  • どちらの勝ちかを計算して結果を表示
  • phaseを+1する
  • 選択できる駒から使用した駒を削除
  • 獲得ポイントを加算
  • 獲得した駒を駒台に追加

このうち下3つはVuexのステートで定義した変数を変える処理になります。
これはVuexのミューテーションで行います。
本章は上3つの処理を実装します。

Comの駒をランダムに決定

○手目をクリックしたらbetが呼ばれてComの駒がランダムに決まるように処理を追加します。

src/components/ShogiPoker.vue

methods: {
  // playerが駒を選択
  select(komaIndex) {
    // 省略
  },
  // 以下追加
  // ○手目をクリック
  bet() {
    // comの駒をランダムに決める
    let size = this.comSelectable.length
    this.comSelectingKoma = this.comSelectable[Math.floor(Math.random() * size)]
  }
}
src/components/ShogiPoker.vue

<td @click="bet()" class="phase">

これで○手目をクリックするとComの駒が選択されて表示されます。

06-020comrandom

ランダムに駒を選択するところは若干ややこしいですが、JSではシンプルに書けないのでこのようになります。

Math.random()は0から1未満のランダムな値(0.7493709みたいな)で、それに配列の要素数を掛ければ0から配列の要素数未満のランダムな値になり、小数点以下を切り捨てれば配列のインデックスをランダムに決めることができます。
例えば、要素数が3の配列なら均等な確率で0, 1, 2のどれかになります。

ComとPlayerでバトル

お互いの駒が選択されたので、どちらの勝ちか計算して結果を表示します。
battleという関数を作って、betの中から呼び出します。

src/components/ShogiPoker.vue

// ○手目をクリック
bet() {
  // comの駒をランダムに決める
  let size = this.comSelectable.length
  this.comSelectingKoma = this.comSelectable[Math.floor(Math.random() * size)]

  this.battle()  // 追加
},
// 以下追加
// 対決
battle() {
  // PlayerとComの駒ポイントを比較
  const playerKomaPoint = this.komaList[this.playerSelectingKoma].point
  const comKomaPoint = this.komaList[this.comSelectingKoma].point
  if (playerKomaPoint > comKomaPoint) {
    this.phaseResult = "WIN"
  } else if (playerKomaPoint < comKomaPoint) {
    this.phaseResult = "LOSE"
  } else {
    this.phaseResult = "DRAW"
  }
}

このように内部から別の関数を呼ぶこともできます。

駒を選択して○手目をクリックすると結果が表示されたと思います。

06-030phaseresult

phaseを加算

battleが終わったらphaseを+1する必要があるので追加します。

src/components/ShogiPoker.vue

// ○手目をクリック
bet() {
  // comの駒をランダムに決める
  let size = this.comSelectable.length
  this.comSelectingKoma = this.comSelectable[Math.floor(Math.random() * size)]

  this.battle()

  // 以下追加
  if (this.phase < 7) {
    this.phase++
  }
},

これで初手の次は2手目、3手目と増えていき7手目以降は増えなくなります。

ある程度ゲームのロジックができてきました。

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

次章 はVuexのmutationsを扱います。

連載記事