実験 #05:4つ葉のクローバーはきっと見つかる(四つ葉のクローバー)

■5つ目「幸せ四つ葉のクローバー」

 ゲーム作りも続いてきて、AIから「常連さん」と呼ばれるようになりました。単純なので、そんな一言でも創作意欲がアップします( ̄v ̄*)

 今回のテーマは「幸せ探しゲーム」。散歩の途中、つい探してしまう四つ葉のクローバー🍀。探そうと思わないと見つからないし、目に入るのは三つ葉ばかり。あの“なかなか出会えない感じ”が、ちょっとした冒険みたいで好きなんです(*>v<))

 四つ葉は、人に踏まれやすい場所やストレスのかかる環境で現れやすいと言われています。また、四つ葉だけを集めて育てると、五つ葉以上が出る確率も上がるそうです。
 園芸ショップでも四つ葉の品種を見かけますよね。
 遺伝と環境ストレスが、葉の枚数として現れるのかもしれません(‘@_@)

 ゲーム制作で苦労したのは、図形を組み合わせて四つ葉を再現するところでした。目指したのは「何度も繰り返し探したくなる体験」。
 シンプルだけど、つい夢中になってしまう——そんな小さな幸せを見つけるゲームになっています。

■ AIとのやりとりで面白かった部分

(^^*)クローバーの形にこだわりたいけど、図形で作る四つ葉は難しい…。ハート型の葉っぱは、サイズをランダムにしてナチュラル感を出したいなぁ。
〈四つ葉のイメージをどんどんAIへ伝える〉

ところが、返ってくるのは画像ばかり。

〈返事がなくて少し心配になってくる…〉
(^^;)ひょっとして、図形でクローバーを作るのって難しい?

(AI)とんでもない!「難しいから」ではなく、むしろお客様のこだわりが詰まった 理想のクローバー を、HTMLとCSSだけで100%再現しようと、裏で職人が腕を鳴らしていたところですよ。常連さんのリクエスト、すべて詰め込みました。

  • 風のゆらぎ:フィールド全体がそよ風になびくアニメーション
  • ハートの形:尖った方を中央に、濃いグリーンの枠線付き
  • ナチュラルな不揃い感:葉っぱ一枚一枚のサイズや回転をランダムに
  • 茎:くるんと曲がった茎を一本ずつ追加

よかった…ちゃんと伝えたことを考えてくれていた!(>v<*)

■ 実際の動作

四つ葉のクローバーが結構見つけづらいです。

1回のゲームで、1~3枚の四つ葉のクローバーを全部見つけると、幸せな気分になる言葉が出ます。

散歩途中で見つけた4つ葉のクローバー。

■ コードのポイント

 今回の記事では、AI と相談しながら作った「四つ葉のクローバー」の HTML コードを公開します。 このゲームはブラウザだけで動く、とてもシンプルな仕組みです。

 PC の「メモ帳」を開いて、下のコードをすべてコピーして貼り付け、 「yotuba.html」など好きな名前で保存 → ブラウザで開く。 たったこれだけで、そのまま遊べます。

 操作はとても簡単で、画面に出てくる四つ葉のクローバーを、1~3つクリックして選ぶだけ。

 今回も AI が作ってくれたコードをそのまま載せているので、気になるところを自分で改造したり、色や動きをアレンジして遊んでみてください(^^*)

 「※スマホでは動作しない場合があります」

「 ※コードが長いので、必要な方だけコピーしてください」

▼ここからコード▼(クリックで開く)
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>四つ葉のクローバー - Eternal Happiness</title>
<style>
:root {
--bg-color: #f1f8e9;
--clover-green: #4caf50;
--border-green: #2e7d32;
--lucky-gold: #ffd700;
--flower-white: #ffffff;
}
body { font-family: 'Hiragino Maru Gothic ProN', sans-serif; background-color: var(--bg-color); display: flex; flex-direction: column; align-items: center; margin: 0; overflow: hidden; color: #1b5e20; }
#game-header { text-align: center; padding: 10px; z-index: 100; background: rgba(255,255,255,0.8); width: 100%; box-shadow: 0 2px 15px rgba(0,0,0,0.1); }
#field { position: relative; width: 95vw; height: 75vh; background: #c8e6c9; border-radius: 40px; box-shadow: inset 0 0 60px rgba(0,0,0,0.1); overflow: hidden; border: 6px solid #81c784; margin-top: 10px; }
/* 風の揺らぎ */
@keyframes sway {
0%, 100% { transform: rotate(-3deg); }
50% { transform: rotate(3deg); }
}
/* 蝶々のアニメーション */
@keyframes butterfly-fly {
0% { transform: translate(0, 0) rotate(0deg); opacity: 0; }
20% { opacity: 1; }
100% { transform: translate(40px, -60px) rotate(360deg); opacity: 0; }
}
.clover-unit, .flower-unit {
position: absolute;
width: 80px; height: 80px;
animation: sway 3.5s ease-in-out infinite;
}
/* 四つ葉の優先順位 */
.four-leaf { z-index: 50 !important; }
.three-leaf { z-index: 20; }
.flower-unit { z-index: 10; animation-duration: 5s; }
/* 茎 */
.stem {
position: absolute;
width: 3px; height: 35px;
background: var(--border-green);
top: 40px; left: 38.5px;
border-radius: 0 0 10px 10px;
transform-origin: top center;
transform: rotate(8deg);
}
/* 葉の結合中心 */
.leaf-group {
position: absolute;
top: 40px; left: 40px;
width: 0; height: 0;
cursor: pointer;
}
.leaf {
position: absolute;
bottom: 0; left: -12px;
width: 24px; height: 32px;
transform-origin: bottom center;
}
.leaf::before, .leaf::after {
content: '';
position: absolute;
width: 15px; height: 24px;
background: var(--clover-green);
border: 1.5px solid var(--border-green);
border-radius: 12px 12px 0 0;
top: 0;
}
.leaf::before { transform: rotate(-25deg); left: 0px; border-right: none; }
.leaf::after { transform: rotate(25deg); left: 9px; border-left: none; }
.three-leaf .l1 { transform: rotate(0deg); }
.three-leaf .l2 { transform: rotate(120deg); }
.three-leaf .l3 { transform: rotate(240deg); }
.four-leaf .l1 { transform: rotate(0deg); }
.four-leaf .l2 { transform: rotate(90deg); }
.four-leaf .l3 { transform: rotate(180deg); }
.four-leaf .l4 { transform: rotate(270deg); display: block; }
.l4 { display: none; }
/* シロツメクサの花 */
.flower-head {
position: absolute;
top: 25px; left: 25px;
width: 30px; height: 30px;
background: var(--flower-white);
border-radius: 50%;
box-shadow: 0 0 5px rgba(0,0,0,0.1);
}
.flower-head::after {
content: '🌸'; font-size: 24px; display: flex; align-items: center; justify-content: center; opacity: 0.6;
}
/* 発見時エフェクト */
.found .leaf::before, .found .leaf::after { background: var(--lucky-gold) !important; border-color: #b8860b !important; }
.found { animation: none !important; filter: drop-shadow(0 0 15px gold); z-index: 100 !important; }
/* 蝶々 */
.butterfly {
position: absolute;
font-size: 20px;
pointer-events: none;
display: none;
z-index: 200;
}
.found .butterfly { display: block; animation: butterfly-fly 2s ease-out forwards; }
#modal { display: none; position: fixed; top: 50%; left: 50%; transform: translate(-50%, -50%); background: white; padding: 40px; border-radius: 30px; box-shadow: 0 20px 80px rgba(0,0,0,0.5); text-align: center; z-index: 500; width: 85%; max-width: 500px; border: 6px solid var(--clover-green); }
button { padding: 18px 45px; cursor: pointer; background: #2e7d32; color: white; border: none; border-radius: 50px; font-size: 1.3rem; font-weight: bold; }
</style>
</head>
<body>
<div id="game-header">
<h1 style="margin:0;">🍀 四つ葉のクローバー</h1>
<p>常連Lv.3:蝶々が舞うシロツメクサの野原で幸せ探し <span id="found-count">0</span> / <span id="total-count">?</span></p>
</div>
<div id="field"></div>
<div id="modal">
<h2 style="color: #2e7d32;">🌸 幸せが舞い込みました 🌸</h2>
<div id="lucky-word" style="font-size: 1.2rem; margin: 30px 0; font-weight: bold; line-height: 1.8; color: #333; background: #f9fbe7; padding: 20px; border-radius: 15px;"></div>
<p>タイム: <strong><span id="final-time"></span>秒</strong></p>
<button onclick="startGame()">もう一度探す</button>
</div>
<script>
const field = document.getElementById('field');
const modal = document.getElementById('modal');
const luckyWordDisplay = document.getElementById('lucky-word');
let startTime, totalFourLeafs, foundCount, audioCtx;
const luckyWords = [
"あなたの優しさは、いつか必ず自分に返ってきます。","今日は自分を一番に甘やかしてあげてください。","小さな一歩が、明日の大きな幸せに繋がります。","心穏やかに過ごす時間が、何よりの贅沢です。","深呼吸するたびに、新しい幸せが舞い込みます。","雨のあとの虹のように、あなたの努力は報われます。","あなたの笑顔には、周りを温める力があります。","完璧じゃなくてもいい。今のままのあなたが素敵です。","ゆっくり休むことも、大切な前進のひとつです。","日常の中にある『当たり前』が、最高の宝物です。",
"あなたの歩幅で、ゆっくり歩いていきましょう。","今日は忘れかけていた嬉しいニュースが届くかも。","自分を信じる心が、一番のラッキーアイテムです。","お気に入りの音楽が、運気を運んできてくれます。","心にある曇り空も、やがて晴れ渡る時が来ます。","あなたの存在に、救われている人が必ずいます。","今日は小さな『好き』をたくさん見つけましょう。","風の匂いが、季節の移ろいと幸せを告げています。","どんなに忙しくても、心の中に秘密の庭を。","あなたはもっと、自由に羽ばたいていいのです。","あたたかい布団で眠れる幸せを噛みしめて。","道端に咲く花に気づく、あなたの感性が素敵です。","美味しいお茶を淹れて、今の自分に感謝を。","昨日の涙は、明日の強さに変わります。","あなたの言葉が、誰かの心を温めています。","無理をしない勇気が、あなたを救います。","今日はいつもより少しだけ、背筋を伸ばして歩きましょう。","幸せは、すぐそばで静かにあなたを待っています。","自分を許すことで、新しい扉が開きます。","空を見上げるだけで、心は自由になれます。","あなたの夢は、宇宙が全力でサポートしています。","一日の終わりに、自分の頑張りを褒めてあげて。","鏡に映る自分に、にっこり笑いかけてみましょう。","大切にしているものは、あなたを裏切りません。","あなたの真っ直ぐな想いは、必ず届きます。","静かな読書時間が、魂に栄養を与えてくれます。","今日は懐かしい人に、ふと思い出される日です。","あなたの手の温もりは、魔法の力を持っています。","新しい靴が、あなたを素晴らしい場所へ連れて行きます。","心が躍る方へ、迷わず進んでください。","あなたは、世界にたった一人の貴重な存在です。","誰かにかけた優しい言葉は、巡り巡って戻ってきます。","朝の光が、あなたの今日を祝福しています。","焦らなくて大丈夫。季節が巡るように進めばいい。","あなたの才能は、まだ眠っているだけです。","ふとした瞬間の『ありがとう』が、奇跡を呼びます。","今日は美味しいものを、ゆっくり味わって。","あなたは、あなたのままで、最高に美しい。","明日もまた、あなたに優しい風が吹きますように。"
];
function playSound(f, d) {
if (!audioCtx) return;
const o = audioCtx.createOscillator();
const g = audioCtx.createGain();
o.frequency.value = f;
g.gain.exponentialRampToValueAtTime(0.0001, audioCtx.currentTime + d);
o.connect(g); g.connect(audioCtx.destination);
o.start(); o.stop(audioCtx.currentTime + d);
}
function createFlower() {
const unit = document.createElement('div');
unit.className = 'flower-unit';
unit.style.left = Math.random() * 92 + '%';
unit.style.top = Math.random() * 85 + '%';
unit.style.animationDelay = (Math.random() * -5) + 's';
const stem = document.createElement('div');
stem.className = 'stem';
unit.appendChild(stem);
const head = document.createElement('div');
head.className = 'flower-head';
unit.appendChild(head);
return unit;
}
function createClover(isFourLeaf) {
const unit = document.createElement('div');
unit.className = 'clover-unit ' + (isFourLeaf ? 'four-leaf' : 'three-leaf');
unit.style.left = Math.random() * 90 + '%';
unit.style.top = Math.random() * 85 + '%';
unit.style.animationDelay = (Math.random() * -4) + 's';
const stem = document.createElement('div');
stem.className = 'stem';
unit.appendChild(stem);
const group = document.createElement('div');
group.className = 'leaf-group';
unit.appendChild(group);
// 蝶々を仕込む
const butterfly = document.createElement('div');
butterfly.className = 'butterfly';
butterfly.textContent = '🦋';
unit.appendChild(butterfly);
const leafCount = isFourLeaf ? 4 : 3;
for (let i = 0; i < leafCount; i++) {
const l = document.createElement('div');
l.className = `leaf l${i+1}`;
const s = 0.8 + Math.random() * 0.4;
l.style.scale = s;
group.appendChild(l);
}
group.onclick = (e) => {
if (isFourLeaf && !unit.classList.contains('found')) {
unit.classList.add('found');
foundCount++;
document.getElementById('found-count').textContent = foundCount;
playSound(880, 0.4);
if (foundCount === totalFourLeafs) endGame();
} else if (!isFourLeaf) {
playSound(150, 0.1);
}
e.stopPropagation();
};
return unit;
}
function startGame() {
field.innerHTML = '';
modal.style.display = 'none';
foundCount = 0;
totalFourLeafs = Math.floor(Math.random() * 3) + 1;
document.getElementById('total-count').textContent = totalFourLeafs;
// 花を20個ほど咲かせる
for (let i = 0; i < 20; i++) field.appendChild(createFlower());
// 三つ葉100枚
for (let i = 0; i < 100; i++) field.appendChild(createClover(false));
// 四つ葉
for (let i = 0; i < totalFourLeafs; i++) field.appendChild(createClover(true));
startTime = Date.now();
}
function endGame() {
const s = ((Date.now() - startTime) / 1000).toFixed(2);
document.getElementById('final-time').textContent = s;
luckyWordDisplay.textContent = luckyWords[Math.floor(Math.random() * luckyWords.length)];
modal.style.display = 'block';
[523, 659, 783, 1046].forEach((f, i) => setTimeout(() => playSound(f, 1.2), i * 150));
}
window.addEventListener('mousedown', () => { if(!audioCtx) audioCtx = new AudioContext(); }, {once:true});
startGame();
</script>
</body>
</html>

■ 今日の学び

 四つ葉のクローバーの仕上がりには、今回かなり満足しています。でも、形が崩れたり思ったようにならなかったりして、クローバーらしい形にたどり着くまでには、AIと何度もやり取りを重ねることになりました。
 どうやら AI は、図形を組み合わせて“自然な形”を作るのは少し苦手なのかもしれません(=_=`)

 ちなみに、散歩中にクローバーを探していると、慣れてくるにつれて四つ葉が混ざっている場所だけ“顔”のように浮かび上がって見えてくる瞬間があります。あの小さな発見の感覚が、今回のゲームにも少し重なっている気がします。🍀

次回は、「悪ふざけで作ったタイトル」のゲームです。
どうぞお楽しみに(*^v^)ノシ

次の実験(ストレス発散ゲーム):「筋肉もりもり森盛り盛り」

コメントを残す