ミューテーションでステートを更新
本章ではstore.js
で定めたステートをミューテーションで更新する処理を行います。
現状のstore.js
はこのようになっています。
import Vue from "vue"
import Vuex from "vuex"
Vue.use(Vuex)
const komaIndexList = ["fu", "kyosha", "keima", "gin", "kin", "kaku", "hisha"]
const store = new Vuex.Store({
state: {
komaList: {
fu: { point: 1, label: "歩" },
kyosha: { point: 3, label: "香" },
keima: { point: 4, label: "桂" },
gin: { point: 6, label: "銀" },
kin: { point: 7, label: "金" },
kaku: { point: 9, label: "角" },
hisha: { point: 10, label: "飛" }
},
playerPoint: 0,
comPoint: 0,
playerKomadai: [],
comKomadai: [],
playerSelectable: Object.assign([], komaIndexList),
comSelectable: Object.assign([], komaIndexList)
},
mutations: {}
})
export default store
空になっているmutations
に更新する関数を作っていきます。
mutations: {
// Playerの選択可能な駒を更新
updatePlayerSelectable(state, komaIndex) {
const index = state.playerSelectable.indexOf(komaIndex)
state.playerSelectable.splice(index, 1)
},
// Comの選択可能な駒を更新
updateComSelectable(state, komaIndex) {
const index = state.comSelectable.indexOf(komaIndex)
state.comSelectable.splice(index, 1)
},
// Playerのポイントを加算
addPlayerPoint(state, point) {
state.playerPoint += point
},
// Comのポイントを加算
addComPoint(state, point) {
state.comPoint += point
},
// Playerの駒台に駒を追加
addPlayerKoma(state, komaIndex) {
state.playerKomadai.push(komaIndex)
},
// Comの駒台に駒を追加
addComKoma(state, komaIndex) {
state.comKomadai.push(komaIndex)
}
}
たくさんありますが処理はどれもシンプルです。
全ての関数の一つ目の引数はstate
になるのはVuexの決まりです。
ミューテーションを実行する時は2番目以降の引数を与えてれば良いです。
選択可能な駒の更新では渡ってきたkomaIndex
(fuやkinなど)を配列から削除しています。
ポイント加算はポイントが渡ってくるので、それを足すだけです。
駒台に駒追加はkomaIndex
を配列に追加しています。
またmutations
に定めた関数をミューテーションハンドラ、第2引数をペイロードと呼びます。
ミューテーションを実行
ミューテーションをコンポーネントから実行するには$store.commit(ミューテーションハンドラ, ペイロード)
とすればできます。
bet
でComの駒が決まった後に使用できる駒の更新を呼び出します。
bet() {
// comの駒をランダムに決める
// 省略
// 使用可能な駒の更新
this.$store.commit("updatePlayerSelectable", this.playerSelectingKoma) // 追加
this.$store.commit("updateComSelectable", this.comSelectingKoma) // 追加
this.battle()
これで使用した駒にclass="unselectable"
がついて、表示が薄くなります。
次はポイントの加算を呼び出します。
battleでPlayerが勝てばComの駒ポイントを加算、Comが勝てばPlayerの駒ポイントを加算します。
さらに駒台にもそれぞれ駒を追加します。
// 対決
battle() {
// PlayerとComの駒ポイントを比較
const playerKomaPoint = this.komaList[this.playerSelectingKoma].point
const comKomaPoint = this.komaList[this.comSelectingKoma].point
if (playerKomaPoint > comKomaPoint) {
this.phaseResult = "WIN"
this.$store.commit("addPlayerPoint", comKomaPoint) // 追加
this.$store.commit("addPlayerKoma", this.comSelectingKoma) // 追加
} else if (playerKomaPoint < comKomaPoint) {
this.phaseResult = "LOSE"
this.$store.commit("addComPoint", playerKomaPoint) // 追加
this.$store.commit("addComKoma", this.playerSelectingKoma) // 追加
} else {
this.phaseResult = "DRAW"
}
}
これでPlayerが勝った時はComの駒ポイントが加算されて、駒台にComの駒が表示されました。
リセットボタン
リセットボタンをクリックした時の処理をemit
とミューテーションを使って実装します。
リセットするには全ての変数が初期値になれば良いので、ShogiPoker.vue
のdata()
とstore.js
のstate
を全て初期値に戻します。
emit
を使ってdata()
を初期値にします。
methods: {
battle() {
// 省略
},
// 以下追加
// リセット
reset() {
this.phase = 1
this.gameResult = null
this.phaseResult = null
this.playerSelectingKoma = null
this.comSelectingKoma = null
this.canBattle = false
}
}
<reset-btn @reset-data="reset" />
<template>
<div @click="clickReset()" class="reset-btn">リセット</div>
</template>
<script>
export default {
methods: {
clickReset() {
this.$emit("reset-data")
}
}
}
</script>
これでリセットボタンがクリックされたらShogiPoker.vue
のreset
が呼ばれます。
次にstate
の変数を初期化します。
mutations: {
// Comの駒台に駒を追加
addComKoma(state, komaIndex) {
state.comKomadai.push(komaIndex)
},
// 以下追加
// リセット
reset(state) {
state.playerPoint = 0
state.comPoint = 0
state.playerKomadai = []
state.comKomadai = []
state.playerSelectable = Object.assign([], komaIndexList)
state.comSelectable = Object.assign([], komaIndexList)
}
}
methods: {
clickReset() {
this.$store.commit("reset") // 追加
this.$emit("reset-data")
}
}
これでゲーム途中でもリセットボタンで最初の状態に戻すことができます。
ゲーム結果の表示
ゲームのおおよその機能は出来上がったので、残っている処理を仕上げていきます。
終了時にゲーム結果を表示します。
ゲーム結果を決めるsetGameResult
を作ります。
methods: {
// リセット
reset() {
// 省略
},
// 以下追加
// ゲーム結果の表示
setGameResult() {
if (this.playerPoint > this.comPoint) {
this.gameResult = "勝ち"
} else if (this.playerPoint < this.comPoint) {
this.gameResult = "負け"
} else {
this.gameResult = "引き分け"
}
}
}
PlayerとComの点数を比べて勝ち or 負け or 引き分けをgameResult
に代入しています。
これをbattle
のあとにphase
が7なら呼び出します。
// ○手目をクリック
bet() {
// 省略
if (this.phase < 7) {
this.phase++
} else {
this.setGameResult() // 追加
}
},
これで終了時にゲーム結果が表示されるようになります。
対決可能な条件
ゲーム自体はほぼ完成しました。
ただいくつかバグがあるので手を加えていきます。
現状では○手目をクリックすると必ずbet
が動いてしまいます。
ゲーム終了後と駒が未選択の時は処理が行われないようにしなければなりません。
このためにdata()
にあるcanBattle
で制御していきます。
bet
の最初でcanBattle
がfalseならその後の処理に進まないようにreturnさせます。
// ○手目をクリック
bet() {
// 対決不可なら処理をしない
if (!this.canBattle) {
return
}
// comの駒をランダムに決める
// 省略
},
そして必要な箇所でcanBattle
を切り替えていきます。
trueにするのはPlayerが駒を選択したときです。
// playerが駒を選択
select(komaIndex) {
if (this.playerSelectable.includes(komaIndex)) {
this.playerSelectingKoma = komaIndex
this.canBattle = true // 追加
}
},
そしてbet
が実行されると決まった直後にfalseにすれば、再び駒が選択されるまでは処理されません。
// ○手目をクリック
bet() {
// 対決不可なら処理をしない
if (!this.canBattle) {
return
}
this.canBattle = false // 追加
// 省略
},
これで対決の制御ができてバグがなくなりました。
最後に体裁を整えるためにPlayerが駒を選択したら、Comが前に選んでいた駒の非表示にします。
// playerが駒を選択
select(komaIndex) {
if (this.playerSelectable.includes(komaIndex)) {
this.playerSelectingKoma = komaIndex
this.canBattle = true
this.comSelectingKoma = null // 追加
}
},
これで全て完成しました。
Vueでの開発のイメージがついてもらえたら幸いです。
ここまでのコードはこちらにあります。
番外編 としてこのゲームの最高点を取る方法を考えたのでこちらもご覧ください。