概要
- 『メディア学体系2 CGとゲームの技術』の「8. ゲームAIと群衆シミュレーション」に、BOIDという興味深いアルゴリズムが出てきたため、実装してみた
- ※実際は、Opus4.5に実装して「もらった」という方が正しい。あまりにも便利過ぎる
Boidアルゴリズムとは
- 群衆シミュレーションを実現するための基本的なアルゴリズムで、1980年に C.Laynolds によって提唱された
- 「分離」「整列」「結合」の3つの式から成る比較的シンプルなアルゴリズム
- 分離: 近くにいる別の個体とぶつからないようにする (適度に距離を取る)
- 整列: 近くにいる別の個体と同じ方向に進む (群れ全体が同じ方向に進む)
- 結合: 群れの中心に向かおうとする (群れを維持する)
- この3つの式を上手くパラメータを調整することで、本物の生物の群れのような動きを実現できる
- ゲーム内で「群れ」を表現したい時に使われるとのこと。ピクミンとかで使われてそう?(筆者の勝手な憶測です)
実装に当たって
- 数式が3つしかなく、その数式もそこまで複雑でないことから、雑にAIに投げても実装してもらえそうだなと思い、バイブコーディングで実装することを決めた
- 相方は Claude Opus4.5。評判の良さを以前から聞いていたので、いかに強力なのかを試す目的もあった
デモムービー
リポジトリ
実装プロセス
実行環境: VSCode + GithubCopilot + ClaudeOpus4.5 (Agent)
会話
筆者「boidアルゴリズムを実装してC++で」
Opus4.5「あい」(CLIで動くものが完成)
筆者(一応CLI上でそれらしきものが動いてるが、あんま動物の群れっぽくないな……。)
筆者(CLIで動かすことに無理がありそうなので、GUIで実装させよう)
筆者「CLIだと分かりづらかったから、GUIのフレームワークをなんか入れて。」
Opus4.5「あい」(SFMLインストール)(GUI版完成)
筆者(おぉ動いとる……。でもmain.cppやboid.cppに処理が全部記述されててちょっと読みにくいな……。)
筆者「GUI版のmain.cppやboid.cppが長くて読みづらいので、複数のファイルに分割して可読性やメンテナンス性を上げて」
Opus4.5「あい」(ファイル分割完了、ビルドも実行済み)
筆者(だいぶ読みやすくなったがルートに全ファイルぶっこんでるな)「srcフォルダとincludeフォルダに分けて」
Opus4.5「あい」(ファイル整理完了)
筆者(お、いい感じになってきた。最後に後から見返しやすいようにドキュメント作ってもらお)「ディレクトリ構造や設計思想についてmdにまとめて」
Opus4.5「あい」(文書作成完了)
筆者「テスト書いて」
Opus4.5「あい」(テスト実装完了・実行して全件パスすることも確認済)
筆者「テストの種類や内容についてmdにまとめて」
Opus4.5「あい」(文書作成完了)
ほとんどこんな感じです。若干省略した箇所もありますが、ほぼプロンプトそのまんま
実装プロセスの改善点
- あまりにも行き当たりばったり過ぎる。適当にAIで遊んでいただけなのでまぁいいのだが、もう少し洗練されたやり方にしたい
- 例えば、「ファイルを複数に分割する」「srcとincludeに分ける」「テストを実装する」「ディレクトリ構造や設計思想、テストについてのドキュメントを整備する」という要件は、どのプロジェクトにも共通して必要なので、
copilot-instructions.mdなどのファイルに記述して、↑のような会話のラリーを省略したい
- 例えば、「ファイルを複数に分割する」「srcとincludeに分ける」「テストを実装する」「ディレクトリ構造や設計思想、テストについてのドキュメントを整備する」という要件は、どのプロジェクトにも共通して必要なので、
- GUIを使うアプリケーションの場合は、デモムービーの撮影とアップロード、Qiita用にgifを生成するところまで自動化したい
- 特に趣味のゲーム開発では高サイクルで作品を公開していきたいため、作品を公開する際の定型作業は極力自動化したい
- 今回は単発の「作り捨て」のリポジトリなのでそこまで問題にならないが、長期的に運用するプロジェクトならCI自動化とかもしたい
補足
- なお、本記事は冒頭で述べた通り『メディア学体系2 CGとゲームの技術』を読んでる最中にBOIDアルゴリズムを見つけたことが執筆のきっかけですが、本書で紹介されていたBOIDアルゴリズムと今回AIに実装してもらったものでは数式が若干違います。
- 分離・整列・結合の3つの数式から構成される点は同じ
- AI実装の方は分離の数式にて「距離の逆二乗で重みづけ」するという一工夫がされていました。
- 本書の実装とAI実装で実際の動きがどう異なってくるのか、機会あれば比較してみたいと思います
数式のもう少し細かい説明
コードを読めば分かるとはいえ、数式の記載が一切ないのは不親切な気もするので以下に記載します。
なお、この数式もコードを読ませてAIに生成させたものです。ざっと目を通して合っていそうなことは確認しましたが、もし何かしら誤りがございましたらご指摘いただけますと幸いです。
(以下の数式に対応する実装は、 src/boid.cpp にあります )
① 分離 (Separation) — 衝突回避
近すぎる仲間から離れる力です。距離の逆二乗で重み付けすることで、近いほど急激に離れようとします。
- 理想的な方向ベクトル ($\mathbf{s}_{\text{raw}}$):
\mathbf{s}_{\text{raw}} = \frac{1}{N} \sum_{j \in \text{neighbors}} \frac{\mathbf{p}_i - \mathbf{p}_j}{d_{ij}^2}
② 整列 (Alignment) — 速度の一致
周囲の仲間と同じ方向、同じ速さで飛ぼうとする力です。
- 平均速度 ($\mathbf{v}_{\text{avg}}$):
\mathbf{v}_{\text{avg}} = \frac{1}{N} \sum_{j \in \text{neighbors}} \mathbf{v}_j
- 理想的な速度:
\mathbf{v}_{\text{desired}} = \mathbf{v}_{\text{avg}}
③ 結合 (Cohesion) — 群れの中央へ
バラバラにならないよう、仲間の中心(重心)へ向かおうとする力です。
- 仲間の重心 ($\mathbf{C}$):
\mathbf{C} = \frac{1}{N} \sum_{j \in \text{neighbors}} \mathbf{p}_j
- 理想的な方向ベクトル: $\mathbf{s}_{\text{raw}} = \mathbf{C} - \mathbf{p}_i$