ことばさがし
katayamawp
コード公開
CSS
section.wrapper {
font-family: "Comic Sans MS", "Comic Sans", cursive, sans-serif;
max-width: 900px;
/* PC幅対応に広げる */
margin: 30px auto;
padding: 40px 50px;
/* 横の余白を多めに */
text-align: center;
background: linear-gradient(135deg, #87ceeb, #3b5998);
color: #fff;
user-select: none;
border-radius: 12px;
box-shadow: 0 0 40px rgba(0, 0, 0, 0.5);
min-height: 100vh;
/* 縦の余白確保 */
box-sizing: border-box;
}
.word {
font-size: 3rem;
/* 少し大きく */
letter-spacing: 0.7em;
margin-bottom: 10px;
/* 風船を近くにするため */
text-shadow: 1px 1px 6px #000a;
}
/* 風船はwordDisplayのすぐ下に配置 */
.balloons {
margin: 10px 0 30px 0;
/* 上を狭く、下を広く */
text-align: center;
}
.balloon {
display: inline-block;
font-size: 3.5rem;
/* さらに大きく */
margin: 0 10px;
color: #ff3366;
user-select: none;
transition: opacity 0.3s ease;
animation: float 3s ease-in-out infinite;
filter: drop-shadow(0 2px 3px rgba(0, 0, 0, 0.4));
vertical-align: middle;
}
.balloon:nth-child(odd) {
animation-duration: 3.5s;
}
.balloon.burst {
opacity: 0.3;
text-decoration: line-through;
animation: none;
color: #888888;
filter: none;
}
/* 文字ボタンは横並びいっぱい使う */
.letters {
margin: 20px 0;
max-width: 100%;
display: flex;
flex-wrap: wrap;
justify-content: center;
gap: 10px;
}
button.letter-btn {
flex: 1 1 50px;
/* 幅50px以上で伸縮 */
max-width: 60px;
margin: 5px;
padding: 14px 0;
font-size: 1.5rem;
cursor: pointer;
border-radius: 8px;
border: none;
background: linear-gradient(145deg, #ffcc66, #ffb347);
box-shadow: 0 5px #c68e17;
transition: all 0.2s ease;
color: #442a00;
font-weight: bold;
user-select: none;
}
button.letter-btn:hover:not(:disabled) {
background: linear-gradient(145deg, #ffd977, #ffc866);
box-shadow: 0 7px #db9e3a;
transform: translateY(-3px);
}
button.letter-btn:active:not(:disabled) {
box-shadow: 0 2px #a5700d;
transform: translateY(1px);
}
button.letter-btn:disabled {
background: #555555;
box-shadow: none;
cursor: default;
color: #ccc;
}
.message {
font-weight: bold;
margin-top: 40px;
font-size: 1.8rem;
color: #ffe066;
text-shadow: 1px 1px 5px #0008;
user-select: none;
}
.difficulty {
margin-bottom: 25px;
font-size: 1.3rem;
color: #ffe066;
text-shadow: 1px 1px 3px #000a;
user-select: none;
}
input[type="radio"] {
transform: scale(1.3);
margin-right: 6px;
cursor: pointer;
}
@keyframes float {
0%,
100% {
transform: translateY(0);
}
50% {
transform: translateY(-15px);
}
}
JS
document.addEventListener("DOMContentLoaded", function() {
// 難易度別単語リスト(文字数を考慮して分ける)
const wordListByDifficulty = {
easy: [
"りんご", "さかな", "うみべ", "はなび", "すいか", "とけい", "くつした"
],
medium: [
"さくらんぼ", "にほんご", "おちゃわん", "がっこう", "しゃしん", "ぴあの", "やまのぼり"
],
hard: [
"てんきよほう", "たいよう", "つきみ", "やきゅう", "ちず", "かばん", "みずうみ"
]
};
// ひらがな+濁点・半濁点も含めた候補文字
const hiragana = [
"あ", "い", "う", "え", "お",
"か", "き", "く", "け", "こ",
"さ", "し", "す", "せ", "そ",
"た", "ち", "つ", "て", "と",
"な", "に", "ぬ", "ね", "の",
"は", "ひ", "ふ", "へ", "ほ",
"ま", "み", "む", "め", "も",
"や", "ゆ", "よ",
"ら", "り", "る", "れ", "ろ",
"わ", "を", "ん",
"が", "ぎ", "ぐ", "げ", "ご",
"ざ", "じ", "ず", "ぜ", "ぞ",
"だ", "ぢ", "づ", "で", "ど",
"ば", "び", "ぶ", "べ", "ぼ",
"ぱ", "ぴ", "ぷ", "ぺ", "ぽ"
];
// 難易度ごとの設定
const difficultySettings = {
easy: {
disableCount: 20, // かんたんは20文字無効化(選べない)
balloonMultiplier: 3 // 風船の数は文字数×3
},
medium: {
disableCount: 15,
balloonMultiplier: 2 // 文字数×2
},
hard: {
disableCount: 10,
balloonMultiplier: 2
}
};
// ゲーム状態
let word = "";
let maxBalloons = 0;
let foundLetters = new Set();
let missed = 0;
// 要素取得
const wordDisplay = document.getElementById("wordDisplay");
const lettersContainer = document.getElementById("lettersContainer");
const balloonsContainer = document.getElementById("balloonsContainer");
const message = document.getElementById("message");
const startBtn = document.getElementById("startBtn");
// 風船を描く
function drawBalloons() {
balloonsContainer.innerHTML = "";
for (let i = 0; i < maxBalloons; i++) {
const span = document.createElement("span");
span.className = "balloon";
span.textContent = "🎈";
if (i < missed) {
span.classList.add("burst");
span.textContent = "💥";
}
balloonsContainer.appendChild(span);
}
}
// 単語の表示(隠された文字は■)
function drawWord() {
let display = "";
for (let char of word) {
if (foundLetters.has(char)) {
display += char + " ";
} else {
display += "■ ";
}
}
wordDisplay.textContent = display.trim();
}
// 文字ボタンを作る
function createLetterButtons(disableCount) {
lettersContainer.innerHTML = "";
// まず、無効化候補を決める
// → 単語に含まれない文字の中からdisableCount個をランダム選択
const charsNotInWord = hiragana.filter(c => !word.includes(c));
shuffleArray(charsNotInWord);
const disabledLetters = charsNotInWord.slice(0, disableCount);
for (let char of hiragana) {
const btn = document.createElement("button");
btn.textContent = char;
btn.className = "letter-btn";
// 単語に含まれていない && ランダムに選ばれた無効化文字ならdisabled
if (disabledLetters.includes(char)) {
btn.disabled = true;
}
btn.addEventListener("click", () => {
if (missed >= maxBalloons) return; // ゲーム終了
btn.disabled = true;
if (word.includes(char)) {
foundLetters.add(char);
drawWord();
checkWin();
} else {
missed++;
drawBalloons();
checkLose();
}
});
lettersContainer.appendChild(btn);
}
}
// 勝利判定
function checkWin() {
for (let char of word) {
if (!foundLetters.has(char)) return;
}
message.textContent = "🎉 クリア!おめでとう!";
disableAllButtons();
}
// 敗北判定
function checkLose() {
if (missed >= maxBalloons) {
message.textContent = "💥 風船が全部割れました。ゲームオーバー!";
revealWord();
disableAllButtons();
}
}
// 全文字を見せる
function revealWord() {
let reveal = "";
for (let char of word) {
reveal += char + " ";
}
wordDisplay.textContent = reveal.trim();
}
// すべてのボタンを無効化
function disableAllButtons() {
const btns = lettersContainer.querySelectorAll("button");
btns.forEach(btn => btn.disabled = true);
}
// 配列をシャッフル(Fisher–Yatesアルゴリズム)
function shuffleArray(arr) {
for (let i = arr.length - 1; i > 0; i--) {
const j = Math.floor(Math.random() * (i + 1));
[arr[i], arr[j]] = [arr[j], arr[i]];
}
}
// 難易度に応じて単語を選ぶ
function chooseWord(difficulty) {
const candidates = wordListByDifficulty[difficulty] || [];
if (candidates.length === 0) {
// 万一空なら全体からランダム選択
const allWords = [].concat(...Object.values(wordListByDifficulty));
return allWords[Math.floor(Math.random() * allWords.length)];
}
return candidates[Math.floor(Math.random() * candidates.length)];
}
// ゲーム初期化
function initGame() {
foundLetters.clear();
missed = 0;
message.textContent = "";
wordDisplay.textContent = "";
balloonsContainer.textContent = "";
lettersContainer.textContent = "";
const difficulty = document.querySelector('input[name="difficulty"]:checked').value;
word = chooseWord(difficulty);
maxBalloons = word.length * difficultySettings[difficulty].balloonMultiplier;
drawWord();
createLetterButtons(difficultySettings[difficulty].disableCount);
drawBalloons();
}
startBtn.addEventListener("click", initGame);
});