
【ゲーム】JavaScript:59 絵文字並び替えパズル
「🎲 絵文字並び替えパズル 🎲」は、バラバラに並んだ絵文字をお手本どおりの順序にドラッグ&ドロップで並び替えるパズルゲームです。制限時間45秒以内に並べ替えを完了するとクリア。レベルが上がるごとに絵文字の種類が増え、難易度がアップします。
遊び方・操作方法
- スタートボタンをクリックすると、今のレベルの絵文字パズルが開始します。
- 上部に表示される「お手本」の順序をよく見て覚えてください。
- 下のエリアに並ぶ絵文字を、ドラッグ&ドロップで位置を入れ替えて並べ替えます。
- 正しい順序になったら自動的にクリア判定が入り、次のレベルへ(または終了画面へ)進みます。
- 制限時間45秒を過ぎるとゲームオーバーです。
ルール
- 制限時間:45秒
- レベル数:全7ステージ
- 各レベル:レベル1→4種類、レベル2→5種類…最大レベル7→9種類の絵文字を使用
- クリア条件:並び替えた絵文字が「お手本」と完全に一致
- 失敗条件:制限時間内に並び替えが完了しない。
🎮ゲームプレイ
以下のリンク先から実際にプレイできます。
59 絵文字並び替えパズル
素材のダウンロード
以下のリンクから使用する素材をダウンロードできます。
emoji_sorting_puzzle_title.png | emoji_sorting_puzzle_bg.png |
---|---|
![]() | ![]() |
ゲーム画面イメージ

プログラム全文(emoji_sorting_puzzle.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('emoji_sorting_puzzle_bg.png') no-repeat center center fixed;
background-size: cover;
}
body {
width: 100vw;
height: 100vh;
overflow: auto;
}
.container {
width: 1000px;
margin: 40px auto;
background: rgba(255,255,255,0.94);
border-radius: 22px;
box-shadow: 0 4px 24px rgba(0,0,0,0.13);
padding-bottom: 32px;
min-height: 600px;
position: relative;
}
.title-img {
display: block;
margin: 20px auto 18px auto;
width: 400px;
max-width: 80%;
height: auto;
}
h1 {
text-align: center;
font-size: 2.1em;
margin: 0.6em 0 0.15em 0;
color: #3b5195;
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: #3b5195;
}
.rule-text {
text-align: left;
font-size: 1.09em;
line-height: 1.65;
color: #233d6c;
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, #7eafff, #3b5195);
color: #fff;
font-weight: bold;
box-shadow: 0 2px 8px #3b519577;
cursor: pointer;
transition: background 0.2s;
}
.btn:hover { background: linear-gradient(90deg, #a7cfff, #233d6c); }
.game-area {
width: 900px;
margin: 36px auto 0 auto;
background: rgba(240,248,255,0.96);
border-radius: 16px;
box-shadow: 0 1px 10px #3b519555;
display: flex;
flex-direction: column;
align-items: center;
min-height: 220px;
padding: 24px 0 36px 0;
user-select: none;
}
.timer-bar {
font-size: 1.18em;
color: #c62828;
margin-bottom: 12px;
font-weight: bold;
letter-spacing: 0.06em;
text-align: center;
}
.level-bar {
font-size: 1.11em;
color: #1976d2;
margin-bottom: 8px;
font-weight: bold;
letter-spacing: 0.03em;
text-align: center;
}
.answer-sample {
display: flex;
justify-content: center;
align-items: center;
margin-bottom: 18px;
gap: 15px;
flex-wrap: wrap;
background: rgba(255,255,255,0.93);
border-radius: 12px;
padding: 8px 10px 2px 10px;
border: 1px solid #90caf9;
font-size: 1.05em;
}
.sample-item {
display: flex;
align-items: center;
gap: 5px;
margin-bottom: 6px;
min-width: 86px;
}
.sample-emoji {
font-size: 1.6em;
margin-right: 3px;
vertical-align: middle;
}
.emoji-list {
display: flex;
justify-content: center;
margin: 18px 0;
gap: 18px;
min-height: 80px;
}
.emoji-cell {
font-size: 2.7em;
background: #fff;
border: 3px solid #3b5195;
border-radius: 15px;
width: 70px;
height: 70px;
display: flex;
align-items: center;
justify-content: center;
margin: 0 4px;
box-shadow: 0 2px 8px #3b519533;
cursor: grab;
transition: border-color 0.1s, background 0.1s;
}
.emoji-cell.drag-over {
border-color: #fbc02d;
background: #fffde7;
}
.message-box {
text-align: center;
background: rgba(235,245,255,0.98);
font-size: 2em;
color: #3b5195;
font-weight: bold;
border-radius: 16px;
box-shadow: 0 4px 24px #3b519533;
width: 80%;
max-width: 480px;
margin: 40px auto 0 auto;
padding: 38px 18px;
position: relative;
z-index: 2;
}
.center-btn { margin: 24px auto 0 auto; }
@media (max-width: 1100px) {
.container { width: 98vw !important; min-width: 0; }
.game-area { width: 98vw !important; min-width: 0; }
.emoji-list { flex-wrap: wrap; }
.emoji-cell { width: 54px; height: 54px; font-size:2em;}
.sample-item { min-width: 60px;}
}
</style>
</head>
<body>
<div class="container" id="main-container"></div>
<script>
// ====== 絵文字並び替えパズル ======
// 各レベルの絵文字セットと日本語名称
const EMOJI_SETS = [
{emojis: ["🍎","🍌","🍇","🍉"], names: ["りんご", "バナナ", "ぶどう", "すいか"]},
{emojis: ["🚗","🚌","🚙","🚓","🚕"], names: ["車", "バス", "SUV", "パトカー", "タクシー"]},
{emojis: ["🌸","🌻","🌼","🌹","🌺","🌷"], names: ["さくら", "ひまわり", "たんぽぽ", "ばら", "ハイビスカス", "チューリップ"]},
{emojis: ["🐶","🐱","🐰","🦊","🐻","🐼","🐨"], names: ["いぬ", "ねこ", "うさぎ", "きつね", "くま", "パンダ", "コアラ"]},
{emojis: ["🥕","🍆","🥦","🌽","🥒","🍅","🍄","🧄"], names: ["にんじん", "なす", "ブロッコリー", "とうもろこし", "きゅうり", "トマト", "きのこ", "にんにく"]},
{emojis: ["🔴","🟠","🟡","🟢","🔵","🟣","⚪","⚫","🟤"], names: ["赤", "オレンジ", "黄", "緑", "青", "紫", "白", "黒", "茶"]},
{emojis: ["🦁","🐯","🐮","🐸","🐵","🐧","🐔","🦆","🐳"], names: ["ライオン", "トラ", "うし", "かえる", "さる", "ペンギン", "にわとり", "アヒル", "くじら"]}
];
let level = 0;
let emojiOrder = [];
let answerOrder = [];
let answerNames = [];
let timer = 45;
let intervalId = null;
let dragFrom = null;
// タイトル画面
function showTitleScreen() {
clearInterval(intervalId);
document.getElementById('main-container').innerHTML = `
<h1>🎲 絵文字並び替えパズル 🎲</h1>
<img src="emoji_sorting_puzzle_title.png" class="title-img" alt="絵文字並び替えパズル タイトル">
<div class="rule-section">
<div class="rule-title">🎲 遊び方・ルール 🎲</div>
<div class="rule-text">
・バラバラに並んだ絵文字をドラッグ&ドロップで正しい順番に並び替えましょう。<br>
・正しい順番にできたらクリアです。<br>
・レベルが上がるごとに絵文字が増えていきます。<br>
・制限時間(45秒)以内にクリアできなければゲームオーバーです。<br>
・「お手本」として正しい順番が上に表示されます。
</div>
</div>
<button class="btn" id="start-btn">スタート</button>
`;
document.getElementById('start-btn').onclick = ()=>startGame(0);
}
// ゲーム開始
function startGame(startLevel) {
level = startLevel;
startStage();
}
// 各レベルの開始
function startStage() {
clearInterval(intervalId);
// 絵文字セットと日本語名称
let emojiSet = EMOJI_SETS[level];
answerOrder = emojiSet.emojis.slice();
answerNames = emojiSet.names.slice();
// シャッフル(元と同じなら再シャッフル)
do {
emojiOrder = shuffleArray(emojiSet.emojis);
} while (emojiOrder.join('') === answerOrder.join(''));
timer = 45;
showGameScreen();
updateTimerBar();
intervalId = setInterval(() => {
timer--;
updateTimerBar();
if (timer <= 0) {
clearInterval(intervalId);
setTimeout(showEndScreen, 300, false);
}
}, 1000);
}
// 配列をランダムシャッフル
function shuffleArray(arr) {
let tmp = arr.slice();
for (let i = tmp.length-1; i>0; i--) {
let j = Math.floor(Math.random() * (i+1));
[tmp[i], tmp[j]] = [tmp[j], tmp[i]];
}
return tmp;
}
// ゲーム画面
function showGameScreen(msg) {
document.getElementById('main-container').innerHTML = `
<h1>🎲 絵文字並び替えパズル 🎲</h1>
<div class="game-area">
<div class="timer-bar" id="timer-bar"></div>
<div class="level-bar">レベル:${level+1} / ${EMOJI_SETS.length}</div>
<div class="answer-sample" id="answer-sample"></div>
<div class="emoji-list" id="emoji-list"></div>
</div>
`;
drawAnswerSample();
drawEmojiList();
updateTimerBar();
}
// 正解順サンプル(絵文字+日本語名称)を描画
function drawAnswerSample() {
const area = document.getElementById('answer-sample');
area.innerHTML = '';
for(let i=0; i<answerOrder.length; i++){
const div = document.createElement('div');
div.className = "sample-item";
div.innerHTML = `<span class="sample-emoji">${answerOrder[i]}</span> ${answerNames[i]}`;
area.appendChild(div);
}
}
// 並べ替え対象の絵文字リストを描画
function drawEmojiList() {
const list = document.getElementById('emoji-list');
list.innerHTML = '';
for (let i = 0; i < emojiOrder.length; i++) {
const cell = document.createElement('div');
cell.className = "emoji-cell";
cell.textContent = emojiOrder[i];
cell.draggable = true;
cell.dataset.index = i;
// ドラッグイベント
cell.ondragstart = e => {
dragFrom = i;
cell.style.opacity = 0.5;
};
cell.ondragend = e => {
dragFrom = null;
cell.style.opacity = 1;
};
cell.ondragover = e => {
e.preventDefault();
cell.classList.add("drag-over");
};
cell.ondragleave = e => {
cell.classList.remove("drag-over");
};
cell.ondrop = e => {
e.preventDefault();
cell.classList.remove("drag-over");
if (dragFrom !== null && dragFrom !== i) {
// スワップ
let tmp = emojiOrder[dragFrom];
emojiOrder[dragFrom] = emojiOrder[i];
emojiOrder[i] = tmp;
drawEmojiList();
checkClear();
}
};
list.appendChild(cell);
}
}
// タイマーバー更新
function updateTimerBar() {
const bar = document.getElementById('timer-bar');
if (bar) bar.textContent = `残り時間:${timer}秒`;
}
// クリア判定
function checkClear() {
if (emojiOrder.join('') === answerOrder.join('')) {
clearInterval(intervalId);
setTimeout(()=>{
if (level === EMOJI_SETS.length-1) {
showEndScreen(true, true); // 全クリア
} else {
showEndScreen(true, false);
}
}, 350);
}
}
// 終了画面
function showEndScreen(isClear, isAllClear) {
document.getElementById('main-container').innerHTML = `
<h1>🎲 絵文字並び替えパズル 🎲</h1>
<img src="emoji_sorting_puzzle_title.png" class="title-img" alt="絵文字並び替えパズル タイトル">
<div class="message-box">
${
isClear
? (isAllClear
? `🎉 全レベルクリア!おめでとう! 🎉`
: `クリア! 次のレベルに進みましょう!`)
: `ゲームオーバー…<br>もう一度挑戦してみてね!`
}
</div>
<button class="btn center-btn" id="back-title-btn">${isClear && !isAllClear ? "次のレベルへ" : "タイトル画面に戻る"}</button>
`;
document.getElementById('back-title-btn').onclick = () => {
if (isClear && !isAllClear) {
startGame(level+1);
} else {
showTitleScreen();
}
};
}
// 初期表示
showTitleScreen();
</script>
</body>
</html>
アルゴリズムの流れ
手順 | 処理内容 |
---|---|
1 | showTitleScreen() でタイトル画面を描画し、スタートボタンに startGame(0) を紐付け |
2 | startGame(n) → startStage() でレベル n の絵文字セットをロードし、並び替え順序をシャッフル |
3 | 制限時間45秒のカウントダウンを開始し、showGameScreen() でゲーム画面を描画 |
4 | drawAnswerSample() で「お手本」を表示、drawEmojiList() でドラッグ可能な絵文字セルを配置 |
5 | セルはドラッグ開始・終了・オーバー・ドロップの各イベントをハンドリング |
6 | ドロップ時にスワップ処理を行い、checkClear() で完成判定 |
7 | 正解なら次レベル(または全クリアエンディング)、時間切れならゲームオーバー画面 |
関数の詳細
関数名 | 機能概要 | 詳細説明 |
---|---|---|
showTitleScreen() | タイトル画面の描画 | ルール説明&スタートボタンを表示。既存タイマーをクリア。 |
startGame(startLevel) | ゲーム開始/レベル設定 | 引数で開始レベルを設定し、startStage() を呼び出す |
startStage() | レベル初期化 | 該当レベルの絵文字セットを取得し、正解順 answerOrder をコピー。シャッフルして emojiOrder に設定。 |
shuffleArray(arr) | 配列シャッフル | Fisher–Yatesアルゴリズムで配列をランダム化。 |
showGameScreen() | ゲーム画面描画 | タイマー・レベル表示・お手本エリア・絵文字エリアを生成し、それぞれ描画関数を呼び出す |
drawAnswerSample() | お手本エリア描画 | answerOrder と answerNames を組み合わせて絵文字+日本語名称を順に表示 |
drawEmojiList() | 絵文字セルエリア生成 | emojiOrder に応じて .emoji-cell 要素を生成し、ドラッグ&ドロップイベントを登録 |
updateTimerBar() | タイマー表示更新 | 毎秒呼び出され、残り時間をDOMに反映 |
checkClear() | クリア判定 | emojiOrder と answerOrder の文字列比較で完成判定。クリアなら次ステージ or エンディングへ移行 |
showEndScreen(isClear,allClear) | 終了画面描画 | 成功/失敗メッセージとボタン表示。ボタンは次レベル or タイトルへ戻る処理を紐付け |
改造のポイント
- レベル追加・カスタムセット:
EMOJI_SETS
に好きな絵文字+ラベルを追加すれば、オリジナルテーマのパズルが作成可能。 - 制限時間調整:ステージごとに時間を伸縮したり、残り時間を基にスコアボーナスを付与する仕組みを追加。
- アニメーション強化:ドラッグ中のセルにスムーズな移動アニメーションや、クリア時に祝福エフェクトを出すと満足度アップ。
- ヒント機能:一定回数失敗したら、一部セルのお手本を一瞬表示する「ヒント」を実装。
- スマホ操作最適化:タッチでのスワップや長押し操作を追加し、モバイルUXを向上させる。
アドバイス
まずはコアのドラッグ&ドロップ動作を安定させ、次にUI演出(エフェクト・BGM・サウンド)を追加してゲーム性を高めると、ユーザー体験が格段に向上します。ステージ選択やハイスコア保存などの機能を段階的に実装すると、リプレイ性が増し飽きられにくくなります!