v0でラーメンを作るゲームを作った話

## v0とはなにか

v0は、AIを活用したUI生成ツールです。ユーザーはUIの要件を入力するだけで、その場で実行可能なUIを生成してくれます。

例えば、「カルーセルを作ってほしい」と入力すると、v0がUIを瞬時に生成し、その場でプレビューして動作を確認できます。生成されたカルーセルはスムーズに画像が切り替わり、クリックや自動切り替えなどインタラクティブな操作も実際に試すことができます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/154239/5c7283a3-1669-f6a0-af65-43926fe40ca3.png)


生成されたコードも確認でき、ReactとTailwindなどを使って作っていることを確認することができます。また、このコードはカスタマイズが可能で、必要に応じて自身のプロジェクトに合わせて変更することもできます。
CLIを使ってプロジェクトに取り込むこともできますし、生成されたUIを公開することもできます。
## 今回何をしたのか？

某ラーメン店をイメージしたゲームを作りました！
https://b_o6rhm6xrmpx.v0.build/

本来は上で紹介したようなUIコンポーネントを作るツールなのですが、クライアントで完結するようなアプリであれば頑張って作ることができます。
このゲームはそこそこロジックが複雑なのですが、ちゃんと動くように作るため試したことなどをこの記事に書いていきます。

## 対象読者

* v0で何ができるのか知りたい人
* v0でゲームやアプリを作ってみたい人
* ReactやTailwindについては分からなくてもOK
* 何なら開発者じゃなくてもOK

## 書かないこと

* 生成されたUIをプロジェクトに取り込む方法
* 他ツールとの比較

## 環境

v0のFreeプランのみを使って製作しました。
執筆時点ではFreeプランは1日における生成リクエストの回数に制限があり、おおよそ10回程度の指示しか行えませんでしたが、朝9時(UTC24時)に回数が復活するので毎日ちょっとずつ指示をしていけば何とか作ることができます。

## 留意事項

v0はすごい勢いで進化しているため、ここで書いてあることは読んでいる時点では古い情報の可能性があります。
実際にこのゲームを作っている間でも
* コードの直接編集ができるようになった
* QuickEditという機能が追加された

などがありました。

## 生成のステップ

### 仕様を渡して全体を一度作成してもらう

まずは全体の骨組みを一度作成してもらい、その後、少しずつ調整していくのが効率的だと思います。必要な要素を追加・修正したり、配置を微調整することで完成度を高めていくことができます。

そのために、ゲームの概要や仕様、画面のイメージを具体的に渡し、プロトタイプをまるごと作ってもらいます。

実際に投げるプロンプトはエンジニアに渡すような仕様書をイメージしてもらえば良いと思います。具体的には、以下の内容を含めるようにします：

* アプリの概要: アプリの目的やどのような機能を持つのか
* ロジックの仕様: アプリの動作の流れや各機能のロジック
* 画面一覧と詳細: 各画面に表示される内容、ユーザーが行う操作
* 画面レイアウトとインターフェース: 主要なボタンや入力欄などの配置

これらを含めることで、生成AIにとっても理解しやすい仕様書になります。

まとめるのが難しければchatGPTなどの他の生成AIに仕様書として作ってもらうのもアリだと思います。
例えばchatGPTの有料プランに入っているなら「chatGPT with canvas」などを使って作るのがいいと思います。

今回最初に投げたプロンプトはこんな感じでした。


```
# ゲーム仕様書

## ゲームの概要

- **目的**: 1分間の制限時間内に、できるだけ多くのラーメンを正確に作って提供し、スコアを稼ぐ。

---

## ゲーム開始前の説明

1. **お客さんのコールに合わせてラーメンを仕上げよう！**
2. **コールの種類は3種類、ヤサイ、ニンニク、アブラがあるよ**
3. **それぞれ、なし/普通/マシ/マシマシから選べるよ。普通なら1回、マシなら2回、マシマシなら3回、対応するトッピングのボタンを押してね**
4. **ヤサイについてはコールがなくても普通の量が必要だよ。だけど、「ヤサイなし」と言われた場合はヤサイを押さないでね**
5. **ニンニクとアブラはコールなしの場合はなし。また、トッピング名だけ言われた場合は普通の量だよ（例：「ニンニクアブラ」は「ニンニク普通アブラ普通」と同じだよ）**
6. **各コールは順番が入れ替わることもあるよ**
7. **全マシと言われたら全部2回ずつ、全マシマシは全部3回ずつ押してね**

---

## ゲームの流れ

- **スタート**: ゲーム開始と同時に、お客さんがランダムなコールを言います。

- **操作**:
  - プレイヤーはコールに従ってトッピングのボタンを押します。
    - **ヤサイ**:
      - コールがなくても必ず1回押す（普通の量）。
      - ただし、「ヤサイなし」と言われた場合は押さない。
    - **ニンニク・アブラ**:
      - コールがなければ押さない（なし）。
      - トッピング名だけ言われた場合は1回押す（普通の量）。
      - 「マシ」: 2回押す。
      - 「マシマシ」: 3回押す。
    - **全マシ**:
      - ヤサイ、ニンニク、アブラをそれぞれ2回押す。
    - **全マシマシ**:
      - ヤサイ、ニンニク、アブラをそれぞれ3回押す。
  - **トッピングの順序**:
    - ボタンを押す順番は関係ありません。
  - **リセット機能**:
    - トッピングを押し間違えた場合は、リセットボタンで回数をリセットできます。
  - **提供**:
    - 最後に「提供」ボタンを押してラーメンを提供します。

- **得点**:
  - 正しいトッピングを行い提供すると、スコアが100点加算されます。
  - 間違った場合は得点が入りませんが、他のペナルティはありません。

- **時間制限**:
  - 1分間でできるだけ多くのラーメンを提供します。

---

## ユーザーインターフェース（UI）

- **上部**:
  - 吹き出しの中にお客さんのコールが表示されます。
- **中央**:
  - お客さんの画像が表示されます。
- **下部**:
  - **左側（縦に配置）**:
    - ヤサイボタン
    - ニンニクボタン
    - アブラボタン
    - リセットボタン（アブラの下）
  - **右側**:
    - 提供ボタン

---

## ゲーム終了後

- **結果発表画面**:
  - ゲーム終了後、獲得したスコアを表示する結果発表画面を表示します。

---

## 補足事項

- **コールの解釈**:
  - 「ヤサイニンニクアブラ」は「ヤサイ普通、ニンニク普通、アブラ普通」と同じ意味です。
  - 「ニンニクアブラ」の場合、ヤサイのコールがなくてもヤサイを1回押します（普通の量）。
  - ただし、「ヤサイなし」と言われた場合はヤサイを押しません。
  - 各トッピング名のみを言われた場合、そのトッピングは普通の量となります。

```

一発目からそこそこ動くアプリができました！

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/154239/25a6c880-1f68-6e58-5763-ef83332b5151.png)

ただ、動かしてみるといろいろとおかしいところがあるので調整していきます。

### アプリを調整していく

期待と違う動作をするポイントを伝え、直してもらうように指示していきます
複数の指示をいっぺんにお願いするとリクエスト回数の節約になりますが、うまくいかないこともあるので基本的には1リクエスト1指示でリクエストしていきます。

```
お客さんのコールの順番が一定になってしまっているのでコールを順不同にもなるようにしてください。
たとえば、アブラニンニクヤサイなしみたいなものも出すようにしてください
```

```
マシマシがマシとして認識されちゃってます 「アブラマシマシヤサイマシマシニンニクマシ」 というコールで

期待される注文：

ヤサイ: 2 ニンニク: 2 アブラ: 2

になってしまっています。期待される注文は

ヤサイ: 3 ニンニク: 2 アブラ: 3

であるべきです。修正してください。
```

UIについても調整していきます。

```
各トッピングのボタンをクリックすると数字が+1されるようになっていますが、
4以上は使わないので3の時にクリックしたら0になるようにしてください
```

```
正解した時と不正解の時にそれぞれエフェクトを出すようにしてください
```

最初に与えた仕様も変更できます。

```
間違えたら-100点にするようにしましょう
```

指示がうまく通れば直っていくはずです。
ただ、何度指示をしてもうまく直らないこともよくあります。
直らないままその日のリクエスト回数がなくなってしまうこともたびたびありますが、無料でやり遂げるためには気合と根性が必要です。

その中で工夫してみたことなどを次のセクションで書いてみます。

## 生成の際に工夫したこと

### コンポーネントを分けてみた

生成するときは、すべてのコードを書き直す処理が走ります。そのため、一つのファイルで作っている場合、UI部分しか変更がない場合でもロジックまですべて生成してしまい、時間がとてもかかります。

そこで、UIとロジックでファイルを分ければ生成の時間の節約になるのでは？と思ったので試してみました。


![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/154239/27fe1bb9-ce68-0a20-43ba-1ace2ababb5d.png)


この指示は上の通り成功し、ロジックはすべてUIと別のファイルに切り分けてくれたのですが...

ロジックのファイルのみを修正しても、UIが見ている先はそのUIを作った時にあったバージョンのロジックのファイルになってしまうという罠があり、ロジックを修正するたびにそれを確認するには

```
UIとロジックをつなげてください
```

のような指示が必要になり、結局この中でUIの再生成が走るため完全に無意味どころかリクエスト回数の無駄遣いになってしまいました。

あとでプロジェクトに取り込む場合は分かれていたほうが便利かもしれませんが、アプリを作ることが目的の場合は避けたほうがよさそうです。

ちなみに、修正箇所が少ない場合はv0の「QuickEdit」という機能が動き、行単位の修正をしてくれることがあります。
これめっちゃ早いので出ると嬉しいのですが、発動条件は分かりません。

### テストコードを書いてもらった

コールの処理について仕様が少し複雑な部分があり、何回指示してもコールのロジックがうまく直らないということがありました。
そこで思いついたのが、テストがあれば「✖✖のテストケースが通っていないため、それが通るようにロジックを修正してください。」のような指示をすることができるのでは？という事で、まずテストコードを書いてもらうことにしました。

```
テストを作ってください
テストケースには以下を含めて、これが通るように、また仕様に沿うようにロジックも修正してください
・「全マシ」の場合はすべて2ずつ
・「全マシマシ」の場合はすべて3ずつ
・「ニンニクヤサイ」など順序が違うコール
・「ニンニクアブラ」など、ヤサイに言及がない場合はヤサイを1
・「ニンニクなし」など、なしを含むコール
・「ニンニク普通アブラ普通」など「普通」を含むコール
```

テストコードは作ってくれたのですが、そのテストコードの実行はできないようで、残念ながら通るように修正という事はできませんでした。

### テスト画面を作ってもらった

テストコードが実行できないのであれば、テストを実行する画面をつくってもらえばいいのでは？という事をひらめき、作ってもらいました。

そして、これは抜群に効果がありました！

```
ヤサイコールがないときにヤサイがあってもなくても成功するように見えます。
組み合わせのテストケースをたくさん作ってテストを書いて、そのテストを実行できる画面を作ってください。 
テスト実行画面では、テストケースと実行ボタンと実行結果が出るような形で
その画面はタイトルから呼び出せるようにしてください
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/154239/a3d2ce47-3ce8-d113-a96d-dbe416407da7.png)

すべてのテストケースがパスしているように見えますが、テストケースが間違っていたため、修正の指示を出します。

```
テストケースですが、
注文: アブラマシマシ
トッピング: {"ヤサイ":0,"ニンニク":0,"アブラ":3}
期待結果: 正解
これはテストケースが間違っていて、期待結果は不正解が正しいです。
ヤサイはコールがない場合は1になるので正しくは
{"ヤサイ":1,"ニンニク":0,"アブラ":3}です
同様に
注文: ニンニク
トッピング: {"ヤサイ":0,"ニンニク":1,"アブラ":0}
期待結果: 正解
も不正解で
{"ヤサイ":1,"ニンニク":1,"アブラ":0}です
また、同様に
注文: アブラマシマシ
トッピング: {"ヤサイ":1,"ニンニク":0,"アブラ":3}
期待結果: 不正解
これは正解が正しいです。

これを元にロジックを修正してテストをすべて通るようにしてください
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/154239/e76602dc-8c7c-0008-dacc-c05b50acb0ec.png)

今度はテストが失敗している部分があるのでそれを修正してもらいます。

```
テストケース 5: 失敗
ヤサイなし場合はヤサイを0にする必要があります
テストケース 9: 失敗
これはテストケースが間違っています。期待結果は正解です
ロジックを修正してテストがすべて通るようにしてください
```

こんな感じでテストケースに応じて修正をお願いしていくことでそれまでうまく直せなかったロジックを完璧に直すことができました！

### どうあがいても直らないところはコードの指摘をする

これは本当に最終手段です。これやるなら自分で書けばいいじゃんってなるので...
ただ効果はダントツです。

```
2回連続で正解した時に2回目のエフェクトが出ません。
lastResultって2連続で正解の場合に値が変わらないからエフェクトが更新されないのではないでしょうか？
```

ちなみにv0は直接コード編集も可能になったので直したほうが早いです。
でも今回はReactが書けなくてもアプリが作れる！というコンセプトなので...

## ゲームをつくってみて

やり取りを見返したところ今回このゲームが完成するために生成リクエストをした回数は52回でした。
これに加えて、リクエストを修正してもう一度実行したりなどもあったため、60回を超えていると思います。
正直、まともなエンジニアであればこの程度のアプリなら数時間で作れると思いますし、ちゃんとしたアプリを作るのには微妙です。

そもそも、UI生成ツールでがっつりロジックがあるゲームを作ろうとしているのが間違いなのでは？と言われたらその通りで(記事を書くために情報を集めるまでアプリを作るツールだと思ってたのは内緒)

むしろv0はエンジニアが使うものではなく、PdMとかがプロトタイピングで使うのに適していると思います。

エンジニア不要で動く紙芝居的なプロトタイプを作れるので、それを自分たちで触ってみるとかお客さんに当ててみるとか、そういった使い方にはめちゃくちゃよさそうだと思いました。

## 終わりに

私の最高スコアは2600点なのでそれを越えられたら自慢してもいいです。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/154239/f433cb66-3ac6-e545-5e67-ff9164ec2b16.png)

おしまい