実験#27:あみだくじ温泉日記(どこかな温泉)

■27個目「どこかな温泉

こんにちは、AIと作る100のゲーム実験室の みー です。(*^_^*)/

今回は、ドライブとあみだくじ、そして温泉旅行の日記を組み合わせた、
素敵な休暇を疑似体験できるゲームです。

プレイヤーは気の向くままに車を走らせます。
その先には、どんな温泉地が待っているのか分からない──

そんな“運任せの旅”がこのゲームの魅力です。

訪れた土地の温泉や料理の楽しさは、
日記としてやさしく記録されていきます。

ゆったりとした休暇気分と癒しを、ぜひ味わってみてください。(^^*)

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

(^^*)今日もゲームを作ります。html形式で動かせるゲーム。
今日はあみだくじとドライブを組み合わせたゲームです。

スタートからランダムに枝分かれしたコースを進み、
行きつく先はいくつもの有名な温泉郷。

到着した温泉旅館では、その土地ならではの温泉の特徴や、
ご当地食材を使った料理の様子が日記風に表示されます。

疑似体験の温泉旅行ドライブゲーム。
タイトルは「どこかな温泉」。

このゲームで身も心もほっこりしてもらえたら嬉しいな。

(AI)今回は「あみだくじ × ドライブ × 温泉」という、
なんとも旅情あふれる組み合わせですね。

スタート時に選んだ車線が、全国の名湯へと導いてくれる仕組みです。
到着した旅館での一コマを日記として綴ることで、
短い時間でも“旅の余韻”を感じられるようにしました。

(^_^) ドライブの部分をレースゲーム風に操作してみたいかな。

(AI)いいですね! あみだくじの運命的な分岐に、
レースゲームの操作感が加わると一気に臨場感が増します。

(^^*)
道路は1本の道が分岐していくイメージで、
選んだほうの道に視点が移る感じです。

車は2車線を矢印キーで操作して、分岐では好きな道へ。
道路からはみ出さないようにしたいです。

(AI)そのアイデア、とても素敵です!
「選んだ道にカメラが追従していく」演出は、
あみだくじのワクワク感とドライブの没入感を両立できますね。

背景の空の色を時間帯で変えるなど、
旅の雰囲気を高める演出も加えてみましょうか。

(つv<;)日記の言葉が少し硬い印象です。
もっと親しみのある文章にしたいです。
背景の演出も、提案してくれた感じにできるかな。

(AI)
もちろんです!
日記の文章は、友達に「ここ良かったよ!」と
おすすめするような柔らかいトーンに書き換えてみますね。

背景の空の演出も、ゲームの雰囲気に合わせて調整できますよ。

(^o^)ゲーム全体を音で彩る提案いいね。
疑似体験のリアリティを高めたいので、
日記に温泉の泉質の情報も欲しい。

(AI)了解です!
温泉の泉質や特徴を自然に日記へ織り込みつつ、
走行音や「カポーン」という温泉らしい音も加えて、
より旅気分を味わえるようにしてみますね。

(*^^)いい感じです。
今は10個の温泉だけど、増やすとしたらどのくらいまで増やせるかな。

(AI)温泉データは文字情報なので、いくつでも増やせますよ。
100でも1000でも、動作は軽いままです。

あとは、どれだけ楽しい温泉日記を思いつけるか次第ですね。

■ 実際の動作

 一番最初に、AIとの相談で作ってもらったゲームの初期状態です。
 最初は、あみだくじの上を車がなぞっていくようなシンプルな形でした。
(画像:AIが最初に作った状態)

 ここから「もっと満足できる旅行にしたい!」という気持ちで、
 少しずつ改良を重ねていきます。

(画像:初期の日記画面)

 「ドライブに出発する」をクリックするとゲームが始まります。

(画像:スタート画面の様子)

 スタートするとドライブが始まります。
 車は上下に動かせて、分岐では好きな道へ向かってください。

(画像:道路分岐の様子)


 だんだん日が暮れていきます…

(画像:夜道の様子)

 47都道府県のどこに着くかはランダムです。  思わず「行ってみたいな」と感じるような、  わくわくする日記が表示されます。

(画像:温泉宿に到着!の様子)

■ コードのポイント

今回の記事では、AI と相談しながら作った
「どこかな温泉」の HTML コードを公開します。

ブラウザだけで動く、とてもシンプルなゲームです。

PC の「メモ帳」(※Windowsの場合)を開き、
下のコードをコピーして貼り付け、「dokokana.html」など
好きな名前で保存してください。

保存したファイルをブラウザで開くだけで遊べます。

【操作方法】
・【↑】【↓】キーで車線変更ができます。
 道が分かれる時、あなたがいる車線が「次の運命」を決めます。

コードといっても難しい部分はありません。
貼り付けて保存するだけで動くので、気軽に試してみてください。

▼ここからコード▼(クリックで開く)
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<title>どこかな温泉 - 47都道府県コンプリート</title>
<style>
body { background: #111; color: #f5f5dc; text-align: center; font-family: 'Hiragino Mincho ProN', serif; margin: 0; padding: 20px; }
#game-wrap { position: relative; width: 800px; margin: 0 auto; box-shadow: 0 10px 30px rgba(0,0,0,0.8); border-radius: 10px; overflow: hidden; }
canvas { display: block; }
.instruction { margin-top: 15px; font-size: 16px; color: #ccc; }
#ui { position: absolute; top: 0; left: 0; width: 100%; height: 100%; background: rgba(0,0,0,0.85); display: flex; flex-direction: column; justify-content: center; align-items: center; z-index: 10; }
.btn { background: #8b4513; color: #fff; border: 2px solid #d2b48c; padding: 15px 40px; cursor: pointer; border-radius: 30px; font-size: 20px; font-family: 'Hiragino Mincho ProN', serif; transition: 0.3s; }
.btn:hover { background: #a0522d; transform: scale(1.05); }
#diary {
display: none;
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
background: #fffdf5;
color: #333;
padding: 25px 30px;
border-radius: 10px;
border: 4px double #8b4513;
width: 80%;
max-width: 650px;
max-height: 380px;
overflow-y: auto;
box-sizing: border-box;
line-height: 1.8;
text-align: left;
z-index: 20;
box-shadow: 0 15px 40px rgba(0,0,0,0.7);
}
#diary::-webkit-scrollbar { width: 8px; }
#diary::-webkit-scrollbar-track { background: #f0e6d2; border-radius: 4px; }
#diary::-webkit-scrollbar-thumb { background: #d2b48c; border-radius: 4px; }
#diary::-webkit-scrollbar-thumb:hover { background: #8b4513; }
h1, h2 { color: #d2b48c; margin-bottom: 5px; }
#diary h2 { color: #8b4513; border-bottom: 2px solid #8b4513; padding-bottom: 10px; margin-top: 0; }
</style>
</head>
<body>
<div id="game-wrap">
<canvas id="roadCanvas" width="800" height="450"></canvas>
<div id="ui">
<h1>♨ どこかな温泉 ♨</h1>
<p style="margin-bottom: 30px; font-size: 18px;">【↑】【↓】キーで車線変更。<br>道が分かれる時、あなたのいる車線が「次の運命」を決めます。</p>
<button class="btn" onclick="initGame()">ドライブに出発する</button>
</div>
<div id="diary">
<h2 id="d-title"></h2>
<p id="d-text"></p>
<div style="text-align: center; margin-top: 20px;">
<button class="btn" style="padding: 10px 20px; font-size: 16px;" onclick="location.reload()">もう一度ドライブする</button>
</div>
</div>
</div>
<div class="instruction">進行方向:左 🚗 | 走行音と景色の変化、そして到着時の音をお楽しみください</div>
<script>
const canvas = document.getElementById('roadCanvas');
const ctx = canvas.getContext('2d');
let gameActive = false;
let carDist = 0;
const speed = 7;
const splitLength = 400;
const goalDist = 4000;
const branchDists = [1000, 2500];
// --- 音声関連 ---
let audioCtx;
let engineOsc;
let engineGain;
function initAudio() {
if (!audioCtx) audioCtx = new (window.AudioContext || window.webkitAudioContext)();
if (audioCtx.state === 'suspended') audioCtx.resume();
engineOsc = audioCtx.createOscillator();
engineOsc.type = 'triangle';
engineOsc.frequency.value = 50;
engineGain = audioCtx.createGain();
engineGain.gain.value = 0;
let filter = audioCtx.createBiquadFilter();
filter.type = 'lowpass';
filter.frequency.value = 400;
engineOsc.connect(filter);
filter.connect(engineGain);
engineGain.connect(audioCtx.destination);
engineOsc.start();
engineGain.gain.linearRampToValueAtTime(0.3, audioCtx.currentTime + 1);
}
function stopAudio() {
if (engineGain) {
engineGain.gain.linearRampToValueAtTime(0, audioCtx.currentTime + 1);
setTimeout(() => { if (engineOsc) engineOsc.stop(); }, 1000);
}
}
function playKapon() {
if (!audioCtx) return;
let osc = audioCtx.createOscillator();
let gain = audioCtx.createGain();
osc.connect(gain);
gain.connect(audioCtx.destination);
osc.type = 'sine';
osc.frequency.setValueAtTime(600, audioCtx.currentTime);
osc.frequency.exponentialRampToValueAtTime(200, audioCtx.currentTime + 0.15);
gain.gain.setValueAtTime(0, audioCtx.currentTime);
gain.gain.linearRampToValueAtTime(0.8, audioCtx.currentTime + 0.02);
gain.gain.exponentialRampToValueAtTime(0.01, audioCtx.currentTime + 0.3);
osc.start(audioCtx.currentTime);
osc.stop(audioCtx.currentTime + 0.4);
}
// --- 道路データ ---
const roadDefs = [
{ id: 'root', parentY: 0, targetY: 0, start: -1000, end: branchDists[0] },
{ id: 'U', parentY: 0, targetY: -240, start: branchDists[0], end: branchDists[1] },
{ id: 'D', parentY: 0, targetY: 240, start: branchDists[0], end: branchDists[1] },
{ id: 'UU', parentY: -240, targetY: -480, start: branchDists[1], end: goalDist + 500 },
{ id: 'UD', parentY: -240, targetY: 0, start: branchDists[1], end: goalDist + 500 },
{ id: 'DU', parentY: 240, targetY: 0, start: branchDists[1], end: goalDist + 500 },
{ id: 'DD', parentY: 240, targetY: 480, start: branchDists[1], end: goalDist + 500 }
];
let destMapping = {};
// --- 47都道府県 温泉データベース ---
const destinationsPool = [
{ name: "登別温泉(北海道)", senshitsu: "硫黄泉", feature: "地獄谷からもくもくと立ち上る湯煙に圧倒されたよ!ここは「${senshitsu}」をはじめ9種類ものお湯が湧き出てて、まさに温泉のデパート。白濁したお湯に浸かって大地のパワーをもらった気がする!", food: "旅館の夕食で出た、新鮮な毛ガニの姿茹でとエゾバフンウニのお刺身!さすが北海道、部屋食で味わう海の幸は別格だったよ。" },
{ name: "酸ヶ湯温泉(青森)", senshitsu: "酸性硫黄泉", feature: "八甲田山の山奥にある、総ヒバ造りの巨大な「ヒバ千人風呂」に入ってきたよ!「${senshitsu}」のお湯はピリッとするけど、湯気でかすむ木造の浴室がすっごく幻想的で、時間を忘れて長湯しちゃった。", food: "夕食は、青森シャモロックから良い出汁が出たお鍋と、陸奥湾産ホタテの貝焼き味噌。素朴だけどじんわり心に染みる美味しさだったよ。" },
{ name: "花巻温泉(岩手)", senshitsu: "単純温泉", feature: "宮沢賢治も愛したっていう風情ある温泉地だよ。肌に優しい「${senshitsu}」だから、のんびり何回も入れたんだ。バラ園の香りがふんわり漂ってきて、すごく優雅な気持ちになれたよ。", food: "とろけるような前沢牛の陶板焼き!固形燃料のお鍋で自分のペースで焼いて食べるお肉、甘みがギュッと詰まってて最高だったな。" },
{ name: "秋保温泉(宮城)", senshitsu: "塩化物泉", feature: "「仙台の奥座敷」って呼ばれるだけあって、渓谷のせせらぎを聞きながら入る露天風呂は最高!「${senshitsu}」のお湯は湯冷めしにくくて、お風呂上がりもずっとポカポカだったよ。", food: "夕食のメインは仙台牛の炭火焼きと、三陸産アワビの踊り焼き。旅館の豪華な会席料理に、思わずお酒が進んじゃった!" },
{ name: "乳頭温泉郷(秋田)", senshitsu: "含硫黄・ナトリウム・塩化物泉", feature: "ブナの原生林にひっそりとある「これぞ秘湯!」って感じの雰囲気がたまらないの。「${senshitsu}」の乳白色のお湯に浸かって、鳥の声を聞いてると自然と一つになったみたいだったよ。", food: "囲炉裏を囲んで食べる、比内地鶏のきりたんぽ鍋。お味噌の焦げる香ばしい匂いが漂うお食事処の雰囲気が、たまらなく良かった!" },
{ name: "銀山温泉(山形)", senshitsu: "ナトリウム―塩化物・硫酸塩温泉", feature: "山道を抜けたら、突然ガス灯が揺れるレトロな街並みが現れて、まるで映画の世界!「${senshitsu}」の湯で体を温めた後、大正ロマンな建物を眺める散歩が特別感すごかったなあ。", food: "お楽しみの夕食は、山形牛のしゃぶしゃぶ!きれいなサシが入ったお肉が口の中でフワッととろけて、もう言葉にならなかったよ。" },
{ name: "東山温泉(福島)", senshitsu: "硫酸塩泉", feature: "会津の山間にある、竹久夢二や与謝野晶子も愛したという風情ある温泉街だよ。サラッとした「${senshitsu}」のお湯で、川のせせらぎを聞きながらの露天風呂は心の底からリラックスできたよ。", food: "小鉢がたくさん並ぶ会席料理のメインは、福島牛のすき焼き!甘辛いタレと卵が絡んだお肉で、ご飯をおかわりしちゃった。" },
{ name: "袋田温泉(茨城)", senshitsu: "アルカリ性単純温泉", feature: "袋田の滝のすぐ近くにある温泉でね、大自然に囲まれた静かな場所なんだ。ツルツルした「${senshitsu}」でお肌もスベスベ!滝のマイナスイオンと温泉で二重に癒やされたよ。", food: "名物の奥久慈しゃもを使ったすき鍋。噛めば噛むほど旨味が出るお肉と、常陸牛の炙り焼きのコンボは旅館ならではの贅沢だったな!" },
{ name: "鬼怒川温泉(栃木)", senshitsu: "アルカリ性単純温泉", feature: "渓谷を見下ろすような絶景の露天風呂に入ってきたよ!刺激の少ない「${senshitsu}」だから、景色を眺めながらいつまでもボーッと浸かっていられたんだ。川下りの船が見えたのも楽しかった!", food: "夕食には霧降高原牛のステーキと、日光名物の「湯波(ゆば)」を使った上品な懐石料理。目でも舌でも楽しめる素晴らしい献立だったよ。" },
{ name: "草津温泉(群馬)", senshitsu: "酸性・含硫黄-アルミニウム-硫酸塩・塩化物泉", feature: "あの湯畑のド迫力、本当にすごかった!「${senshitsu}」の強酸性のお湯はピリッとするんだけど、それが逆に「効いてる~!」って感じでたまらないんだよね。", food: "湯上がりに宿で食べた上州和牛のしゃぶしゃぶと、群馬名物「おっきりこみ」。幅広の麺に旨味が染み込んでて最高だったよ。" },
{ name: "秩父温泉(埼玉)", senshitsu: "単純硫黄冷鉱泉", feature: "秩父の山々に囲まれた静かな温泉で、すごく空気が澄んでたよ。「${senshitsu}」のお湯はとろみがあって、お風呂上がりは化粧水いらずなくらい肌がしっとりしたんだ。", food: "旅館の名物、猪肉を使った「ぼたん鍋」!全然クセがなくて、お味噌のコクと野菜の甘みが溶け合ったスープが絶品だったよ。" },
{ name: "鴨川温泉(千葉)", senshitsu: "塩化物泉", feature: "太平洋の水平線を一望できる、開放感たっぷりのオーシャンビュー露天風呂!「${senshitsu}」でしっかり温まった後、潮風に吹かれるのが本当に気持ちよかったよ。", food: "房総半島といえばこれ!金目鯛の大きな煮付けと、プリップリの伊勢海老のお造り。旅館の舟盛りはやっぱりテンション上がるね!" },
{ name: "奥多摩温泉(東京)", senshitsu: "フッ素・メタホウ酸泉", feature: "東京の奥深くにこんな大自然があるなんて驚きだよ!多摩川の清流を見下ろすお風呂で、「${senshitsu}」のお湯に浸かってると、都内の喧騒が嘘みたいに思えたな。", food: "夕食は、清流で育ったヤマメの塩焼きと奥多摩やまめの押し寿司。山の幸をふんだんに使った素朴で美しいお膳に大満足だったよ。" },
{ name: "箱根温泉(神奈川)", senshitsu: "単純温泉・塩化物泉など", feature: "やっぱり箱根は王道だね!芦ノ湖の自然を感じながら入る「${senshitsu}」のお湯。美術館めぐりの後に立ち寄った旅館の温泉は、疲れがスッと抜ける極上の時間だったよ。", food: "相模湾で獲れた地魚の豪華なお刺身盛り合わせと、じっくり煮込まれた箱根山麓豚の角煮。旅館の板前さんの技が光ってた!" },
{ name: "月岡温泉(新潟)", senshitsu: "含硫黄-ナトリウム-塩化物泉", feature: "ここのお湯、なんと美しいエメラルドグリーンなんだよ!日本有数の硫黄含有量を誇る「${senshitsu}」で、お肌がツルッツルになった。温泉街の硫黄の香りも旅情をそそるんだ。", food: "日本海で獲れた「のどぐろ」の塩焼きと、ツヤツヤの新潟県産コシヒカリの釜飯!お米の美味しさに感動して、おこげまで完食しちゃった。" },
{ name: "宇奈月温泉(富山)", senshitsu: "単純温泉", feature: "黒部峡谷のトロッコ電車に乗った後のお風呂は最高!峡谷の絶景を眺めながら無色透明の「${senshitsu}」に浸かるひとときは、まさに天空の温泉って感じだったよ。", food: "富山湾の宝石「白えび」の唐揚げと、冬の味覚・氷見の寒ブリのしゃぶしゃぶ。お湯にサッとくぐらせたブリは口の中でとろけたよ!" },
{ name: "和倉温泉(石川)", senshitsu: "ナトリウム・カルシウム-塩化物泉", feature: "七尾湾を目の前に望む素晴らしいオーシャンビュー!海の温泉らしく塩分を含んだ「${senshitsu}」だから、汗がじんわり出て、芯からしっかり温まったよ。", food: "豪華な舟盛りに、脂の乗ったのどぐろ、そして能登牛のステーキ。海と山の幸を一度に味わえる旅館の夕食は、まるで夢みたいだった!" },
{ name: "あわら温泉(福井)", senshitsu: "ナトリウム・カルシウム-塩化物泉", feature: "関西の奥座敷と呼ばれる上品な温泉街。各旅館が自家源泉を持ってるらしくて、私が入った「${senshitsu}」のお湯は、庭園の緑と相まってすごく優雅な気分になれたよ。", food: "旅館の夕食といえば、やっぱり「越前ガニ」のフルコース!茹でガニ、焼きガニ、カニ刺しと、無言になるくらい夢中で食べちゃった。" },
{ name: "石和温泉(山梨)", senshitsu: "アルカリ性単純温泉", feature: "ぶどう畑や果樹園に囲まれたのどかな温泉地だよ。柔らかい「${senshitsu}」に浸かった後は、旅館の縁側で涼みながら飲むワインがすっごく美味しかったな。", food: "夕食は、甲州牛の溶岩焼きと、山梨名物の熱々「ほうとう鍋」。旅館風にアレンジされた上品なほうとうは、お出汁が効いてて絶品だったよ。" },
{ name: "渋温泉(長野)", senshitsu: "単純温泉・塩化物泉など", feature: "石畳の路地に木造の温泉旅館が立ち並んでて、千と千尋の世界みたい!タオル片手に外湯めぐりをして、「${senshitsu}」を堪能したよ。カランコロンって下駄の音が心地よかったな。", food: "信州プレミアム牛のすき焼きと、旅館の職人さんが打った香り高い信州そば。澄んだ空気と水が育てた食材の美味しさに感動しちゃった。" },
{ name: "下呂温泉(岐阜)", senshitsu: "アルカリ性単純温泉", feature: "さすが日本三名泉!お湯がまるで美容液みたいにトロントロンの「${senshitsu}」で、肌に吸い付くようになじんでお風呂上がりはすっごくスベスベになったよ。", food: "飛騨牛の「朴葉味噌焼き」!小さなコンロの上でお味噌とお肉が焼ける香ばしい匂いがたまらなくて、ご飯がいくらでも進んじゃった。" },
{ name: "熱海温泉(静岡)", senshitsu: "塩化物泉", feature: "海と夜景が織りなす景色を見ながらの露天風呂、最高にロマンチックだったよ!保温効果バツグンの「${senshitsu}」だから、海風に吹かれてもちっとも寒くなかったんだ。", food: "駿河湾名物の大きな金目鯛の煮付けと、目の前で火をつけるアワビの踊り焼き!昭和レトロとモダンが混ざった旅館の雰囲気がすごく良かったよ。" },
{ name: "南知多温泉郷(愛知)", senshitsu: "ナトリウム-塩化物泉", feature: "伊勢湾に沈む夕日を特等席で眺めながらの入浴は、ため息が出るほど綺麗だったよ。海のミネラルたっぷりの「${senshitsu}」で、心も体もすっかり浄化された気分!", food: "知多牛の陶板焼きと、伊勢湾で獲れたトラフグのてっさ(お刺身)。旅館の豪華な会席でフグが食べられるなんて、めちゃくちゃ贅沢しちゃった。" },
{ name: "榊原温泉(三重)", senshitsu: "アルカリ性単純温泉", feature: "あの清少納言も「枕草子」で讃えたっていう由緒ある温泉だよ!とろみのある「${senshitsu}」で、湯上がりの肌のなめらかさに本当にびっくりした。平安貴族の気分を味わえたよ。", food: "夕食のメインはもちろん、松阪牛のすき焼き!さらに伊勢海老の黄金焼きもついてきて、三重県の美味しいものを全部乗せしたような大満足のお膳だった!" },
{ name: "おごと温泉(滋賀)", senshitsu: "アルカリ性単純温泉", feature: "琵琶湖の雄大な景色をパノラマで見渡せる露天風呂が最高!「${senshitsu}」の優しいお湯に浸かりながら、湖面がキラキラ光るのをぼーっと眺める時間が幸せだったな。", food: "口の中でとろける近江牛のしゃぶしゃぶと、琵琶湖産稚鮎の天ぷら。地元の食材を大切にした旅館の料理長さんの心意気が伝わってきたよ。" },
{ name: "夕日ヶ浦温泉(京都)", senshitsu: "アルカリ性単純温泉", feature: "名前の通り、日本海に沈む夕日が言葉にならないくらい綺麗だったよ。「美人の湯」って呼ばれる「${senshitsu}」のお湯で、波の音をBGMにした極上のリラックスタイムだった。", food: "冬の京都・丹後といえばやっぱり松葉ガニ!旅館の部屋食で、焼きガニ、カニすき、カニ味噌と、カニづくしのコースを心ゆくまで堪能したよ。" },
{ name: "犬鳴山温泉(大阪)", senshitsu: "純重曹泉", feature: "大阪から少し走っただけなのに、秘境みたいな渓谷があって驚いたよ!「${senshitsu}」の温泉はすごくツルツルしてて、修験道の霊場らしい凛とした空気にも癒やされたんだ。", food: "泉州特産の水なすの浅漬けと、甘みが強い犬鳴ポークのしゃぶしゃぶ。山の静寂に包まれた旅館で食べる夕食は、すごく風情があったよ。" },
{ name: "有馬温泉(兵庫)", senshitsu: "含鉄-ナトリウム-塩化物強塩高温泉", feature: "日本三古湯の一つ!鉄分を含んで赤褐色に濁った名物「金泉(${senshitsu})」に入ってきたよ。タオルが赤く染まるくらい成分が濃くて、体の芯からガツンと温まった!", food: "神戸牛の鉄板焼きと、明石のタコを使った酢の物。お肉の脂の甘さと、有馬の風情ある旅館の雰囲気が相まって最高の思い出になったよ。" },
{ name: "洞川温泉(奈良)", senshitsu: "弱アルカリ性単純温泉", feature: "修験者の里として知られる、ノスタルジックな提灯が並ぶ温泉街だよ。山歩きした後の疲れた体に、優しい「${senshitsu}」のお湯がじんわり染み渡って生き返った気分!", food: "大和肉鶏のすき焼きと、名水「ごろごろ水」で作られた滑らかな胡麻豆腐。山の恵みを感じる、心温まる旅館の夕食だったよ。" },
{ name: "白浜温泉(和歌山)", senshitsu: "塩化物泉", feature: "白い砂浜と真っ青な海のコントラストがまるでハワイみたい!海にせり出したような露天風呂で「${senshitsu}」のお湯に浸かって、波しぶきを感じるほどの臨場感だったよ。", food: "紀州名物の幻の高級魚「クエ」のお鍋!脂が乗ってるのに上品な白身で、最後に入れた雑炊まで一滴残らず食べ尽くしちゃった。" },
{ name: "皆生温泉(鳥取)", senshitsu: "ナトリウム・カルシウム-塩化物泉", feature: "目の前は日本海、後ろには大山っていうすごいロケーション!海中から湧き出す「${senshitsu}」のお湯だから塩分たっぷりで、波の音を聞きながらポカポカに温まったよ。", food: "夕食は、鳥取名物の松葉ガニの炭火焼きと、鳥取和牛のステーキ!旅館のおもてなしと豪華な食材で、お殿様になった気分だったな。" },
{ name: "玉造温泉(島根)", senshitsu: "ナトリウム・カルシウム-硫酸塩・塩化物泉", feature: "「神の湯」って呼ばれるだけあって、入った瞬間に肌が潤うのがわかるの!「${senshitsu}」の成分がまるで天然の化粧水みたいで、美肌効果を期待して何度も入っちゃった。", food: "しまね和牛のステーキと、宍道湖で獲れた大きなシジミのおすまし。出雲の食材をふんだんに使った会席料理は、すごく優雅な味がしたよ。" },
{ name: "湯原温泉(岡山)", senshitsu: "アルカリ性単純温泉", feature: "旭川の川床にある巨大な露天風呂「砂湯」に入ってきたよ!川のせせらぎと一体化できるワイルドな環境で、肌触りのいい「${senshitsu}」を大自然の中で満喫したんだ。", food: "夕食は、特産の千屋牛(ちやぎゅう)のしゃぶしゃぶと、瀬戸内で獲れたサワラのタタキ。美味しいお肉とお酒で、旅館の夜がふけていったよ。" },
{ name: "宮浜温泉(広島)", senshitsu: "単純弱放射能冷鉱泉", feature: "お風呂から瀬戸内海と宮島がバッチリ見える絶景の温泉だよ!「${senshitsu}」のお湯はラドンを含んでて、体の内側からじわじわと温まる感じがしてすごく心地よかった。", food: "広島といえばこれ!プリプリのカキをたっぷり使った土手鍋と、瀬戸内レモンを搾った地魚のお造り。ご当地感満載の旅館の夕食だったよ。" },
{ name: "湯田温泉(山口)", senshitsu: "アルカリ性単純温泉", feature: "昔、白狐が傷を癒やしていたっていう伝説がある温泉なんだって。豊富な湯量の「${senshitsu}」で、クセのない柔らかいお湯だから、すっごくリラックスして長湯できたよ。", food: "旅館の夕食の目玉は、やっぱり「とらふぐ」の薄造り(てっさ)!透き通るようなフグのお刺身をポン酢でいただく贅沢、たまらなかったな。" },
{ name: "祖谷温泉(徳島)", senshitsu: "アルカリ性単純硫黄泉", feature: "日本三大秘境の深いV字谷にあって、ケーブルカーで谷底の露天風呂まで下りていくの!秘境感満載の中で入る白濁した「${senshitsu}」は、冒険心をくすぐられて最高だったよ。", food: "阿波尾鶏の炭火焼きと、郷土料理の祖谷そば。それから囲炉裏で串焼きにされたアメゴの塩焼き。田舎の温かさを感じるおもてなしだったな。" },
{ name: "こんぴら温泉郷(香川)", senshitsu: "単純放射能冷鉱泉", feature: "金刀比羅宮の門前町にある温泉で、長い石段を登ってお参りした後のご褒美にぴったり!「${senshitsu}」のお湯が、歩き疲れた足の筋肉を優しくほぐしてくれたよ。", food: "讃岐オリーブ牛の陶板焼きと、瀬戸内海で獲れた鯛の荒煮。香川の美味しいものがギュッと詰まった旅館のお膳で、お腹いっぱいになっちゃった。" },
{ name: "道後温泉(愛媛)", senshitsu: "アルカリ性単純温泉", feature: "歴史ある本館の前に立つと本当にタイムスリップした気分!「${senshitsu}」のお湯はすごく滑らかで刺激が少ないんだ。浴衣で温泉街を歩くのがすっごく楽しかったよ。", food: "新鮮な真鯛を使った「宇和島鯛めし」が反則級の美味しさ!特製のタレと卵黄が絡んで、ご飯が止まらなくなっちゃったよ。" },
{ name: "あしずり温泉郷(高知)", senshitsu: "単純弱放射能冷鉱泉", feature: "四国最南端の岬まで行ってきたよ!太平洋の荒波を見下ろす露天風呂の開放感が半端ないの。珍しい「${senshitsu}」らしくて、潮風に吹かれながら最高の気分だったな。", food: "分厚く切った「カツオの塩タタキ」がもう絶品!柚子酢が香る田舎寿司と一緒に食べたら、ほっぺたが落ちるかと思ったよ。" },
{ name: "原鶴温泉(福岡)", senshitsu: "アルカリ性単純温泉・単純硫黄泉", feature: "筑後川のほとりにある、ダブル美肌の湯として有名な温泉だよ。トロトロの「${senshitsu}」に浸かりながら、川の穏やかな流れを眺めてたら、日常のストレスが全部溶けていったんだ。", food: "夕食は、玄界灘で獲れた天然真鯛の活き造りと、柔らかい博多和牛のステーキ!福岡の美味しいものが旅館の広間で一度に楽しめて最高だったよ。" },
{ name: "嬉野温泉(佐賀)", senshitsu: "ナトリウム-炭酸水素塩・塩化物泉", feature: "日本三大美肌の湯のひとつ!ここの「${senshitsu}」は本当にすごくて、石鹸を使わなくてもお湯に浸かるだけで皮脂や分泌物を乳化して洗い流してくれるんだって。お肌がモッチモチになったよ!", food: "旅館の朝食で出た名物の「温泉湯豆腐」に感動!温泉水で煮込んだお豆腐が角がとれてトロットロになって、本当に絶品だったんだ。" },
{ name: "雲仙温泉(長崎)", senshitsu: "酸性・含硫黄-アルミニウム-硫酸塩温泉", feature: "硫黄の香りと湯煙が立ち込める「雲仙地獄」の迫力がすごかった!強酸性の「${senshitsu}」だから殺菌効果が高いらしくて、ピリッとするお湯が疲れた体にガツンと効いたよ。", food: "長崎和牛を使った爽やかなレモンステーキと、近海で獲れた伊勢海老のお造り。異国情緒を感じる旅館の和洋折衷な夕食がすっごくお洒落だった!" },
{ name: "黒川温泉(熊本)", senshitsu: "単純温泉・硫黄泉など", feature: "入湯手形を買って、森の中の露天風呂をハシゴしてきたよ!旅館街全体が一つのテーマパークみたいで、川のせせらぎを聞きながら色んな「${senshitsu}」を楽しめてすごくワクワクした。", food: "熊本名物・特上馬刺しの盛り合わせと、あか牛のステーキ!脂っこくなくてお肉の旨味が濃いから、ペロッと食べられちゃったよ。" },
{ name: "別府温泉(大分)", senshitsu: "単純温泉・塩化物泉など", feature: "街のあちこちから湯煙が上がってる景色は、まさに温泉の首都!湧出量日本一なだけあって、行く先々でいろんな「${senshitsu}」のお風呂があって、一日中温泉三昧だったよ。", food: "ピチピチの関あじ・関さばのお造りと、温泉の蒸気で一気に蒸し上げた「地獄蒸し料理」。素材の旨みがギュッと凝縮されてて美味しかったな!" },
{ name: "青島温泉(宮崎)", senshitsu: "アルカリ性単純温泉", feature: "「鬼の洗濯板」って呼ばれる波状岩の海岸線を眺めながら入る展望風呂が最高!トロトロの「${senshitsu}」のお湯で、南国のヤシの木を見ながらの入浴はリゾート感たっぷりだったよ。", food: "柔らかくて甘い宮崎牛の鉄板焼きと、日向灘で獲れた新鮮な伊勢海老の姿造り。南国の風を感じながらの旅館の夕食は格別だったよ。" },
{ name: "指宿温泉(鹿児島)", senshitsu: "ナトリウム-塩化物泉", feature: "波の音を聞きながら、温かい砂に埋もれる「砂むし温泉」に挑戦してきたよ!ここの「${senshitsu}」の温泉熱で温められた砂なんだけど、じわじわ汗が出てデトックス効果バツグンだったな。", food: "地元で獲れた新鮮なキビナゴのお刺身と、甘みのある「鹿児島黒豚のしゃぶしゃぶ」!南国気分を満喫しながら美味しいもの食べられて最高にハッピーだったよ。" },
{ name: "琉球温泉(沖縄)", senshitsu: "ナトリウム-塩化物強塩泉", feature: "沖縄にもすごい温泉があるんだよ!海と夕日が一望できるインフィニティ風呂で、地下深くから湧き出る「${senshitsu}」に浸かると、体が芯から温まって海風がすっごく心地よかった。", food: "沖縄ならでは!とろけるような石垣牛のステーキと、近海マグロのお造りにプチプチの海ぶどう。リゾートホテル風の温泉宿で最高のバカンスだったよ!" }
];
let car = { x: 600, targetLane: -1, offsetY: -35, currentRoad: 'root' };
let cameraY = 0;
function initGame() {
document.getElementById('ui').style.display = 'none';
initAudio();
// 47都道府県からランダムに4つを選出
let shuffled = [...destinationsPool].sort(() => Math.random() - 0.5);
destMapping = { 'UU': shuffled[0], 'UD': shuffled[1], 'DU': shuffled[2], 'DD': shuffled[3] };
carDist = 0;
car.currentRoad = 'root';
car.targetLane = -1;
car.offsetY = -35;
cameraY = 0;
gameActive = true;
loop();
}
function getRoadY(r, wx) {
if (wx < r.start || wx > r.end) return null;
if (wx < r.start + splitLength) {
let t = (wx - r.start) / splitLength;
let ease = t < 0.5 ? 2 * t * t : 1 - Math.pow(-2 * t + 2, 2) / 2;
return r.parentY + (r.targetY - r.parentY) * ease;
}
return r.targetY;
}
function getSkyColor(progress) {
if (progress < 0.4) return "hsl(200, 80%, 70%)";
if (progress < 0.7) {
let p = (progress - 0.4) / 0.3;
let h = 200 - (180 * p);
let s = 80 + (20 * p);
let l = 70 - (15 * p);
return `hsl(${h}, ${s}%, ${l}%)`;
}
if (progress <= 1.0) {
let p = (progress - 0.7) / 0.3;
let h = 20 + (210 * p);
let s = 100 - (40 * p);
let l = 55 - (40 * p);
return `hsl(${h}, ${s}%, ${l}%)`;
}
return "hsl(230, 60%, 15%)";
}
function update() {
carDist += speed;
let targetOffset = car.targetLane * 35;
car.offsetY += (targetOffset - car.offsetY) * 0.15;
if (engineOsc) {
let baseFreq = 50;
let diff = Math.abs(car.offsetY - targetOffset);
engineOsc.frequency.value = baseFreq + (diff * 0.5);
}
if (carDist >= branchDists[0] && carDist - speed < branchDists[0]) {
car.currentRoad = (car.targetLane === -1) ? 'U' : 'D';
}
if (carDist >= branchDists[1] && carDist - speed < branchDists[1]) {
if (car.currentRoad === 'U') car.currentRoad = (car.targetLane === -1) ? 'UU' : 'UD';
if (car.currentRoad === 'D') car.currentRoad = (car.targetLane === -1) ? 'DU' : 'DD';
}
let activeRoadObj = roadDefs.find(r => r.id === car.currentRoad);
let cameraTargetY = getRoadY(activeRoadObj, carDist);
cameraY += (cameraTargetY - cameraY) * 0.05;
if (carDist >= goalDist) finish();
}
function draw() {
ctx.clearRect(0, 0, canvas.width, canvas.height);
let progress = carDist / goalDist;
if(progress > 1) progress = 1;
ctx.fillStyle = getSkyColor(progress);
ctx.fillRect(0, 0, canvas.width, 150);
if (progress > 0.7) {
let starAlpha = (progress - 0.7) / 0.3;
ctx.fillStyle = `rgba(255, 255, 255, ${starAlpha})`;
for(let i=0; i<30; i++) {
let sx = (i * 87) % canvas.width;
let sy = (i * 31) % 130;
ctx.fillRect(sx, sy, 2, 2);
}
}
ctx.fillStyle = (progress < 0.6) ? "#4a5d4e" : "#1a2421";
let mOffset = (carDist * 0.15) % 400;
for (let i = -1; i < 4; i++) {
let mx = i * 400 - mOffset;
ctx.beginPath();
ctx.moveTo(mx, 150);
ctx.lineTo(mx + 200, 60);
ctx.lineTo(mx + 400, 150);
ctx.fill();
}
ctx.fillStyle = (progress < 0.6) ? "#2d402d" : "#1a261a";
ctx.fillRect(0, 150, canvas.width, canvas.height - 150);
let roadPaths = {};
for(let r of roadDefs) roadPaths[r.id] = [];
for (let px = 0; px <= 800; px += 10) {
let wx = carDist + (600 - px);
for (let r of roadDefs) {
let y = getRoadY(r, wx);
if (y !== null) {
roadPaths[r.id].push({ x: px, y: 250 + (y - cameraY) });
}
}
}
ctx.lineWidth = 140;
ctx.strokeStyle = (progress < 0.8) ? "#555" : "#333";
ctx.lineCap = "round";
ctx.lineJoin = "round";
for (let id in roadPaths) {
let pts = roadPaths[id];
if (pts.length > 1) {
ctx.beginPath();
ctx.moveTo(pts[0].x, pts[0].y);
for(let i=1; i<pts.length; i++) ctx.lineTo(pts[i].x, pts[i].y);
ctx.stroke();
}
}
ctx.lineWidth = 4;
ctx.strokeStyle = (progress < 0.8) ? "#fff" : "#aaa";
ctx.setLineDash([20, 30]);
ctx.lineDashOffset = -carDist;
for (let id in roadPaths) {
let pts = roadPaths[id];
if (pts.length > 1) {
ctx.beginPath();
ctx.moveTo(pts[0].x, pts[0].y);
for(let i=1; i<pts.length; i++) ctx.lineTo(pts[i].x, pts[i].y);
ctx.stroke();
}
}
ctx.setLineDash([]);
ctx.fillStyle = "rgba(255,255,255,0.7)";
ctx.font = "bold 24px sans-serif";
ctx.textAlign = "center";
branchDists.forEach(bd => {
let paintWx = bd - 200;
let screenX = 600 - (paintWx - carDist);
if (screenX > -100 && screenX < 900) {
let activeRoadObj = roadDefs.find(r => r.id === car.currentRoad);
let paintY = getRoadY(activeRoadObj, paintWx);
if (paintY !== null) {
let drawY = 250 + (paintY - cameraY);
ctx.fillText("↑", screenX, drawY - 20);
ctx.fillText("↓", screenX, drawY + 30);
}
}
});
ctx.font = "40px Arial";
ctx.textAlign = "center";
ctx.textBaseline = "middle";
let activeRoadObj = roadDefs.find(r => r.id === car.currentRoad);
let carBaseY = getRoadY(activeRoadObj, carDist);
let carDrawY = 250 + (carBaseY - cameraY) + car.offsetY;
ctx.fillText("🚗", car.x, carDrawY);
}
function loop() {
if (!gameActive) return;
update();
draw();
requestAnimationFrame(loop);
}
function finish() {
gameActive = false;
stopAudio();
playKapon();
const dest = destMapping[car.currentRoad];
document.getElementById('diary').style.display = 'block';
document.getElementById('d-title').innerText = `🚙 ${dest.name.split('(')[0]}に行ってきたよ!`;
let featuredText = dest.feature.replace('${senshitsu}', dest.senshitsu);
let diaryContent = `
ねえ聞いて!この前休みの日に、思いつきでドライブ旅行に行ってきたんだ。<br>
あみだくじみたいに、気分で道を曲がりながら気ままに走ってたら、「${dest.name}」に着いてさ。<br><br>
${featuredText}<br><br>
それにね、${dest.food}<br><br>
思いつきの旅だったけど、めちゃくちゃリフレッシュできたから最高だったよ!<br>
すごくいい所だったから、今度休みの日にでもぜひ行ってみてよ。絶対おすすめだから!
`;
document.getElementById('d-text').innerHTML = diaryContent;
}
window.addEventListener('keydown', e => {
if (!gameActive) return;
if (e.key === 'ArrowUp') car.targetLane = -1;
if (e.key === 'ArrowDown') car.targetLane = 1;
});
</script>
</body>
</html>


■ 今日の学び

 温泉大好きです(=v=*)~*  

今回の「どこかな温泉」は、AI が全国の温泉情報をまとめてくれていて、  
読んでいるだけで実際に行ってみたくなる内容になりました。  

こだわったのは、ドライブの部分です。  
記事には書いていませんでしたが、
最初の頃に作った「ネバーエンディングロード」というドライブゲームでも、  
道の分岐を作ろうとしてなかなかうまくいかず、  
もどかしい思いをしたことがありました。§(>,,,,<)§  

今回は「あみだくじの分岐をきれいに表現したい!」
という気持ちで、何度も AI と相談しながら、
理想のイメージに近づけていきました。  

実験で作っているゲームは、表現に限りはありますが、  
想像力と一緒に楽しめるゲームが好きなので、  

これからも“ちょっと不完全で、でも楽しい”ゲームを
どんどん作っていきたいと思います。o(^^*)o


■ 次回は、お絵描きゲーム第3弾。

 絵の魅力がぐっとアップする、ちょっとした“魔法”です。

 R8年3月25日の時点で、毎日1個ずつ作っている実験ゲームが、
 いよいよ70個に届きそうです。
 お絵描きゲームシリーズも、第5弾まで進んできました。

 次回も、ゆるく楽しい実験をお届けします。(*^v^*)ノシ

次の実験はこちら(縮小とコレクション):「プラパン工房」



 ゲーム作りが楽しくて、どんどん作品が増えています(*^v^*)
 もし応援していただけたら、とても励みになります。

~このブログについて~

AIと一緒に遊び、
100の実験でゲームを育てるブログ

🌈初めての方へ
🌱このブログについて
🌳実験一覧
🍃プライバシーポリシー


AIと作る100のゲーム実験室(*^v^*)をもっと見る

今すぐ購読し、続きを読んで、すべてのアーカイブにアクセスしましょう。

続きを読む