OSSゲームエンジン比較:Godot vs Bevy vs pygame でインディーゲームを開発する
オープンソースラボ編集部 ・ 2026年6月14日
OSSゲームエンジン比較:Godot vs Bevy vs pygame で2Dゲームを開発する
2D/3Dゲーム開発ではGodot(GDScript/C#・2D/3D統合)・Bevy(Rust製・ECSアーキテクチャ・最新)・pygame(Python・手軽・2D専用)の3つがOSSゲームエンジンの中でも個人・インディー開発者に人気です。Unity(月$22〜・Runtime Fee問題)・Unreal Engine(ロイヤリティ5%)の代替として注目されています。
OSSゲームエンジンを選ぶ理由
- コスト: Unity Pro(月$2,040/年〜)→ Godot/Bevy/pygameで$0、ロイヤリティなし
- ソースコード公開: エンジンのバグを自分で修正・フォーク・改造できる
- 学習目的: ゲームエンジンの内部実装(ECS・レンダリングパイプライン)を学べる
- Unity 2023 Runtime Fee後: Unity離れが加速しGodotへの移行が急増
主要エンジンの概要
Godot Engine
2014年公開、C++製のOSSです。GitHubスター92k+(急増)。2D/3D両対応のフル機能ゲームエンジンで、GDScript(Pythonライクな独自言語)・C#・C++(GDExtension)で開発できます。ビジュアルエディタが付属していて非エンジニアでもゲームを制作できます。Godot 4.xからVulkan/DirectX 12レンダリング・GI・プロシージャルジオメトリをサポートしました。
# GDScript: 2Dプラットフォームゲームのプレイヤーコントローラー
extends CharacterBody2D
const SPEED = 300.0
const JUMP_VELOCITY = -600.0
# 重力を物理サーバーから取得
var gravity: float = ProjectSettings.get_setting("physics/2d/default_gravity")
func _physics_process(delta: float) -> void:
# 重力を適用(空中のみ)
if not is_on_floor():
velocity.y += gravity * delta
# ジャンプ処理
if Input.is_action_just_pressed("ui_accept") and is_on_floor():
velocity.y = JUMP_VELOCITY
# 左右移動
var direction := Input.get_axis("ui_left", "ui_right")
if direction != 0.0:
velocity.x = direction * SPEED
else:
# 摩擦で速度を減衰
velocity.x = move_toward(velocity.x, 0.0, SPEED)
move_and_slide()
func _on_enemy_detected(enemy: Node2D) -> void:
# 敵を踏んだ時の処理
if velocity.y > 0:
enemy.die()
velocity.y = JUMP_VELOCITY / 2 # バウンス
# GDScript: ゲームマネージャー(シングルトン)
extends Node
signal score_changed(new_score: int)
signal game_over
var score: int = 0
var lives: int = 3
var high_score: int = 0
func add_score(points: int) -> void:
score += points
emit_signal("score_changed", score)
if score > high_score:
high_score = score
save_high_score()
func lose_life() -> void:
lives -= 1
if lives <= 0:
emit_signal("game_over")
func save_high_score() -> void:
var save_data := {"high_score": high_score}
var file := FileAccess.open("user://save_data.json", FileAccess.WRITE)
file.store_string(JSON.stringify(save_data))
func load_high_score() -> void:
if FileAccess.file_exists("user://save_data.json"):
var file := FileAccess.open("user://save_data.json", FileAccess.READ)
var data: Dictionary = JSON.parse_string(file.get_as_text())
high_score = data.get("high_score", 0)
Bevy
2020年公開、Rust製のOSSです。GitHubスター37k+。ECS(Entity-Component-System)アーキテクチャをRustで実装したモダンなゲームエンジンです。まだ0.x系(活発開発中)ですが、データ指向設計・並列処理・WebAssemblyエクスポートを特徴としています。
// Bevy: シンプルなスプライト移動ゲーム
use bevy::prelude::*;
fn main() {
App::new()
.add_plugins(DefaultPlugins)
.add_systems(Startup, setup)
.add_systems(Update, (move_player, check_bounds))
.run();
}
#[derive(Component)]
struct Player {
speed: f32,
}
fn setup(
mut commands: Commands,
asset_server: Res<AssetServer>,
) {
// カメラを追加
commands.spawn(Camera2dBundle::default());
// プレイヤースプライトを追加
commands.spawn((
SpriteBundle {
texture: asset_server.load("player.png"),
transform: Transform::from_xyz(0.0, 0.0, 0.0),
..default()
},
Player { speed: 300.0 },
));
}
fn move_player(
keyboard: Res<ButtonInput<KeyCode>>,
time: Res<Time>,
mut query: Query<(&Player, &mut Transform)>,
) {
for (player, mut transform) in &mut query {
let mut direction = Vec3::ZERO;
if keyboard.pressed(KeyCode::ArrowLeft) { direction.x -= 1.0; }
if keyboard.pressed(KeyCode::ArrowRight) { direction.x += 1.0; }
if keyboard.pressed(KeyCode::ArrowUp) { direction.y += 1.0; }
if keyboard.pressed(KeyCode::ArrowDown) { direction.y -= 1.0; }
transform.translation += direction.normalize_or_zero() * player.speed * time.delta_seconds();
}
}
fn check_bounds(mut query: Query<&mut Transform, With<Player>>) {
for mut transform in &mut query {
transform.translation.x = transform.translation.x.clamp(-400.0, 400.0);
transform.translation.y = transform.translation.y.clamp(-300.0, 300.0);
}
}
pygame
1998年公開(SDL wrapping)、Python製のOSSです。GitHubスター7k+。Pythonで2Dゲームを最も手軽に作れるライブラリで、教育・プロトタイプ・ゲームジャム(48時間ゲーム制作)に最適です。フル機能のゲームエンジンではなく2Dレンダリング・入力・サウンドを提供するライブラリです。
# pygame: シンプルなシューティングゲーム
import pygame
import random
pygame.init()
WIDTH, HEIGHT = 800, 600
screen = pygame.display.set_mode((WIDTH, HEIGHT))
pygame.display.set_caption("Space Shooter")
clock = pygame.time.Clock()
class Player(pygame.sprite.Sprite):
def __init__(self):
super().__init__()
self.image = pygame.Surface((50, 40), pygame.SRCALPHA)
pygame.draw.polygon(self.image, (0, 200, 255), [(25, 0), (0, 40), (50, 40)])
self.rect = self.image.get_rect(center=(WIDTH // 2, HEIGHT - 60))
self.speed = 5
self.bullets: list['Bullet'] = []
def update(self, keys):
if keys[pygame.K_LEFT] and self.rect.left > 0:
self.rect.x -= self.speed
if keys[pygame.K_RIGHT] and self.rect.right < WIDTH:
self.rect.x += self.speed
def shoot(self) -> 'Bullet':
bullet = Bullet(self.rect.centerx, self.rect.top)
self.bullets.append(bullet)
return bullet
class Bullet(pygame.sprite.Sprite):
def __init__(self, x, y):
super().__init__()
self.image = pygame.Surface((4, 12))
self.image.fill((255, 255, 0))
self.rect = self.image.get_rect(center=(x, y))
self.speed = 8
def update(self, *args):
self.rect.y -= self.speed
if self.rect.bottom < 0:
self.kill()
class Enemy(pygame.sprite.Sprite):
def __init__(self):
super().__init__()
self.image = pygame.Surface((40, 40), pygame.SRCALPHA)
pygame.draw.rect(self.image, (255, 50, 50), (5, 5, 30, 30))
self.rect = self.image.get_rect(
x=random.randint(0, WIDTH - 40),
y=random.randint(-100, -40),
)
self.speed = random.uniform(1.5, 3.5)
def update(self, *args):
self.rect.y += self.speed
if self.rect.top > HEIGHT:
self.kill()
# ゲームループ
player = Player()
all_sprites = pygame.sprite.Group(player)
bullets = pygame.sprite.Group()
enemies = pygame.sprite.Group()
score = 0
font = pygame.font.Font(None, 36)
shoot_cooldown = 0
running = True
while running:
clock.tick(60)
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
if event.type == pygame.KEYDOWN and event.key == pygame.K_SPACE and shoot_cooldown <= 0:
bullet = player.shoot()
all_sprites.add(bullet)
bullets.add(bullet)
shoot_cooldown = 15
keys = pygame.key.get_pressed()
all_sprites.update(keys)
shoot_cooldown -= 1
# 敵をランダム生成
if random.random() < 0.02:
enemy = Enemy()
all_sprites.add(enemy)
enemies.add(enemy)
# 衝突判定
hits = pygame.sprite.groupcollide(enemies, bullets, True, True)
score += len(hits) * 10
screen.fill((10, 10, 30))
all_sprites.draw(screen)
score_text = font.render(f"Score: {score}", True, (255, 255, 255))
screen.blit(score_text, (10, 10))
pygame.display.flip()
pygame.quit()
機能比較表
| 比較項目 | Godot | Bevy | pygame |
|---|---|---|---|
| 対応次元 | 2D/3D | 2D/3D | 2Dのみ |
| 言語 | GDScript/C# | Rust | Python |
| 学習コスト | 中 | 高 | 低 |
| ビジュアルエディタ | ✅ | ❌ | ❌ |
| WASM出力 | ✅ | ✅ | △ |
| GitHub Stars | 92k+ | 37k+ | 7k+ |
OSSゲームエンジンはDevOpsカテゴリ/categories/devopsのCI/CD(GitHub Actions)でユニットテスト・WASM自動ビルド・itch.ioデプロイを自動化できます。セキュリティカテゴリ/categories/securityのRustのメモリ安全性はBevyのサーバーサイドゲームロジック(チート検出・スコア検証)の信頼性を高めます。
FAQ
Q. Godot 4とGodot 3.xのどちらを学ぶべきですか?
A. 2024年以降の新規プロジェクトはGodot 4一択です。Godot 4の主な変更点: ①GDScript 2.0(型ヒント強化・ラムダ関数・静的変数)②Vulkan/DirectX 12レンダリング(3Dグラフィック品質向上)③GDExtension(C++プラグインのバイナリ互換)④ダブルバッファ物理エンジン(CharacterBody2D/3Dの改善)。ただしGodot 3向けのチュートリアル・アセット(godotassetlibrary)はまだ多く、基本的なゲームメカニクスの学習にはGodot 3のリソースも参照できます。Godot 4への移行ツール(godot --headless --convert-3to4)で既存プロジェクトを部分的に変換できます。
Q. pygameとGodotはどう使い分けますか?
A. 48時間ゲームジャム・Pythonプロジェクト・教育目的ならpygame、ビジュアルエディタで制作・公開を目指す・2D/3D両対応ならGodotが向いています。pygameの限界: ①エンジンの機能(物理演算・アニメーションステートマシン・シェーダー)を自分で実装する必要がある②大規模プロジェクト(1000+スプライト)でパフォーマンスが低下③WebExportやモバイルへのビルドが複雑。Godotの強み: ①ビジュアルエディタとシーンシステムでゲームを構造化②AnimationPlayer・AnimationTree・ShaderEditorが標準搭載③Android/iOS/HTML5/PCへのワンクリックエクスポート。
Q. BevyはゲームJam(ゲームジャム)に使えますか?
A. 使えますが、まだ学習コストが高く48時間ジャムには向かない場合が多いです。Bevyの課題: ①0.x系の開発中でAPIの破壊的変更が多い②ビジュアルエディタなし(コードのみ)③アセット・プラグインエコシステムが小さい(Bevy Asset Hubは成長中)。Bevyが輝く場面: ①Rustの安全性とパフォーマンスが重要なゲームサーバー②ECSアーキテクチャでゲームロジックを学びたい③WebGPUを試したい。ゲームジャムにはGodot(GDScript習得済みなら)またはpygame(Pythonエンジニア)の方がイテレーション速度が高いです。
Q. Godotからモバイル(iOS/Android)向けにビルドするには?
A. Godotのエクスポートテンプレート機能を使います。①Godot Editorの「プロジェクト→エクスポート」からAndroid/iOSプリセットを追加②Android: Android SDK(API 33+)・Gradleをインストールしてエクスポートテンプレートのパスを設定③iOS: macOS+Xcodeが必要(LinuxやWindowsからはHTML5経由やリモートmacでビルド)④Google Play Store向け: aab(Android App Bundle)形式でエクスポートしてPlay Consoleからリリース⑤AdMob等の広告SDK: godot-admob-androidプラグインで対応。2Dゲームは60fps実行が多くの中位Android端末で達成できます。3DはGLES3(Compatibility renderer)を使って低〜中位端末向けに最適化します。
まとめ
| ユースケース | 推奨ツール |
|---|---|
| インディーゲーム・2D/3D・公開を目指す | Godot 4 |
| Rust学習・ECS・WebGPU | Bevy |
| Python・教育・ゲームジャム・プロトタイプ | pygame |