ゼビウスが教えてくれたRustの真実
~なぜ現代ゲーム開発はオブジェクト指向を捨てたのか~
私は60歳を過ぎてからRustの勉強を始めました。
最近の若いプログラマーは当たり前のように、
「ECSが主流です」
「継承よりCompositionです」
「Classは使わなくても困りません」
と言います。
しかし1990年代からプログラミングを続けてきた私たち世代には、どうも納得できない部分があります。
なぜなら、オブジェクト指向こそが究極の開発手法だと信じてきたからです。
Java全盛期。
C++全盛期。
PHPでもオブジェクト指向化が進み、
私たちは長年にわたり
「クラスを作れ」
「継承を使え」
「設計しろ」
と学んできました。
ところがRustにはClassがありません。
さらに驚くことに、現代ゲーム開発ではオブジェクト指向そのものが主役の座から降りつつあります。
その理由を理解するために、今回は最新ゲームではなく1984年の傑作シューティングゲーム『ゼビウス』を使って考えてみたいと思います。
なぜゼビウスなのか
最近のゲームは複雑すぎます。
- マインクラフト
- フォートナイト
- 原神
- エルデンリング
どれも素晴らしい作品ですが、システムが巨大すぎて設計の話をするには向いていません。
その点、ゼビウスは実に美しい構造をしています。
- 自機 ソルバルウ
- ガルザカート
- ドモグラム
- ザカート
- アンドアジェネシス
登場物体も比較的シンプルです。
しかも動作も分かりやすい。
- 飛ぶ
- 移動する
- 撃つ
- 当たる
- 壊れる
つまりゲームプログラミングの本質だけを取り出して考えることができるのです。
1995年のプログラマーならこう考える
オブジェクト指向全盛期なら、まず共通の親クラスを作ります。
そしてそこから派生させます。
├ Player
├ Enemy
├ Bullet
└ GroundObject
ここまでは美しい設計です。
さらに敵を細分化します。
├ FlyingEnemy
├ GroundEnemy
└ BossEnemy
そして具体的な敵を追加します。
├ GaruZakato
├ Bee
├ Torkan
└ FighterEnemy
当時の教科書にも載っていそうな模範解答です。
しかし実際のゲーム開発になると問題が始まります。
ゲームは例外だらけである
現実のゲーム開発では例外が必ず発生します。
例えば、
- 飛ぶけど地上にも降りる敵
- ボスだけど雑魚敵扱いもする敵
- 地上物なのに移動する敵
- 途中で形態変化する敵
こうした例外が次々に登場します。
すると継承構造はどんどん複雑になります。
MovingGroundEnemy
SpecialFlyingBossEnemy
TransformableBossEnemy
気が付くとクラスの森が出来上がります。
そして誰も全体像を把握できなくなります。
開発者の悪夢
ゲーム開発では仕様変更が日常茶飯事です。
「敵AIを少し変えたい」
「ボスにも移動能力を追加したい」
こうした変更が毎週発生します。
親クラスを修正したら関係ない敵まで動作が変わる。
バグを直したら別の場所が壊れる。
継承は便利でしたが、依存関係も大量に生み出したのです。
現代ゲーム開発は発想を変えた
ここで考え方が変わります。
重要なのは、
「どんな能力を持つか」
なのです。
ゼビウスのソルバルウを考えてみましょう。
Moveable
AirShooter
GroundShooter
Destroyable
これで十分です。
戦闘機クラスも主人公クラスも必要ありません。
能力だけで表現できます。
ガルザカートを能力で表現する
Moveable
Flyable
Destroyable
たったこれだけです。
クラス階層は登場しません。
必要な能力を並べているだけです。
アンドアジェネシスはどうなるか
Destroyable
Boss
MultiPart
巨大ボスも能力の集合体になります。
名前ではなく特徴で構成されているのがポイントです。
ECSという考え方
これが現代ゲーム開発で主流になったECSです。
Entity Component System の略です。
Entity
Entityは単なる識別子です。
Entity #2
Entity #3
Component
Componentは能力やデータです。
Health
Velocity
Attack
System
Systemは処理です。
Attack System
Collision System
Render System
この3つを組み合わせてゲームを作ります。
料理に例えるとよく分かる
オブジェクト指向は定食屋です。
焼魚定食
生姜焼定食
最初から完成しています。
便利ですが柔軟性は低い。
一方ECSはビュッフェ形式です。
肉
魚
サラダ
味噌汁
好きな部品を自由に組み合わせます。
だからゲームのように例外だらけの世界と相性が良いのです。
RustがECSと相性抜群な理由
Rustは最初から組み合わせ重視の設計思想を持っています。
オブジェクト指向が中心だった時代は、
Inheritance
が重要でした。
しかしRustは違います。
Trait
Composition
これが中心です。
Traitは能力そのもの
trait Shooter
trait Destroyable
RustのTraitは能力を表現するのに非常に向いています。
飛べる。
撃てる。
壊れる。
それぞれを独立した能力として定義できます。
まるでゼビウスの敵設計そのものです。
なぜBevyがECSを採用したのか
現在Rustゲームエンジンの代表格であるBevyもECSを採用しています。
理由は単純です。
ゲームに向いているからです。
新しい敵を追加したい場合、
継承構造を見直す必要はありません。
必要な能力を追加するだけです。
Destroyable
Shooter
この組み合わせだけで新しい敵が作れます。
拡張が圧倒的に楽なのです。
60代プログラマーほど感動する理由
若い世代にとっては当たり前かもしれません。
しかし私たち世代には衝撃です。
長年、
- 継承が正義
- クラス設計が重要
- オブジェクト指向が最終解
だと思ってきたからです。
私自身、最初はRustにClassがないと知った時、
不安しかありませんでした。
しかしECSを学び、
頭の中でゼビウスを設計してみると考えが変わりました。
なるほど。
これは退化じゃない。
進化なんだ。
そう思えたのです。