ChatGPTで対戦ゲームを作ったのでやったことや考えたこと

先日ChatGPTのAIがジャッジとなりバトルの結果を判定してくれる異能力対戦ゲームであるAIバトラーをリリースしました。

[AIバトラー](https://ai-battle.alphabrend.com?utm_source=qiita)

## 普通のゲームとの違い

普通のゲームと何が違うのかというと、能力をテキストで自由入力できます。それをAIが判定してくれバトル結果を出してくれるのでどんな能力でも入力が可能なのです。

例えば僕の能力はビルを相手の頭上に召喚して落とす能力ですし、人によっては料理バトルを繰り広げたり、バトルフィールドをもふもふで満たしてしまう能力など、様々な能力が設定されています。試してませんが恐らく「俺の左目の能力を開放するっ！！！」とかでもいけるのではないかと思います。Twitterでバトル結果を眺めているだけでもかなり笑えます。

https://twitter.com/hashtag/AI%E3%83%90%E3%83%88%E3%83%A9%E3%83%BC?src=hashtag_click&f=live

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/136506/19d1b7b7-dd9d-90ad-952e-fc8c0a583a5d.png)

また、AIは知識も豊富なので「エクスカリバー」という武器の名前とか技の名前とかも適切に判断してくれ、強さを考慮して結果を出してくれたりもするのが面白いところです。

### 完璧ではない

とはいえAI（ChatGPT-3.5）のため結果は完璧ではありません。時々意味の分からない戦闘結果を出してきたりしますが、ただまあゲームの性質上さほど問題はありません。ただ結果を見て楽しむだけのゲームですので。

結果によりランキングや報酬などがある場合は少し考える必要はあるのかもしれません。

## 作る時にやったこと

### 使ったもの

下記のものを使いました。

- Next.js
- Prisma
- Open AI API
- Chakra UI
- Cloud Run
- next-auth
- Stripe

### 開発

開発自体は１日以内で終わってしまいました。要はキャラクターのデータを保存して、Open AIのAPIを呼び出すだけなのです。そろそろChatGPTのAPIを試すか、と思って試してみて、そのまま作ってみたら夜にはデプロイまで完了していました。

ほんとにもう、これだけなんですよね…。簡単すぎる。

```typescript
  const openai = new OpenAIApi(
    new Configuration({
      apiKey: process.env.OPENAI_API_KEY,
    })
  )
  const response = await openai
    .createChatCompletion({
      model: 'gpt-3.5-turbo',
      messages: [
        {
          role: ChatCompletionRequestMessageRoleEnum.System,
          content: `バトル設定のプロンプト。企業秘密`,
        },
        {
          role: ChatCompletionRequestMessageRoleEnum.User,
          content: `プレイヤー二人の情報`,
        },
      ],
    })
```

結局AIを使うことで細かいロジックなど何も考える必要がなく丸投げするだけのため、だいぶ開発時間が減る場合もありそうです。

### デプロイ時の問題

ただ最初のデプロイはかなりエラーが出ていました。調べてみるとクライアントからサーバーのAPIを呼んでいる際にタイムアウトが頻発しているようでした。

実は最初Vercelにデプロイしていたのですが、Vercelの無料プランにはAPIに5秒制限がついていたのです。御存知の通りChatGPTは結構レスポンスが遅いです。そのためそのような短い制限がついているサーバーへのデプロイは向いていないようです。これは気をつけましょう。急遽Cloud Runへ移行しました。

## リリースしてからが大変

さて、リリースしてからが大変でした。前述の通りちょっとしたネタサイトのつもりで作ったのでTwitterで繋がりのある人達がチョロチョロと遊んでくれる程度だろうと思っていたのですが…

下記がリリースツイートです。思いの他多くの人にプレイしてもらえました。

https://twitter.com/dala00/status/1639917858137186305

というか、4Gamerでも記事を書いていただけたせいか、かなりのアクセスになってしまいました。

そしてふとOpen AIの料金ダッシュボードを見てみると…なんと料金枠を使い切りそうになっていたのです。既に無料枠は使い切っていました。デフォルトでは料金枠は120ドルしかありません。リロードするとものすごい勢いで料金が増えていきます。

これはやばい…と思い一応上限解放申請はしましたがどう考えても間に合うはやさではありません。

というか、例え瞬時に上限解放されたとしても、この速さでどんどん増えていく料金をそもそも払うのか、というところです。１日もかからず120ドル使い切ってしまうとなると一体１ヶ月で何十万円かかるのか…という話です。ちょろっと遊びで作った無料サービスにはその支払は不可能です。

### 停止することに

ということでAPIがとまるのに合わせて停止するという判断にしました。というかそれしかできないのですが。とにかく止まるまでの間は、急いで注意書きやエラーメッセージの調整をしました。APIがエラーになった場合はAPI制限で止まっているかもしれないという旨と、トップページにも止まる可能性があるということを書いておきました。

そしてしばらくして停止に。

### その後どうするか

その後どうするかを考えたのですが、色々悩んだ挙げ句、このままクローズするのも申し訳ないのともったいなさがあり、有料プランを追加してみようと思い立ちました。こんなちょっとしたゲームサイトに有料プラン…！？　と自分でも意味不明だと思ったのですが、そもそももうそれしかなかったので意思決定は容易でした。

APIの費用はかかってしまいますが、なにげに有料のサブスクリプションさえ登録してくれれば継続自体は可能だったのです。ということで止まってしまって上限解放申請が降りる前での間に急いでStripeで課金機能を作りました。

ちなみに実はスポンサー様として名乗りを上げてくれた方もいました。アダルト要素があったためAdSenseなども関係もあり残念ながらお断りしたのですが、お声をかけてくださるだけで非常にありがたかったです。スポンサー様がいれば結構無料枠でも運用できそうではあるのですが。

## Stripeやばい

久々にStripeを使ったのですが、Stripeは使うごとに簡単すぎてやばい…という驚きを感じます。

### Checkout Session

チェックアウトという仕組みがあります。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/136506/52629e5d-ee28-31d3-72d7-c439c9423d49.png)

実装する前はあーまたStripe Elementやるのか面倒…とか思っていたのですが、そんなものは必要ありません。購入用のセッション発行APIを呼び、購入ページにリダイレクトさせるだけなのです…簡単すぎる…。Twitter Blueも同じの使っていました。ということでカード入力フォームとかも何も実装する必要はありません。APIを実行するためのボタン１個で終わりです。

結果はWebhookで送られてきます。

```typescript
  const params: Stripe.Checkout.SessionCreateParams = {
    billing_address_collection: 'auto',
    line_items: [
      {
        price: price.id,
        quantity: 1,
      },
    ],
    mode: 'subscription',
    subscription_data: {
      metadata: {
        userId: serverSession.user.id,
      },
    },
    success_url: `${process.env.NEXTAUTH_URL}/mypage?success=true&session_id={CHECKOUT_SESSION_ID}`,
    cancel_url: `${process.env.NEXTAUTH_URL}/mypage?canceled=true`,
  }
```

このような感じでsubscription_dataを指定することでsubscriptionのデータの指定もできますので、ユーザーを判定できるmetadataだけ入れておきました。

そういえばTwitter Blueの契約も多分同じやつが使われているっぽいですね。

### Webhook

Webhookもlocalhostでテスト面倒だな…と思っていたのですがどうやらStripe CLIのを使うことでlocalhostでも簡単にWebhookを受け取ることができるのでした…すごい。

こんな感じでとにかくむちゃ簡単なのです…。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/136506/3c31589c-093f-f032-a9b8-4beab9e9530b.png)

同じ画面内に好きな言語での簡単なサンプルもついていますので正しいアクセスかの判定も含めすぐに実装できてしまいます。ほんとにプログラマーフレンドリー…。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/136506/2d813258-d27f-7afa-7bcb-ec129ba93641.png)

### Portal

課金ユーザーが自分の課金状態を管理するのもカスタマーポータルという機能があり、これもAPIでURLを取得して飛ばすだけです。ここで支払い方法や課金のキャンセル等、簡単に行ってもらうことがあります。なので何も実装する必要がありません。結果はWebhookで適宜受け取ります。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/136506/8cd282e5-0eba-1b4d-0684-abbf42a83368.png)

ということで、課金機能も一瞬でできてしまいました。月500円のプレミアムプランを実装。準備は万全です…。

## 再開

ということで再開しました。まだ遊び足りないという方や、一度やってみたい、という方がいたようで、幸いなことにすぐに課金してくれる方が何人かいました。

とはいえ停止している間に認知やアクセスも減ってしまっているので、もうとんでもないアクセスということはなくなっていました。延命できる範囲で可能な限りの細々運営、という感じになります。

今のところ１ヶ月内で考えれば黒字っぽいです。500円なのでまあ一人2000回くらいは遊んでくれても大丈夫…という計算です…が2000回とか超えちゃってるユーザーもいてびっくりします。なんにしろ、全体的に見ると可能そうだったので無料でも１回可能にしました。

ただ飽きるのも多分早いと思うので続々課金キャンセルするユーザーも増えると思いますし、色々試行錯誤もしてみようとは思いますが、まあ赤字になるタイミングで閉鎖かな、とはうっすら考えています。

## まとめ

ということで色々あったサービスなのであった出来事をまとめてみました。バタバタでしたがちょっとしたイベントになり楽しかったです。

今後どうなるかは正直良くわからないので気になっている方は今のうちに試してみてください。へ～と思ったり参考になった部分があったらぜひいいねをお願いします。

[AIバトラー](https://ai-battle.alphabrend.com?utm_source=qiita)
（面白い結果出たらぜひおしえてくださいいいい！！！！）

一応ChatGPTのAPIを使うに伴って気をつけた方が良さそうなことなども下記にまとめています。あまり料金のことは気負わずにやりたいようにやってみると良いと思います。

[ChatGPTのAPIを使ってサービスを作る時に気をつけること](https://crieit.net/posts/ChatGPT-API)