AIゲーム開発研究室

2026-09-08 13:17:00

ポン実装編 ― AIが生成した「動き」はどこに記録されていたのか

AIゲーム開発研究室

「森のどんぐり大作戦」開発ドキュメント

ポン実装編 ― AIが生成した「動き」はどこに記録されていたのか

前回までの実装によって、パンタがどんぐりを3個キャッチすると大喜びし、そのまま画面下へ退場し、次のキャラクターであるポンが登場するところまで完成しました。

今回は、その続きとしてポンのゲームシステムを実装していきます。

目標は、

ポンがどんぐりをキャッチする

キャラクターごとの取得数とゲーム全体の取得数を表示する

3個キャッチすると操作を停止する

ポンが大喜びする

というところまでです。

ところが今回、実装を進める中で予想していなかった重要な問題が見つかりました。

それは、画像生成AIによって制作されたアニメーション素材の「動き」の一部が、Unityへ読み込む過程で失われていたという問題です。


1.キャラクターごとの取得数と合計取得数

まず、スコア表示を整理しました。

これまでは単純に取得したどんぐりの数を表示していましたが、キャラクター交代を実装したことで、二種類の数字が必要になりました。

Current Score

現在操作しているキャラクターが取得したどんぐり数。

Total Score

ゲーム開始から全キャラクターが取得したどんぐりの累計数。

パンタが3個取得した場合、

どんぐり:3 / 3
合計:3

となります。

その後パンタが退場し、ポンの登場が完了した時点でCurrent Scoreだけをリセットします。

どんぐり:0 / 3
合計:3

そしてポンが1個取得すると、

どんぐり:1 / 3
合計:4

となります。

Unity AI Agentは既存のScoreManagerを拡張し、Current ScoreとTotal Scoreを同時に管理する構造を実装しました。

重要なのは、キャラクター交代の途中ではCurrent Scoreをリセットせず、ポンが通常プレイ位置へ到着した時点でリセットするようにしたことです。

これによって、パンタの退場中やポンの登場途中でスコア表示が不自然に切り替わることを防いでいます。


2.ポンにもどんぐりキャッチを実装する

次に、ポンがどんぐりをキャッチできるようにします。

パンタにはすでに、

BasketCatchArea

というどんぐりを受け取るための当たり判定が実装されています。

Unity AI Agentに既存システムを調査させたところ、この仕組みはパンタ専用に作り直す必要がなく、そのままポンにも利用できることが分かりました。

そこで新しいキャッチ用スクリプトを作るのではなく、既存のBasketCatchAreaをポンにも使用しました。

ただし、パンタとポンでは体形も籠の位置も異なります。

そのため、ポン用にColliderの位置だけを調整しました。

これによって、

共通のキャッチシステム

キャラクター固有の位置設定

を分離することができました。

実際にPlayモードで確認すると、ポンも正常にどんぐりをキャッチし、

1個目では、

どんぐり:1 / 3
合計:4

2個目では、

どんぐり:2 / 3
合計:5

3個目では、

どんぐり:3 / 3
合計:6

と正しく表示されました。


3.ポンの大喜びは、人間が構成する

パンタの大喜びアニメーションでは、少し変わった実験を行いました。

画像生成AIによって制作された7枚の独立した大喜びポーズをUnity AI Agentに見せ、

どの画像を使うか

どの順番にするか

どのタイミングで表示するか

をUnity AI Agent自身に判断させました。

その結果、Unity AI Agentは、

05 → 02 → 04 → 01 → 06 → 03 → 07

という、人間が事前に指定していない順序を構成しました。

Playモードで確認すると、これが予想以上に自然な大喜びアニメーションになりました。

今回は比較のため、ポンでは別の方法を試します。

画像生成AIが制作した8枚の大喜び候補から、人間が5枚を選択しました。

さらに、

01 → 02 → 03 → 04 → 05

という使用順序も人間が決定しました。

一方、各画像をどれくらいの時間表示するかについてはUnity AI Agentに任せました。

つまりパンタでは、

AIがポーズ選択・順序・時間を決定

したのに対して、ポンでは、

人間がポーズ選択・順序を決定し、AIが時間と実装を担当

します。

同じ大喜びアニメーションでも、人間とAIの役割分担を変えてみたわけです。


4.Unity AI Agentが決めたポンの時間

Unity AI Agentは、5枚を確認したうえで、

6fps

を採用しました。

各画像の表示時間は約0.167秒。

全体では約0.833秒です。

順序は指定通り、

01 → 02 → 03 → 04 → 05

です。

Unity AI Agentが6fpsを選択した理由は、既存のポンの待機・移動アニメーション、さらにパンタの大喜びアニメーションも6fpsで構成されており、ゲーム全体のテンポと統一できるためでした。

ここでは、人間がポーズの構成を決め、AIが既存ゲームの実装を参照しながら時間軸へ変換しています。


5.Playボタンを押して分かった二つの問題

Unity AI Agentからは、

「正常に実装完了」

という報告が返ってきました。

しかし、ここでいつものように人間がPlayボタンを押します。

すると二つの問題が見つかりました。

一つ目は、

大喜びになっても、どんぐりをキャッチし続ける

という問題です。

見た目は大喜び状態へ変わっていますが、BasketCatchAreaのColliderは動作したままでした。

そのため大喜びしているポンの近くをどんぐりが通ると、Current ScoreもTotal Scoreも増えてしまいます。

そこでCelebration開始と同時に、ポンのBasketCatchAreaのColliderだけを無効化するよう修正しました。

共通で使用しているBasketCatchArea.csそのものは変更していません。

これによってパンタには影響を与えず、ポンだけが大喜び開始後にキャッチできなくなりました。

ここでも、

見た目の状態が変わったことと、ゲーム内部の状態が変わったことは同じではない

ということが分かります。


6.もう一つの違和感

しかし、もう一つ気になることがありました。

ポンの大喜び素材は、制作した段階ではかなり大きく上下するアクションになっていました。

ところがUnity上では、

思ったほど上下していない。

最初はUnity側でTransformのY座標を動かす必要があるのではないかとも考えました。

しかし、そうではありません。

元画像を思い出すと、すでに画像そのものの中でポンの位置を上下させていました。

つまり5枚を同じ位置で切り替えるだけで、本来ならポンは上下して見えるはずなのです。

では、なぜ動かなかったのでしょうか。


7.消えていた「透明な運動情報」

Unity AI Agentに画像のImport状態を調査させました。

そこで原因が判明しました。

ポンの大喜び素材はすべて、

320×400

という同じサイズの透明キャンバス上に制作されていました。

そして、そのキャンバスの中でポンの位置そのものを上下させています。

ところがUnityへImportした際、キャラクターが描かれている部分だけが画像ごとに自動的にトリミングされていました。

さらに、切り取られたそれぞれのSpriteの中央がPivotになっていました。

つまり、

元画像ではポンが上にいる

ポンの周囲だけ切り取る

切り取った画像の中央をPivotにする

Unity上では再び中央に表示される

ということが起きていました。

画像生成AIが作った上下位置の差が、UnityへのImportによって相殺されていたのです。


8.透明キャンバス全体をSpriteとして扱う

そこで大喜び素材5枚を、

Rect:320×400のキャンバス全体

Pivot:すべてCenter(0.5, 0.5)

に統一しました。

Transformによる上下移動は一切追加していません。

GameObjectそのものは同じ位置に置いたままです。

変えたのはSpriteのImport方法だけです。

Playボタンを押してみます。

すると――

ポンがめちゃくちゃ大喜びしました。

素材画像の中に最初から存在していた上下動が、そのままゲーム画面に現れたのです。


9.「いまいち飛んでいない」の正体

ここで、以前から感じていた別の違和感にも気づきました。

ポンの通常キャッチアクションです。

ポンのキャッチ素材も画像生成時には上下に跳ねるようなポーズとして制作していました。

しかしゲーム上では、

「いまいち飛んでいないな」

という印象がありました。

そこで、

Pon_Catch_Up

Pon_Catch_Right

についても同じ問題が起きていないか調査しました。

結果は同じでした。


10.Pon_Catch_Upでも運動情報が消えていた

Pon_Catch_Upの5枚は、すべて、

340×400

のキャンバスです。

しかし修正前には、それぞれ異なるSprite Rectでトリミングされていました。

特に上下位置を見ると、

01は y=0、

02は y=74、

03は y=82、

04は y=40、

05は y=0

からキャラクター部分が切り出されていました。

これは非常に分かりやすい結果です。

元画像では02、03でポンが明らかに上へ移動しています。

ところが、その位置からキャラクターだけを切り出して中央をPivotにしたため、Unity上ではその高さの違いが消えていました。

そこで5枚すべてを、

Rect:340×400

Pivot:Center(0.5, 0.5)

へ統一しました。

Transformによる上下移動は追加していません。


11.右移動でも同じことが起きていた

Pon_Catch_Rightでも同様でした。

こちらの5枚は、

400×400

です。

やはり各画像が個別にトリミングされており、03ではy=38、04ではy=31から切り取られていました。

これも、

Rect:400×400

Pivot:Center(0.5, 0.5)

へ統一しました。

右移動の場合は少し構造が違います。

上下方向のアクションはSprite画像そのものが担当します。

一方、画面右方向への移動はUnityのTransformが担当します。

つまり、

Sprite画像内の上下運動

UnityによるX方向移動

によって、一つの右移動アクションが成立しています。

左移動では、このアニメーションをflipXによって反転しています。


12.動きにリズムが生まれた

修正後、再びPlayボタンを押しました。

今度は明らかに違いました。

停止中のキャッチでも、左右移動中のキャッチでも、ポンが上下に跳ねます。

これまで少し平坦に見えていた動きに、はっきりとしたリズムが生まれました。

しかもUnity側で新しいジャンプ処理を追加したわけではありません。

今回の修正では、

Scriptの変更はありませんでした。

画像生成AIが制作した素材には、最初からその動きが存在していたのです。

Unityへ受け渡す過程で、それが見えなくなっていただけでした。


13.透明部分は「何もない」のか

今回の実験から、非常に興味深いことが分かりました。

一般に透明PNGの透明部分は、

「何も描かれていない部分」

と考えがちです。

しかし、今回のアニメーション素材では違いました。

透明キャンバスの中で、

キャラクターがどこに存在しているか

その位置自体が、フレーム間の運動を表現していました。

つまり透明部分は、単なる余白ではありません。

キャラクターの空間的位置を記録するための座標空間

として機能していたのです。

したがって今回の素材では、

透明キャンバスそのものがアニメーション情報の一部

だったことになります。


14.AIからAIへ渡す途中で情報が失われる

今回の問題は、画像生成AIが正しく素材を作れなかったことが原因ではありません。

Unity AI Agentがアニメーションを作れなかったことが原因でもありません。

画像生成AIが作った素材には、すでに必要な上下動が存在していました。

問題が発生したのは、

画像生成AIによる素材制作

PNG

Unity Import

Animation Clip

という工程の途中です。

生成物そのものでも、実装コードでもなく、

制作工程間の情報変換によって情報が失われていた

のです。

AI時代のゲーム開発では、複数のAIやソフトウェアを連携させることになります。

そのとき重要なのは、

それぞれのAIが正しく仕事をしたか

だけではありません。

一つの工程で作られた情報が、次の工程へ正しく受け渡されたか

を確認する必要があります。


15.人間が見つけたもの

Unity AI Agentは、それぞれの作業について実装完了を報告しました。

しかし、

「ポンがいまいち飛んでいない」

という違和感を感じたのは、人間でした。

大喜びアニメーションをPlayして、その違いがさらに明確になりました。

そこから原因を疑い、Unity AI Agentに調査させたことで、Import設定の問題が発見されました。

今回も、

AIが実装する

人間がPlayする

人間が違和感を発見する

AIが原因を調査する

AIが修正する

人間が再びPlayして評価する

という循環が発生しています。

これはこれまで繰り返し現れてきた、

設計 → 制作 → 実装 → 検証 → 発見 → 再設計

というAIゲーム開発の循環そのものです。


16.今回得られた制作ルール

今回の実験から、今後の2Dアニメーション素材制作に使える重要なルールが得られました。

連続アクション用Spriteでは、透明キャンバス内におけるキャラクターの位置も運動情報の一部として扱う。

画像生成AIによって同一キャンバス内でキャラクターの上下位置を変化させている場合、Unity Import時に各フレームをキャラクター輪郭で個別にトリミングしてはなりません。

同一アクションを構成するSpriteは、

共通キャンバス

共通Sprite Rect

共通Pivot

を維持します。

そして、画像内ですでに上下動が設計されている場合には、Unity側でさらにTransform Yを動かす必要はありません。

一方、画面内を左右へ移動するようなゲーム上の移動についてはUnity側で制御します。

つまり、

素材が担当する動き

ゲームエンジンが担当する動き

を分離します。


17.ポンらしい動きが生まれた

今回の修正によって、ポンの動きはパンタとはかなり違うものになりました。

これは当初から数値で細かく設計した結果ではありません。

画像生成AIによって制作された複数のアクション素材を実際にゲームへ組み込み、Playし、その動きを見たことで、

「ポンはこう動くキャラクターなんだ」

という個性が見えてきました。

キャラクター設定から動きを作るだけではありません。

生成された動きを見ることで、キャラクターのゲーム上の個性が決まっていく。

ここでも、

設計 → 生成

だけではなく、

生成 → 発見 → 設計

という逆方向の流れが生まれています。

パンタについては、現在使用している3カット素材を今後5カット素材へ全面的に入れ替える予定です。

その際には、今回得られた共通キャンバスと共通Pivotのルールを最初から適用します。


今回の到達点

今回の実装によって、

パンタが3個キャッチ

パンタ大喜び

パンタ退場

ポン登場

Current Scoreを0へリセット

ポンがどんぐりをキャッチ

Current ScoreとTotal Scoreを同時管理

ポンが3個キャッチ

操作停止

キャッチ判定停止

ポン大喜び

までが完成しました。

ポンの大喜び、待機キャッチ、左右移動キャッチについても、画像生成時に素材へ組み込まれていた本来の上下運動が復元されました。

残る基本ゲームループは、

ポン大喜び → ポン退場 → ゲーム終了

です。

ただし、今回はここで実装を止めることにしました。

Unity AI Agentの残りクレジットは、

114 / 1,000

となりました。

 

次回はクレジットに余裕がある状態で、ポンの退場とゲーム終了を実装します。