
九保すこひです(フリーランスのITコンサルタント、エンジニア)
さてさて、Vueを使うと簡単に高機能なことを実現することができますが、これは通常のウェブサイトだけに使えるわけではなく、応用すればちょっとしたゲーム開発にも利用することができます。
例えば、以前公開した意外と簡単!VueJSで反射神経ゲームをつくってみよう(ダウンロード可)のようにすればリアルタイムで変化するゲームを作れますし、初心者向き!VueJS で3択クイズゲームをつくってみようのようなテレビ番組のようなシステムもつくることができます。
そこで!
今回はVueを使って簡単なタイピングゲームのつくりかたを紹介します。
最後にソースコードをダウンロードできますので、ぜひ学習に役立ててくださいね。
※ 開発環境: Vue 2.5
目次 [非表示]
やりたいこと
- 表示されたテキストをタイプしていく
- 正解するまで次の問題にはいけない
- 問題は10問で、ランダムに出題される
レイアウトをつくる
まず今回必要になるのは大きく分けて以下の2ブロックです。
- ゲーム開始前に表示する部分 ・・・ スタートボタン
- ゲーム中に表示する部分 ・・・ タイピング
なお、せっかく作るのでタイピングがうまくいっていれば、good.png
、タイピングにミスがあればbad.png
という画像を切り替え表示するようにします。
では実際のレイアウトです。
<html>
<head>
<link href="https://stackpath.bootstrapcdn.com/bootstrap/4.1.3/css/bootstrap.min.css" rel="stylesheet">
</head>
<body>
<div id="app" class="text-center">
<!-- ゲーム中に表示する部分 -->
<div>
<div class="row">
<div class="col-12">
<!-- タイピング内容で画像を切り替え -->
<img src="/images/good.png">
<img src="/images/bad.png">
</div>
</div>
<div class="badge badge-dark" style="margin:15px 0;">第1問</div>
<h1>ここに問題</h1>
<div class="row">
<div class="offset-4 col-4">
<input id="input-typing" type="text" class="form-control">
</div>
</div>
<br>
<div class="row">
<div class="col-12">
<button type="button" class="btn btn-light btn-lg">やり直す</button>
</div>
</div>
</div>
<!-- ゲーム開始前に表示する部分 -->
<div style="padding:15px;">
<button type="button" class="btn btn-danger btn-lg">タイピングをスタート</button>
</div>
</div>
</body>
</html>
まず、きれいなボタンや入力ボックスを使いたいので<head>〜</head>
内でbootstrap
をcdn
で呼び出しています。
そして、ゲーム中と開始前の2ブロックがあり、ゲーム中にはタイピング内容によって切り替わる2枚の画像、出題テキスト、入力ボックス、そしてやり直しボタンを用意します。
また、ゲーム開始前の部分はスタートボタンだけを表示します。
では、このレイアウトでJavaScript部分をつくっていきましょう。
JavaScript(Vue)部分をつくっていく
Vueがつかえるようにする
ではVue.jsが使えるように設定しましょう。
bootstrap
と同じくcdn
でVueを読み込みVueの基本形をつくります。
<script src="https://cdn.jsdelivr.net/npm/vue@2.5.17/dist/vue.min.js"></script>
<script>
new Vue({
el: '#app'
})
</script>
2ブロックの切り替えができるようにする
では続いて先ほど書いた以下2ブロックの表示切り替えができるようにしましょう。
- ゲーム開始前
- ゲーム中
data
に変数trying
を追加し、v-if
を使って表示切り替えをするようにします。
new Vue({
el: '#app',
data: {
trying: false
}
})
<!-- ゲーム中に表示する部分 -->
<div v-if="trying">
<!-- 省略 -->
</div>
<!-- ゲーム開始前に表示する部分 -->
<div style="padding:15px;" v-if="!trying">
<!-- 省略 -->
</div>
つまり、trying
がtrue
の場合はゲーム中ということになります。
初期状態ではtrying
はfalse
のため、現在ページを表示すると以下のようにスタートボタンだけが表示されることになります。
スタートボタンをクリックしたときの処理を実行する
では、スタートボタンがクリックされたときのコードを作っていきましょう。
まずボタンにクリックイベントを設定し、start()
が実行されるようにします。
<button type="button" class="btn btn-danger btn-lg" @click="start()">タイピングをスタート</button>
start()
の中身はこうなります。
methods: {
start() {
this.trying = true
Vue.nextTick(() => {
document.getElementById('input-typing').focus()
})
}
}
中身は、先ほど設定したtrying
をtrue
(表示をゲーム中のブロックに切り替える)へ変更し、さらに、すぐ入力できるように<input>
へフォーカスを移動しています。
※ Vue.nextTick()
を使っているのは、表示切り替えが完了した後でないとフォーカスを移動できないからです。
問題を表示する部分をつくる
では、実際にタイピングすべき問題(単語)を登録し、ランダムで表示できるようにしてみましょう。
まずdata
変数words
に出題する問題を登録し、さらに出題が重複しないよう回答済みの単語を保持するsolvedWords
も登録します。
data: {
// 省略
words: [
'egg',
'bag',
'rose',
'chair',
'bat',
'fish',
'notebook',
'pencil',
'dog',
'desk'
],
solvedWords: []
},
では、次にwords
の中からランダムに単語を取り出す疑似変数currentWord
をcomputed
につくります。
currentWord() {
const unsolvedWords = this.words.filter((word) => {
return (!this.solvedWords.includes(word)) // 解答されてないものだけ
})
const randomIndex = Math.floor(Math.random()*unsolvedWords.length)
return unsolvedWords[randomIndex]
},
内容としては、filter()
で解答されていない単語だけを取得し、その中からランダムにひとつだけ単語を取得しています。
では、このランダムに取得できる単語を表示できるようにしてみましょう。
<h1 v-text="currentWord"></h1>
実際に表示してみるとこうなります。(問題はランダムに表示されます)
なお、変数solvedWords
はゲーム開始時にクリアするようにしておきましょう。
start() {
this.trying = true
this.solvedWords = []
Vue.nextTick(() => {
document.getElementById('input-typing').focus()
})
}
問題番号を表示する部分をつくる
では、今が何問目かがわかるように「第●問」が自動的に切り替わるようにしましょう。
まずは現在の問題番号を返す疑似変数currentWordNumber
をcomputed
へ追加します。
computed: {
// 省略
currentWordNumber() {
return this.solvedWords.length + 1
}
}
そして、次のようにバインディングしましょう。
<div class="badge badge-dark" style="margin:15px 0;">第{{ currentWordNumber }}問</div>
これで、変数solvedWords
の内容が変化したら、自動的に「第●問」も変化するようになります。
タイピングする部分をつくる
では、今回一番メインになる部分のタイピング部分を作っていきます。
まずは、data
変数に現在タイピングしている内容が入ってくるtypingText
を追加します。
data: {
// 省略
typingText: '',
// 省略
},
そして、このtypingText
を入力ボックスにバインディングします。
<input id="input-typing" type="text" class="form-control" v-model="typingText">
これで、入力内容が変化すると自動的にtypingText
も変化するようになりました。
では、このタイピング内容が正しいかどうかをチェックし、正しければgood.png
、間違っていればbad.png
を表示切り替えするコードを作っていきましょう。
まずcomputed
へ疑似変数isTypingCorrect
をつくります。
computed: {
// 省略
isTypingCorrect() {
const typingTextLength = this.typingText.length
return (this.typingText === this.currentWord.slice(0, typingTextLength))
}
}
中身としては、タイピングしている内容と出題された内容(の一部)が同じであればtrue
、そうでなければfalse
を返すようにしています。
実際に実行すると(タイピングにミスがある場合)、次のように画像が切り替わるようになりました。
正解したら問題が変わるようにする
では、タイピングが正解していたら、次の出題に移るようにします。
先ほど作成したisTypingCorrect()
内に次のようなコードを追加します。
isTypingCorrect() {
if(this.typingText == this.currentWord) {
this.solvedWords.push(this.currentWord)
this.typingText = ''
if(this.words.length == this.solvedWords.length) {
this.solvedWords = []
this.trying = false
alert('全問正解!')
}
return true
}
// 省略
}
まず、タイピング内容が正解しているかチェックし、もし正解なら回答済みの単語が入る変数solvedWords
にその単語を追加。そして、タイピング内容を空白にします。
さらに、words
とsolvedWords
の中身の数を比較し、同じなら(つまり全問解答したら)アラートで「全問正解!」と表示するようにします。
また、どちらにしてもタイピング内容は間違っていないのでreturn
はtrue
になります。
やり直すボタンをつくる
最後にゲームを最初からやり直すためのボタンをつくりましょう。
といっても、ボタンにクリックイベントをつけstart()
が実行されるようにするだけです。
<button type="button" class="btn btn-light btn-lg" @click="start()">やり直す</button>
これで完成です!
デモを用意しました
今回のタイピングゲームを実際にタイピングしていただくためにデモページを用意しました。ぜひ楽しんでみてください。
※ ただし、ES6を使ってコードを書いているのでIEは動きません。(みなさん、IEはそろそろやめましょうM_ _M(開発者としての切なる願い…))
教材ソースコードをダウンロードできます
今回実際に開発したソースコードを以下からダウンロードすることができます。CSS
, JavaScript
ともにcdn
から呼び出しているので展開してすぐ実行することができます。
※ ただし、画像はご自身で用意してください。
おわりに
ということで、今回はVueで簡単なタイピングゲームを作ってみました。
現在はブラウザも高速ですし、PCのスペックも高いのでこういったブラウザのゲームでもサクサク動いてくれるのではないでしょうか。(現在はだいぶ改善されましたが、jQueryでがそれほど高速実行できなかったのも原因のひとつかもしれません)
また、今回は基本構造だけだったのであまり装飾部分のコードは書いていませんが、出題されているテキストの一部分の色を変えて、今タイピングしている場所がよくわかるようにするのも面白いかもしれませんし、出題数をたくさん増やして制限時間内に何問タイプできるか??というルールに変えてもいいかもしれません。
ぜひみなさんもオリジナルの改造をやってみてくださいね。
ではでは〜♪