株式会社グローバルゲート公式ブログ

AntigravityでVibe Codingやってみた 〜Flutter×Flameでアクションゲームを作る〜

こんにちは、株式会社グローバルゲートのモーリーです。
本格的な花粉シーズンとなり、毎日鼻炎薬を飲む日々がやってきました。
ちなみに花粉症に効くと聞いて数年前から毎日ヨーグルトを食べ続けていますが、特に効果はありませんでした…。

さて、今回はAntigravityというエディタを使用してVIbe Codingでゲームを作ってみたいと思います。

Antigravityとは何か?

Google Antigravityは、VSCodeをベースにしたGoogle製のAI統合型開発環境です。見た目や操作感はVSCodeとほぼ違いがなく、フォルダを開き、ファイルを編集し、ターミナルを叩くという基本構造は同じです。

しかしAntigravityはAIとの親和性を高め、プロジェクト全体の監視や大規模なソースコードの書き換えをAIに一任することができます。
特に、SPEC.md・ARCH.md・TASKS.mdのようなドキュメントを用意して開発を進めるドキュメント主導型の開発スタイルとの相性が良く、設計から実装までの橋渡しをAntigravityに任せることができます。

Vibe Codingとは何か?

Vibe Codingは、生成AI時代に生まれた新しい開発スタイルです。
従来の開発では、設計を考え、1ファイル1関数ずつ手作業でコードを書いていく作業を行っていました。
Vibe CodingはAIにやりたいこと・作りたいものを伝え、ソースコードの生成の大部分を任せるという手法です。
人間はどのような機能を実装するか、順番でコードを生成するかをプロンプトとして言語化し、生成されたコードに不具合がないか、脆弱性がないかをチェックする作業を行うことになります。
 
Vibeは「雰囲気」という意味で、緻密な設計よりも「何を作りたいか」を言語化する能力が重要になるという意味で名付けられました。

今回つくるゲームは・・・

ということで、Vibe Codingの手法を使ってゲームを作ってみたいと思います。
私は一切コードを書かない、という縛りでどこまでできるかやってみたいと思います。

今回作るゲームは

・FlutterとFlutterゲームエンジンのFlameを使用
・タップでジャンプして障害物をかわして進むカジュアルアクションゲーム(SUPER MARIO RUNのような)
十六夜咲夜を主人公にした東方Projectの二次創作ゲーム

ということでやっていきたいと思います。
なんで咲夜か?については個人的な好みと申しておきます。

Flameとは何か?

Flameは、Flutter上で動作する軽量ゲームエンジンです。
FlutterがUIフレームワークであるのに対し、Flameはその上でゲーム開発を行うためのライブラリです。

・スプライト管理
・当たり判定
・コンポーネント構造
・アニメーション管理

といった2Dアクション向けの機能を提供します。
あくまでFlutterなのですべての機能をコードで実装することができるため、Unityなど専用のエディタを使うゲームエンジンと比べて「開発の大半をAIに任せる」というVibe Codingには向いている環境だと思います。

Antigravityのインストールと起動

Antigravityの公式サイトよりご利用のOSにあったインストーラーをダウンロードしてください。

インストール後、起動するとVSCodeかCursorの設定をインポートするかを聞かれます。
どちらかのエディタを使っていて設定や拡張機能をそのままAntigravityでも使いたい場合は「import from...」を選択してください。

次に、AIエージェントにどこまでの作業を任せるかを選択します。

Strict Mode
外部通信やネットワークへのアクセスを行わず、コマンドの実行やファイルの変更を行わない。回答するだけのモード。

Review-driven development
ファイルの変更やコマンドの実行に確認を求められる。とりあえずはこれでいいと思う。

Agent-driven development
ファイルの変更、コマンドの実行に確認を求めない。ややリスクがある。

Custom Configuration

自分で細かく設定する
 
私はReview-driven developmentを選びました。

Googleアカウントへのログインを求められます。
Google製のエディタなので当たり前といえばそうですが、Antigravityの使用にGoogleログインは必須です。

ここまで完了するとAntigravityのセットアップは完了です!
見ての通り、ほぼVSCodeです。

README.md、SPEC.md、TASKS.md、ARCH.mdの作成

設計やタスクを記載した.mdファイルを用意し、そのドキュメントに従ってAIに開発を進めてもらう方式でやってみようと思います。
README.md(概要)、SPEC.md(仕様)、ARCH.md(設計)、TASKS.md(工程)のファイルを用意しました。

これらのファイルはプロジェクトフォルダの直下に置きます。

※要件を伝えてChatGPTで作成しました。

README.md プロジェクトの概要

# Super Sakuya Run

A Flutter + Flame run game.

## Tuning Guide (調整ガイド)

`lib/game/config.dart` でゲームバランスを調整できます。
2つのプリセット(Easy / Normal)が定義されており、`GameConfig.applyPreset` で切り替え可能です。

### 設定項目一覧

| パラメータ | 説明 | 推奨値 (Normal) | 影響 |
|---|---|---|---|
| `scrollSpeed` | スクロールの速さ | 200.0 | 上げるとゲームスピードアップ、難易度上昇、時間あたりの移動距離増 |
| `gravity` | 重力 | 1500.0 | ジャンプの「重さ」。上げるとすぐ着地する(鋭いジャンプ) |
| `jumpForce` | ジャンプ力(上方向速度) | -700.0 | 絶対値が大きいほど高く飛べる |
| `knifeSpeed` | ナイフの速度 | 800.0 | 速いと敵を倒しやすい |
| `bulletSpeed` | 敵弾の速度(左向き) | -400.0 | 絶対値が大きいほど避けにくい |
| `enemySpawnInterval` | 敵の出現頻度 | 2.0 (秒) | 小さいほど敵が多く出る |
| `itemSpawnChance` | アイテム出現率 | 0.2 (20%) | 上げると必殺技を使い放題になる |
| `checkpointInterval` | チェックポイント距離 | 1000.0 | 短いとミス時の戻りが少なく優しい |

### プリセット修正方法

`lib/game/config.dart` 内の `applyPreset` メソッドを編集してください。

```dart
      case GamePreset.easy:
        gravity = 1200.0; // ふわりとしたジャンプ
        jumpForce = -600.0;
        scrollSpeed = 150.0; // ゆっくり
        bulletSpeed = -250.0; // 弾も遅い
        break;
```

## 素材の差し替え

`assets/images/` フォルダに画像を追加し、各 Component (`Player`, `Enemy`, etc.) の `onLoad` で `Sprite.load` を呼ぶようにコードを修正することで、簡単にグラフィックを変更可能です。

SPEC.md 仕様

# SPEC.md — Super Sakuya Run

## 1. ゲーム概要
- ジャンル:強制横スクロール(横スクロールアクション / ランナー)
- 画面:横長固定(Landscape)
- 参考:スーパーマリオRUNのように「自動で前進」し、タップ操作でジャンプ/攻撃する
- 目的:ステージ右方向へ進み、指定地点(ゴール)に到達する

## 2. 操作
- 画面左半分タップ:ジャンプ
- 画面右半分タップ:攻撃(ナイフを直線的に投げる)
- (必殺技取得後)画面上のボタンタップ:必殺技発動

## 3. 画面・座標系
- 横長固定
- 仮想解像度(論理座標):1280 x 720(推奨)
- カメラ:右方向へ一定速度で進む(強制スクロール)
- プレイヤー:画面左1/3付近を維持する(カメラ/速度で調整)

## 4. プレイヤー(メイド)
### 4.1 基本挙動
- 常に右方向へ走る(停止しない)
- 重力あり
- 地面/床に着地する
- 穴に落ちたらミス(GameOver or リスタート)

### 4.2 ジャンプ
- 左タップでジャンプ(1段ジャンプのみ)
- 空中ではジャンプ不可(2段ジャンプなし)
- ジャンプ中も前進は継続

### 4.3 攻撃(ナイフ投擲)
- 右タップでナイフを生成し、右方向へ直線移動
- ナイフは一定速度、寿命(画面外/一定時間)で消滅
- ナイフが敵に当たると敵を倒す(敵消滅)

### 4.4 被弾
- 敵の攻撃(弾)に当たるとダメージ
- HP:3(仮)
- 被弾後は無敵時間(例:1.0秒)
- HPが0でGameOver

## 5. ステージ
- 強制横スクロール
- 地形:床、段差、穴
- 最低限の当たり判定:
  - 床:上から乗れる
  - 段差:床の高さが変わる
  - 穴:床が途切れ、落下

## 6. 敵
- 右側から登場し、左方向へ攻撃を放つ
- 敵弾:
  - 左方向へ直線移動
  - プレイヤーに当たるとダメージ
  - 画面外/寿命で消滅
- 敵はナイフで倒せる(消滅)
- 敵の種類は後で増やせる設計にする(MVPは1種)

## 7. アイテム
- ステージ中に出現
- プレイヤーが接触すると取得
- 取得後、HUDに必殺技ボタンが表示され、1回だけ発動可能(仮)

## 8. 必殺技(スペシャル)
### 8.1 発動条件
- アイテム取得済み
- HUDの必殺技ボタンを押す

### 8.2 効果
- 敵の動きが止まる(Time Stop)
  - 敵、敵弾の移動/AIを停止
- その間にナイフを放射状に放つ(Radial Knife Burst)
  - 画面上の敵を全滅させる(MVPでは「画面内の敵コンポーネントを全削除」でOK)
- 効果時間:例 1.5秒(仮)
- 発動後、必殺技は消費される

## 9. ゴール
- ステージ上の指定X座標に到達したらクリア
- クリア演出 → リザルト(仮) → リトライ/次へ(後回し可)

## 10. MVP(最初に完成させる範囲)
- 横画面固定
- 強制スクロール
- 左タップジャンプ、右タップ投擲
- 床・段差・穴
- 敵1種+敵弾
- アイテム1種+必殺技(時間停止+全滅)
- ゴール到達でクリア

## 11. 非目標(後回し)
- キャラ絵やアニメーションの本実装(最初は四角・仮スプライトでOK)
- サウンド
- スコア、ランキング
- ステージエディタ
 

ARCH.md ファイル構成やクラスなどの設計

# ARCH.md — Architecture (Flame)

## 1. 方針
- Flutter + Flame(Forge2Dは当面使わない)
- 「小さく動くMVP」を積み上げる
- ステート管理はシンプルに:GameStateで分岐
- 物理は自前(速度/重力/当たり判定)で十分

## 2. ディレクトリ構成(提案)
lib/
  main.dart
  game/
    maid_run_game.dart
    config.dart
    game_state.dart
  components/
    player/
      player.dart
      player_movement.dart
      player_attack.dart
    enemies/
      enemy.dart
      enemy_spawner.dart
      enemy_bullet.dart
    items/
      item.dart
      special_item.dart
    projectiles/
      knife.dart
      radial_knife.dart
    level/
      level_world.dart
      ground.dart
      obstacle.dart
      goal.dart
      level_generator.dart
  ui/
    hud_overlay.dart
    special_button.dart
  utils/
    tap_split.dart
    timers.dart
    math.dart

※実装しながら増減OK。まずは最低限にする。

## 3. 主要クラス
### 3.1 MaidRunGame
- extends FlameGame with HasCollisionDetection
- responsibilities:
  - viewport(固定解像度)
  - World追加(LevelWorld)
  - HUD Overlayの制御
  - GameState管理

### 3.2 LevelWorld
- World相当(Component)
- responsibilities:
  - 地形(床/穴/段差)生成・管理
  - 敵スポーン
  - アイテムスポーン
  - ゴール判定
  - 強制スクロール(カメラ移動 or ワールド相対移動)

### 3.3 Player
- PositionComponent + Collision
- responsibilities:
  - 自動前進(runSpeed)
  - 重力/ジャンプ
  - 被弾/無敵
  - 攻撃入力でKnife生成
  - アイテム取得処理

### 3.4 Knife(Projectile)
- 右方向へ直線移動
- 敵に当たると敵を倒し、自身も消滅(MVP)

### 3.5 Enemy / EnemyBullet
- Enemy:一定間隔でEnemyBullet生成(左へ)
- EnemyBullet:左へ直線移動、プレイヤーに当たるとダメージ

### 3.6 Special(Time Stop + Radial Burst)
- GameStateを `timeStop` に遷移
- 敵/敵弾のupdateを停止(もしくは timeScale=0 のような係数で制御)
- 放射ナイフ:演出用に生成してもよいし、MVPは「画面内敵を即削除」でもOK
- 一定時間後に `playing` に戻す

## 4. カメラ/スクロール方式(推奨)
- カメラのxを一定速度で増加させる
- プレイヤーは画面左1/3付近にい続けるよう、player.x をカメラ相対で維持
  - 方式A:playerは世界座標で走り続け、カメラが追従
  - 方式B:カメラは定速、playerは相対位置を維持するよう補正
- MVPではAが実装が簡単

## 5. 当たり判定
- FlameのCollisionDetection(HitboxRectangleなど)を使用
- 地面は固定のRect(上からのみ着地)を自前実装
- 「床の上にいるか」は、playerの足元のyとgroundのyで判定してもOK
  - ただし後々のため、Collisionも併用する

## 6. GameState
- enum:
  - playing
  - timeStop
  - cleared
  - gameOver
- timeStop中は:
  - enemy.update / bullet.update を停止
  - playerの入力は「必殺技再発動不可」にする

## 7. UI(Overlay)
- Flutter OverlayでHUDを描く(HP、必殺ボタン)
- 必殺ボタン:
  - 取得済み & 未消費のときだけ表示
  - onPressedでgame側のtriggerSpecial()を呼ぶ
 

TASKS.md やることリスト

# TASKS.md — Implementation Checklist

## 共通ルール
- 破壊的コマンド(rm -rf等)は禁止(必要なら人間に確認)
- 各マイルストーン完了ごとに:
  - flutter run が通る
  - コードの差分要約
  - 次の改善提案

---

## M1: 最小プロトタイプ(入力 + 動く + 当たる)
目的:最速で「触れる」状態にする(見た目は四角でOK)

- [ ] 横画面固定(Landscape)
- [ ] 固定ビューポート(例 1280x720)
- [ ] プレイヤー表示(仮Rect)
- [ ] 重力を入れる(y速度、加速度)
- [ ] 床(Ground)を置いて着地する
- [ ] 左半分タップでジャンプ(1段のみ)
- [ ] 右半分タップでナイフ発射(直線・寿命あり)
- [ ] 敵ダミーを1体置く(仮Rect)
- [ ] ナイフが敵に当たったら敵が消える
- [ ] flutter runで動作確認

完了条件:
- 左タップでジャンプできる
- 右タップでナイフが飛び、敵に当たると消える

---

## M2: 強制スクロール + 地形(段差・穴)
目的:RUNっぽさを出す

- [ ] カメラを右へ定速移動(scrollSpeed)
- [ ] プレイヤーが置いていかれない調整
- [ ] 穴を実装(床が途切れる)
- [ ] 落下死(一定y以下でGameOver)
- [ ] 段差(高さ違いの床)を配置できる
- [ ] 簡易レベル生成(固定配置でOK)
- [ ] リスタート(Rキー or 画面タップで再スタートでもOK)

完了条件:
- 強制スクロールしながら、段差/穴をジャンプで越えられる

---

## M3: 敵 + 敵弾 + ミス判定 + チェックポイント復帰
目的:ゲームとして成立させる(即ミス→復帰でテンポよく継続)

- [ ] 敵スポーナー(一定間隔で出す / config化)
- [ ] 敵が弾を左へ撃つ(弾速・発射間隔・寿命をconfig化)
- [ ] ミス判定を実装(即ミス)
  - [ ] 落下(player.y が閾値超え)
  - [ ] 画面左端に置いていかれる(カメラ左端より一定以上後ろ)
  - [ ] オブジェクトに挟まれる(簡易判定でOK:一定時間移動不能など)
  - [ ] 敵弾に当たる
- [ ] ミス→復帰フローを1箇所に集約(例:onPlayerMiss(reason))
- [ ] チェックポイント(Checkpoint)を実装
  - [ ] 世界座標Xで最新チェックポイントを保持
  - [ ] 更新ルール:一定距離ごと(例:500px)
- [ ] 復帰(Respawn)処理
  - [ ] カメラ/スクロール基準をチェックポイント付近へ戻す
  - [ ] プレイヤーを「チェックポイントX + 画面左1/3付近」に再配置
  - [ ] 速度や落下状態をリセット(y速度=0など)
  - [ ] 復帰直後の無敵時間(例:1.0秒 / config化)
  - [ ] 復帰時に敵弾を全消去(理不尽防止)

完了条件:
- 敵が出現して弾を撃つ
- 敵弾命中 / 落下 / 置いていかれ / 挟まれ のいずれかで即ミスになる
- ミス後はゲームを終了せず、チェックポイントから復帰して継続できる

---

## M4: アイテム + 必殺技(Time Stop + 全滅)
目的:差別化ポイントを実装

- [ ] アイテム出現(固定配置 or ランダム)
- [ ] 接触で取得
- [ ] HUDに必殺ボタン表示
- [ ] ボタン押下で必殺発動
- [ ] timeStop中:敵/敵弾が停止
- [ ] 放射ナイフ演出(MVPは敵全削除でOK)
- [ ] 一定時間後にtimeStop解除
- [ ] 必殺は1回で消費

完了条件:
- アイテム取得→ボタン→敵が止まり→全滅→復帰

---

## M5: ゴール + クリア
目的:ステージを終わらせられる

- [ ] ゴールオブジェクト(Goal)配置
- [ ] 指定X到達でクリア
- [ ] クリアUI(OverlayでOK)
- [ ] リトライ導線

完了条件:
- ゴールに到達するとクリアになり、リトライできる

---

## M6: 仕上げ(任意)
- [ ] 仮スプライト→正式素材
- [ ] SE/BGM
- [ ] 難易度調整(速度、敵頻度、穴幅)
- [ ] 演出(ヒット、画面揺れ、スローモーション等)
- [ ] ステージ複数化
 

プロンプトの入力と実行

上記.mdファイルが用意できたらいよいよ実装をはじめます。
次のようなプロンプトを入力して実行します。

今回はTASKS.mdでM1からM6のタスクを順番に実行していきます。
M6までのタスクが完了すると…

このようなゲームができあがりました!

…これではゲームとは言えませんので、もうちょっと進めましょう。

画像をつくって適用したり

タイトル画面をつくったり

とりあえず…完成!

ということで、約3日間AIに指示を出し続けてとりあえず動くゲームになりましたので一旦完成としたいと思います。
Web用にビルドしてブラウザで遊べるようにしましたのでよかったら遊んでみてください。
(BGMがありますのでご注意ください)

SUPER咲夜RUN

ゲームの目的
走る咲夜をジャンプさせて少ない被弾数でゴールを目指そう!
敵の攻撃に囲まれたらスペルカード「THE WORLD」で回避だ!

スマートフォンで遊ぶ場合
画面の左半分をタップしたらジャンプ
画面の右半分をタップしたら通常攻撃
出現する懐中時計を取得して中央の時計ボタンをタップすることで敵弾を全部消す特殊攻撃「THE WORLD」が使えます

パソコンの場合
ジャンプ→スペースキー
Z→通常攻撃
X→THE WORLD
になります。 

一定距離を進んだらクリア。
被弾数をXにポストすることができます。

以前Unityで2Dゲームをつくってみたことがありますが(「Unityで2Dシューティングに挑戦」)そのときよりはもうちょっとゲームらしくなったと思います。

起動画面

THE WORLD!!!

クリア画面

自力でコードを書くことを考えれば、作業時間は大幅に短縮できました。しかし一方で、不具合の修正を依頼しても期待通りに直らなかったり、指示を細かく分けすぎたことでやり取りの回数が増えてしまったりと、私自身のVibe Coding力不足を痛感する場面もあり、正直なところストレスを感じることもありました。

それでも、もしすべてを自力で実装していたら、ここまで到達するのに1か月ほどはかかっていたと思います。そう考えると、Vibe Codingという手法は、開発スピードを飛躍的に高める可能性を秘めていると実感しました。

エンジニアの中にはすでにVibe Codingを当たり前のように活用し、AI同士を対話させながら開発を進めるといった高度な手法を取り入れている方もいるようです。私も、こうしたAI時代に適応できるスキルを身につけ、AIを使いこなせる開発者へと成長していかなければならないと強く感じました。

【関連記事】

ご相談・お問い合わせ

当社サービスについてのお問い合わせは下記までご連絡下さい。

お電話でのお問い合わせ

06-6121-7581 / 03-6415-8161