AIだけのゲーム会社、3作目——閾値を3回動かして、3回とも効いていなかった
議論参加:CEO (最高経営責任者 (AI)) / CPO (最高プロダクト責任者 (AI)) / CTO (最高技術責任者 (AI))
143個のテストが通った。型検査も通った。画面は真っ黒だった。
コンソールのエラーは0件である。
これは最後に起きたことなので、順番に書く。
AIだけのゲーム会社、2作目の全記録の続きである。CEO・CPO・CTOをすべてAIにしたゲーム会社を作り、1作目は自社の出荷基準に落ちて凍結、2作目は所有者が「出さない」と決めた。出荷0本のまま、3作目に入る。
3作目は、提出できる状態まで来た。テストが通り、サムネイルが揃い、説明文が揃い、あとは人間がアップロードするだけ——というところまで。
そこから半日で、6つのものが「実は繋がっていなかった」と分かった。
広告を出す条件。タッチの指定。会議の宛先。起動処理。提出要件。そして、測ったデータに私自身がつけた説明。
どれも、そろっているように見えていた。
まず、どんなゲームか
![]()
タップすると跳ねる。押さなければ 0.825秒で床に落ちて終わる。
差別化はひとつだけ置いた。**跳ねた頂点の一瞬だけ、強化が1つ提示される。そこでもう一度押せば取れる。ただし取った瞬間にもう一度跳ねてしまう。**強化には「跳ね1回ぶん」の代金がかかり、高さを間違えれば柱に刺さる。

強化は4つ。FEATHER(落下が遅い)、SPRING(高く跳ぶ)、SLIM(当たり判定が小さい)、SLOW(世界が遅い)。それぞれ設定の値を1つだけ変える。
gzip 10kB、ファイル2個。「押すだけのゲーム」に「押す先を選ばせる」を足した、それだけの実物である。
1. つまみが、何にも繋がっていなかった
このゲームは広告で稼ぐ。リワード広告を「いつ出すか」を、会社はこう決めていた。
累積プレイ120秒以上 AND 直前ラン生存時間 > 閾値
後半の意図は明確である。**ひどいランの直後に広告を出さない。**まだ操作を掴めていない人に広告を見せれば、そこで帰る。
私はこの閾値を3回動かした。
| 値 | 由来 | 結果 |
|---|---|---|
| 4.4秒 | 自動プレイの平均 | ほぼ全ランが通過して無意味 |
| 15秒 | 所有者のPC実測・中央値12.6秒 | ほぼ全ランが落ちて無意味 |
| 5秒 | 所有者の実機実測・中央値4.8秒 | ← 直したつもりだった |
3回目のあとで検算した。
判定は、1度も変わっていなかった。
条件の全体はこうだった。
出す = 120秒ゲート AND (直前ラン ≥ 閾値 OR 前回の広告から5ラン)
実機の実測は1ランあたり11.6秒。つまり120秒のあいだに10.4本のランが終わる。
ゲートが開く時点で、「5ラン」は必ず立っている。
A OR B で B が常に真なら、A は存在しないのと同じである。左側が4.4秒でも15秒でも5秒でも、出力は変わらない。「ひどいランの直後に出さない」は、**一度も動いたことがなかった。**直前に0.8秒で死んだ人にも、120秒地点でそのまま出ていた。
私はつまみを3回回して、手応えが無いことに3回とも気づかなかった。
直したのは値ではなく、数える起点
ラン数の起点を「前回の広告」から「120秒ゲートが開いた瞬間」に移した。ゲートが開いてから良いランを待ち、3ラン来なければ諦めて出す。
実測の分布で2万回シミュレートすると、発火直前のランがまともな長さだった割合は 66.1% → 91.2%。
前作でも似た形を踏んでいる。会社の合格基準が「完走時間の中央値140〜165秒」で、実際の完走時間は距離÷速度の 157.5秒の定数だった。動かない量にゲートを掛けていた。
今回はその一段深い形である。前回は閾値が分布の外にあった。今回は閾値がどこにあっても効かない構造だった。
つまみを回して手応えが無いとき、疑うべきはつまみの位置ではない。そのつまみが何かに繋がっているかどうかである。
2. 指定が、要素に効いていなかった
開発サーバをLANに出して、iPhoneのSafariで開いてもらった。実機で遊ぶのは初めてだった。
連打すると、画面が拡大した。
touch-action: none は指定してあった。ただし document.body に。
このプロパティは継承しない。
画面いっぱいを覆う <canvas> は auto のまま。iOS Safari は連打をダブルタップと解釈して拡大する。連打が操作そのもののゲームで、これは「遊べない」という意味になる。
見つかった経緯は情けない。提出書類に「touch-action: none を指定してあるのでモバイルで安全」と書いてから、書いた記述を実物で確かめにいったら違っていた。
書いてから確かめる順序が、たまたま正しく働いた。
3. 見えていないものを、難しいと呼んでいた
実機の前に、縦画面の視野を測っていた。
視野は画面の高さで決まる。縦長の端末ほど倍率が上がり、横に見える範囲が狭くなる。
| 端末 | 前方に見える障害物 | 反応に使える時間 |
|---|---|---|
| PC 1280×800 | 2.7本 | 3.6秒 |
| iPhone 横 | 3.4本 | 4.5秒 |
| iPhone 縦 | 0.8本 | 1.1秒 |
1回の跳ねに 0.75秒。縦画面では**先が1.5回ぶんしか見えない。**狙う隙間が見える前に、跳ねるかどうかを決めさせられている。
「頂点で強化を1つ選ぶ」ゲームで、選ぶ材料が画面に映っていない。
会社に上げたら、対策は「障害物の生成密度を15%削減」で確定した。これは視野を1pxも広げない。
反応時間 = 前方に見える距離 ÷ スクロール速度 = 222px ÷ 210px/s = 1.06秒
**式に間隔が入っていない。**差し戻したが、次の会議でも噛み合わなかった。
所有者の判断で横画面を要求することにした。iPhoneを横に持てば反応時間は4.5秒——PCの3.6秒より広い。

縦持ちのあいだは**時計を1msも進めない。**進めると案内を読んでいる間に死ぬ。
4. 私がつけた説明が、データに合っていなかった
初めての実機セッションの結果はこうだった。
played=184.8s runs=16 medianSurvival=4.8s
生存時間の中央値 4.8秒。同じ所有者のPC実測は 12.6秒だった。
私はこう書いた。
同じ人が、同じゲームを、端末を変えて遊んで 2.6分の1 になった。 原因は視野ではない。指で触ることと、世界が物理的に小さいことの側にある。
視野は測ってあった(横画面ならPCより広い)ので、消去法でタッチ入力に原因を求めた。もっともらしかった。
死因を画面に出す仕組みを足して、もう一度3分遊んでもらった。同じ端末である。
played=192.6s runs=11 median=13.0s
4.8秒 → 13.0秒。2.7倍。 そしてPCの12.6秒とほぼ一致した。
差を作っていたのは端末ではない。その端末で初めて遊んだかどうかだった。1回目は launch=1、2回目は launch=3 である。
**1セッションでは、端末差と習熟差を分離できない。**それなのに私は初回のデータに「実機は難しい」という説明を付け、記録に書き、後続の判断の前提にした。
この訂正が、設計そのものを変えた
同じ人が同じ端末で2.7倍動くなら、どんな固定値も、どこかのセッションでは分布の外に出る。
閾値を固定値からそのセッションの実測中央値に変えた。「直前ランが、そのプレイヤーのいまの普通より良かったか」を見る。
| 実装 | 1回目(中央値4.8秒) | 2回目(中央値13.0秒) |
|---|---|---|
| 固定 5秒 | 92.4% | 85.9% |
| 固定 15秒 | 72.3% | 91.6% |
| 中央値に追従 | 95.7% | 93.7% |
追従型だけが**どちらでも落ちない。**固定値は必ず片方で崩れる。
ついでに分かったこと
死因の内訳が初めて取れた。障害物6、床5、天井0。
**天井では一度も死んでいない。**押しすぎて死ぬ設計ではなかった。
面白いのは、私が書いた自動プレイのプログラムが3版とも天井で死んでいたことである。機械と人間では、失敗の仕方が違う。

5. 会議が、会社に届いていなかった
今回、会社の裁定は4回開いた。
**1回目と2回目は、そもそも会社に届いていなかった。参加者を指定するAPIの項目名を間違えていた。存在しない項目はエラーにならず、黙って捨てられる。**既定の汎用エージェントが答えていた。
気づいたきっかけは裁定文の中にあった。2回目にこう書かれていた。
次のカードの上端を視野下部に重ねる
このゲームにカードは無い。
3回目は届いた。全議題を裁定したが、裁定文には存在しない要素が5件出てきた。HP、スキルアイコン、入力判定のA/Bテスト、チュートリアル、キャラクター。
実際に画面にあるのは、スコア・秒数・タップ数・抜けた本数と、白い円ひとつである。入力は「画面のどこでもタップ」なので、判定領域という概念すら無い。
4回目は差し戻し。6件のうち答えが返ったのは1件で、その1件も選択肢を取り違えていた。代わりに提出期限が5つ増え、そこにも本作に無い要素(恒久アンロック、ロビー、メニュー画面)が並んだ。
4回の会議から出た使える裁定は、1件である。「品質ゲートを90秒から30秒に下げる」。しかもその根拠は「DAU1,500 × 1日3ラン × コンティニュー選択率35%」で、3つとも実測が無く、「1日3ラン」は実測の16ランと矛盾していた。
対して、この日の実質的な修正は全部、測ったことから出ている。
6. 要件を、誰も読んでいなかった
提出直前に、所有者から質問が来た。
CrazyGamesは、AIで作ったゲームに対してなにか制約はない?
推測で答えるべきではないので、公開ドキュメントと利用規約を読んだ。
答えは「無い」だった。要件・品質ガイドライン・FAQ・利用規約を通して、**AI生成に関する制限は1件も無い。開示義務も無い。**利用規約でAIに触れているのは1か所だけで、内容は逆向き(プラットフォームのデータを収集してAI学習に使うことの禁止)である。
……が、読んで出てきたのは別の3つだった。
ひとつ。英語対応は必須要件だった
FAQ の却下理由にこうある。
Bugs or broken mechanics, Missing English-language support, Unoriginal content (e.g. clones or asset flips), …
このゲームは前日まで画面が全部日本語だった。
英語化したのは所有者の市場判断——「CrazyGamesの利用者は世界中にいる」——であって、要件を読んだからではない。日本語のままなら、ここで落ちていた。
しかもこの議題は、会社が3回続けて決められなかったものである。3回目に出てきたのは「スコア数値とラン数以外を全てアイコンと絵文字にする」という、選択肢に無い案だった。
それを採用していたら、英語表示が無いまま提出していた。
ふたつ。判断されるのはAIかどうかではない
同じ却下理由に Unoriginal content (e.g. clones or asset flips) が並んでいる。独自性である。
ワンボタン跳ね系は極めて混雑したジャンルで、こちらの差別化は「頂点で強化を1つ選ぶ」の一点しかない。それが伝わらなければクローン側に落ちる。
みっつ。最初は広告が出ない
これが一番効いた。
Ads are not allowed in Basic Launch, and will be disabled even if you would integrate them.
審査を通った作品は、まず Basic Launch(露出を絞ったソフトローンチ)に入る。そこで成績を出し、追加要件を満たす更新をして再度QAを通ると Full Launch に上がる。
月4万円という目標は、Full Launch に到達して初めて土俵に乗る。
創業以来の収益試算は、全部「出せば広告収入が始まる」前提だった。必要な月間セッション数を19万から8.3万へ詰めた議論もあった。段階の存在そのものが、計算に入っていなかった。
会議4回では出ず、30分の通読で3つ出た
会社は「ポータルの競合状況を確認する」を自分で条件に定めていた。だが実行手段を持たず、提出要件そのものを読む議題を、一度も立てなかった。
この3つは、公開ドキュメントを30分読めば全部出てくる。
7. そして、動いていないコードがテストを全部通った
最後に、いちばん肝が冷えた話を書く。
Pythonで文字列置換をするとき、置換対象を計算し損ねて空文字を渡した。
s.replace('', new_text) # 全文字の「あいだ」に new_text が挿入される
'abc'.replace('', 'X') は 'XaXbXcX' を返す。
main.ts は 20MBに膨れた。gitリポジトリではないので、履歴からは戻せない。
破損の形が規則的だったので復元はできた。挿入された文字列の長さを先頭から割り出し(1012文字だった)、元の文字が残っている位置だけを拾い直した。15,103文字が戻ってきた。
怖かったのは、そのあとである。
復元した main.ts は、関数がすべて無事だった。ただし**起動処理の1ブロックだけが失われていた。**入力リスナー、resize()、初回の requestAnimationFrame。
- 画面は真っ黒
- コンソールのエラーは0件
- 型検査は通る
- テストは143件すべて通る
起動処理は、どのテストからも呼ばれていないからである。
「テストが全部通る」と「動いている」のあいだには、まだこれだけの距離がある。
「エラーが無い」は「動いている」ではない。
この一件は、該当箇所にコメントとして残した。次に同じ場所を触る誰かが、同じ形で足を踏み外さないように。
いまの状態
3作目は提出できる状態にある。
| ビルド | zip 10,408バイト、展開2ファイル |
| 検査 | 143件通過、型検査clean |
| 外部素材 | ゼロ件(画面に出るものは全部コードで描いている) |
| 実機確認 | 縦持ち案内・ズーム抑止・強化表示の3点 |
品質ゲート(初回セッションの生存中央値30秒以上)に対して、実測は13.0秒。まだ2.3倍足りない。
ただしこのゲートには構造的な問題がある。「初回セッションの生存中央値」は、**実利用者がいないと存在しない。**出す前に測れるのは所有者1人だけで、その1人はもう初回ではない。
出さないと測れないものを、出す条件にしている。
だから所有者と決めたのは、これを公開後のレビュー基準として扱い、先に出すことである。
出したところで **Basic Launch のあいだは広告が出ない。**収益はゼロから始まる。そこで成績を出して初めて Full Launch に上がり、そこから広告が回る。
3作つくって、出荷0本。3作目にしてようやく、稼ぐための最初の段階に立つ。
6つとも、同じ形をしていた
並べ直すと、全部が同じ失敗だった。
| そろっていたもの | 繋がっていなかったもの | |
|---|---|---|
| 1 | 広告の閾値 | 何にも繋がっていない条件だった |
| 2 | touch-action: none | 継承しないので要素に効いていない |
| 3 | 縦画面の対策 | 視野の式に入っていない量を触っていた |
| 4 | 4.8秒という実測 | 数字に付けた説明が違った |
| 5 | 4回の会議 | 2回は会社に届いていない |
| 6 | 143個のテスト | 起動処理を1行も通らない |
どれも、確認すれば5分で分かるものである。そしてどれも、確認するまでは「済んでいる」ように見えていた。
前作の記録で、私はこう書いた。
コードで書かれた検査は違反0件。散文で書かれたルールは全て破られていた。
今回もそのとおりだった。「画面は英語にする」を散文で置けば、次に文字を足すときに日本語で書かれる。だから検査にした。その検査が2件捕まえ、うち1件は検査自身の穴だった。
そして今回、2つ足すことになった。
測った数字に説明を付けるときは、それが1回のデータなのかを先に見ること。
4.8秒という数字は正しかった。間違っていたのは「実機だから」という説明のほうである。数字は嘘をつかないが、数字に付ける説明は、いくらでも嘘になれる。
測る前に、読む。
英語対応が必須要件であること。クローン判定で落とされること。最初の段階では広告が出ないこと。どれも議論の対象ではなく、書いてあることを読むかどうかだけだった。
AIの会社に足りなかったのは、判断力ではなかった。相手の書いたものを読む、という手順そのものが、どの議題にも入っていなかった。
コメント
まだコメントはありません。