はじめに
Reactを使って、選択肢に答えていくだけで自分にあったウォーゲームが見つけられるサイトアプリを制作しました。
Qiitaの規約に抵触しないよう極力宣伝や広告にならないよう注意して書いていきたいと思います!
そもそもウォーゲームって?
ウォーゲームは、皆さんおなじみの「人生ゲーム」をはじめとするボードゲームの一種です。
かいつまんで説明すると、名前通り「戦争や紛争をテーマにしたシミュレーションゲーム」となります。ミリタリー好きはもちろん、歴史好きな方とかも楽しめるかもしれません。
筆者の所属企業ではウォーゲームの制作や販売などをしているのですが、数が多いので筆者のような超素人でも関心を持てるような「初心者ウェルカムな雰囲気」を何とか醸し出せないかと考えていました。
そこで、Reactの勉強がてら自分にあったウォーゲームが見つけられるサイトアプリを制作しようと思い立ったのです。
選択肢ごとのポイントを加算する単純な仕組み
こういった選択肢で結果が変わるアプリやゲームって、選択した項目に沿ってルート分岐するみたいなものあるかと思います。
しかし悲しいかな、筆者のスキル不足でそんなルート分岐みたいな機能は実装できず(泣)、選択肢の内容・点数に応じた加算だけという単純な造りです。下記の型定義に則った jsonデータを作って、それを読み込むようにしています。
type quizType = {
quiz: string; // 質問内容
imgsrc?: string; // 質問内容の説明補佐を行うイメージ画像
// 選択肢1〜3の 項目名 と 点数
one: {
txt: string;
point: string;
};
two: {
txt: string;
point: string;
};
three: {
txt: string;
point: string;
}
}
ただし進んでいった選択肢の内容に応じて「ここでこんな質問が来るなら、さっきの選択肢は別のものを選んでいたなぁ」と思われるユーザーもいるかと思って、戻って回答し直せる仕組みにしています。
let countNum: number = 0; // 設問数カウンター
const oneBox: Array<string> = []; // 結果表示用のone数カウンター配列
const twoBox: Array<string> = []; // two数...
const threeBox: Array<string> = []; // three数...
/* for文:ボタンクリックイベント内の[splice]での上書き処理のために[設問数分を空セット(初期設定)]して[BtnActionFunc]関数に渡す */
for (let i = 0; i < resObj.length; i++) {
oneBox.push('');
twoBox.push('');
threeBox.push('');
}
/* 戻る・次へのボタンクリックイベントの関数 */
BtnActionFunc(
'#nextBtn',
'#backBtn',
'.contentView .firstContents',
rootEl,
countNum,
oneBox,
twoBox,
threeBox
);
// 設問関連
<div class='firstContents'>
<h2><span>設問:${i + 1}/${resObj.length}</span>${resEl.quiz}</h2>
<p class="thumbnails"><img src="${resEl.imgsrc}" alt="設問「${resEl.quiz}」を視覚的に表現した画像" /></p>
<ul>
<li><label htmlFor="one"><input id="one" type="radio" name="quizChoices" value="${resEl.one.point}" />${resEl.one.txt}</label></li>
<li><label htmlFor="two"><input id="two" type="radio" name="quizChoices" value="${resEl.two.point}" />${resEl.two.txt}</label></li>
<li><label htmlFor="three"><input id="three" type="radio" name="quizChoices" value="${resEl.three.point}" />${resEl.three.txt}</label></li>
</ul>
</div>
// ボタン関連
<div className="contentControler">
<ol>
<li><button id="backBtn" type="button">戻る</button></li>
<li><button id="nextBtn" type="button">次へ</button></li>
</ol>
</div>
この回答し直せる仕組みに結構時間がかかってしまいました。きっともっと美しくて効率的なコードがあるのでしょうね(白目)
実際はもっと大量のコードなのですが冗長になりすぎても読みづらいかと思い、一部のみを記載しております。
作ってみて
こういった個人開発的なアプリはあんまり使ってもらえないというお話を耳にしていたのですが、ウォーゲーム人口は一定数いらっしゃるお陰で、本当にありがたいことにSNSなどで話題にしてくださり、皆様に遊んでいただけました。
ウォーゲームソムリエのような機能と言ってくださる方もいて感動しました。(本当にそんな大したものではありませんので恥ずかしさも感じながら)
もちろん好意的な感想だけでなくネガティブなものも見かけましたが、実際に遊んでくださってそれを発信してくださっていること自体に感無量でした。ありがたい限りです。
ちなみに設問をはじめ、選択肢の内容や点数、結果に応じて表示されるウォーゲームに関しては、
所属企業のウォーゲーム歴の長いマネージャーに用意いただきました。
この場だけでお礼をお伝えします。ご協力ありがとうございました(←面と向かってお礼を言えよ)
なお結果表示に関しても、該当する点数に応じた解答用の jsonデータを読み込むようになっているのですが、マネージャー様は作っているうちに熱が入ったようで、なんと100件以上のjsonデータを用意してくださいました。
その結果、下記のような内容で点数ごとの条件分岐をしていくことに──。
// 上にもたくさん同じような条件分岐が...
else if (resultCounter === 274) {
AnswersFunc('サイトのドメイン/パス/jsons/answers/answer-00274.json');
// CreateParentElFunc:結果を表示するための機能
CreateParentElFunc(resultCounter);
}
else if ((resultCounter <= 273) && (resultCounter >= 272)) {
AnswersFunc('サイトのドメイン/パス/jsons/answers/answer-00272-00273.json');
CreateParentElFunc(resultCounter);
}
else if (resultCounter === 271) {
AnswersFunc('サイトのドメイン/パス/jsons/answers/answer-00271.json');
CreateParentElFunc(resultCounter);
}
// そして下にもたくさん同じような条件分岐が...
そもそも単純な加算式構造のせいでこんな事態になったのですが、この作業が結構骨が折れましたし、
全然スマートではないコードを見て自分の実力不足を(本当に)嫌というほど味わいました。
実際1700行もあります。あと、マネージャーも大変だったでしょうから申し訳なさもありますね。
く、悔しい(泣)。
悔しい経験を経て
この経験を経た上でアプリを改良するのではなく、
誰でも100点を取れて自己肯定感を爆アゲしてくれるかも?な毛色の違ったアプリを作りました。
間違った選択肢を選ぶと選択肢の文言が変化して正解に導いてくれるため100%正解できる機能です。
使い道?それがどこで何の役に立つ??ナニソレオイシイノ?
実際は、もう少し改良して小さい子ども向けの知育ゲームにできないかなぁ〜?とか考えています。
とはいえ、やっぱりモノづくりって楽しいですよね。
web界隈は技術の進歩・陳腐化が激しい業界でキャッチアップがしんどいときもありますが、
やっぱり自分はモノづくりが好きなんだなと、改めて認識させてくれる経験でした。
遊んでくださった方々、感想をつぶやいてくださった方々には本当に感謝しております。
あと、こんな拙い記事をここまで読んでくださった貴方様も、ありがとうございました!
もしウォーゲームやこのアプリに少しでも興味を持ってくださったら、
以下より少し遊んでみてください〜^^
おまけ
冒頭で少し触れた選択肢に応じてルートが分岐する的な仕組みって、今回ので言うと「設問ごとの現状点数を判断して違う設問内容を読み込んだり、回答選択肢の文字列を取得・判断して同じように違うものを読み込んだりしている」のでしょうか。
筆者のスキルと頭脳では想像もできない方法で実装されているのかもしれませんが、、、。