
【ゲーム】JavaScript:68 ユニーク絵文字クリックゲーム
「ユニーク絵文字クリックゲーム」は、16個の絵文字パネルから “重複しないもの”(一度だけ出現) と “重複するもの”(同じ絵文字が2つ出現) が混在する中で、
- 重複しない絵文字は 必ずタップ
- 重複する絵文字は どちらか片方だけタップ
というルールで、制限時間内に正しくすべてのパネルを消すミニゲームです。
正しくクリアできれば「クリア!」、重複絵文字を両方消すと「ゲームオーバー」、時間切れは「タイムアップ」となります。
遊び方・操作方法
- スタート ボタンをクリックしてゲーム開始。
- 16個のパネルが表示されるので、
・一度しかない絵文字は タップ
・同じ絵文字が2個並んでいるものは、どちらか 片方だけタップ - タップすると該当パネルがグレーアウト&無効化。
- 重複絵文字を両方消す と即ゲームオーバー。
- 制限時間(30秒)内に全正解パネルを消せばクリア。
ルール
- パネルは 8種類のユニーク絵文字 ×1、4種類の絵文字 ×2、合計16枚。
- 重複絵文字は「2つ」のうち どちらか1つだけ を消す。
- 同じ重複絵文字を両方タップすると 即ゲームオーバー。
- 制限時間は 30秒。
- すべてルール通りに消せば「クリア」、時間切れは「タイムアップ」です。
🎮ゲームプレイ
以下のリンク先から実際にプレイできます。
素材のダウンロード
以下のリンクから使用する素材をダウンロードできます。
unique_emoji_clicking_game_title.png | unique_emoji_clicking_game_bg.png |
---|---|
![]() | ![]() |
ゲーム画面イメージ

プログラム全文(unique_emoji_clicking_game.html)
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<title>✨ ユニーク絵文字クリックゲーム ✨</title>
<style>
html, body {
margin: 0; padding: 0;
width: 100vw; height: 100vh;
font-family: 'Yu Gothic', 'Meiryo', sans-serif;
background: url('unique_emoji_clicking_game_bg.png') no-repeat center center fixed;
background-size: cover;
}
body {
width: 100vw; height: 100vh;
overflow: auto;
}
.container {
width: 800px;
margin: 40px auto;
background: rgba(255,255,255,0.96);
border-radius: 22px;
box-shadow: 0 4px 24px rgba(0,0,0,0.13);
padding-bottom: 32px;
min-height: 520px;
position: relative;
}
.title-img {
display: block;
margin: 20px auto 18px auto;
width: 340px;
max-width: 80%;
height: auto;
}
h1 {
text-align: center;
font-size: 2.1em;
margin: 0.6em 0 0.15em 0;
color: #1976d2;
text-shadow: 1px 1px 7px #fff;
letter-spacing: 0.04em;
}
.rule-section {
background: rgba(235,245,255,0.98);
border-radius: 14px;
margin: 28px 32px 14px 32px;
padding: 16px 24px;
box-shadow: 0 2px 8px #4d90fe22;
}
.rule-title {
text-align: center;
font-weight: bold;
font-size: 1.3em;
margin-bottom: 10px;
color: #1976d2;
}
.rule-text {
text-align: left;
font-size: 1.09em;
line-height: 1.65;
color: #174078;
letter-spacing: 0.01em;
}
.btn {
display: block;
margin: 28px auto 0 auto;
padding: 14px 50px;
font-size: 1.2em;
border: none;
border-radius: 28px;
background: linear-gradient(90deg, #87c9fa, #1565c0);
color: #fff;
font-weight: bold;
box-shadow: 0 2px 8px #1976d266;
cursor: pointer;
transition: background 0.2s;
}
.btn:hover { background: linear-gradient(90deg, #b7e4fe, #1976d2); }
.game-area {
width: 740px;
margin: 36px auto 0 auto;
background: rgba(240,248,255,0.96);
border-radius: 16px;
box-shadow: 0 1px 10px #1565c055;
display: flex;
flex-direction: column;
align-items: center;
min-height: 320px;
padding: 16px 0 20px 0;
user-select: none;
}
.info {
text-align: center;
color: #1976d2;
font-size: 1.19em;
margin: 5px 0 0 0;
}
.emoji-list {
display: flex;
flex-wrap: wrap;
justify-content: center;
gap: 22px 30px;
margin: 36px 0 12px 0;
min-height: 120px;
}
.emoji-btn {
font-size: 2.8em;
width: 66px; height: 66px;
border-radius: 50%;
border: 2.5px solid #1976d2;
background: #fff;
box-shadow: 0 2px 8px #b3e5fc99;
cursor: pointer;
transition: background 0.12s, box-shadow 0.14s;
user-select: none;
margin-bottom: 10px;
position: relative;
outline: none;
}
.emoji-btn.used {
background: #b0bec5;
color: #fff;
cursor: default;
border: 2.5px solid #b0bec5;
opacity: 0.55;
}
.timer-bar {
text-align: center;
font-size: 1.18em;
margin: 0 0 12px 0;
color: #388e3c;
font-weight: bold;
letter-spacing: 0.07em;
}
.message-box {
text-align: center;
background: rgba(235,245,255,0.98);
font-size: 1.7em;
color: #1976d2;
font-weight: bold;
border-radius: 16px;
box-shadow: 0 4px 24px #1976d233;
width: 80%;
max-width: 480px;
margin: 34px auto 0 auto;
padding: 32px 18px;
position: relative;
z-index: 2;
}
.center-btn { margin: 22px auto 0 auto; }
</style>
</head>
<body>
<div class="container" id="main-container"></div>
<script>
// ==========================================
// ✨ ユニーク絵文字クリックゲーム(重複は1つだけ消せばOK・両方消すとゲームオーバー)
// ==========================================
const EMOJI_POOL = [
"🍎", "🍌", "🍇", "🍉", "🍊", "🍓",
"🍒", "🥝", "🍍", "🥑", "🥕", "🥦",
"🍆", "🍋", "🍈", "🍑", "🥔", "🍐"
];
const GAME_TIME = 30; // 制限時間(秒)
const PANEL_COUNT = 16; // 表示パネル数
let gameEmojis = [];
let clickedIndices = [];
let alreadyClickedEmojis = {};
let emojiCountMap = {}; // 出現回数
let duplicateClickedMap = {}; // 重複絵文字で既に消したか
let remaining = GAME_TIME;
let timer = null;
let playing = false;
// タイトル画面
function showTitleScreen() {
clearInterval(timer);
playing = false;
document.getElementById('main-container').innerHTML = `
<h1>✨ ユニーク絵文字クリックゲーム ✨</h1>
<img src="unique_emoji_clicking_game_title.png" class="title-img" alt="ユニーク絵文字クリック タイトル">
<div class="rule-section">
<div class="rule-title">✨ 遊び方・ルール ✨</div>
<div class="rule-text">
・パネルに出てくる<strong>重複しない</strong>絵文字(1つしか出てこない絵文字)は押して消そう!<br>
・<strong>重複する</strong>絵文字(同じものが2個出る場合)は<strong>どちらか一つだけ</strong>押して消そう!<br>
・同じ重複絵文字を2個とも消すとゲームオーバー。<br>
・制限時間は${GAME_TIME}秒、正しく全て消すとクリア!
</div>
</div>
<button class="btn" id="start-btn">スタート</button>
`;
document.getElementById('start-btn').onclick = startGame;
}
// ゲーム開始
function startGame() {
// 8個ユニーク, 4個ダブル=16個
let pool = EMOJI_POOL.slice();
let uniqueEmojis = [];
let duplicateEmojis = [];
for (let i = 0; i < 8; i++) {
let idx = Math.floor(Math.random() * pool.length);
uniqueEmojis.push(pool.splice(idx, 1)[0]);
}
for (let i = 0; i < 4; i++) {
let idx = Math.floor(Math.random() * pool.length);
duplicateEmojis.push(pool.splice(idx, 1)[0]);
}
let chosen = [...uniqueEmojis, ...duplicateEmojis, ...duplicateEmojis];
// シャッフル
for (let i = chosen.length - 1; i > 0; i--) {
let j = Math.floor(Math.random() * (i + 1));
[chosen[i], chosen[j]] = [chosen[j], chosen[i]];
}
gameEmojis = chosen;
clickedIndices = Array(PANEL_COUNT).fill(false);
alreadyClickedEmojis = {};
emojiCountMap = {};
duplicateClickedMap = {};
for (const emoji of gameEmojis) {
emojiCountMap[emoji] = (emojiCountMap[emoji] || 0) + 1;
}
for (const emoji in emojiCountMap) {
if (emojiCountMap[emoji] === 2) duplicateClickedMap[emoji] = false;
}
remaining = GAME_TIME;
playing = true;
renderGameScreen();
timer = setInterval(() => {
remaining -= 0.1;
if (remaining <= 0) {
remaining = 0;
clearInterval(timer);
playing = false;
setTimeout(() => showEndScreen(false), 500);
}
updateTimer();
}, 100);
}
// ゲーム画面
function renderGameScreen() {
let emojiHtml = "";
for (let i = 0; i < gameEmojis.length; i++) {
emojiHtml += `<button class="emoji-btn${clickedIndices[i] ? ' used' : ''}"
${clickedIndices[i] ? 'disabled' : ''}
onclick="clickEmoji(${i})">${gameEmojis[i]}</button>`;
}
document.getElementById('main-container').innerHTML = `
<h1>✨ ユニーク絵文字クリックゲーム ✨</h1>
<div class="game-area">
<div class="timer-bar" id="timer-bar">残り: ${remaining.toFixed(1)} 秒</div>
<div class="emoji-list">${emojiHtml}</div>
<div class="info">重複しない絵文字は押して消し、重複する絵文字はどちらか一つだけ消してください。</div>
</div>
`;
}
// タイマー更新
function updateTimer() {
let t = document.getElementById('timer-bar');
if (t) t.textContent = `残り: ${remaining.toFixed(1)} 秒`;
}
// クリック処理
window.clickEmoji = function(idx) {
if (!playing) return;
if (clickedIndices[idx]) return;
let emoji = gameEmojis[idx];
// 重複絵文字なら、すでに片方が消されていたらゲームオーバー
if (emojiCountMap[emoji] === 2) {
if (duplicateClickedMap[emoji]) {
// 2つ目を押してしまった
clickedIndices[idx] = true;
renderGameScreen();
clearInterval(timer);
playing = false;
setTimeout(() => showEndScreen(false, true), 400);
return;
} else {
duplicateClickedMap[emoji] = true; // 片方だけ消す
clickedIndices[idx] = true;
renderGameScreen();
}
} else {
// ユニーク(1回しか出ない)は普通に消す
clickedIndices[idx] = true;
renderGameScreen();
}
// クリア判定
if (isAllCorrectEmojisClicked()) {
clearInterval(timer);
playing = false;
setTimeout(() => showEndScreen(true), 600);
}
};
// 正しい条件で全て押したかチェック
function isAllCorrectEmojisClicked() {
let counted = {}; // 重複の1つだけ押したか管理
for (let i = 0; i < gameEmojis.length; i++) {
let emoji = gameEmojis[i];
if (emojiCountMap[emoji] === 1) {
if (!clickedIndices[i]) return false; // ユニークは全部消す必要あり
} else if (emojiCountMap[emoji] === 2) {
// 重複はどちらか片方だけ消せばOK
if (!(emoji in counted)) counted[emoji] = 0;
if (clickedIndices[i]) counted[emoji]++;
}
}
for (let emoji in counted) {
if (counted[emoji] !== 1) return false; // どちらか一つだけ消えている
}
return true;
}
// 終了画面
function showEndScreen(isClear, isMiss = false) {
let message = "";
if (isClear) {
message = `🎉 クリア!正しい絵文字をすべて消しました!`;
} else if (isMiss) {
message = `❌ 重複する絵文字を2つとも消してしまいました…<br>ゲームオーバー`;
} else {
message = `⏰ 時間切れ!もう一度挑戦してみましょう!`;
}
document.getElementById('main-container').innerHTML = `
<h1>✨ ユニーク絵文字クリックゲーム ✨</h1>
<img src="unique_emoji_clicking_game_title.png" class="title-img" alt="ユニーク絵文字クリック タイトル">
<div class="message-box">${message}</div>
<button class="btn center-btn" id="back-title-btn">タイトル画面に戻る</button>
`;
document.getElementById('back-title-btn').onclick = showTitleScreen;
}
// 初期表示
showTitleScreen();
</script>
</body>
</html>
アルゴリズムの流れ
手順 | 処理内容 | 実装箇所/関数 |
---|---|---|
1 | タイトル画面表示 | showTitleScreen() |
2 | スタート→パネル選出・シャッフル→初期化 | startGame() |
3 | 16個パネルのHTML生成&タイマー開始 | renderGameScreen() |
4 | パネルクリック判定 | clickEmoji(idx) |
5 | 重複絵文字 → 既に1つ消していた場合GAMEOVER | duplicateClickedMap |
6 | 全正解判定 | isAllCorrectClicked() |
7 | クリア or ゲームオーバー or タイムアップ | showEndScreen() |
関数の詳細
関数名 | 説明 |
---|---|
showTitleScreen() | タイトル画面のHTMLを生成し、スタートボタンにイベントを登録 |
startGame() | ユニーク8種+重複4種×2 の16絵文字をランダム選出&シャッフル、各種初期化 |
renderGameScreen() | タイマー・絵文字リスト・操作説明をHTML出力 |
updateTimer() | タイマー表示を 0.1秒ごとに更新 |
clickEmoji(idx) | パネルクリック処理。重複判定・ゲームオーバー判定・クリア判定を呼び出し |
isAllCorrectClicked() | 「ユニークは全消し&重複は片方のみ消し」のクリア条件をチェック |
showEndScreen(isClear,isMiss) | 終了時のメッセージを切り替え表示。タイトル画面に戻るボタンも設置 |
改造のポイント
- パネル数・重複数 を変えて難易度調整(例:ユニーク10+重複3種×2 → 16枚)。
- TIME 定数をいじって時間制限を緩めたり厳しく。
- Emojii pool を増やして種類をバリエーションアップ。
- サウンド:クリック時/クリア時/ゲームオーバー時に効果音を追加して盛り上げ。
- UI:モバイル対応にタップ感やアニメーション(消えるときのフェードなど)を追加。
- スコア保存:
localStorage
やサーバー連携でハイスコアを記録可能。
これらを活用して、あなた独自のルールや演出を盛り込んだ楽しさあふれるゲームに仕上げてみてください!