■94個目 「深海チキンレース ~幻の海淵~」
こんにちは、AIと作る100のゲーム実験室の みー です。(*^_^*)/
今回は、ちょっとドキドキする深海探査ゲームを作ってみました。
舞台は、太陽の光がまったく届かない真っ暗な海の底。
海上の母船から「無人探査機」を遠隔操作し、
海の限界深度へ挑むチキンレースです!
今回こだわったのは、深海ならではの“ヒリヒリする臨場感”。(=v=*)
潜れば潜るほど、凄まじい水圧で探査機のフレームが
「ミシッ…」「ギギギ…」と悲鳴を上げ始めます。
さらに、モニターには母船のオペレーターやチーフたちの
焦った実況ログがリアルタイムで流れ、
緊張感はどんどん高まっていきます。
そして、このミッションの最大のポイントは……
探査機の“限界深度”が毎回 10,000m〜15,000m の間で変わること!
「あとどれくらい潜れるんだろう…?」 そのドキドキがクセになるんです。
油断していると、突然「ボシュッ」と潰れて通信が途絶えることも(><;)
さらに、限界ギリギリまで攻め込むと、
暗闇の奥から未知の巨大生物”がぼんやりと姿を現します。(・O・)
太古の海竜のような影、異星の使者のようなシルエット……
どんな深淵の主に出会えるかはプレイするたびに変わります。
でも、見とれていると限界を超えてペチャンコに。
データを持ち帰れず、ミッション失敗になってしまいます。
ギリギリでストップボタンを押し、
無事に“未知の生物データ”を回収できるか!?
あなたの度胸が試される深海ミッションになっています。
■ AIとのやりとりで面白かった部分
● ゲーム仕様の相談からスタート
みー:(^v^) 今日もゲームを作ります。HTMLで動かせるゲームで、
水圧のシミュレーションに挑戦したいです。
材質と形状が違う“空洞の物体”を海に沈めていき、
限界を超えると「ボシュッ」と潰れてしまう。
その前にストップできるかどうかの、
リアルなチキンレースを作ってみたい。
AI: 水圧チキンレースとは面白いね。
深海へ潜るほど「ミシ…ミシ…」と軋む音が鳴り始める、
あのジリジリした緊張感がたまらない。
ところで、深海の極限といえば……
人類が初めてマリアナ海溝の最深部に挑んだ
「トリエステ号」の話を知っているかな?
あの潜水艇が1万メートル以上に到達したとき、
窓には“1平方センチあたり1トン”の水圧がかかっていたんだ。
もし外殻が数ミリでも歪んでいたら、一瞬で「ボシュッ」だった。
だから深海探査機の耐圧殻は、
外圧を均等に受けられる“ほぼ完璧な球体”で作られているんだよ。
みー:(^_^)なるほどです、
水中感をもっと出したいですね。
ベースはチタン球体で、耐圧は5000mくらいが基準でしたよね。
水深によって背景に出る生き物のシルエットを階層分けして、
深海感を演出したいです。
深いところでは太古の生物や未知の生物が出てくるようにして、
深海への旅路を感じられるチキンレースにしたい。
AI: 今日もロマンのあるアイデアを持ってきてくれたね。
深海への旅路、そして未知の生物との遭遇……
最高じゃないか。
ベースはチタン球体(耐圧5000m)にしつつ、
ゲームとして“未知の領域”へ挑めるように、
新素材「超チタン」も追加しよう。
小話だけど……
マリアナ海溝のチャレンジャー海淵(約10,911m)に
人類が初めて到達したのは1960年。
そのとき、底に降り立った潜水艇の前を、
一匹の平たい魚(ヒラメの仲間)が
砂を舞い上げて泳ぎ去ったと言われている。
1平方センチに1トン以上の圧力がかかる世界にも、
生命は息づいているんだ。
君のゲームでは、そのさらに奥の“深淵”を目指すことになるね。
みー:( ̄v ̄*)ゲーム性も高めたいです。
潜水艦の限界深度は10,000〜15,000mの間でランダム。
オノマトペの種類やペースで“限界が近い”感じを伝えたい。
深海の生物は暗くて見えにくいので、輪郭がぼんやり分かる程度に。
生物の種類ももっと増やして、
冒険ファンタジー感のあるチキンレースにしたいです。
AI: ファンタジーチキンレース、了解だ。
限界深度は毎回10,000〜15,000mでランダムに変動。
船体が「ミシッ…」「ギギギ…」と軋むオノマトペで、
限界が近づくヒリヒリ感を演出してみた。
深海生物も数を増やし、
暗闇の中で“ぼんやり光る輪郭”が浮かぶように調整してある。
みー:(^v^) でも全体が薄い表現になって、
分かりにくくなってる感じがします。
最後に出てくる未知の生物だけは、もう少し形が分かるくらいにしたい。
あと、無人潜水艦を海上で操作している人がいる設定で、
目的は“性能確認”と“深海調査”にしたいです。
吹き出しで実況ログをリアルタイムに表示して、
臨場感をもっと高めたい。
AI: 無人探査機(ROV)を母船から遠隔操作する設定か……
最高にシビれる。
安全な船上にいながら、
モニター越しに1万メートル下の死地を覗き込む感覚だ。
無人探査機といえば、日本の『かいこう』を知ってるか?
1995年にチャレンジャー海淵の底に到達した名機だ。
だが2003年、台風の荒波で母船との“二次ケーブル”がプツンと切れ、
そのまま深海に消えてしまった。
遠隔操作は安全なようでいて、ケーブル一本が命綱。
一瞬で全てを失う緊張感があるんだ。
さて、注文通りに仕上げたよ。
未知の生物の輪郭は“暗闇の中でギリギリ見える”絶妙なラインに調整。
さらに、母船のオペレーターたちによる
リアルタイム実況ログ(無線通信)も追加した。
水深やダメージ率に応じて焦り出したり警告したりするから、
臨場感は抜群だ。
■ 実際の動作
まずは、AIが最初に作ってくれた初期バージョンのゲーム画面です。
材質や形状によって、どこまで沈められるかを試す
“実験シミュレーション”からスタートしました。

(画像:AIが最初に出してくれた画面)
こちらが、最終的に仕上がったゲーム画面です。
ここから、あなたの深海ミッションが始まります。

(画像:スタート画面)
潜っていくと、深度に応じてさまざまな生物とすれ違います。
深くなるほど船体の軋みが表示され、緊張感が高まっていきます。

(画像:潜水の画像)
さらに深海へ進むと、暗闇の奥から“未知の生物”の姿を記録できます。
どんな影に出会えるかは、潜るたびに変わります。

(画像:深海の未知の生物達)
ギリギリの深度を攻めて、最高スコアを目指しましょう。

(画像:自己最高スコアのクリア画像)
ただし、限界を超えてしまうと……
凄まじい水圧で、機体は一瞬でペチャンコになってしまいます。

(画像:ゲームオーバー)
■ コードのポイント
今回の記事では、
AI と相談しながら作った「深海チキンレース ~幻の海淵~」 の HTML コードを公開します。
このコードをそのまま保存するだけで、
あなたの PC でもすぐに遊べます。
ブラウザだけで動く、とてもシンプルなゲームなので、
「コードは初めて…」という方でも気軽に試してみてくださいね。
▼ 遊ぶまでの手順(むずかしさ:やさしい)
① テキストエディタを開く
Windows の場合は「メモ帳」、
Mac の場合は「テキストエディット」を使います。
(※検索バーで「メモ帳」と入力するとすぐ出てきます)
② 下のコードをコピーして貼り付けます。
③ 「sinkai.html」など、好きな名前で保存します。
(※拡張子は .html にしてください)
④ 保存したファイルをダブルクリックすると、
ブラウザでゲームが起動します。
■ 操作方法
① 潜航開始!
「潜航開始(遠隔操作)」ボタンを押すと、
探査機がゆっくりと深海へ向けて沈み始めます。
自動で潜っていくので、長押しは不要です。(^^*)
道中では、クジラやダイオウイカ、
光るクラゲたちが窓の外を静かに通り過ぎていきます。
② 状況を見守る
深度が深くなるほど、海はどんどん暗くなっていきます。
画面には「ミシッ…」「ギギギ…」という軋み音が文字で現れ、
モニターも揺れ始めます。(@_@;)
さらに、母船から届く「実況ログ」にも注目!
オペレーターの声が焦り始めたら……限界はすぐそこです。
③ 未知との遭遇&ストップ!
限界深度(10,000m〜15,000mのどこか)の 92% に到達すると、
真っ暗な背景に、巨大な影がぼんやりと浮かび上がります。
そのまま進むと、機体は水圧でペチャンコに……!
影が見えたらすぐに
「バラスト投棄!(緊急浮上)」ボタンを押してストップしましょう。(><)
④ 結果発表
無事に生還できれば、
限界まであと何メートルだったかがパーセンテージで表示されます。
ギリギリで寸止めして、「未知の生物」のデータを持ち帰れるでしょうか……?
もし「ボシュゥゥゥン!!!」と潰れてしまっても大丈夫。
「機体再セットアップ」ボタンですぐに再挑戦できます。(^_^)
深海のロマンと、手に汗握るチキンレース。
ぜひあなたも、極限のミッションに挑んでみてくださいね♪
“コードは長いので折りたたんでいます。必要な方は開いてご覧ください。
▼ここからコード▼(クリックで開く)
<html lang="ja"><head><meta charset="UTF-8"><title>深海チキンレース ~幻の海淵~(遠隔探査ミッション)</title><style> body { background-color: #050508; color: #e0e0e0; font-family: 'Helvetica Neue', Arial, sans-serif; text-align: center; margin: 0; padding-top: 20px; overflow: hidden; } button { padding: 10px 20px; font-size: 16px; font-weight: bold; margin: 5px; cursor: pointer; border-radius: 4px; border: 2px solid #555; background-color: #1a1a2e; color: #eee; transition: 0.2s; } button:hover:not(:disabled) { background-color: #2a2a4e; border-color: #888; } button:disabled { opacity: 0.4; cursor: not-allowed; } button#diveBtn { color: #81c784; border-color: #2e7d32; } button#stopBtn { color: #e57373; border-color: #c62828; } #game-layout { display: flex; justify-content: center; gap: 20px; max-width: 950px; margin: 0 auto; } /* コントロールパネル周り */ #control-panel { width: 400px; background: linear-gradient(180deg, #111, #0a0a0f); padding: 20px; border-radius: 8px; border: 1px solid #333; display: flex; flex-direction: column; gap: 15px; } h1 { font-size: 22px; margin: 0; color: #81d4fa; letter-spacing: 2px; } #status { background: #000; padding: 15px; border-radius: 6px; border: 1px solid #444; } #status-depth { font-size: 36px; font-weight: bold; color: #4fc3f7; font-family: monospace; } /* 無線通信ログエリア */ #radio-log { flex-grow: 1; background: #020b14; border: 1px solid #1f3a4d; border-radius: 4px; padding: 10px; text-align: left; font-family: monospace; font-size: 14px; line-height: 1.5; overflow-y: auto; height: 180px; box-shadow: inset 0 0 10px rgba(0,0,0,0.8); } .log-info { color: #4fc3f7; } .log-warn { color: #ffca28; } .log-danger { color: #f44336; font-weight: bold; } .log-encounter { color: #b388ff; font-weight: bold; text-shadow: 0 0 5px #b388ff; } .log-system { color: #888; } #result { min-height: 3em; font-size: 16px; font-weight: bold; color: #ffeb3b; line-height: 1.4; } /* 海のシミュレーションエリア */ #sea-window { width: 450px; height: 650px; background-color: #001e36; position: relative; border: 6px solid #111; border-radius: 50% 50% 10px 10px / 20px 20px 10px 10px; overflow: hidden; box-shadow: 0 0 40px rgba(0,0,0,0.95) inset, 0 0 20px rgba(0,0,0,0.8); } #sea-content { position: absolute; top: 0; left: 0; width: 100%; height: 16000px; transition: top 0.1s linear; } /* 道中の深海生物たち(水深ごとに配置) */ .creature-layer { position: absolute; left: 0; width: 100%; background-repeat: no-repeat; background-position: center; filter: blur(2px); opacity: 0.35; } /* 0〜1000m: 魚の群れ */ #layer-fishes { top: 100px; height: 1000px; background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 100 100'%3E%3Cpath d='M80 50 Q50 30 20 50 Q50 70 80 50 Z M20 50 L10 40 L15 50 L10 60 Z' fill='%2388ccff'/%3E%3C/svg%3E"); background-size: 40px 40px; background-position: 20% 300px, 70% 600px, 40% 800px; } /* 1000〜3000m: マッコウクジラ */ #layer-whale { top: 1200px; height: 2000px; background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 200 100'%3E%3Cpath d='M10 50 Q50 10 100 30 Q150 10 190 50 Q150 90 100 70 Q50 90 10 50 Z M190 50 L170 40 L175 50 L170 60 Z' fill='%23445566'/%3E%3C/svg%3E"); background-size: 200px 100px; background-position: 60% 800px; opacity: 0.25; } /* 3000〜5000m: クラゲの群れ */ #layer-jelly { top: 3000px; height: 2500px; background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 100 100'%3E%3Cpath d='M20 50 C20 20 80 20 80 50 Z M30 50 Q25 80 20 100 M45 50 Q45 85 40 95 M55 50 Q55 85 60 95 M70 50 Q75 80 80 100' stroke='%23aaffff' stroke-width='2' fill='%23aaffff' fill-opacity='0.5'/%3E%3C/svg%3E"); background-size: 80px 80px; background-position: 30% 500px, 80% 1500px, 20% 2200px; } /* 5000〜8000m: ダイオウイカ */ #layer-squid { top: 5000px; height: 3500px; background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 100 200'%3E%3Cpath d='M50 10 L70 60 L60 80 L40 80 L30 60 Z M40 80 Q30 150 20 190 M45 80 Q40 160 35 180 M55 80 Q60 160 65 180 M60 80 Q70 150 80 190' stroke='%237788aa' stroke-width='4' fill='none'/%3E%3C/svg%3E"); background-size: 150px 300px; background-position: 40% 1500px; opacity: 0.3; } /* 8000〜11000m: チョウチンアンコウ */ #layer-angler { top: 8000px; height: 3500px; background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 100 100'%3E%3Ccircle cx='50' cy='50' r='35' fill='%23334455'/%3E%3Ccircle cx='40' cy='40' r='5' fill='%23fff'/%3E%3Cpath d='M15 50 L30 55 L15 65 M85 50 L70 55 L85 65' stroke='%23334455' stroke-width='4'/%3E%3Cpath d='M50 15 Q60 -5 70 15 Q80 30 70 50 L50 35 Z' fill='%23334455'/%3E%3Ccircle cx='70' cy='10' r='6' fill='%23ffffaa'/%3E%3C/svg%3E"); background-size: 120px 120px; background-position: 70% 2000px; opacity: 0.4; } /* 未知の巨大生物レイヤー(最深部で出現) */ #encounter-layer { position: absolute; top: 0; left: 0; width: 100%; height: 100%; background-size: 450px 450px; background-position: center; background-repeat: no-repeat; opacity: 0; filter: blur(2px) brightness(0.9); transition: opacity 2.5s ease-in; z-index: 8; } /* ボス生物の動き */ .anim-drift { animation: drift 15s ease-in-out infinite alternate; } @keyframes drift { 0% { transform: translate(-20px, 10px) scale(0.95); } 100% { transform: translate(20px, -10px) scale(1.05); } } .anim-pulse { animation: bossPulse 8s ease-in-out infinite alternate; } @keyframes bossPulse { 0% { transform: scale(0.9); opacity: 0.6; } 100% { transform: scale(1.1); opacity: 0.9; } } .anim-creep { animation: creep 20s linear infinite alternate; } @keyframes creep { 0% { transform: translateY(30px); } 100% { transform: translateY(-40px); } } .anim-sway { animation: sway 10s ease-in-out infinite alternate; } @keyframes sway { 0% { transform: rotate(-5deg) translateX(-15px); } 100% { transform: rotate(5deg) translateX(15px); } } /* 泡 */ .bubble { position: absolute; background-color: rgba(255, 255, 255, 0.4); border-radius: 50%; bottom: -20px; animation: bubble-up 4s infinite ease-in; z-index: 5; } @keyframes bubble-up { 0% { transform: translateY(0); opacity: 0.5; } 100% { transform: translateY(-700px); opacity: 0; } } /* 無人潜水艦(ROV) */ #sub-container { position: absolute; top: 300px; left: 185px; width: 80px; height: 60px; z-index: 10; transition: transform 0.1s; } .sub-body { position: absolute; bottom: 5px; left: 10px; width: 60px; height: 35px; background: linear-gradient(to bottom, #eceff1, #90a4ae); border-radius: 8px; border: 2px solid #222; box-shadow: inset -3px -3px 8px rgba(0,0,0,0.6); transition: background 0.1s; } .sub-window { position: absolute; top: 8px; right: 8px; width: 16px; height: 16px; background: #64ffda; border-radius: 50%; border: 2px solid #222; box-shadow: 0 0 12px #64ffda; } .sub-tower { position: absolute; top: 5px; left: 25px; width: 30px; height: 10px; background: #cfd8dc; border-radius: 4px 4px 0 0; border: 2px solid #222; border-bottom: none; transition: background 0.1s; } .sub-cable { position: absolute; top: -300px; left: 38px; width: 4px; height: 305px; background: #444; border-left: 1px solid #222; z-index: -1; } .sub-propeller { position: absolute; bottom: 12px; left: -5px; width: 15px; height: 20px; background: #546e7a; border-radius: 2px; border: 2px solid #222; } .spin { animation: spinProp 0.15s linear infinite; } @keyframes spinProp { 0% { transform: scaleX(1); } 50% { transform: scaleX(0.2); } 100% { transform: scaleX(1); } } /* 振動とオノマトペ */ .onomatopoeia { position: absolute; font-weight: bold; font-style: italic; pointer-events: none; text-shadow: 0 0 5px #000; animation: floatUp 1s ease-out forwards; z-index: 20; } @keyframes floatUp { 0% { transform: translateY(0) scale(0.8); opacity: 1; } 100% { transform: translateY(-40px) scale(1.2); opacity: 0; } } .shake { animation: shake 0.5s infinite; } @keyframes shake { 0% { transform: translate(1px, 1px) rotate(0deg); } 20% { transform: translate(-2px, 0px) rotate(1deg); } 40% { transform: translate(1px, -1px) rotate(1deg); } 60% { transform: translate(-2px, 1px) rotate(0deg); } 80% { transform: translate(-1px, -1px) rotate(1deg); } 100% { transform: translate(1px, -2px) rotate(-1deg); } }</style></head><body> <div id="game-layout"> <div id="control-panel"> <h1>[母船CIC] 無人探査機オペレーション</h1> <div id="status"> 現在深度: <span id="status-depth">0</span> m<br> <span style="font-size:14px; color:#aaa;">限界性能テスト(想定深度10,000〜15,000m)</span> </div> <div id="radio-log"> <span class="log-system">システム起動。母船とのリンク確立。</span><br> </div> <div> <button id="diveBtn">潜航開始 (遠隔操作)</button> <button id="stopBtn" disabled>バラスト投棄!(緊急浮上)</button> </div> <div id="result"></div> <button id="resetBtn" style="width:100%;">機体再セットアップ</button> </div> <div id="sea-window"> <div id="sea-content"> <div id="layer-fishes" class="creature-layer"></div> <div id="layer-whale" class="creature-layer"></div> <div id="layer-jelly" class="creature-layer"></div> <div id="layer-squid" class="creature-layer"></div> <div id="layer-angler" class="creature-layer"></div> </div> <div id="encounter-layer"></div> <div id="sub-container"> <div class="sub-cable"></div> <div class="sub-tower" id="sub-tower"></div> <div class="sub-body" id="sub-body"> <div class="sub-window" id="sub-window"></div> </div> <div class="sub-propeller" id="sub-propeller"></div> </div> </div> </div> <script> let currentDepth = 0; let maxDepth = 0; let timer = null; let bubbleTimer = null; let isCrushed = false; let onomaTimer = 0; let logCounter = 0; let encounterTriggered = false; let currentEncounterName = ""; const diveBtn = document.getElementById('diveBtn'); const stopBtn = document.getElementById('stopBtn'); const resetBtn = document.getElementById('resetBtn'); const depthSpan = document.getElementById('status-depth'); const resultDiv = document.getElementById('result'); const radioLog = document.getElementById('radio-log'); const seaWindow = document.getElementById('sea-window'); const seaContent = document.getElementById('sea-content'); const encounterLayer = document.getElementById('encounter-layer'); const subCont = document.getElementById('sub-container'); const encounters = [ { name: "太古の海竜 リヴァイアサン", class: "anim-drift", svg: "url(\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 300 300'%3E%3Cpath d='M250 50 Q200 100 150 50 T50 50 T10 150 Q50 250 100 200 T200 250 T280 150 Z' stroke='%237a7e99' stroke-width='15' fill='none'/%3E%3C/svg%3E\")", shadow: "rgba(120, 120, 180, 0.6)" }, { name: "異星の使者 マグナピンナ", class: "anim-creep", svg: "url(\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 200 300'%3E%3Cpath d='M100 20 Q130 10 120 60 Q150 60 180 80 L180 300 M100 20 Q70 10 80 60 Q50 60 20 80 L20 300 M120 60 L140 300 M80 60 L60 300 M100 60 L100 300' stroke='%236a8a8a' stroke-width='10' fill='none'/%3E%3C/svg%3E\")", shadow: "rgba(80, 180, 180, 0.5)" }, { name: "深淵を覗く 巨大な眼球", class: "anim-pulse", svg: "url(\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 200 200'%3E%3Ccircle cx='100' cy='100' r='70' fill='%233a2a34' stroke='%23854354' stroke-width='10'/%3E%3Cellipse cx='100' cy='100' rx='15' ry='50' fill='%23050505'/%3E%3C/svg%3E\")", shadow: "rgba(200, 50, 80, 0.6)" }, { name: "海底を這う クトゥルフの影", class: "anim-sway", svg: "url(\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 200 200'%3E%3Cpath d='M100 20 C150 20 180 80 150 120 C180 160 120 190 100 150 C80 190 20 160 50 120 C20 80 50 20 100 20 Z' fill='%232b363c' stroke='%234b565c' stroke-width='5'/%3E%3C/svg%3E\")", shadow: "rgba(50, 100, 100, 0.6)" }, { name: "星を喰らう 触手の群れ", class: "anim-drift", svg: "url(\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 200 200'%3E%3Cpath d='M100 200 Q150 100 180 20 M100 200 Q100 100 100 20 M100 200 Q50 100 20 20 M100 200 Q180 150 190 80 M100 200 Q20 150 10 80' stroke='%23755a79' stroke-width='12' fill='none'/%3E%3C/svg%3E\")", shadow: "rgba(150, 80, 180, 0.6)" }, { name: "亡霊艦隊の主 幽霊エイ", class: "anim-creep", svg: "url(\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 200 200'%3E%3Cpath d='M100 10 L190 100 L100 150 L10 100 Z M100 150 Q120 180 100 200 Q80 180 100 150' fill='%233b4a52' stroke='%235b6a72' stroke-width='3'/%3E%3C/svg%3E\")", shadow: "rgba(100, 150, 180, 0.5)" }, { name: "深海の大顎 メガロドン", class: "anim-sway", svg: "url(\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 300 200'%3E%3Cpath d='M20 100 Q150 20 280 100 Q150 180 20 100 Z M280 100 L250 80 L250 120 Z' fill='%232a303c' stroke='%234a505c' stroke-width='4'/%3E%3C/svg%3E\")", shadow: "rgba(80, 90, 110, 0.6)" }, { name: "無貌の肉塊 ショゴス", class: "anim-pulse", svg: "url(\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 200 200'%3E%3Ccircle cx='100' cy='100' r='80' fill='%233d2b3e'/%3E%3Ccircle cx='70' cy='70' r='20' fill='%23111'/%3E%3Ccircle cx='130' cy='110' r='30' fill='%23111'/%3E%3C/svg%3E\")", shadow: "rgba(120, 50, 120, 0.6)" }, { name: "幾千の腕 百手巨人", class: "anim-drift", svg: "url(\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 200 200'%3E%3Cpath d='M100 100 L20 20 M100 100 L180 20 M100 100 L20 100 M100 100 L180 100 M100 100 L20 180 M100 100 L180 180 M100 100 L100 20 M100 100 L100 180' stroke='%234e6a4d' stroke-width='10'/%3E%3Ccircle cx='100' cy='100' r='40' fill='%232e3a2d'/%3E%3C/svg%3E\")", shadow: "rgba(80, 140, 80, 0.6)" }, { name: "名状しがたい 幾何学の狂気", class: "anim-pulse", svg: "url(\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 200 200'%3E%3Cpolygon points='100,10 190,150 10,150' fill='none' stroke='%23888' stroke-width='5'/%3E%3Cpolygon points='100,190 10,50 190,50' fill='none' stroke='%23666' stroke-width='5'/%3E%3Ccircle cx='100' cy='100' r='50' fill='%23222' stroke='%23aaa' stroke-width='2'/%3E%3C/svg%3E\")", shadow: "rgba(150, 150, 150, 0.5)" } ]; let availableEncounters = []; function getNextEncounter() { if (availableEncounters.length === 0) { availableEncounters = encounters.map((_, i) => i); for (let i = availableEncounters.length - 1; i > 0; i--) { const j = Math.floor(Math.random() * (i + 1)); [availableEncounters[i], availableEncounters[j]] = [availableEncounters[j], availableEncounters[i]]; } } return encounters[availableEncounters.pop()]; } function addLog(text, className = "log-info") { const time = new Date().toLocaleTimeString('ja-JP', { hour12: false }); const line = document.createElement('div'); line.innerHTML = `<span style="color:#555;">[${time}]</span> <span class="${className}">${text}</span>`; radioLog.appendChild(line); radioLog.scrollTop = radioLog.scrollHeight; } function initGame() { maxDepth = Math.floor(Math.random() * 5001) + 10000; currentDepth = 0; isCrushed = false; encounterTriggered = false; currentEncounterName = ""; onomaTimer = 0; logCounter = 0; depthSpan.innerText = "0"; resultDiv.innerHTML = ""; radioLog.innerHTML = `<span class="log-system">システム再起動完了。機体データ正常。潜航準備よし。</span><br>`; diveBtn.disabled = false; stopBtn.disabled = true; seaWindow.style.backgroundColor = '#001e36'; seaContent.style.top = '0px'; encounterLayer.style.opacity = '0'; encounterLayer.className = ''; subCont.style.transform = 'none'; subCont.classList.remove('shake'); document.getElementById('sub-propeller').classList.remove('spin'); document.getElementById('sub-body').style.background = 'linear-gradient(to bottom, #eceff1, #90a4ae)'; document.getElementById('sub-tower').style.background = '#cfd8dc'; document.getElementById('sub-window').style.boxShadow = '0 0 12px #64ffda'; document.getElementById('sub-window').style.backgroundColor = '#64ffda'; document.querySelectorAll('.onomatopoeia, .bubble').forEach(e => e.remove()); } function createBubble() { const bubble = document.createElement('div'); bubble.className = 'bubble'; const size = Math.random() * 6 + 4 + 'px'; bubble.style.width = size; bubble.style.height = size; bubble.style.left = Math.random() * 100 + '%'; bubble.style.animationDuration = Math.random() * 2 + 2 + 's'; seaWindow.appendChild(bubble); setTimeout(() => { if (bubble.parentNode) bubble.remove(); }, 4000); } function spawnOnomatopoeia(text, color, size) { const span = document.createElement('span'); span.className = 'onomatopoeia'; span.innerText = text; span.style.color = color; span.style.fontSize = size + 'px'; const offsetX = (Math.random() - 0.5) * 120; const offsetY = (Math.random() - 0.5) * 80; span.style.left = `calc(50% + ${offsetX}px)`; span.style.top = `calc(300px + ${offsetY}px)`; seaWindow.appendChild(span); setTimeout(() => { if (span.parentNode) span.remove(); }, 1000); } diveBtn.addEventListener('click', () => { diveBtn.disabled = true; stopBtn.disabled = false; document.getElementById('sub-propeller').classList.add('spin'); addLog("オペレーター:「潜航シークエンス開始。スラスター出力正常。」", "log-info"); addLog("チーフ:「本日のミッションは限界性能の確認と深層調査だ。頼むぞ。」", "log-system"); bubbleTimer = setInterval(createBubble, 150); timer = setInterval(() => { currentDepth += 23; depthSpan.innerText = Math.floor(currentDepth); let lightness = Math.max(0.5, 20 - (currentDepth / 600)); seaWindow.style.backgroundColor = `hsl(210, 100%, ${lightness}%)`; seaContent.style.top = `-${currentDepth * 0.9}px`; let ratio = currentDepth / maxDepth; onomaTimer += 50; logCounter += 50; if (logCounter % 1500 === 0 && ratio < 0.92) { const infoLogs = [ `オペレーター:「現在深度${Math.floor(currentDepth)}m、降下レート安定しています。」`, "オペレーター:「外装温度低下。耐圧殻のデータ、正常値です。」", "チーフ:「カメラに深海生物の影が映っているな。記録しておけ。」", "オペレーター:「ソナーに微細な反応。周辺の生態系は豊かのようです。」", "システム:『水圧が設計安全基準を超過。マニュアル操作を継続します。』" ]; addLog(infoLogs[Math.floor(Math.random() * infoLogs.length)], "log-info"); } if (ratio > 0.92 && !encounterTriggered) { encounterTriggered = true; const randBoss = getNextEncounter(); currentEncounterName = randBoss.name; encounterLayer.style.backgroundImage = randBoss.svg; encounterLayer.style.filter = `blur(2px) drop-shadow(0 0 20px ${randBoss.shadow}) brightness(1.2)`; encounterLayer.className = randBoss.class; encounterLayer.style.opacity = '0.75'; addLog("オペレーター:「ちょ、チーフ!カメラ映像にノイズが...いや、何かいます!!」", "log-warn"); addLog(`チーフ:「なんだこの巨体は!? 生物データベースに該当なし!【${currentEncounterName}】と仮称する!」`, "log-encounter"); } if (ratio > 0.95) { subCont.classList.add('shake'); if (onomaTimer % 100 === 0) spawnOnomatopoeia("ピシィィィッ!!", "#ff1744", 32); if (onomaTimer % 1000 === 0) addLog("システム:『警告。外殻歪み率95%超過。即時の浮上を推奨。』", "log-danger"); } else if (ratio > 0.85) { if (onomaTimer % 200 === 0) spawnOnomatopoeia("メキメキッ!", "#ff9100", 26); if (onomaTimer % 1500 === 0) addLog("オペレーター:「フレームから異音!機体が限界を訴えています!」", "log-warn"); } else if (ratio > 0.7) { if (onomaTimer % 400 === 0) spawnOnomatopoeia("ギギギ...", "#ffea00", 20); if (onomaTimer % 2000 === 0) addLog("チーフ:「水圧がエグいな。応力センサーに黄色信号が出始めたぞ。」", "log-warn"); } else if (ratio > 0.5) { if (onomaTimer % 800 === 0) spawnOnomatopoeia("ミシッ...", "#ccc", 16); } if (currentDepth >= maxDepth) crushObject(); }, 50); }); function crushObject() { clearInterval(timer); clearInterval(bubbleTimer); isCrushed = true; stopBtn.disabled = true; subCont.classList.remove('shake'); document.getElementById('sub-propeller').classList.remove('spin'); subCont.style.transform = 'scaleY(0.1) scaleX(1.5)'; document.getElementById('sub-body').style.background = '#222'; document.getElementById('sub-tower').style.background = '#111'; document.getElementById('sub-window').style.boxShadow = 'none'; document.getElementById('sub-window').style.backgroundColor = '#050505'; spawnOnomatopoeia("ボシュゥゥゥン!!!", "red", 50); addLog("オペレーター:「ダメです! メインフレーム圧壊!!」", "log-danger"); addLog("システム:『通信途絶。探査機とのリンクをロストしました。』", "log-system"); addLog("チーフ:「...くそっ! やっちまったか...」", "log-system"); let msg = `通信途絶... ミッション失敗。<br>今回の限界は ${maxDepth}m だった。`; if (encounterTriggered) { msg = `深淵の主【${currentEncounterName}】の影に呑まれ、通信途絶...<br>限界: ${maxDepth}m`; } resultDiv.innerHTML = msg; resultDiv.className = "danger"; } stopBtn.addEventListener('click', () => { clearInterval(timer); clearInterval(bubbleTimer); stopBtn.disabled = true; subCont.classList.remove('shake'); document.getElementById('sub-propeller').classList.remove('spin'); addLog("オペレーター:「バラスト投棄! スラスター全開で急浮上します!」", "log-info"); addLog("システム:『緊急浮上シークエンス移行。機体上昇中...』", "log-system"); if (!isCrushed) { let ratio = (currentDepth / maxDepth) * 100; let remain = Math.floor(maxDepth - currentDepth); let msg = `浮上成功。深度${Math.floor(currentDepth)}mから生還。<br>`; if (encounterTriggered) { addLog(`チーフ:「よく止めてくれた! 【${currentEncounterName}】の映像データ、しっかり回収したぞ!」`, "log-encounter"); msg += `👑 大成功! 未知の存在【${currentEncounterName}】のデータ回収に成功!<br>限界までわずか ${remain}m (${ratio.toFixed(1)}%)`; resultDiv.className = "success"; } else if (ratio >= 85) { addLog("チーフ:「良いデータが取れた。だが未知の領域には一歩届かなかったな。」", "log-info"); msg += `🎉 性能テスト完了。だが真の深淵には届かず...<br>限界まであと ${remain}m`; resultDiv.className = "success"; } else { addLog("チーフ:「おいおい、チキンすぎるだろ。まだまだ潜れたぞ。」", "log-warn"); msg += `まだまだ余裕だな。深淵は遠いぞ。<br>限界まであと ${remain}m`; } resultDiv.innerHTML = msg; } }); resetBtn.addEventListener('click', () => { clearInterval(timer); clearInterval(bubbleTimer); initGame(); }); initGame(); </script></body></html>
■ 今日の学び
最初は、「水圧でモノが潰れる実験」と「チキンレース」を組み合わせた、
シンプルなアイデアから始まりました。
でも、演出を少しずつ足していくうちに、
いつの間にか“ギリギリの深海探索ゲーム”という、
ひとつの世界観を持った作品へと進化していきました。(⊙_⊙)
制作の途中で気づいたのは、
深海という未知の世界が持つ「畏怖」と「ワクワク」の感情です。
ホラーゲームや怖い映画を見ているときのような、
「怖い……でも、この先がどうなっているのか気になって仕方ない!」
という、あの独特の感覚。
「あと少しだけ先に進んだら、隠された何かに出会えるかもしれない……」
そんな“闇の向こうへの好奇心”が、
限界を攻めるチキンレースのゲーム性とぴったり重なり、
今回のテーマである
「ギリギリへの挑戦」をより深いものにしてくれました。(✧_✧)
ただのシステムでも、
世界観や人間の心理(とくに好奇心)と噛み合うと、
ゲーム体験は一気に面白くなる。
そんな、深海だけに“深い”学びを得られた実験でした。
■ 次回は、頭の中の霧も晴れるゲームです。
4字熟語って、意味はなんとなく覚えているのに、
ふとした瞬間に「あれ…?」と度忘れしてしまうこと、ありますよね。
そんな“頭の中の霧”を、
マグネチックスターラーのように キリンがぐるぐるとかき回して
スッキリ晴らしてくれるゲームを作りました!
次回も、楽しみにしてくださいね(*^v^)ノシ
✨今日も最後まで読んでくださって、ありがとうございます。
みーの実験室は、みなさんの応援で元気に動いています。(*^v^*)






🌈はじめての方へ
🌳 実験一覧
🌱 このブログについて
🍃 プライバシーポリシー
🐣未記事ゲーム展示室