たった1ファイルだけ!Vueでタイピングゲームをつくる

さてさて、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>内でbootstrapcdnで呼び出しています。

そして、ゲーム中と開始前の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>

つまり、tryingtrueの場合はゲーム中ということになります。

初期状態ではtryingfalseのため、現在ページを表示すると以下のようにスタートボタンだけが表示されることになります。

スタートボタンをクリックしたときの処理を実行する

では、スタートボタンがクリックされたときのコードを作っていきましょう。
まずボタンにクリックイベントを設定し、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()

        })

    }
}

中身は、先ほど設定したtryingtrue(表示をゲーム中のブロックに切り替える)へ変更し、さらに、すぐ入力できるように<input>へフォーカスを移動しています。

Vue.nextTick()を使っているのは、表示切り替えが完了した後でないとフォーカスを移動できないからです。

問題を表示する部分をつくる

では、実際にタイピングすべき問題(単語)を登録し、ランダムで表示できるようにしてみましょう。

まずdata変数wordsに出題する問題を登録し、さらに出題が重複しないよう回答済みの単語を保持するsolvedWordsも登録します。

data: {

    // 省略

    words: [
        'egg',
        'bag',
        'rose',
        'chair',
        'bat',
        'fish',
        'notebook',
        'pencil',
        'dog',
        'desk'
    ],
    solvedWords: []
},

では、次にwordsの中からランダムに単語を取り出す疑似変数currentWordcomputedにつくります。

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()

    })

}

問題番号を表示する部分をつくる

では、今が何問目かがわかるように「第●問」が自動的に切り替わるようにしましょう。

まずは現在の問題番号を返す疑似変数currentWordNumbercomputedへ追加します。

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にその単語を追加。そして、タイピング内容を空白にします。

さらに、wordssolvedWordsの中身の数を比較し、同じなら(つまり全問解答したら)アラートで「全問正解!」と表示するようにします。

また、どちらにしてもタイピング内容は間違っていないのでreturntrueになります。

やり直すボタンをつくる

最後にゲームを最初からやり直すためのボタンをつくりましょう。
といっても、ボタンにクリックイベントをつけstart()が実行されるようにするだけです。

<button type="button" class="btn btn-light btn-lg" @click="start()">やり直す</button>

これで完成です!

デモを用意しました

今回のタイピングゲームを実際にタイピングしていただくためにデモページを用意しました。ぜひ楽しんでみてください。

※ ただし、ES6を使ってコードを書いているのでIEは動きません。(みなさん、IEはそろそろやめましょうM_ _M(開発者としての切なる願い…))

教材ソースコードをダウンロードできます

今回実際に開発したソースコードを以下からダウンロードすることができます。CSS, JavaScriptともにcdnから呼び出しているので展開してすぐ実行することができます。

Vueでタイピングゲーム

※ ただし、画像はご自身で用意してください。

おわりに

ということで、今回はVueで簡単なタイピングゲームを作ってみました。

現在はブラウザも高速ですし、PCのスペックも高いのでこういったブラウザのゲームでもサクサク動いてくれるのではないでしょうか。(現在はだいぶ改善されましたが、jQueryでがそれほど高速実行できなかったのも原因のひとつかもしれません)

また、今回は基本構造だけだったのであまり装飾部分のコードは書いていませんが、出題されているテキストの一部分の色を変えて、今タイピングしている場所がよくわかるようにするのも面白いかもしれませんし、出題数をたくさん増やして制限時間内に何問タイプできるか??というルールに変えてもいいかもしれません。

ぜひみなさんもオリジナルの改造をやってみてくださいね。

ではでは〜♪