■12個目「シマエナガ大好きゲーム」
今回はこの「シマエナガ」のゲームを作ってみました。ヽ(^o^)ノ
このゲームは、シマエナガを羽ばたかせて落ちずに飛び続けるゲームです。
家にはシマエナガグッズがたくさんあります。
シマエナガを見ていると心が癒されます。そんな癒しの妖精を主人公にしたゲームを作ってみたいと思い、AIと相談しながら作りました。
前に作った「丸太郎と突撃猪」のゲームでは、丸太郎が跳ねる動きをしていました。
今回はその動きをシマエナガに置き換えて、羽ばたくようにしたらどうかな?というところからイメージを膨らませています。
実物のシマエナガを見たことはないのですが、きっと厳しい環境で生きているんだろうな…という想像から、ゲームの内容を設定してみました。
操作するシマエナガは1羽で、5秒ごとに仲間のシマエナガが増えていきます。
10羽になると、一回り大きなシマエナガ1羽に進化して、また仲間が増えていきます。
これを5段階まで繰り返すとゲームクリア!o(>v<*)o”
途中にはアイテムとして“赤い実”と“青い実”があります。
・赤い実を食べると、仲間が+1されます。
・青い実を食べると加速します。
・画面下に落ちるとゲームオーバーです。
・画面上にあがりすぎたり、枝に当たるとがっくり落ちます。
・マウスクリックで羽ばたくので、落ちてしまわないように頑張って操作します。
■ AIとのやりとりで面白かった部分
(^^*)今日もゲーム作ります。今日はシマエナガ大好きゲーム。
横画面スクロールで、雪が降る中飛んでいくシマエナガ。マウスクリックで羽ばたいて少し上昇します。
画面下に落ちてしまうとゲームオーバー。途中で枝にぶつかると、少し×2の下降。5秒ごとに同じサイズのシマエナガが一羽ずつ増えていき、10羽目より増えると、一回り大きいシマエナガになります。5段階まで大きくなる。
達成すると正面を向いたシマエナガが首をかしげて、「大好き。ありがとう」と言ってくれます。
(AI)いらっしゃいませ!「シマエナガ大好きゲーム」ですね。雪の降る中、仲間が増えてどんどん大きくなっていくなんて、想像しただけで癒やされます。常連さんのリピート率も上がってきましたので、今日は少し「ツウ」な豆知識も添えておきました。
〈豆知識。毎回楽しいにしてます〉(つv<*)
(AI)今日のシマエナガ豆知識:レベル3
「お客様、お目が高い。実はシマエナガって、冬の間は『群れ』で作戦会議をするんですよ。一羽でいるよりも、みんなで集まって飛んだり、夜は枝にぎゅっと並んで『エナガ団子』になって暖め合ったりします。
今日のゲームで仲間が増えていくのは、まさに冬を生き抜くシマエナガの知恵そのものなんです。10羽以上の大きな群れ(進化)になると、もう無敵の可愛さですね!」
(=v=*)枝の出現を今の2倍にできるかな。
まだ簡単な感じなので、ふと長い枝も追加で、縦の枝も混ぜてみるのも面白いね。
太い枝の出現ももっと増やしてみたい。
ついでに太い縦枝も入れてみよう。
(AI)承知いたしました。お客様、かなりの「腕利き」とお見受けしました。もはや癒やし系ゲームの皮をかぶった、超絶技巧のアクションゲームの領域ですね。
( ̄~ ̄*)画面上部に行くと、少し下降×20ぐらいでどうかな。
(AI)「上に行けば落とされ、枝に当たれば叩きつけられる」
……ふふふ、常連様、なかなかハードなシマエナガ愛をお持ちですね。でも、その厳しさがあるからこそ、5段階目の巨大な姿を拝めた時の感動は一入ですよ。
パタパタと画面を叩くたびに、シマエナガたちが懸命に羽ばたき、仲間を増やしていく……。お客様の優しさと、ほんの少しの(?)ドS心が詰まった、世界にひとつだけのゲームです。
■ 実際の動作
5秒ごとに仲間が増えます。10匹になると1周り大きくなります。

赤い実を食べると仲間が増えて、青い実を食べるとスピードアップです。

途中AIの作ったイメージです。無料版の時は字がなんだか変です。(^^;)

■ コードのポイント
今回の記事では、AI と相談しながら作った「シマエナガ大好きゲーム」の HTML コードを公開します。ブラウザだけで動く、とてもシンプルなゲームです。
PC の「メモ帳」(※Windowsの場合)を開き、下のコードをコピーして貼り付け、「simaenaga.html」など好きな名前で保存 → ブラウザで開く。これだけで遊べます。
操作はとても簡単で、マウスクリックで羽ばたきます。メインのシマエナガが画面下に落ちてしまわないように操作します。
途中にはアイテムとして “赤い実” と “青い実” があります。
・赤い実を食べると、仲間が+1されます。
・青い実を食べると加速します。
・画面下に落ちるとゲームオーバーとなります。
・画面上にあがりすぎたり、枝に当たるとがっくり落ちます。
今回も AI が作ってくれたコードをそのまま載せているので、気になるところを自分で改造したり、色や動きをアレンジして遊んでみてください(^^*)
「※スマホでは動作しない場合があります」
「※コードが長いので、必要な方だけコピーしてください」
▼ここからコード▼(クリックで開く)
<!DOCTYPE html><html lang="ja"><head> <meta charset="UTF-8"> <title>シマエナガ大好きゲーム - 北海道の冬</title> <style> body { margin: 0; overflow: hidden; background: #cceeff; font-family: 'Hiragino Kaku Gothic Pro', sans-serif; cursor: pointer; } canvas { display: block; background: linear-gradient(#a8d8ea, #f0f8ff); } #msg { position: absolute; top: 15%; left: 50%; transform: translate(-50%, -50%); font-size: 36px; color: #333; text-align: center; display: none; background: rgba(255,255,255,0.9); padding: 20px 40px; border-radius: 50px; border: 5px solid #fff; box-shadow: 0 10px 20px rgba(0,0,0,0.1); z-index: 10; } </style></head><body> <div id="msg"></div> <canvas id="gameCanvas"></canvas><script>const canvas = document.getElementById('gameCanvas');const ctx = canvas.getContext('2d');const msgDiv = document.getElementById('msg');canvas.width = window.innerWidth;canvas.height = window.innerHeight;let frame = 0;let gameOver = false;let gameClear = false;let birdCount = 1;let evolutionStage = 1;let baseSize = 25;let birds = [];let items = [];let branches = [];let speedBoostTimer = 0;let floatingTexts = [];let snowflakes = [];// 雪の初期生成for(let i=0; i<80; i++) { snowflakes.push({ x: Math.random()*canvas.width, y: Math.random()*canvas.height, r: Math.random()*3+1, v: Math.random()*1+0.5 });}// 背景用let bgMountains = [];for(let i=0; i<3; i++) { bgMountains.push({ x: i * canvas.width * 0.8, w: canvas.width * 0.9, h: 300 });}function createBird(isLeader, index) { const spacingFactor = 1 + (evolutionStage * 0.4); const angle = (index * 0.8) % (Math.PI * 2); const distance = (40 + (index * 15)) * spacingFactor; return { isLeader: isLeader, x: 350, y: canvas.height / 2, vy: 0, offsetX: isLeader ? 0 : -Math.cos(angle) * distance - (50 * spacingFactor), offsetY: isLeader ? 0 : Math.sin(angle) * distance, phase: Math.random() * Math.PI * 2 };}function addFriend(x, y, type) { if (gameClear || gameOver) return; birdCount++; if(type === 'red') floatingTexts.push({x: x, y: y, text: "ジュリリ!もぐもぐ", life: 60, color: "#ff4444"}); if(type === 'time') floatingTexts.push({x: x, y: y, text: "チチチッ♪", life: 60, color: "#333"}); if (birdCount > 10) { evolutionStage++; if (evolutionStage >= 5) { gameClear = true; return; } birdCount = 1; baseSize += 15; const leader = birds.find(b => b.isLeader); birds = [createBird(true, 0)]; birds[0].y = leader.y; birds[0].vy = 0; } else { birds.push(createBird(false, birdCount)); }}birds.push(createBird(true, 0));function drawBird(x, y, size, isClear) { ctx.save(); ctx.translate(x, y); if (isClear) ctx.rotate(Math.sin(frame * 0.1) * 0.2); ctx.fillStyle = "white"; let wingMove = Math.sin(frame * 0.2) * (size/4); ctx.beginPath(); ctx.ellipse(-size, wingMove, size/2, size/4, 0, 0, Math.PI*2); ctx.fill(); ctx.beginPath(); ctx.ellipse(size, wingMove, size/2, size/4, 0, 0, Math.PI*2); ctx.fill(); ctx.beginPath(); ctx.arc(0, 0, size, 0, Math.PI * 2); ctx.fill(); ctx.strokeStyle = "#eee"; ctx.lineWidth = 2; ctx.stroke(); ctx.fillStyle = "#333"; let eyeOffset = size/3; ctx.beginPath(); ctx.arc(-eyeOffset, -size/5, size/10, 0, Math.PI*2); ctx.fill(); ctx.beginPath(); ctx.arc(eyeOffset, -size/5, size/10, 0, Math.PI*2); ctx.fill(); ctx.beginPath(); ctx.moveTo(-size/10, 0); ctx.lineTo(size/10, 0); ctx.lineTo(0, size/8); ctx.fill(); if (!isClear) { ctx.fillStyle = "#444"; ctx.fillRect(-size * 1.4, -size/6, size, size/3); } ctx.restore();}function update() { if (gameOver || gameClear) return; frame++; let gameSpeed = speedBoostTimer > 0 ? 12 : 8; if (speedBoostTimer > 0) speedBoostTimer--; const leader = birds.find(b => b.isLeader); leader.vy += 0.32; leader.y += leader.vy; if (leader.y < 10) leader.vy = 20; if (leader.y > canvas.height + 100) gameOver = true; birds.forEach(b => { if (!b.isLeader) { let targetX = leader.x + b.offsetX; let targetY = leader.y + b.offsetY + Math.sin(frame * 0.05 + b.phase) * 15; b.x += (targetX - b.x) * 0.1; b.y += (targetY - b.y) * 0.1; } }); if (frame % 300 === 0) addFriend(leader.x, leader.y, 'time'); // 背景移動 bgMountains.forEach(m => { m.x -= gameSpeed * 0.2; if (m.x + m.w < 0) m.x = canvas.width; }); // 雪の移動(ここが復活!) snowflakes.forEach(s => { s.y += s.v; s.x -= gameSpeed * 0.3; // スピードに合わせた横流れ if (s.y > canvas.height) s.y = -10; if (s.x < 0) s.x = canvas.width; }); // 枝の生成 if (frame % 25 === 0) { const rand = Math.random(); let w = 80, h = 15, isVer = false, isThick = false; if (rand < 0.15) { w = 60; h = 300; isVer = true; isThick = true; } else if (rand < 0.3) { w = 25; h = 200; isVer = true; } else if (rand < 0.55) { w = 160; h = 60; isThick = true; } else if (rand < 0.75) { w = 320; h = 50; isThick = true; } branches.push({ x: canvas.width, y: Math.random() * (canvas.height - 300) + 150, w: w, h: h, isVertical: isVer, isThick: isThick }); } if (frame % 180 === 0) { items.push({ x: canvas.width, y: Math.random() * (canvas.height - 200) + 100, type: Math.random() < 0.7 ? 'red' : 'blue', size: 10 }); } branches.forEach((br, i) => { br.x -= gameSpeed; if (leader.x + baseSize > br.x && leader.x - baseSize < br.x + br.w && leader.y + baseSize > br.y && leader.y - baseSize < br.y + br.h) { leader.vy += br.isThick ? 28 : 12; branches.splice(i, 1); } }); items.forEach((it, i) => { it.x -= gameSpeed; const dx = leader.x - it.x; const dy = leader.y - it.y; if (Math.sqrt(dx*dx + dy*dy) < baseSize + it.size) { if (it.type === 'red') addFriend(it.x, it.y, 'red'); else { speedBoostTimer = 300; floatingTexts.push({x: it.x, y: it.y, text: "ピピィーッ!加速!", life: 60, color: "#4444ff"}); } items.splice(i, 1); } }); floatingTexts.forEach((t, i) => { t.y -= 1; t.life--; if(t.life <= 0) floatingTexts.splice(i, 1); });}function draw() { ctx.clearRect(0, 0, canvas.width, canvas.height); // 背景の山 ctx.fillStyle = "#e0f0f5"; bgMountains.forEach(m => { ctx.beginPath(); ctx.moveTo(m.x, canvas.height); ctx.lineTo(m.x + m.w/2, canvas.height - m.h); ctx.lineTo(m.x + m.w, canvas.height); ctx.fill(); }); // 針葉樹 ctx.fillStyle = "#78909c"; for(let i=0; i<10; i++) { let tx = (i * 200 - (frame*2)%2000 + 2000) % 2000 - 100; ctx.beginPath(); ctx.moveTo(tx, canvas.height); ctx.lineTo(tx + 40, canvas.height - 120); ctx.lineTo(tx + 80, canvas.height); ctx.fill(); } // 雪 ctx.fillStyle = "white"; snowflakes.forEach(s => { ctx.beginPath(); ctx.arc(s.x, s.y, s.r, 0, Math.PI*2); ctx.fill(); }); // 枝・実 branches.forEach(br => { ctx.fillStyle = br.isVertical ? (br.isThick ? "#1b0000" : "#3e2723") : (br.isThick ? "#2e1a1a" : "#6d4c41"); ctx.fillRect(br.x, br.y, br.w, br.h); ctx.fillStyle = "rgba(255,255,255,0.4)"; if(!br.isVertical) ctx.fillRect(br.x, br.y, br.w, 5); // 枝の上の積雪 }); items.forEach(it => { ctx.fillStyle = it.type === 'red' ? "#ff4444" : "#4444ff"; ctx.beginPath(); ctx.arc(it.x, it.y, it.size, 0, Math.PI*2); ctx.fill(); }); // 鳥 if (gameClear) { drawBird(canvas.width/2, canvas.height/2 + 80, 130, true); msgDiv.style.display = "block"; msgDiv.innerHTML = "❤️ 大好き。ありがとう ❤️"; } else if (gameOver) { msgDiv.style.display = "block"; msgDiv.innerHTML = "吹雪に負けちゃったかな…<br><span style='font-size:20px'>クリックでリトライ</span>"; } else { birds.forEach(b => drawBird(b.x, b.y, baseSize, false)); ctx.fillStyle = "#333"; ctx.font = "bold 20px sans-serif"; ctx.fillText(`仲間: ${birdCount}/10 | 成長: ${evolutionStage}/5`, 30, 40); if (speedBoostTimer > 0) { ctx.fillStyle = "blue"; ctx.fillText(`⚡ SPEED UP: ${Math.ceil(speedBoostTimer/60)}s`, 30, 70); } } floatingTexts.forEach(t => { ctx.fillStyle = t.color; ctx.font = "bold 24px sans-serif"; ctx.fillText(t.text, t.x, t.y); });}function loop() { update(); draw(); requestAnimationFrame(loop); }window.addEventListener('mousedown', () => { if (gameOver) location.reload(); else { const leader = birds.find(b => b.isLeader); if(leader) leader.vy = -8; }});loop();</script></body></html>
■ 今日の学び
けなげに頑張るシマエナガのゲームに満足です。(* ⌒ V ⌒ * )
ただ…難易度を上げすぎたので、ゴールがなかなかできなくなってしまい、クリア後のシマエナガを見るのが難しくなってしまいました(^^;)
このゲームも、ぜひ試してみてください。クリア後の「大好き。ありがとう」を、その目で見届けていただければと思います(^^*)
前回の記事を作っているときに、急にブログが作れなくなって焦りました(TT)
どうやら自動スパムに誤認知されたみたいで、AI に相談すると「AIブログは誤検知されやすいタイプのひとつ」とのことでした。
運営さんへ連絡すると、次の日にはすぐ戻してもらえました(><、)
AIがいなかったら途方に暮れていたところで、本当に助かりました。
心から感謝です(*^人^*)
次回は「タイピングホラー」ゲームです。
どうぞお楽しみに(*^v^)ノシ
次の実験はこちら(A~Zタイピング): 「THE BACK」

コメントを残す