
【ゲーム】JavaScript:32 速読訓練ゲーム
「⚡️ 速読訓練ゲーム ⚡️」は、流れる文章を素早く読み取り、その内容に関するクイズに即答することで速読力を鍛えるWebゲームです。合計10ラウンドで得点と平均回答時間を競います。
遊び方・操作方法
- タイトル画面で「スタート 🚀」をクリック
- 画面中央の短文が右から左へスクロール
- 下部に表示される4択の選択肢から正しい答えを選ぶ(ボタンをクリック)
- 回答するとメッセージ欄に正誤と回答時間が表示され、次のラウンドへ
- 全10ラウンド終了後、スコアと平均回答時間を確認
ルール
- テキスト表示:各ラウンド、用意された長文が一定速度でスクロール
- 制限時間:スクロールが終わるまでに回答
- 回答方法:4択ボタンをクリック
- 得点:正解1点、不正解0点
- 終了条件:10ラウンド消化後に結果画面へ
🎮ゲームプレイ
以下のリンク先から実際にプレイできます。
32 速読訓練ゲーム
素材のダウンロード
以下のリンクから使用する素材をダウンロードできます。
speed_reading_title.png | speed_reading_bg.png |
---|---|
![]() | ![]() |
ゲーム画面イメージ

プログラム全文(speed_reading.html)
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>⚡️ 速読訓練ゲーム ⚡️</title>
<style>
/* ===== 全体背景設定 ===== */
body {
margin: 0; /* 余白リセット */
padding: 0;
font-family: 'Arial', sans-serif;
/* 背景画像を固定で表示 */
background: url('speed_reading_bg.png') no-repeat center center fixed;
background-size: cover;
}
/* ===== 中央のオーバーレイ共通スタイル ===== */
.overlay {
position: absolute;
top: 50%; left: 50%;
transform: translate(-50%, -50%); /* 中央配置 */
background-color: rgba(255,255,255,0.9); /* 半透明白 */
padding: 20px;
border-radius: 10px;
width: 90%; max-width: 600px;
text-align: center;
}
/* 非表示用クラス */
.hidden { display: none; }
/* ===== タイトル画面スタイル ===== */
.title-image {
display: block;
margin: 0 auto 10px;
max-width: 80%; height: auto;
}
.instructions {
text-align: left; /* 説明文は左寄せ */
margin-bottom: 10px;
}
.instructions p { margin: 5px 0; }
/* ===== ボタン共通スタイル ===== */
.btn {
padding: 10px 20px;
margin: 10px;
font-size: 16px;
font-weight: bold;
color: #fff;
background-color: #28a745;
border: none;
border-radius: 5px;
cursor: pointer;
box-shadow: 0 2px 4px rgba(0,0,0,0.2);
transition: background-color 0.2s, transform 0.1s;
}
.btn:hover { background-color: #218838; transform: translateY(-2px); }
.btn:active { transform: translateY(0); box-shadow: 0 1px 2px rgba(0,0,0,0.2); }
/* ===== スクロールテキストエリア ===== */
.scroll-container {
width: 100%; overflow: hidden;
border: 1px solid #333; background: #fff;
height: 50px; line-height: 50px;
margin: 20px 0;
position: relative;
}
.scroll-text {
position: absolute; top: 0;
white-space: nowrap; will-change: transform;
}
/* ===== クイズ選択肢 ===== */
.quiz { margin: 20px 0; }
.choices button {
display: block;
width: 80%; margin: 5px auto;
padding: 10px; font-size: 16px;
cursor: pointer;
}
/* ===== メッセージ表示 ===== */
.message {
margin-top: 10px; padding: 8px;
background-color: rgba(0,0,0,0.7);
color: #fff; border-radius: 5px;
min-height: 1.5em;
}
</style>
</head>
<body>
<!-- タイトル画面 -->
<div id="title-screen" class="overlay">
<img src="speed_reading_title.png" alt="速読訓練タイトル" class="title-image">
<h1>⚡️ 速読訓練ゲーム ⚡️</h1>
<div class="instructions">
<p>流れる文章を速く正確に読み、クイズに即答するゲームです。</p>
<p>1. 短文が右から左へスクロール表示されます。</p>
<p>2. 選択肢は常に下部に表示されています。</p>
<p>3. 最後まで読んだら即クリックしましょう!</p>
<p>全10ラウンドでスコアと平均回答時間を競います。</p>
</div>
<button id="start-btn" class="btn">スタート 🚀</button>
</div>
<!-- ゲーム画面 -->
<div id="game-screen" class="overlay hidden">
<!-- 流れるテキスト表示エリア -->
<div class="scroll-container">
<div id="scroll-text" class="scroll-text"></div>
</div>
<!-- クイズ表示部分 -->
<div id="quiz" class="quiz">
<p id="question-text">質問テキスト</p>
<div class="choices">
<button data-index="0"></button>
<button data-index="1"></button>
<button data-index="2"></button>
<button data-index="3"></button>
</div>
</div>
<!-- 状態メッセージ -->
<div id="message" class="message">準備中…</div>
</div>
<!-- 終了画面 -->
<div id="end-screen" class="overlay hidden">
<h2>🎉 ゲーム終了 🎉</h2>
<p id="final-message"></p>
<button id="restart-btn" class="btn">タイトルに戻る 🔄</button>
</div>
<script>
/**
* ラウンドデータ (全10問、長めテキスト)
*/
const ROUNDS = [
{
text: '東京都内に位置する多摩動物公園では、ライオンやキリンなど約320種の動物を飼育しており、自然に近い環境の中で観察できます。',
question: '多摩動物公園で見られるのは?',
choices: ['魚類','昆虫','動物','植物'],
answer: 2
},
{
text: '日本三大祭りの一つ、京都の祇園祭は7月に開催され、華やかな山鉾巡行と伝統行事で知られます。',
question: '祇園祭の開催月は?',
choices: ['5月','6月','7月','8月'],
answer: 2
},
{
text: '北アルプスの立山黒部アルペンルートは絶景と高山植物が楽しめる観光ルートとして人気です。',
question: '立山黒部アルペンルートで楽しめるのは?',
choices: ['海底散歩','砂漠探検','高山植物','熱帯雨林'],
answer: 2
},
{
text: '奈良の東大寺大仏殿にある奈良の大仏は、世界最大級の青銅製仏像として有名です。',
question: '東大寺の大仏は何製?',
choices: ['木製','石製','青銅製','金製'],
answer: 2
},
{
text: '厳島神社の大鳥居は海中にそびえ立ち、満潮時にはまるで海に浮かんでいるかのように見えます。',
question: '厳島神社の鳥居が見られるのは?',
choices: ['満潮時','干潮時','夜間','早朝'],
answer: 0
},
{
text: '北海道美瑛町の丘陵地帯には、ラベンダーやひまわりなど四季折々の花畑が広がり、多くの観光客を魅了します。',
question: '美瑛町で見られない花は?',
choices: ['ラベンダー','ひまわり','桜','コスモス'],
answer: 2
},
{
text: '東京スカイツリーは2012年に完成し、高さ634メートルで世界一の電波塔としてギネスにも登録されました。',
question: 'スカイツリーの高さは?',
choices: ['634m','600m','650m','680m'],
answer: 0
},
{
text: '富士山の御来光は多くの登山者の憧れであり、夏山シーズンには早朝から多くの人が山頂を目指します。',
question: '御来光を見るために登山する季節は?',
choices: ['春','夏','秋','冬'],
answer: 1
},
{
text: '姫路城は別名「白鷺城」と称され、その美しい白亜の外観は世界的にも高く評価されています。',
question: '姫路城の別名は?',
choices: ['黒鷺城','白鷺城','赤鷺城','青鷺城'],
answer: 1
},
{
text: '竹田城跡は早朝に霧が発生すると石垣だけが浮かぶように見え、まるで雲の上の城のような幻想的な景色となります。',
question: '竹田城跡が浮かぶように見えるのは?',
choices: ['雪','霧','光','影'],
answer: 1
}
];
// ゲーム状態変数
let currentRound = 0;
let score = 0;
let totalTime = 0;
let startTime = 0;
// DOM要素取得
const titleScreen = document.getElementById('title-screen');
const gameScreen = document.getElementById('game-screen');
const endScreen = document.getElementById('end-screen');
const startBtn = document.getElementById('start-btn');
const restartBtn = document.getElementById('restart-btn');
const scrollText = document.getElementById('scroll-text');
const questionEl = document.getElementById('question-text');
const choiceBtns = document.querySelectorAll('.choices button');
const messageDiv = document.getElementById('message');
const finalMsg = document.getElementById('final-message');
/**
* タイトル画面を表示
*/
function showTitle() {
titleScreen.classList.remove('hidden');
gameScreen.classList.add('hidden');
endScreen.classList.add('hidden');
}
/**
* ゲーム開始処理
*/
function startGame() {
currentRound = 0;
score = 0;
totalTime = 0;
titleScreen.classList.add('hidden');
gameScreen.classList.remove('hidden');
showRound(); // 最初のラウンドを表示
}
/**
* 各ラウンドの表示処理
*/
function showRound() {
const round = ROUNDS[currentRound];
// 質問と選択肢を画面にセット
questionEl.textContent = round.question;
choiceBtns.forEach((btn, i) => {
btn.textContent = round.choices[i];
btn.onclick = () => handleAnswer(i);
});
messageDiv.textContent = `ラウンド ${currentRound + 1} / ${ROUNDS.length}`;
// 流れるテキストを右端外に配置して準備
scrollText.textContent = round.text;
scrollText.style.transition = 'none';
const containerWidth = document.querySelector('.scroll-container').offsetWidth;
scrollText.style.transform = `translateX(${containerWidth}px)`;
// 強制リフローで位置リセットを反映
void scrollText.offsetWidth;
// スクロール速度を設定(少し遅め)
const duration = Math.max(2, 6 - currentRound * 0.3); // 最低2秒
const distance = scrollText.offsetWidth + containerWidth;
scrollText.style.transition = `transform ${duration}s linear`;
scrollText.style.transform = `translateX(-${distance}px)`;
// 回答時間の計測開始
startTime = Date.now();
}
/**
* ユーザーの回答処理
*/
function handleAnswer(index) {
const elapsed = (Date.now() - startTime) / 1000;
totalTime += elapsed;
const round = ROUNDS[currentRound];
// 正解判定
if (index === round.answer) {
score++;
messageDiv.textContent = `正解! (${elapsed.toFixed(2)}秒)`;
} else {
messageDiv.textContent = `不正解… 正解は「${round.choices[round.answer]}」 (${elapsed.toFixed(2)}秒)`;
}
currentRound++;
// 次ラウンドまたは終了へ遷移
if (currentRound < ROUNDS.length) {
setTimeout(showRound, 1500);
} else {
setTimeout(endGame, 1500);
}
}
/**
* ゲーム終了処理と結果表示
*/
function endGame() {
gameScreen.classList.add('hidden');
endScreen.classList.remove('hidden');
const avg = (totalTime / ROUNDS.length).toFixed(2);
finalMsg.textContent = `スコア: ${score}/${ROUNDS.length}、平均回答時間: ${avg}秒`;
}
// イベントリスナー登録
document.addEventListener('DOMContentLoaded', showTitle);
startBtn.addEventListener('click', startGame);
restartBtn.addEventListener('click', showTitle);
</script>
</body>
</html>
アルゴリズムの流れ
ステップ | 内容 | 関数/命令 |
---|---|---|
1. タイトル表示 | 初期ロード時にタイトル画面のみ表示 | showTitle() |
2. ゲーム開始 | 「スタート」クリックで変数リセット、最初のラウンド表示 | startGame() |
3. ラウンド設定 | 問題テキスト・選択肢表示、スクロールテキストの初期位置・速度設定 | showRound() |
4. スクロール開始 | CSS トランジションでスクロールテキストを左に移動 | scrollText.style.transition , .transform |
5. 回答入力 | 選択肢ボタンクリックで回答処理、回答時間計測 | 各ボタンの onclick → handleAnswer() |
6. 正誤判定 | 回答が正解か比較、スコア加算・メッセージ表示 | if (index===answer) … |
7. 次のラウンド遷移 | 全ラウンド未消化なら次ラウンドへ、消化済なら終了処理 | setTimeout(showRound/endGame) |
8. 終了処理 | 終了画面を表示し、スコア・平均回答時間を計算・表示 | endGame() |
関数の詳細
関数名 | 説明 |
---|---|
showTitle() | タイトル画面を表示し、他画面を非表示に設定 |
startGame() | ゲーム開始処理。ステージカウンタやスコアの初期化 |
showRound() | 各ラウンドの問題文・選択肢をセット、スクロール準備 |
handleAnswer(i) | 回答処理。正誤判定、時間計測、次ラウンド or 終了 |
endGame() | ゲーム終了画面の表示と最終結果の計算・反映 |
改造のポイント
- 文章長さ/スクロール速度を可変化
難易度設定でテキスト長やスクロール速度を変動させると、多層的な訓練が可能。 - リプレイ機能
終了後に各ラウンドの平均回答時間や正誤ログを確認できる履歴画面を追加。 - ランダム問題生成
JSON 外部ファイルから問題を動的に読み込んで、コンテンツを拡張。 - 音声ナレーション
音声合成 API でスクロールテキストを読み上げ、聴覚的な速読訓練モードを実装。 - マルチユーザー/ランキング
スコアと平均時間をサーバーに送信し、オンラインランキングで競わせる。
アドバイス:モバイル端末ではスクロール領域の高さやフォントサイズを調整して可読性を確保すると、幅広い環境で快適にプレイできます。また、回答ボタンの大きさや押しやすさも見直してみてください!