yotiky Tech Blog

とあるエンジニアの備忘録

Unity - R3 を使った Pure C# のModel層プロジェクトの作成

目次

概要

  • ピュアC# の.NETプロジェクトでModel層を作成する
  • R3 を導入してRxをシームレスに利用する
  • Unity プロジェクトはすでに存在するものとする

環境

  • Unity 2022.3.21f1
  • R3 1.1.11

手順

  • 新しいクラスライブラリプロジェクトを作成する
  • フレームワークは、.NET Standard 2.1 を選択

  • NuGet でR3をインストール
  • Directory.BUild.props を作成
    • Unity側からビルド出力のフォルダが無視されるようにする
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
    <PropertyGroup>
        <ArtifactsPath>$(MSBuildThisFileDirectory).artifacts</ArtifactsPath>
    </PropertyGroup>
</Project>
  • csproj を開いて編集
    • LangVersion : 9.0
    • None Remove を追加する
      • Unityが生成するUnity向けのファイルを.NETのプロジェクトで無視するようにする
  <PropertyGroup>
    <TargetFramework>netstandard2.1</TargetFramework>
    <LangVersion>9.0</LangVersion>
    <Nullable>enable</Nullable>
  </PropertyGroup>
    <ItemGroup>
        <None Remove="**\package.json" />
        <None Remove="**\*.asmdef" />
        <None Remove="**\*.meta" />
    </ItemGroup>
    <ItemGroup>
        <PackageReference Include="R3" Version="1.1.11" />
    </ItemGroup>
  • package.jsonを追加する
{
  "name": "xrproject_vnext.models.shared.unity",
  "displayName": "Models.Shared.Unity",
  "description": "Models.Shared.Unity",
  "version": "0.0.1",
  "unity": "2022.3",
  "author": "yotiky",
  "dependencies": {
    "org.nuget.r3": "1.1.11",
    "org.nuget.microsoft.net.stringtools": "1.0.0"
  }
}
  • asmdefを追加する
{
  "name": "Models.Shared.Unity",
  "references": [],
  "optionalUnityReferences": [],
  "includePlatforms": [],
  "excludePlatforms": [],
  "allowUnsafeCode": false,
  "overrideReferences": false,
  "precompiledReferences": [],
  "autoReferenced": true,
  "defineConstraints": []
}
  • 以降Unityプロジェクトで
  • Add package from disk... で上記package.jsonを追加する
  • Unityプロジェクト側のasmdefに上記asmdefの参照を追加する
  • Packages\manifest.json絶対パス相対パスに修正する
    • "xrproject_vnext.models.shared.unity": "file:../../Models/ClassLibrary1",

サンプル実装

.NET プロジェクト

    public class SampleClass
    {
        private readonly ReactiveProperty<int> _number = new(0);
        public ReadOnlyReactiveProperty<int> Number => _number;

        private Subject<Unit> _onCalled = new Subject<Unit>();
        public Observable<Unit> OnCalled => _onCalled;

        public void Increment()
        {
            _number.Value++;
        }
        public void CallOnNext()
        {
            _onCalled.OnNext(Unit.Default);
        }
    }

Unity プロジェクト - サンプルコードを実装して空のGameObjectに追加する

void Start()
{
        var model = new SampleClass();
        model.OnCalled
            .Subscribe(_ => Debug.Log("OnCalled"))
            .RegisterTo(destroyCancellationToken);
        model.Number
            .Subscribe(x => Debug.Log($"Number changed : {x}"))
            .RegisterTo(destroyCancellationToken);

        model.CallOnNext();
        model.Increment();
        model.CallOnNext();
        model.Increment();
}

実行結果

参考