😸

無心でやる遊びを作る(Web アプリ)

2024/08/20に公開

目的

瞑想のよい噂を聞くものの、心を長時間無にするのは私には難しかったです。

インターネットを見ていると、必ずしも静止していないと効果がないわけでもなく、ウォーキング, 塗り絵などを勧めている方もいらっしゃいました。

そこで、そこへファーストステップとして、無心でできるゲームの様なものを考えました。瞑想から遠のいているような気もしますが。。。

技術スタック

HTML & javascriptだけ。

文字の読み上げ、キー入力受け入れを取り入れることにしました。

作成物概要

startボタンを押して開始すると、画面上に矢印が出て、音声でその方向を読み上げます(Left, Up, Down, Rightのどれか)。

ユーザは、それを聞いて、対応する矢印キーを押します。

すると、次へ進みます。対応したものを押しても押さなくても進みます。

規定時間でおしまい。

※現状実装できていませんが、正答率も最終的には出したい。

申し訳程度に問題数と正解数が表示&読み上げされます。

コード

リファクタリングしたのち再度公開予定です。

index.html
<!DOCTYPE html>
<html lang="ja">
 <head>
 <script src="script.js"></script>
 <style>
    #duration_min_input {
        font-size: 25px;
    }
 </style>
 </head>
 <body>
    <div style="font-size: 20px; margin: 5px" >音を聞くこと</div>
    <input type="text" id="duration_min_input" placeholder="5" style="font-size: 25px;"><span id="unit_msg" style="font-size: 23px;"> minutes</span></input>
    <button onclick="start_game()" style="font-size: 25px;">start</button>
    <div style="margin-top: 20px; margin-bottom: 20px; font-size: 25px;" id="result"></div>
    <!-- <input type="number"> -->
    <div id="display" style="margin: 20%; font-size: 120px;"></div>    

</body>
</html>
script.js
const KEY_CODE_LEFT = "ArrowLeft"
const KEY_CODE_UP = "ArrowUp"
const KEY_CODE_DOWN = "ArrowDown"
const KEY_CODE_RIGHT = "ArrowRight"

const CHAR_LEFT = "←"
const CHAR_UP = "↑"
const CHAR_DOWN = "↓"
const CHAR_RIGHT = "→"

let key_codes = [KEY_CODE_LEFT, KEY_CODE_UP, KEY_CODE_DOWN, KEY_CODE_RIGHT];

class QuizController {
    constructor() {
        this.arrow = CHAR_LEFT;
        this.go_next = false;
        this.total = 0;
        this.correct_count = 0;

        this.key_code = KEY_CODE_LEFT
        this.up_call = new SpeechSynthesisUtterance("Up!")
        this.down_call = new SpeechSynthesisUtterance("Down!")
        this.left_call = new SpeechSynthesisUtterance("Left!")
        this.right_call = new SpeechSynthesisUtterance("Right!")
        this._voice_over_arrow();
    }

    get_arrow() {
        return this.arrow;
    }

    // TODO: 比較が正しくなるよう修正する
    answer(answer) {
        console.log(answer)
        console.log(this.key_code)
        if (answer == this.key_code) {
            this.correct_count += 1;
        }
        this.go_next = true;
    }

    show_score(){
        this.total-=1
        let result_msg = 'total: '+this.total+'/ correct: '+this.correct_count
        console.log(result_msg)
        let result_dom = document.getElementById('result');
        result_dom.innerText = result_msg;

        let score_msg = "問題数 " + this.total + "、正解数" + this.correct_count + " でした"
        let score_msg_ssuttr = new SpeechSynthesisUtterance(score_msg)
        speechSynthesis.speak(score_msg_ssuttr)
    }


    
    _get_random_arrow_string() {
        this.key_code = key_codes[Math.floor(Math.random() * 4)];
        if(this.key_code == KEY_CODE_LEFT) {
            return CHAR_LEFT
        } else if(this.key_code == KEY_CODE_UP) {
            return CHAR_UP
        } else if(this.key_code == KEY_CODE_DOWN) {
            return CHAR_DOWN
        } else if(this.key_code == KEY_CODE_RIGHT) {
            return CHAR_RIGHT
        }
    }

    _voice_over_arrow(){
        if(this.key_code == KEY_CODE_LEFT) {
            speechSynthesis.speak(this.left_call)
        } else if(this.key_code == KEY_CODE_UP) {
            speechSynthesis.speak(this.up_call)
        } else if(this.key_code == KEY_CODE_DOWN) {
            speechSynthesis.speak(this.down_call)
        } else if(this.key_code == KEY_CODE_RIGHT) {
            speechSynthesis.speak(this.right_call)
        }
    }

    update_arrow(element) {
        console.log('update is called')
        if (!this.go_next) {
            return;
        }
        this.arrow = this._get_random_arrow_string();
        element.innerText = this.arrow;
        this._voice_over_arrow();
        this.total += 1;
        this.go_next = false;
        return;
    }
    

}

let quiz_controller = new QuizController();

document.addEventListener('keydown', event => {
    quiz_controller.answer(event.key)
    // console.log(event);
});


function start_game() {
    let input_duration = document.getElementById('duration_min_input');
    let duration_min = parseFloat(input_duration.value);
    console.log(duration_min)


    var start_time = new Date()

    const end_time = start_time + (duration_min * 60 * 1000);
    console.log(end_time);
    
    let interval_id = setInterval(() => {
        // const current_time = Date.now();
    
        let arrow_display = document.getElementById('display');
        quiz_controller.update_arrow(arrow_display);
    },1000);

    setTimeout(function(){
        clearInterval(interval_id);
        console.log('Well done!');
        quiz_controller.show_score();
    }, duration_min * 60 * 1000);
}

感想

需要?

参考

JavaScriptによりブラウザで読み上げする (WEB SPEECH API)

addEventListenerについてのQA

Discussion