最近、UnityでC++を触ってみたいという話をよく聞きます。
「UnityってC#専用じゃないの?」という声もありますが、実はC++コードをDLLとして組み込むことができます。
わたし自身、C++で書いた演算処理をUnityに組み込んだことがあり、その手順と注意点をまとめました。
「C++ Unity」という組み合わせが気になる方に、ざっくり流れをつかんでもらえたらうれしいです。
UnityはC++ベースだけど、C#がメインスクリプト言語
Unityのエンジン自体はC++で作られています。
でも、開発者が普段触るのはC#。
Unityでは「C#スクリプト→.NETランタイム→ネイティブC++エンジン」という構造になっていて、C++は内部で動いているだけです。
つまり通常のゲーム開発ではC#が圧倒的に便利で、C++を直接使うことはありません。
それでもC++を使いたい場面があります。
たとえば:
- 計算負荷が大きい処理をネイティブコードで最適化したいとき
- 既存のC++ライブラリをUnityに組み込みたいとき
- C++ベースのシステム(外部APIなど)をUnity側で呼びたいとき
こういうときに使えるのが「C++のDLLをUnityから呼ぶ」方法です。
これなら、UnityのC#スクリプトからC++関数を直接呼び出せます。
C++をDLL化する:Visual Studioで最小構成から
まず、C++側でDLLを作ります。
環境は以下のような感じでした:
- Windows 10
- Visual Studio 2022 Community Edition
- Unity 2022.3 LTS
Visual Studioで「新しいプロジェクト」→「C++」→「Windowsデスクトップアプリ」→「DLL(ダイナミックリンクライブラリ)」を選びます。
空のプロジェクトを選択して、余計な設定は外しておきましょう。
今回は「add」という名前で作成しました。
シンプルな加算関数をエクスポートします:
extern "C" __declspec(dllexport) int __stdcall add_function(int a, int b) {
return a + b;
}
ここでポイントは3つ:
-
extern "C":名前のマングリング(装飾)を防ぐ -
__declspec(dllexport):関数を外部に公開 -
__stdcall:呼び出し規約。C#側のDllImportと一致させるため
これをビルドして、Releaseフォルダにできたadd.dllを確認します。
x86/x64どちらも出力しておくと後で便利です。
Unity側でDLLを読み込む:Pluginsフォルダに配置
次に、UnityプロジェクトのAssetsフォルダ直下にPluginsというフォルダを作ります。
その中にx86とx86_64を作成し、それぞれに対応するDLLを入れます。
構成イメージはこんな感じです:
Assets/
└─ Plugins/
├─ x86/
│ └─ add.dll
└─ x86_64/
└─ add.dll
インスペクターでDLLを選択し、Plugin Import Settingsから対象プラットフォームとCPUアーキテクチャを正しく設定します。
(x64ならx86_64を、x86ならx86を指定)
この設定を忘れると、実行時に「DllNotFoundException」が出るので注意です。
C#からDLLを呼び出す:DllImportの書き方
UnityではSystem.Runtime.InteropServicesを使ってC++ DLLを呼び出します。
次のように静的クラスを作り、DllImportで関数を指定します。
using UnityEngine;
using System.Runtime.InteropServices;
static class DLL
{
[DllImport("add", CallingConvention = CallingConvention.StdCall)]
public static extern int add_function(int a, int b);
}
public class DllExecutor : MonoBehaviour
{
void Start()
{
int result = DLL.add_function(3, 5);
Debug.Log("C++ Result: " + result);
}
}
DllImport("add")の引数は拡張子.dllを省いたライブラリ名です。
このとき、UnityはPluginsフォルダを自動的に検索します。
CallingConvention.StdCallはC++側の__stdcallに合わせています。
実行すると、Consoleに「C++ Result: 8」と出力されるはずです。
これでC++関数がUnity上で呼び出せました。
よくあるエラーとハマりポイント
最初の実験でよく出るのがこの2つ:
-
DllNotFoundException: DLLが見つからない(フォルダ構成やアーキテクチャ設定の不一致) -
EntryPointNotFoundException: 関数名が見つからない(extern "C"忘れ)
特に後者は初心者がハマりがち。
C++では関数名に「マングリング(装飾)」が行われるため、C#側から見えなくなってしまうんですね。
そのため必ずextern "C"をつけて、関数名をフラットにしておく必要があります。
また、x64のUnityでx86 DLLを読み込もうとするとロードに失敗します。
ビルド設定(File → Build Settings → Architecture)とDLLのビット数を一致させるのも忘れずに。
C++を使うべき場面と、C#で十分な場面
「C++のほうが速いから全部C++で書きたい」という声もありますが、Unityではあまりおすすめできません。
C++は確かに高速ですが、Unityのエコシステム(コンポーネント、MonoBehaviour、Inspector編集など)はC#前提で作られています。
C++を多用すると、エディタとの連携やデバッグが難しくなります。
一方で、C++が有利なケースもあります。
わたしが試したのは物理演算のシミュレーション部分で、1秒あたりの演算回数を稼ぎたいときにC++化が有効でした。
ループ処理が何百万回も回るような箇所は、C++のネイティブ最適化が効きやすいです。
目安としては:
- ゲームロジック・UI制御・イベント処理:C#
- 重い数値演算・画像処理・外部API連携:C++(DLL)
このすみ分けを意識しておくと、開発効率も保てます。
IL2CPPとネイティブコードの違いも知っておく
Unityのビルドターゲットによっては、裏側でC#がC++に変換されることもあります。
これは「IL2CPP(Intermediate Language to C++)」という仕組みで、iOSやWebGL向けのビルドでは必須です。
つまりC#スクリプトをコンパイル時にC++へ変換→ネイティブコード化して動かすんですね。
この仕組みのおかげで、C#で書いていても実行時にはC++並みに高速化されます。
なので、「C++で書かないと遅い」という時代ではもうありません。
実際、Unity 2021以降のIL2CPPは最適化がかなり進んでいて、C#コードでも十分なパフォーマンスを出せます。
わたしは一時期、DLLでC++に逃げようとしていましたが、最終的にはC# + Job System + Burstで十分だと感じました。
ネイティブ連携は「どうしてもC++が必要なときだけ」でOKです。
UnityとC++の連携を安全に保つためのコツ
C++コードをUnityに渡すときに気をつけたいのが「クラッシュリスク」です。
C++はメモリ管理を自分で行うため、ポインタの扱いを間違えると即クラッシュします。
DLLの境界を越えてポインタを渡すのは避け、できるだけプリミティブ型(intやfloat)で完結させましょう。
また、デバッグが難しくなります。
Unity Editorから呼び出すときは、Visual Studioの「アタッチ」機能を使って、ブレークポイントで挙動を確認できます。
Releaseビルドだと最適化されてステップ実行が飛ぶので、最初はDebugビルドをおすすめします。
わたしは一度、配列ポインタを受け渡す部分でバッファオーバーランを起こして、Unity Editorごと落ちました……。
C#の世界ではめったにない体験です。
安全第一で、小さい単位から検証するのがコツです。
まとめ:C++も使えるけど、目的を明確に
Unityでは基本的にC#で事足ります。
でも、C++をDLLとして組み込むことで、外部ライブラリを再利用したり、高速な演算処理を実装したりできます。
やってみるとC#とC++の橋渡しが見えて、Unityの内部構造を理解するいい勉強にもなります。
わたしの場合、「ゲームエンジンの中ってこうなってるんだ」と腑に落ちました。
C++連携はあくまで“必要なところだけ”。
Unity本体の流儀(C#中心)を尊重しつつ、最適化や外部連携でC++を取り入れるのが現実的です。
もし基礎からUnityを学び直したい方は、Unity入門の森ショップの教材がわかりやすいです。
C#からネイティブ連携まで、自然な流れで理解できると思います。