2026年9月リリース
一年か二年前、自分で作った技術だけでゲームを作ろうと決めました。つまりゲームエンジンが必要でした。慣れた形で、つまりUnityのようなエディターとシーンを取り巻くデザイナーツールで作業したかったので、エンジンにはstudioが必要でした。studioにはGUIが必要で、それがGuinevereになりました。その過程で、汎用の基盤作業の多くをすでに提供してくれるVSCodeのようなプラットフォームの上に乗るほうが、特製のエディターをもう一つ書くより良いと気づきました。そこでstudioはプラグインの汎用ホスト、Gayaとなり、Turianはそのプラグインの一つになりました。ゲームと合わせて、このスタックがMEGA4です。
数ヶ月前、行き詰まってZigを探りに行きました。大きな進歩を遂げ、そのエンジンはTurianZとして生きており、C#への帰郷に戻った理由が書かれています。帰還には直近の二ヶ月がかかりました。
1.0の投稿で、数ヶ月でv23を見ても驚かないと冗談を言いました。v2に至るまでに破壊的変更が六つ。その投稿で挙げたギャップのうち二つ、Studioにアンドゥがないこととプレファブのコピーがソースにリンクされないことは、今や解消されています。

- なぜ2.0か、そしてなぜ今日か
- Bricks:オープンなパッケージ形式
- グローバルはもう不要:依存性注入
- DataAssets:デザイナーの背骨
- リンクを保つプレファブ
- アンドゥ、リドゥ、そして何も失われない
- パフォーマンス
- 自分で書かれるフォーム:Autoformers
- クロームの少ないStudio
- エンジンの内側
- Guinevere:より強固な基盤
- 今後に向けて
なぜ2.0か、そしてなぜ今日か
Turianはセマンティックバージョニングに従います。最初の数字、メジャーバージョンは、変更がプロジェクトを壊しうる場合にしか上がりません。数字による約束です。2.0の後に2.3が見えたら、何も読まずにアップグレードできます。3.0が見えたら、まずガイドを読んでください。
9月の変更のうち六つが、1.xプロジェクトにとってこの約束を破ります:
| 変更 | 壊れるもの | 移行手順 |
|---|---|---|
| カメラリグとゲーム内UIがbricksになった | それらを使うプロジェクトは宣言が必要 | Bricks |
| 依存性注入がグローバルサービスを置き換えた | 静的な Input、Localization、RuntimeServices |
Services |
Transform が不変の値になった |
node.Transform.Position = … |
Transform |
| Inspector属性が共有パッケージへ移動 | 属性の完全名、[HideInEditor] |
Attributes |
IdClass が IdObject に改名 |
アイデンティティAPIを使うプラグイン | IdObject |
| アプリケーションバーと外観がGayaへ移動 | カスタムGayaホストとクローム | Gaya |
最初の変更が届いた9月30日に2.0.0をタグ付けし、同じ日にタグを取り下げました。さらに破壊的な作業が既に進行中でした。これを一週間で2.0、3.0、4.0として出荷すれば、一ヶ月分の作業に三つの移行を強いることになります。そこで破壊的変更は今日、一つの移行ガイドとともにまとめて出荷されます。シーン、プレファブ、データアセットのファイルはidを保つので、コンテンツの変換は不要です。今後、2.xには互換性のある変更しか入りません。次の破壊的変更は、いつ来ても3.0です。
Bricks:オープンなパッケージ形式
2.0の最大の部品はbricksです。brickとはパッケージです。コード、アセット、エディターツールを一つのフォルダに収め、バージョン、依存関係、ライセンスを持ち、どのプロジェクトでもインストール、更新、削除できます。UnityにはPackage Managerがあり、GodotにはAsset Libraryがあります。bricksはそれへの我々の答えで、一つ違うのは、Turianに縛られないことです。
bricksはStudioの下のプラットフォームであるGayaに属し、その形式はオープンな仕様です:package.json マニフェスト、ロックファイル、レジストリインデックス。すべてJSONスキーマ付きで文書化されています。どんなエンジンでも、そもそもエンジンですらないアプリケーションでも、読み取りと公開ができます。Turianは単に最初の利用者です。今後の配布もこれで行います。サンプルプロジェクト、ゲームMOD、Studio拡張はすべてbricksになり、互いに積み重ねて構築できます。
このマシン上のbricksを一覧するBricksパネル。Inspectorにはあるbrickのマニフェストが表示されている
brickに含められるもの
brickはプロジェクトフォルダが持てるものなら何でも持てます:
- スクリプト。独自のアセンブリ定義の下でコンパイルされるため、brickのコードはあなたのコードから隔離されます。
- アセット:モデル、テクスチャ、プレファブ、シーン、サウンド、DataAssets。それぞれが恒久idを持つ
.metaファイルと共に出荷され、brickのプレファブを使うシーンは更新をまたいで参照を保ちます。 - Studio拡張:メニュー、パネル、Inspectorページ。プロデューサー例の
com.acme.inventorybrickは、インストールされた瞬間にStudioにAcmeメニューを追加します。 - ビルド済みコード。
turian-cli brick pack --precastはbrickのスクリプトを事前にコンパイルし、インストールする人はあなたのコードをコンパイルする代わりに出来上がったアセンブリを読み込みます。
エンジンは自分のbricksを食べる
最初のbricksはTurian自身のものです。Follow、Orbit、Free Fly、FPSの各カメラリグがエンジンコアから org.mass4.turian.cameras へ、ゲーム内UI(.ui ドキュメント、.uss スタイルシート、それらを描画するすべて)が org.mass4.turian.ui へ移りました。どちらもTurianと共に出荷され、新規プロジェクトはインストールしますが、不要なゲームは削除できます。UIのないゲームはGuinevereもSkiaも出荷せず、実行ファイルは libSkiaSharp を失い、プラットフォームあたり約13 MBの減量です。
brickが見つからなくても、何も破壊されません。コンポーネントはプレースホルダーとして読み込まれ、アセットはスキップされ、.meta ファイルはそのまま残るので、brickを再インストールすればすべて戻ります。1.xプロジェクトはこの二つのbricksを宣言する必要があります:移行ガイドを参照してください。
bricksのインストールと管理
プロジェクトは Bricks/manifest.json にbricksを列挙します。隣の packages-lock.json は、コミットやファイルハッシュに至るまで、何が解決されたかを正確に記録し、チームのどのマシンでも同じゲームがビルドされます。両方をコミットしてください。brickは五つの場所から来られます:
| ソース | 例 | 用途 |
|---|---|---|
| 組み込み | builtin:org.mass4.turian.cameras |
エンジンに付属するbricks |
| フォルダ | file:../bricks/com.acme.levels |
ゲームの隣で開発中のbrick |
| パックファイル | file:levels-1.0.0.brick |
誰かから送られたbrick |
| Git | git+https://github.com/acme/rules.git#v1.2.0 |
リポジトリ内のbrick、コミットに固定 |
| レジストリ | ^1.0.0 |
レジストリの互換性のある最新リリース |
bricksはマシンごとに一度、~/.gaya/bricks に保存され、プロジェクトへはコピーされないため、同じbrickを使う十のプロジェクトがディスク上の一つのコピーを共有します。GAYA_BRICKS を設定すれば、CIキャッシュなど別の場所に保存できます。
Studioでは、Project → Bricks… がBricksパネルを開きます。プロジェクトがインストールしているものと、各brickがなぜそこにあるのか(つまり何が依存しているか)を一覧し、エディターを出ずにbricksのインストール、更新、削除、埋め込みを行います。Inspectorは選択されたbrickのマニフェストを表示します。AssetsパネルにはAssetsの隣にBricksフォルダーが加わり、brickのプレファブ、テクスチャ、スクリプトを他のアセットと同じようにシーンやInspectorフィールドへドラッグできます。すべてはターミナルからも動きます:turian-cli brick add、remove、list、update、search、そしてマニフェストとロックが不一致ならCIビルドを失敗させる restore --locked。
インストールしたものを変える
インストールされたbricksは読み取り専用です。さもなければ更新があなたの編集を消すからです。代わりに、brickを自分のものにする方法の梯子があります。軽い順に:
| 手順 | 方法 | brickの更新に追従? |
|---|---|---|
| そのまま使う | idで参照する | はい |
| バリアントを作る | プレファブバリアントや、いくつかの値を上書きするデータアセットバリアント | はい。上書きしたもの以外 |
| インポート方法を変える | ProjectSettings/PackageImportOverrides.json |
はい |
| アセットを一つコピー | AssetsパネルのCopy、または brick copy |
いいえ:コピーには新しいidが付く |
| brick全体をフォーク | brick embed |
brick rebase でマージ |
埋め込まれたbrickは Bricks/<id>/ の書き込み可能なコピーで、インストール済みのものより優先されます。brick diff は変更点を表示し、brick rebase はオリジナルの次のリリースをフォークにファイルごとにマージし、同じ行を両方が編集した場所にgitと同じようにコンフリクトを印します。
自分のbrickを作る
turian-cli brick new user.you.inventory は、マニフェスト、アセンブリ定義、最初のスクリプトを持つbrickを作成します。idはJavaやAndroidのパッケージのように逆DNS順で書きます。持っているドメイン(com.acme.inventory)を使うか、なければ user.<name>.… を使います。brick verify はすべてのアセットが一意の .meta を持つか確認し、brick pack はハッシュ付きの .brick ファイルを書き出します。パッキングは再現可能です。同じソースは常に同じバイトを生むので、公開されたbrickがソースコードと一致するか誰でも確認できます。再利用可能なGitHubワークフロー MASS4ORG/Turian/.github/workflows/brick.yml が、brickを検証し、パックし、リリースします。
三つのサンプルプロジェクトがサイクル全体を見せます。example-06-plugin-producer は三つのbricksを作成し(うち一つはエディターコード付き)、example-05-plugins はそれらをインストールし、example-07-team-split はチームを扱います。あるチームがbrickを作り、別のチームがその上にゲームを作るとき、brick stub は同じアセットidと型idを持つプレースホルダーを作るので、ゲームは初日から本物のidを参照し、stubと本物のbrickがズレると brick verify --against が失敗します。
レジストリ
レジストリは、人々が他の人が見つけられるようbricksを公開する場所です。Turianレジストリは署名付きインデックスを持つ静的ウェブサイトなので、GitHub Pagesで十分にホストでき、サーバーは不要です。turian-cli brick registry add studio https://… --scope com.studio --key studio.pub でプロジェクトに追加すると、"com.studio.inventory": "^1.0.0" のような単純なバージョン範囲が互換性のある最新リリースに解決されます。
すべてのリリースは署名されます。公開者はed25519鍵で署名し(turian-cli brick publish --registry site/ --key registry-key)、これはモダンな楕円曲線署名スキームで、GitHubがSSHログインに受け付ける鍵と同じ種類なので、大半の開発者は既に一つ持っています。プロジェクトは自分で列挙した鍵だけを信頼し、ロックファイルはバージョン、ファイルのハッシュ、署名した鍵を記録します。レジストリが侵害されても、改ざんされたbrickは静かにゲームに入り込むのではなく、インストールに失敗します。user.<name>.… の名前は、最初にその名前で公開した人のものです。
Unityパッケージを持ってくる(きわめて実験的)
turian-cli import unitypackage Crates.unitypackage --brick user.you.crates --out bricks/ は、Unityをインストールせずに .unitypackage を直接読み、brickに変えます。テクスチャ、モデル、オーディオはUnityのidを保ち、単純なマテリアルとプレファブも一緒に来ます。移行手段ではなく実験として扱ってください: スクリプト、シェーダー、アニメーションは変換されず、単純なシーンを超えるものは手作業が必要です。レポートはスキップされたものを列挙します。インポートするもののライセンスも確認してください。ツールはファイルを移動するだけで、条件を変えることはありません。
グローバルはもう不要:依存性注入
Turian 2.0.0、チケット #44
Unityは最初の数年にある選択をし、今もなお苦しんでいます。APIがグローバルなのです。Input.GetKey、Time.deltaTime、Camera.main、GameObject.Find は誰でもどこからでも呼べる静的呼び出しで、大半のUnityプロジェクトはその上に独自の GameManager.Instance シングルトンを追加します。初日には素晴らしく便利です。数年後には、Unityコンポーネントが単体でテストしにくい理由、Play Modeを速くするためにドメインリロードを切ると前回の実行を覚えている静的フィールドをすべて狩り出すことになる理由、コミュニティが回避策としてZenjectやVContainerを作った理由が、これです。Unityは静的を削除できませんでした。世界中のプロジェクトが依存しているからです。
Turian 1.0は同じ便利さを、Input や Localization のような静的クラスの後ろに持っていました。2.0は、壊すプロジェクトがまだ少ないうちにそれを排除します。依存性注入とは、コンポーネントが必要なものを探しに行かず、それを宣言するとエンジンが手渡す、ということです。各セッション(書き出したゲーム、Play Modeの各実行、各テスト)は独自のサービスコンテナを持ち、.NET標準の Microsoft.Extensions.DependencyInjection の上に構築されます:
public class Patrol : Component
{
[InjectService, JsonIgnore]
public IInputSource? Input { get; private set; }
public override void OnUpdate(float deltaTime)
{
if (Input?.IsKeyDown(Key.W) == true)
Node.Position += Vector3.UnitZ * deltaTime;
}
}
| Unity | Turian 2.0 | |
|---|---|---|
| 入力を読む | どこからでも Input.GetKey(KeyCode.W) |
IInputSource を注入 |
| 独自サービス | シングルトン、ZenjectやVContainer | IEngineServiceModule、組み込み |
| Play Modeの隔離 | ドメインリロードしない限り静的フィールドが残る | 各セッションが独自のサービスを持つ |
| コンポーネントの単体テスト | グローバルを手で置き換える | テストコンテナを渡す |
| デザイナー所有のサービス | 慣例としてのScriptableObjectシングルトン | DataAsset、セッションごとに共有 |
[InjectService(Optional = true)] により、入力が路由されないStudioでプレビューされるシーンのように、サービスがない場所でもコンポーネントは動けます。ゲームとbricksは IEngineServiceModule を実装して独自のサービスを登録し、Turianはゲームが読み込むすべてのアセンブリでモジュールを発見します。あわせて SceneTicker.TimeScale が登場します。ゲーム時間をスケールし、0 で凍結し、メニューやエフェクトのために非スケール時間は動き続けます。1.xからのアップグレードはいくつかの置換で済み、移行ガイドに列挙されています。
表の最後の行は同じ話のデザイナー側で、独自の節に値します。
DataAssets:デザイナーの背骨
Turian 1.0から2.0、チケット #145、#146、#147、#43、#197
DataAssetはUnityのScriptableObjectのTurian版です。C#クラスで、そのインスタンスはプロジェクト内のファイルとして存在し、コードではなくInspectorで編集されます。WeaponData アセットは剣のダメージと速度を持ち、LevelData はレベルの敵ウェーブを持ちます。プログラマーはクラスを一度書き、デザイナーはスクリプトに触れずに好きなだけアセットを作成、調整、バランス調整します。
2017年、Ryan HippleはUnite Austinで、Game Architecture with Scriptable Objects という講演でこの考えがどこまで行くかを見せました。システムをコードで直結する代わりに、アセットを通して接続するのです。プレイヤーの体力は FloatVariable アセットで、体力バー、オーディオ、セーブシステムがどれも読み、「プレイヤーが死んだ」は誰でもリッスンできる GameEvent アセットです。デザイナーはInspectorでアセットをドラッグしてゲームを組み替えます。このアプローチはSOAP、ScriptableObject Architecture Patternとして知られるようになり、ゲーム構築の最もデザイナーフレンドリーな方法の一つです。Turianはこれに倍の賭けをします。DataAssetsはデザイナーの仕事の背骨になります、そして9月にその基盤が据えられました。
| Unity ScriptableObject | Turian DataAsset | |
|---|---|---|
| アセットごとに一つのインスタンス | はい | はい、セッションごとに共有 |
| Play Mode中の変更 | Play Mode終了後も残る | 捨てられる。作成元のファイルには決して書かれない |
| バリアント | サードパーティ製ツールなしでは不可 | 可。プレファブバリアントと同様 |
| プロジェクト設定 | ProjectSettings/ の特殊ファイル |
DataAssetそのもの |
| シーンオブジェクトの参照 | 保存時に静かに失われる | コンパイル時に拒否され、提案付き |
- 一つの共有インスタンス。 DataAssetを参照するすべてのフィールド、シーン、サービスが同じオブジェクトを得るので、
GameManagerDataAssetはサービスとして働きます。あるシーンでコインを変えれば次のシーンがそれを見ます。別のPlay Mode実行やテストといった二番目のセッションは独自のコピーを得ます。 - 作成されたデータは作成されたまま。 Play Modeは毎回保存された値から始まり、実行中のゲームが行うことはファイルに書き戻されません。Unityでは、実行中のゲームがScriptableObjectに行った変更はPlay Modeを生き延び、バランス調整の午後を失う古典的な方法です。
DataAsset.Instantiateは、必要なときにスクリプトに私的なコピーを渡します。 - バリアント。 DataAssetは別のもののバリアントになれ、プレファブバリアントと同じように、上書きする値だけを格納します。「炎の剣」はダメージの高い「剣」のバリアントにでき、「剣」を再調整すればすべてのバリアントが追従します。Studioか
turian-cli variantで作成できます。 - 設定はDataAsset。 プロジェクトのInput、Graphics、Player、Localizationの各設定はDataAssetで、New → Settings から作成され、他のすべてと同様にInspectorで編集されます。つまり設定はバリアントになれ、bricksに置け、独自データと同じサービスを通して読めます。
- 強化。 シリアライザは実行時のリフレクションではなくコンパイル時に生成されるため、DataAssetは速く読み込まれ、バックグラウンドでプリロードもできます。バリアントは、自分が何であるかを静かに変えるものをすべて拒否します。オーバーライドはアセットのidや型を置き換えられず、バリアントはベースの型を保たねばならず、未知の構文は無視されずに高らかに失敗します。シーンオブジェクトへの参照を保持しようとするDataAssetはコンパイラに報告され(
TUR0001)、代わりに何を使うかの提案が付きます。
リンクを保つプレファブ
プレファブとは、街灯、敵、家一棟のような、シーンの再利用可能な部品で、一度作って何度も配置するものです。1.0では置かれたプレファブはコピーでした。オリジナルを変えてもコピーは気づきません。今は各インスタンスがリンクで、ワークフローはUnityユーザーが知るものです:
- オーバーライドは追跡される。 インスタンスはプレファブについて何を変えるかを覚えています。値、追加されたコンポーネントとノード、削除されたもの。Scene TreeとInspectorが印を付けます。
- Applyとrevert は値ごと、コンポーネントごと、インスタンス全体で機能します。applyは値を所有するプレファブに、最内側から書き込み、ネストされたプレファブへの編集はあるべき場所に届きます。
- ネストされたプレファブとバリアント。 プレファブは他のプレファブのインスタンスを含められます。街灯プレファブで満ちた家プレファブ。ルートが別のプレファブのインスタンスであるプレファブはそのバリアントで、色以外すべてを「家」から継承する「赤い家」のようなものです。
- プレファブモード。 シーンからインスタンスのプレファブを開き、編集し、パンくずで戻ります。開いているシーンのインスタンスはプレファブが変わるとすぐに更新されます。
- Unpack はリンクを断ち、階層を通常のノードとして保ちます。オプションでネストされたインスタンスも展開します。
これらの操作はすべてアンドゥ可能です。シーンファイルも小さく保たれます。インスタンスは、プレファブを使う各シーンに完全なコピーを置く代わりに、プレファブへのリンクと、上書き・追加・削除だけを保存します。
アンドゥ、リドゥ、そして何も失われない
Turian 1.1.0、チケット #81
Studioはすべてのエディター操作にアンドゥとリドゥを持ち、Unityと同じように動きます。プロジェクト全体で一つの履歴であり、各ステップはドキュメントに属します。ドキュメントとは、開いているシーンか、Inspectorが編集しているアセットです。ステップをアンドゥすると、まずそのドキュメントが前面に来るので、何が変わったか必ず見えます。
アンドゥは、ちまちましたイベントのすべてではなく、あなたの意図を追跡します。ギズモでのオブジェクトのドラッグは、何フレーム続いても一つのステップで、数値フィールドのスクラブは一つのステップにマージされます。保存はステップを封印するので、保存後の編集は常に別々にアンドゥされます。シーンを超える変更もカウントされます。Assetsパネルでのファイルの改名や移動、Applyによるプレファブの書き換え。Editメニューは、アンドゥやリドゥしようとするステップを名前で示します。Play Modeがゲームを表示している間、履歴はロックされます。それらの変更はどのみち捨てられるからです。
未保存の作業がある状態でStudioを終了したりプロジェクトを切り替えたりすると、確認されるようになりました。
パフォーマンス
Turian 2.0.0、チケット #32、#132、#58
以下のすべての表で一つの単語が現れます。アロケーションです。C#では、ヒープ上に作られたすべてのオブジェクトは、ガベージコレクタが後で見つけて解放しなければならないメモリです。毎フレームアロケートするゲームはやがて回収のために停止し、プレイヤーは引っかかりを目にします。フレームあたりゼロアロケーションは、エンジンによる引っかかりがないことを意味します。
アロケートしなくなったトランスフォーム
始まりは一つの疑問でした。いくつかのエンジンがそうするように、Turianは Node を2D、3D、UIの特化型に分けるべきか?コンポーネント、シリアライズ、プレファブ、ツールに波及するため、決める前に計測しました。
答えは別のところにありました。各ノードの Transform(位置、回転、スケール)は、変更通知を持つクラスでした。すべての編集がイベントを起こし、ワールド位置のすべての読み取りが階層を歩いてアロケートしていました。2.0では Transform は不変の struct で、独立したオブジェクトではなくノードの内側に格納される小さな値であり、各ノードは自分か親が動くまでワールドトランスフォームをキャッシュします。
10万ノードのツリーで、すべてのノードを動かしてからすべてのワールド位置を読むと:
| フレーム時間 | フレームあたりの割り当て | ノードあたりのメモリ | |
|---|---|---|---|
1.x: クラス Transform |
75.9 ms | 10 MB | 556 バイト |
2.0: 構造体 Transform |
6.5 ms | 0 | 342 バイト |
| フラット3Dストレージ試作 | 0.60 ms | 0 | 85 バイト |
| フラット2Dストレージ試作 | 0.36 ms | 0 | 53 バイト |
これはゴミなしで11.7倍高速ということです。最後の二行は、全ノードのデータをフラットな配列に格納する試作です。2D/3D分割が実際に報われる場所を示しており、将来のメジャーの目標として取っておき、Node は当面一つの型のままです。トランスフォームを書くコードの更新は、ほぼ検索と置換です。移行ガイドを参照してください。
動かなくなるレンダーリスト
レンダラーは毎フレームシーン全体を歩いて描画物のリストを再構築していました。今はリストを保持し、変わったものだけを更新し、GPUの状態切替が減るようマテリアルでソートします。Amazon Lumberyardの街路シーン、Bistroサンプルで300フレームにわたり:
| Bistro、300フレーム | 中央値レンダー | フレームあたりの割り当て |
|---|---|---|
| 前 | 7.2 ms | 797 KiB |
| 後 | 2.1 ms | 0.1 KiB |
採用しないものを測る
ZLinq、LINQ(C#のコレクション向けクエリ構文)の人気のあるアロケーションフリーな代替は、シーンクエリの候補でした。5万ノードでのベンチマークはノーと言いました:
| ゲームプレイクエリ、5万ノード | 標準LINQ | ZLinq | 単純なループ |
|---|---|---|---|
| プレイヤーの近くの敵を数える | 1.8 ms | 3.3 ms | 1.7 ms |
| 名前でノードを見つける | 1.5 ms | 1.9 ms | 0.35 ms |
| 最も近いピックアップ | 1.9 ms | 4.5 ms | 1.7 ms |
| 最弱の10体の敵 | 2.0 ms、40 KiB | 4.6 ms | 1.6 ms、0 KiB |
シーンの走査自体がアロケートしなくなると、単純なループがすべてのクエリに勝ち、新しい依存もありません。代わりにTurianは、渡したリストを埋める GetComponentsInChildren<T>(List<T>) のようなオーバーロードを得て、ゲームプレイコードはアロケートせずに毎フレームクエリできます。Guinevereはレイアウトエンジンで同じ作業を行い、その数値は下にあります。
自分で書かれるフォーム:Autoformers
Turian 1.2.0と2.0.0、チケット #28、#29、#194
C#クラスを書けば、StudioのInspectorはそのフィールドをフォームとして表示します。[Range] にはスライダー、bool にはチェックボックス、色にはカラーピッカー。Turian 1.2はこの機構をプロパティドロワーで拡張可能にし、型や属性の描画方法を変えられるようにしました。[Tooltip] と [InspectorOrder] も一緒です。
それから気づきました。この機構にはゲームに関することは何もないと。Gayaの上に作られたツールはどれも、C#クラスからフォームを生成したいはずです。そこで2.0ではフォーム生成器はGuinevereへAutoformersとして移り、属性は共有の MASS4.Attributes パッケージへ移りました。他のGUIアプリケーションも使えるようになり、Gayaは既に使っています。SettingsパネルはC#設定クラスから、カスタム表示とバリデーション込みで自動生成されます。StudioのInspectorもBricks InspectorもAutoformerフォームです。Turianにはゲームに関する属性だけが残ります。属性名は少し変わりました。移行ガイドを参照してください。
クロームの少ないStudio
Studioのメインメニューは、プロジェクトスイッチャーやプレイコントロールと共有するアプリケーションバーの中の単一ボタンに折りたたまれるようになりました。このバーはOSのタイトルバーも置き換えられます。カスタム装飾により、バーの空きスペースでウィンドウをドラッグし、独自のボタンで最小化・最大化・閉じ、すべての境界と隅からリサイズできます。
Gayaの新しい外観ページにはテーマ、文字サイズ、ズーム、ウィンドウ装飾がまとめてあり、テーマのドロップダウンとView → Themesが保存された選択を共有します。Studioは五つのテーマを同梱します:Dark、Light、Dark Contrast、Darcula、Catppuccin。

ウィンドウクロームを提供するカスタムGayaホストとプラグインには二つの小さな変更が必要です。移行ガイドを参照してください。
エンジンの内側
bricksはコンテンツを合成可能にし、一つの疑問を生みました。コンテンツが多くの場所から来るとき、ゲームの安定性は何が保つのか?2.0はその答えを、コードとテストに書き下ろします。
- コンテンツオーバーレイ。 コンテンツパッケージは依存順でマウントします。競合、循環、欠けている要件はゲーム開始前に報告され、実行中のゲームは開始時のコンテンツを保ち続けます。MODが立つ土台です。
- ランタイムセーブ。 新しい
RuntimeSaveは、実行中のゲームのバージョン付きスナップショットを書き出します。tick、乱数状態、ゲーム状態です。復元前にスナップショットをゲームのコンテンツと照合するので、別のMOD構成で作られたセーブは、間違って読み込まれるのではなく検出されます。古いセーブのアップグレードはコピーの上で行われるため、失敗してもセーブは無傷です。
Guinevere:より強固な基盤
StudioはGUIライブラリGuinevereによって描かれるため、Studioで見えるもののほとんどはGuinevereの仕事で、Guinevereは素晴らしい月を過ごしました。9月9日の1.6から10月2日の5.6まで。パッケージは MASS4.Guinevere.* として公開されています。ハイライト:
Excaliburコントロール。 コアの上に構築された専用のコントロールライブラリで、独立パッケージとして公開。可視行だけを描く仮想化ツリービュー、スライダー、Unity風のスクラブ可能な数値フィールド、タブ、トースト、ツールチップ、メニューバー、コンテキストメニュー、カスケードフライアウト、モーダルダイアログ、ファイルブラウザ。色と寸法は値ごとにテーマ可能です。
ドッキング。
gui.DockSpaceはタブグループ、ネストされた分割、フローティングウィンドウ、ドラッグでドッキング、タブの並べ替えと引き離し、任意の二つのパネルの間のスプリッター。Studioのレイアウト全体がその上に構築されています。Autoformers。 Turianのフォーム生成器はGuinevereに新しい居場所を見つけました。上を参照。
より速いレイアウトエンジン。 サイズは合成可能な式になりました。ピクセル、パーセント、比率、拡張、フィットは加算・スケール・アニメーション可能で、パネルは「200ピクセル」から「ウィンドウの70%」へ滑らかに成長できます。同時にレイアウトはアロケートしなくなり、深いツリーで線形にスケールします:
1,000ノードのシナリオ 前 後 レイアウトあたりの割り当て 幅の広い折り返し 0.035 ms 0.011 ms 45 KB → 0 ネストされたフィットコンテンツ 0.132 ms 0.036 ms 55 KB → 0 テキストの測定 0.035 ms 0.011 ms 52 KB → 0 イベントとカーソル。 マウスとキーボードのイベントはウェブブラウザと同じように、ターゲットまで降りて戻ってくる経路をたどり、どのハンドラもそれを止められます。ウィジェットは自分のカーソル形状を宣言し、ポインタは非表示やロックができ、3Dビューポートのマウスルックに必要です。
プラットフォーム能力。 統合(OpenGL、Vulkan、OpenTK、Raylib)は、カーソル形状、ポインタロック、ウィンドウ移動、クローズの拒否など、何ができるかを宣言します。GayaとTurianは四つのうち最もモダンなVulkanを使います。
Guinevereのアプリケーションバーは道中で形が変わりました。直接使うコードは移行ガイドに従ってください。

今後に向けて
ここに載っていない修正、調整、強化はまだたくさんあります。完全なリストは変更ログを見てください。
リリースページにWindowsとLinuxのTurian 2.0.0があり、移行ガイドが1.xプロジェクトをアップグレードに案内し、ドキュメントにはbricksの新しいページがあります。何か壊れたらGitHubで教えてください。次のリリースの資金援助をしたい方は、PatreonやKo-fiで見つけられます。
#release#engine#studio#dotnet