20
22

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

UnityでC++を使う:C#との違いと実践手順をまとめてみた

Posted at

最近、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というフォルダを作ります。

その中にx86x86_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#からネイティブ連携まで、自然な流れで理解できると思います。

20
22
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
20
22

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?