プログラミング
2026年にニンテンドー64のゲームを作る方法
How to Make a Nintendo 64 Game in 2026 (phoboslab.org)
要約
Dominic Szablewski氏は、自身のJavaScriptゲームエンジンをC言語に移植した「high_impact」を基盤に、ニンテンドー64向けFPSゲーム「Xibalba 64」を開発しました。LibdragonライブラリとSummerCart64のような開発ツールを活用し、現代的なN64ゲームの物理的なリリースを実現した過程と技術的な課題について解説しています。
全文翻訳
ブログ ゲーム プロジェクト Dominic Szablewski, @phoboslab — 2026年8月4日火曜日
2026年にニンテンドー64のゲームを作る方法
2年前、私は理由もなくJavaScriptゲームエンジンをC言語に移植していました。その理由が今見つかりました。それは、新しいN64ゲームを作ることです!その結果が「Xibalba 64」です。これはWolfenstein 3DのようなFPSです。Modretroは、カートリッジ、パッケージ、マニュアルが付属する同社のM64(現代的なN64クローン)の物理的なローンチタイトルとしてこのゲームを出版することに同意しました!
Xibalba 64 on Modretro.com
私の知る限り、これはコンソールの商業的な寿命が終わって以来、新しいN64ゲームの物理的なリリースとしては2番目です。Bitmap Bureauによる悪名高い「Xeno Crisis」は、元々はセガメガドライブ向けの新しいゲームで、その後多くのコンソールでリリースされましたが、2023年にN64にも登場しました。2002年の「Tony Hawk's Pro Skater 3」以降、N64向けに新しいゲームは出版されていません。
エンジン
Impactは、私が2010年に開発したJavaScriptゲームエンジンでした。2Dアクションゲーム向けに調整されており、タイルシート、背景マップ、スプライト、衝突検出を処理しました。非常にシンプルですが、何でも対応できる堅実な基盤です。2年前、私はImpactをC言語で書き直しました。なぜか?理由はわかりません。楽しかったからです。このC言語ポートであるhigh_impactは、「プラットフォームバックエンド」という概念を持っています。プラットフォームは、ウィンドウを開く、描画サーフェスを作成する、入力を読み取るなどの低レベルの配管処理を担当します。high_impactには、標準で2つのプラットフォームバックエンド(SDL2とSokol)が付属しており、どちらか一方を選択してゲームをコンパイルできます。これにより、high_impactゲームはすでに多くの異なるデバイスで実行可能になります。high_impactのレンダリングバックエンドもモジュール式です。ソフトウェアレンダラー、OpenGL、またはMetal(iOS/macOS向け)でゲームをコンパイルできます。新しいプラットフォームバックエンドまたはレンダリングバックエンドのサポートは、他の部分を変更せずに簡単に追加できます。N64ゲームの完璧な出発点です。
N64ハードウェアとプラットフォームライブラリ
N64は癖のあるマシンです。93 MHzのMIPS CPU(ビッグエンディアン!)に加えて、グラフィックスやサウンドなどを処理するための2つのコプロセッサがあります。「Reality Display Processor」(RDP)– 固定機能グラフィックスプロセッサ、「Reality Signal Processor」(RSP)– プログラム可能なベクトルプロセッサ。これら両方は同じ物理パッケージに収まっており、一般的に「Reality Coprocessor」(RCP)と呼ばれます。
N64Brew Wikiより画像
N64の初期数年間、任天堂はRSPへのアクセスを厳密に管理していました。それは任天堂の公式ライセンスプラットフォームライブラリである「libultra」専用でした。後に任天堂はゲームスタジオにRSP用のカスタム「マイクロコード」(実際にはMIPSアセンブリ)を書くことを許可しました。ハードウェアをうまく扱うのは簡単なことではなく、RDPの命令は癖があり複雑です。ベアメタルでゲームをプログラミングするのはほぼ不可能です。近年、任天堂の公式「libultra」はインターネット上に流出しましたが、それを使用すると著作権侵害訴訟のリスクがあります。幸いなことに、N64のホームブリューシーンは過去数年間で非常に盛り上がり、現在では非常に有能な代替手段があります。それがLibdragonです。Libdragonは基本的にN64向けのSDLです。スプライトや三角形の描画、サウンド出力、コントローラー入力などの機能を提供します。Libdragonの上にhigh_impactの新しいプラットフォームバックエンドを構築するのに、数晩しかかかりませんでした。これをBiolab Disasterでテストしました。ゲームコードは変更されていませんでした。パフォーマンスはまあまあでしたが、N64ハードウェアを最も単純な方法で使用していました。
2025年9月17日の私のX投稿からのビデオ、Biolab DisasterがN64エミュレータで実行されている様子
開発環境
Libdragonは、N64用のROMファイルをビルドするために必要なコンパイラなどを提供します。インストール手順やその他のドキュメントは包括的でよく書かれています。ライブラリには、すぐに始められる多くの例が含まれています。一般的に、Libdragonは使いやすかったです。注意点として、おそらくプレビューブランチを使用したいでしょう。なぜなら、「安定」トランクブランチは絶望的に遅れているからです。テストには、優れたエミュレータが不可欠です。長らく、N64のエミュレーションは非常に不正確でした。特にRSPとRDPコプロセッサのエミュレーションの質が悪かったことが、ほとんどの問題の原因でした。ほとんどのエミュレータは、任天堂のプラットフォームライブラリであるlibultraをエミュレートしていました。三角形を描画するという意図をエミュレートしていたのであって、ハードウェアが実際に行うことをエミュレートしていたわけではありません。不正確でしたが、初期の頃はこれでエミュレーションが可能でした。悪名高いUltraHLE(「Ultra High Level Emulator」)は、N64の寿命の間にリリースされ、多くの頭痛の種とそれに続く訴訟を引き起こしました。最近では、AresのN64コアは実際のハードウェアにかなり近くなっています。RDPとRSPは完全にエミュレートされており、RSPの正確なタイミングも含まれています。しかし、N64の悪名高い低速なメモリ帯域幅は、依然として実際のハードウェアでしかテストできません(最近、これが原因で少しがっかりしました)。そのため、実際のN64と、任意の.z64 ROMファイルを再生できるカートリッジが必要です。オープンソースのSummerCart64は優れており、多くのメーカーから入手可能です。注意してください:一部のメーカー(特にAliExpress)は、ボードのコンポーネントを安価に済ませています。SummerCart64には、ROMを保存するための通常のSDカードスロットがありますが、開発に優れている点はUSB-Cポートです。PCに直接接続し、ビルドプロセスの一部としてsc64deployerを使用してROMをアップロードできます。私はN64をPCの横に置き、USB経由で接続し、安価な10ドルのUSBアナログキャプチャカードを使用して、デスクトップ上のウィンドウにビデオ出力を表示しました。Linuxでは、低遅延出力を得るためにmpvで少し手間がかかりました。このセットアップで、実際のハードウェアでのイテレーションは、コンパイルしてN64リセットボタンを押すだけの問題でした。
ゲーム
私は元々Xibalbaを2014年にJavaScriptゲームエンジンのデモとして作成しました。当時、WebGLはまだ注目の新技術でした。ブラウザで3Dゲームをプレイできるのはかなり斬新でした。ゲームは非常に短く、数レベル、敵の種類、武器しかありませんでした。それとは対照的に、Xibalba 64を単なるデモではなく、実際のゲームにしたかったのです。そのため、ゲームをC言語とhigh_impactに移植するだけでなく、より多くのレベル、敵の種類、武器を追加して拡張する必要がありました。high_impactは2Dゲームエンジンですが、Xibalba 64は明らかに3Dです。まあ、厳密には違います。ゲームには高低差がないため、ほとんど2Dとして扱えます。概念的には、Xibalba 64を2Dトップダウン視点からプレイできます。もちろん、それはそれほどエキサイティングではありませんが、すべての物理演算、移動、射撃は同じように機能します。この点において、ゲームはWolfenstein 3Dに非常に似ています。high_impactの物理関数の大半は、.xと.yコンポーネントを持つvec2_t引数を期待します。しかし、描画のためにはどうしても3D位置が必要だったので、vec3_t型の定義を考え出し、entity_t型を変更しました。
typedef struct { float x, y; } vec2_t;
typedef union {
vec2_t xy;
struct { float x, y, z; };
} vec3_t;
typedef struct {
// ...
vec3_t pos;
vec3_t vel;
// ...
} entity_t;
これで、vec2_tを受け入れる関数を呼び出す必要があるたびに、「無料」でvec3_tから「変換」できます。trace_t res = trace(collision_map, entity->pos.xy, entity->vel.xy);
内部のvec3_t構造体は「匿名」なので、すべての値に直接アクセスできます。つまり、entity->pos.zは問題なく機能します。既存のレベルと敵の種類の最初の移植は非常にスムーズに進み、約2週間で完了しました。その後、ゲームの拡張とレンダラーの最適化にさらに数ヶ月を費やしました。Libdragonの関数のほとんどは、新しいプラットフォームとレンダリングバックエンドに自然に適合しましたが、ミキサー(LibdragonにはRSPによってアクセラレーションされる独自のミキサーがあります)とイメージローダーをバイパスするために、high_impactの他の部分をいくつか変更する必要がありました。プロセス全体を通して、SDL2またはSokolバックエンドでゲームをビルドする能力を維持しました。これは、ゲームロジックと敵の挙動のプレイテストに役立ちました。レベルを作成するために、レベルファイルが変更されるたびにトリガーされるシンプルなホットリロードメカニズムも実装しました。
2026年1月25日の私のX投稿からのビデオは、レベル作成の様子を示しています。