はじめに
この記事は初心者の個人的解釈多めな備忘録です。
よって事実と誤っている場合も多々ある可能性がございます。
ご容赦いただけますと幸いです。
今回はJavascriptでクイズゲームを作って学習します。
基礎編と同じ投稿者の方に引き続きお世話になります。
参考動画
https://www.youtube.com/watch?v=fAluwAmHrws
1.設計フェーズ
作る前にどんな機能を付けるのか等をあらかじめ決めておく
画面設計図
アプリケーションのフロントエンド(見た目)の設計図
適当に調べたサイトで作成してみた
http://framebox.org/AuICw
せっかくなんでfigmaでも再作成
Copilotくんに助けてもらいながら作りました
この画面のように問題文が表示されるのでボタン(選択肢)を押して回答するという流れです。

フローチャート
プログラムのロジックと処理の流れを示した図
※4のように分岐がある場合はひし形にする。
frameboxだとひし形が作れなかったのでやっぱりfigmaで作り直しました。
2.クイズゲームを作る(基礎)
html&css と jsファイルを用意
・備忘録1のようにBoilerplateとBootstrapからひな形を探して作成。
・作業フォルダにファイルを作成する。
index.html
app.js
・htmlとjsを紐づける。
<!doctype html>
<html lang="">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title></title>
<link
href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css"
rel="stylesheet" integrity="sha384-9ndCyUaIbzAi2FUVXJi0CjmCapSmO7SnpJef0486qhLnuZ2cdeRhO02iuK6FUUVM" crossorigin="anonymous"
>
<meta name="description" content="">
<meta property="og:title" content="">
<meta property="og:type" content="">
<meta property="og:url" content="">
<meta property="og:image" content="">
<meta property="og:image:alt" content="">
<!-- <link rel="icon" href="/favicon.ico" sizes="any">
<link rel="icon" href="/icon.svg" type="image/svg+xml">
<link rel="apple-touch-icon" href="icon.png">
<link rel="manifest" href="site.webmanifest"> -->
<meta name="theme-color" content="#fafafa">
</head>
<body>
<div class="container"><!--枠組み Webサイトを画面にフィットして表示させる container-->
<div class="mt-3 alert alert-primary" role="alert">
A simple primary alert—check it out!
</div>
<div class="d-flex justify-content-center">
<button type="button" class="btn btn-primary">Primary</button>
<button type="button" class="ms-1 btn btn-secondary">Secondary</button>
<button type="button" class="ms-1 btn btn-success">Success</button>
<button type="button" class="ms-1 btn btn-danger">Danger</button>
</div>
</div>
<script src="app.js"></script> <!--app.jsを読み込む-->
</body>
</html>
Javascriptを書く
まずは一問だけクイズを実行できるようにする
変数・定数を定義する
const question = 'ドラゴンボール原作で二番目に強いとされるキャラクターは誰?';
const answers =[
'魔人ブウ(孫悟飯吸収)',
'魔人ブウ(ゴテンクス吸収)',
'孫悟空(超サイヤ人3)',
'ベジータ(魔人化)']
const correct ='魔人ブウ(孫悟飯吸収)'; //正解
問題文を表示したい
アラート部分に問題文を入れたいので、情報を取得したい。
console.log(document.getElementsByTagName('div')); //問題文をアラート表示させたいのでタグネームを探す でも他にもdivタグはある
Id属性というものをhtmlタグに振ることができるため、
アラート文にIdを付与して、GetElementByIdを使う
Id名は被らないものを作成する。
<div id="js-question" class="mt-3 alert alert-primary" role="alert">
A simple primary alert—check it out!
</div>
console.log(document.getElementById('js-question')); //Idを探す Id属性をHTMLタグに振ることができる。
これはオブジェクト扱いなので、いろいろ関数やプロパティを取得できる。
console.log(document.getElementById('js-question').textContent);
textcontentを書き換える。
これは変数を後から書き換えている。
document.getElementById('js-question').textContent = question;
選択肢を表示したい
document.getElementById('js-question').textContent = question; //問題文をアラートに入れる。
document.getElementsByTagName('Button')[0].textContent = answers[0];//一つ目のボタンを一つ目の選択肢に割り当てる。
document.getElementsByTagName('Button')[1].textContent = answers[1];
document.getElementsByTagName('Button')[2].textContent = answers[2];
document.getElementsByTagName('Button')[3].textContent = answers[3];
一つ目のボタンに正解・不正解を表示させる
addEventlisnerでボタンをクリックしたときに関数を実行させる。
関数の中身はIf文でボタンのテキスト内容を正誤判定する。
正解・不正解をWindowオブジェクトのアラート関数で表示させる。
//定数の文字列をHTMLに反映させる
document.getElementById('js-question').textContent = question; //問題文をアラートの内容を書き換えて表示する。
document.getElementsByTagName('Button')[0].textContent = answers[0];//一つ目のボタンを一つ目の選択肢に割り当てる。
document.getElementsByTagName('Button')[1].textContent = answers[1];
document.getElementsByTagName('Button')[2].textContent = answers[2];
document.getElementsByTagName('Button')[3].textContent = answers[3];
//ボタンをクリックしたら正誤判定する
document.getElementsByTagName('Button')[0].addEventListener('click', () => {
if(correct === document.getElementsByTagName('Button')[0].textContent){//文字列の一致を判定するときは === を使う
window.alert('正解!');//windowオブジェクトのアラート関数を呼び出し
}
else{
window.alert('不正解!');
}
});
何度も使う箇所を定数を使ってまとめる。
const button = document.getElementsByTagName('Button')
を宣言することによって、それ以降のボタンタグに関する記述量を減らせる。
また定数でHTMLのオブジェクトをとってくる場合、
頭に$を付けておくと、他の変数・定数たちと区別がつきやすい。
//定数の文字列をHTMLに反映させる
document.getElementById('js-question').textContent = question; //問題文をアラートの内容を書き換えて表示する。
const $button = document.getElementsByTagName('Button')//ボタンタグを省略するため宣言, htmlのオブジェクトをとってくる変数定数の場合$を入れて見分けやすくする。
$button[0].textContent = answers[0];//一つ目のボタンを一つ目の選択肢に割り当てる。
$button[1].textContent = answers[1];
$button[2].textContent = answers[2];
$button[3].textContent = answers[3];
//ボタンをクリックしたら正誤判定する
$button[0].addEventListener('click', () => {
if(correct === $button[0].textContent){//文字列の一致を判定するときは === を使う
window.alert('正解!');//windowオブジェクトのアラート関数を呼び出し
}
else{
window.alert('不正解!');
}
});
ボタン4つ分の正誤判定を作成
イベントリスナーを4つ分コピーして
4ボタンで正誤判定をできるようにする。
//定数で問題文、選択肢、答えを宣言
const question = 'ドラゴンボール原作で二番目に強いとされるキャラクターは誰?';
const answers =[
'魔人ブウ(孫悟飯吸収)',
'魔人ブウ(ゴテンクス吸収)',
'孫悟空(超サイヤ人3)',
'ベジータ(魔人化)']
const correct ='魔人ブウ(孫悟飯吸収)'; //答え
//console.log(document.getElementsByTagName('div')); //問題文をアラート表示させたいのでタグネームを探す でも他にもdivタグはある
//console.log(document.getElementById('js-question')); //Idを探す Id属性をHTMLタグに振ることができる。
//console.log(document.getElementById('js-question').textContent); //このHTMLタグが持っているテキスト情報を取得
//定数の文字列をHTMLに反映させる
document.getElementById('js-question').textContent = question; //問題文をアラートの内容を書き換えて表示する。
const $button = document.getElementsByTagName('button')//ボタンタグを省略するため宣言, htmlのオブジェクトをとってくる変数定数の場合$を入れて見分けやすくする。
$button[0].textContent = answers[0];//一つ目のボタンを一つ目の選択肢に割り当てる。
$button[1].textContent = answers[1];
$button[2].textContent = answers[2];
$button[3].textContent = answers[3];
//ボタンをクリックしたら正誤判定する
$button[0].addEventListener('click', () => {
if(correct === $button[0].textContent){//文字列の一致を判定するときは === を使う
window.alert('正解!');//windowオブジェクトのアラート関数を呼び出し
}
else{
window.alert('不正解!');
}
});
$button[1].addEventListener('click', () => {
if(correct === $button[1].textContent){
window.alert('正解!');
}
else{
window.alert('不正解!');
}
});
$button[2].addEventListener('click', () => {
if(correct === $button[2].textContent){
window.alert('正解!');
}
else{
window.alert('不正解!');
}
});
$button[3].addEventListener('click', () => {
if(correct === $button[3].textContent){
window.alert('正解!');
}
else{
window.alert('不正解!');
}
});
3.リファクタリング
プログラムの動作を変えずに内部構造を整理・改善すること。
このままだとかなり冗長なコードになってしまい、構造が複雑になってしまう(スパゲッティコード)
思わぬエラーが多発する可能性があるので、整理する。
選択肢割り当ての繰り返しをまとめる(while文)
まず、buttonオブジェクトのテキストをanswersのテキストに上書きする命令を整理。
命令を繰り返すときはwhile文を使って書き換える。
const $button = document.getElementsByTagName('button'); //ボタンタグを省略するため宣言, htmlのオブジェクトをとってくる変数定数の場合$を入れて見分けやすくする。
//変更前
// $button[0].textContent = answers[0]; //一つ目のボタンを一つ目の回答に割り当てる。
// $button[1].textContent = answers[1];
// $button[2].textContent = answers[2];
// $button[3].textContent = answers[3];
//変更後
let buttonIndex = 0; //while文を行うごとに加算する値 変数
let buttonlength = $button.length //ボタンの配列数を取得
while(buttonIndex < buttonlength){ //
//ここに命令
$button[buttonIndex].textContent = answers[buttonIndex];
buttonIndex++; //indexの値を1加算
}
一連の命令を関数にする
定数 $buttonを参照する命令文があるため、
$buttonは関数の上に宣言される形にしておく。
//定数の文字列をHTMLに反映させる
//ボタンオブジェクト取得を省略するため宣言
const $button = document.getElementsByTagName('button'); htmlのオブジェクトをとってくる変数定数の場合$を入れて見分けやすくする。
//クイズの問題文、選択肢を定義
const setupQuiz = () => {
document.getElementById('js-question').textContent = question; //問題文をアラートの内容を書き換えて表示する。
let buttonIndex = 0; //while文を行うごとに加算する値 変数
let buttonlength = $button.length //ボタンの配列数を取得
while(buttonIndex < buttonlength){ //
//ここに命令
$button[buttonIndex].textContent = answers[buttonIndex];
buttonIndex++; //indexの値を1加算
}
}
setupQuiz();//関数呼び出し
正誤判定の繰り返しをまとめる(イベントオブジェクト、関数、if/while文)
次にボタンの正誤判定をする箇所の整理
クリックされた要素に対して、何かしたいときはe.targetに置き換えて書くことができる。
eとはイベントオブジェクトのこと。
イベントオブジェクトは、クリックやキー入力などのイベントが発生したときに自動的に渡される特別な情報のかたまりのこと。
コンソールのtargetを見ると、今クリックされた箇所が分かる。
$button[0].addEventListener('click', (e) => {
console.log(e);
});
// $button[0].addEventListener('click', () => {
// if(correct === $button[0].textContent){ //文字列の一致を判定するときは === を使う
// window.alert('正解!'); //windowオブジェクトのアラート関数を呼び出し
// }
// else{
// window.alert('不正解!');
// }
// });
// $button[1].addEventListener('click', () => {
// if(correct === $button[1].textContent){
// window.alert('正解!');
// }
// else{
// window.alert('不正解!');
// }
// });
// $button[2].addEventListener('click', () => {
// if(correct === $button[2].textContent){
// window.alert('正解!');
// }
// else{
// window.alert('不正解!');
// }
// });
// $button[3].addEventListener('click', () => {
// if(correct === $button[3].textContent){
// window.alert('正解!');
// }
// else{
// window.alert('不正解!');
// }
// });
$button[0].addEventListener('click', (e) => {
if(correct === e.target.textContent){ //文字列の一致を判定するときは === を使う
window.alert('正解!'); //windowオブジェクトのアラート関数を呼び出し
}
else{
window.alert('不正解!');
}
});
$button[1].addEventListener('click', () => {
if(correct === e.target.textContent){
window.alert('正解!');
}
else{
window.alert('不正解!');
}
});
$button[2].addEventListener('click', () => {
if(correct === e.target.textContent){
window.alert('正解!');
}
else{
window.alert('不正解!');
}
});
$button[3].addEventListener('click', () => {
if(correct === e.target.textContent){
window.alert('正解!');
}
else{
window.alert('不正解!');
}
});
関数でif文をまとめる
//ボタンをクリックしたら正誤判定する
const clickHandler = (e) => {
if(correct === e.target.textContent){ //文字列の一致を判定するときは === を使う
window.alert('正解!'); //windowオブジェクトのアラート関数を呼び出し
}
else{
window.alert('不正解!');
}
};
$button[0].addEventListener('click', (e) => {
clickHandler(e);
});
$button[1].addEventListener('click', (e) => {
clickHandler(e);
});
$button[2].addEventListener('click', (e) => {
clickHandler(e);
});
$button[3].addEventListener('click', (e) => {
clickHandler(e);
});
さらに繰り返し箇所をwhile文でまとめる。
//ボタンをクリックしたら正誤判定する
const clickHandler = (e) => {
if(correct === e.target.textContent){ //文字列の一致を判定するときは === を使う
window.alert('正解!'); //windowオブジェクトのアラート関数を呼び出し
}
else{
window.alert('不正解!');
}
};
let handlerIndex = 0;
const buttonLength = $button.length;
while(handlerIndex < buttonLength){
$button[handlerIndex].addEventListener('click', (e) => {
clickHandler(e);
});
handlerIndex++;
};
while文で使用するbuttonLengthが2つ存在してるので、一つにまとめて終わり。
//定数で問題文、選択肢、答えを宣言
const question = 'ドラゴンボール原作で二番目に強いとされるキャラクターは誰?';
const answers =[
'魔人ブウ(孫悟飯吸収)',
'魔人ブウ(ゴテンクス吸収)',
'孫悟空(超サイヤ人3)',
'ベジータ(魔人化)']
const correct ='魔人ブウ(孫悟飯吸収)';
//定数の文字列をHTMLに反映させる
//ボタンオブジェクト取得を省略するため宣言,
//htmlのオブジェクトをとってくる変数定数の場合$を入れて見分けやすくする。
const $button = document.getElementsByTagName('button');
//while文で使用するボタン配列の長さ
const buttonLength = $button.length;
//クイズの問題文、選択肢を定義
const setupQuiz = () => {
//アラートを書き換えて問題文を表示する。
document.getElementById('js-question').textContent = question;
//ボタンテキストを書き替え
//while文を行うごとに加算する値 変数
let buttonIndex = 0;
while(buttonIndex < buttonLength){ //
//ここに命令
$button[buttonIndex].textContent = answers[buttonIndex];
//indexの値を1加算
buttonIndex++;
}
}
//関数呼び出し
setupQuiz();
//ボタンをクリックしたら正誤判定する
//e.targetの内容を正誤判定する関数
const clickHandler = (e) => {
//文字列の一致を判定するときは === を使う
if(correct === e.target.textContent){
//windowオブジェクトのアラート関数を呼び出し
window.alert('正解!');
}
else{
window.alert('不正解!');
}
};
//button0~3までをクリックしたとき、イベントオブジェクトeを関数に渡す。
let handlerIndex = 0;
while(handlerIndex < buttonLength){
$button[handlerIndex].addEventListener('click', (e) => {
clickHandler(e);
});
handlerIndex++;
};
4.クイズゲームを作る(応用)
クイズ一問分の挙動が完成したので、3問に増やしていきます。
クイズ複数問のオブジェクトを一つの配列にまとめる。
//定数で問題文、選択肢、答えを3問分宣言
const quiz = [
{
question: 'ドラゴンボール原作で二番目に強いとされるキャラクターは誰?',
answers: [
'魔人ブウ(孫悟飯吸収)',
'魔人ブウ(ゴテンクス吸収)',
'孫悟空(超サイヤ人3)',
'ベジータ(魔人化)'],
correct: '魔人ブウ(孫悟飯吸収)' //答え
},
{
question: 'ドラゴンボールナメック星編でフリーザにとどめを刺したのは誰?',
answers: [
'ベジータ',
'孫悟空',
'トランクス',
'クリリン'],
correct: '孫悟空'
},
{
question: 'ドラゴンボール原作で単体最強とされるキャラクターは誰?',
answers: [
'孫悟飯(アルティメット)',
'ベジット',
'孫悟空(超サイヤ人3)',
'ベジータ(魔人化)'],
correct: '孫悟飯(アルティメット)'
}
]
//後々while文で使う
const quizLength = quiz.length;
let quizIndex = 0;
クイズ内容を次の問題に更新させる
setupQuiz関数とclickHandler関数を変更。
次の問題がある場合
clickHandlerでは、
選択肢ボタンをクリックするとquizIndexを加算し、setupQuizを実行。
setupQuizでは、
quiz[quizIndex]からオブジェクトを取得し、問題文、選択肢、答えの内容を次の問題へ更新する。
次の問題がない場合
clickHandlerのelse文で終了アラートを実行。
const setupQuiz = () => {
console.log('現在の問題番号:', quizIndex);
//アラートを書き換えて問題文を表示する。
document.getElementById('js-question').textContent = quiz[quizIndex].question;
//ボタンテキストを書き替え
//while文を行うごとに加算する値 変数
let buttonIndex = 0;
while(buttonIndex < buttonLength){ //
//ここに命令
$button[buttonIndex].textContent = quiz[quizIndex].answers[buttonIndex];
//indexの値を1加算
buttonIndex++;
}
}
setupQuiz();//関数呼び出し
//ボタンをクリックしたら正誤判定する
//e.targetの内容を正誤判定する関数
const clickHandler = (e) => {
//文字列の一致を判定するときは === を使う
if(quiz[quizIndex].correct === e.target.textContent){
//windowオブジェクトのアラート関数を呼び出し
window.alert('正解!');
}
else{
window.alert('不正解!');
}
quizIndex++;
if(quizIndex < quizLength){
//問題数がまだあればこちらを実行
setupQuiz();
}
else{
//問題数がもうなければこちらを実行
window.alert('終了!');
}
};
一問目を回答すると...

問題が変わった

最後の問題に回答すると終了アラートが出た。

5.結果画面を作る
最後にクイズの結果画面を作ります。
変数スコアを追加し、正解したらscoreを加算します。
問題が終わったら、score/quizLength(正答率)をアラート表示します。
let score = 0;
const clickHandler = (e) => {
//文字列の一致を判定するときは === を使う
if(quiz[quizIndex].correct === e.target.textContent){
//windowオブジェクトのアラート関数を呼び出し
window.alert('正解!');
//正解したらスコアを足してあげる。
score++;
}
else{
window.alert('不正解!');
}
quizIndex++;
if(quizIndex < quizLength){
//問題数がまだあればこちらを実行
setupQuiz();
}
else{
//問題数がもうなければこちらを実行
window.alert('終了!あなたの正解数は' + score + '/' + quizLength + 'です!');
}
};
//定数で問題文、選択肢、答えを3問分宣言
const quiz = [
{
question: 'ドラゴンボール原作で二番目に強いとされるキャラクターは誰?',
answers: [
'魔人ブウ(孫悟飯吸収)',
'魔人ブウ(ゴテンクス吸収)',
'孫悟空(超サイヤ人3)',
'ベジータ(魔人化)'],
correct: '魔人ブウ(孫悟飯吸収)' //答え
},
{
question: 'ドラゴンボールナメック星編でフリーザにとどめを刺したのは誰?',
answers: [
'ベジータ',
'孫悟空',
'トランクス',
'クリリン'],
correct: '孫悟空'
},
{
question: 'ドラゴンボール原作で単体最強とされるキャラクターは誰?',
answers: [
'孫悟飯(アルティメット)',
'ベジット',
'孫悟空(超サイヤ人3)',
'ベジータ(魔人化)'],
correct: '孫悟飯(アルティメット)'
}
]
//後々while文で使う
const quizLength = quiz.length;
let quizIndex = 0;
//クイズの正解数
let score = 0;
//ボタンオブジェクト取得を省略するため宣言,
//htmlのオブジェクトをとってくる変数定数の場合$を入れて見分けやすくする。
const $button = document.getElementsByTagName('button');
//while文で使用するボタン配列の長さ
const buttonLength = $button.length;
//クイズの問題文、選択肢を定義
const setupQuiz = () => {
console.log('現在の問題番号:', quizIndex);
//アラートを書き換えて問題文を表示する。
document.getElementById('js-question').textContent = quiz[quizIndex].question;
//ボタンテキストを書き替え
//while文を行うごとに加算する値 変数
let buttonIndex = 0;
while(buttonIndex < buttonLength){ //
//ここに命令
$button[buttonIndex].textContent = quiz[quizIndex].answers[buttonIndex];
//indexの値を1加算
buttonIndex++;
}
}
setupQuiz();//関数呼び出し
//ボタンをクリックしたら正誤判定する
//e.targetの内容を正誤判定する関数
const clickHandler = (e) => {
//文字列の一致を判定するときは === を使う
if(quiz[quizIndex].correct === e.target.textContent){
//windowオブジェクトのアラート関数を呼び出し
window.alert('正解!');
//正解したらスコアを足してあげる。
score++;
}
else{
window.alert('不正解!');
}
quizIndex++;
if(quizIndex < quizLength){
//問題数がまだあればこちらを実行
setupQuiz();
}
else{
//問題数がもうなければこちらを実行
window.alert('終了!あなたの正解数は' + score + '/' + quizLength + 'です!');
}
};
//button0~3までをクリックしたとき、イベントオブジェクトeを関数に渡す。
let handlerIndex = 0;
while(handlerIndex < buttonLength){
$button[handlerIndex].addEventListener('click', (e) => {
clickHandler(e);
});
handlerIndex++;
};
ここまでで終了!
メモ
ここから拡張してみることで、もっと学習になりそう。
適当に思いついたことメモ
問題数を増やす。
クイズ配列の順番をランダムにする。
結果画面を別のページで表示する。
クイズ終了後最初の問題に戻る。
その日のスコアランキングを作る。
ページが増えるとhtmlもjsファイルも増えそう。
jsファイル間での変数、定数のやりとりするのかも。
スコアランキングにはデータベースとかが必要かも。
あとは実際にインターネット上のサイトとしてアップロードしてみたり...?聞いたことはあるAWSをやってみる?










