AI

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()

機能比較表

比較項目GodotBevypygame
対応次元2D/3D2D/3D2Dのみ
言語GDScript/C#RustPython
学習コスト
ビジュアルエディタ
WASM出力
GitHub Stars92k+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・WebGPUBevy
Python・教育・ゲームジャム・プロトタイプpygame

関連外部リソース

他の記事も読む

Let's Build Together

OSS導入、自社だけで悩まない。

ツール選定から構築・運用・AI活用まで、オープンソースラボ運営元のClasslessが伴走します。初回のご相談は無料です。