commit bfce70eb6f07f2440322885482954ee0a91ef12a
Author: lrc <571244399@qq.com>
Date: Sun Jun 14 22:49:28 2026 +0800
init uniWindowController 0.9.8
diff --git a/CHANGELOG.md b/CHANGELOG.md
new file mode 100644
index 0000000..bed3b79
--- /dev/null
+++ b/CHANGELOG.md
@@ -0,0 +1,25 @@
+# Changelog
+All notable changes to this package will be documented in this file.
+
+The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/)
+and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html).
+
+## [0.1.0] - 2026-06-14
+
+### This is the first release of *XUniWindowController*.
+
+*Initial port of UniWindowController as a UPM package.*
+
+#### Added
+- Window transparency (Alpha / ColorKey modes)
+- Click-through support (Opacity / Raycast / Manual hit-test)
+- Topmost / Bottommost z-order control
+- Maximize / Restore window state
+- Borderless window mode
+- Window position and size get/set
+- Multi-monitor window fitting
+- File drag-and-drop support
+- Native file open / save dialogs
+- UI drag-move handle
+- Inspector editor integration with PlayerSettings validation
+- All 5 sample scenes ported as UPM samples
\ No newline at end of file
diff --git a/CHANGELOG.md.meta b/CHANGELOG.md.meta
new file mode 100644
index 0000000..b59fd22
--- /dev/null
+++ b/CHANGELOG.md.meta
@@ -0,0 +1,7 @@
+fileFormatVersion: 2
+guid: 816edf7e62e07ff48b6595a4f95d1903
+TextScriptImporter:
+ externalObjects: {}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Documentation.meta b/Documentation.meta
new file mode 100644
index 0000000..af439d5
--- /dev/null
+++ b/Documentation.meta
@@ -0,0 +1,8 @@
+fileFormatVersion: 2
+guid: 21a499598678f954687f9bb157795380
+folderAsset: yes
+DefaultImporter:
+ externalObjects: {}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Documentation/XUniWindowController.md b/Documentation/XUniWindowController.md
new file mode 100644
index 0000000..85c0452
--- /dev/null
+++ b/Documentation/XUniWindowController.md
@@ -0,0 +1,91 @@
+# XUniWindowController
+
+**XUniWindowController** is a Unity native plugin that provides comprehensive standalone application window control for Windows and macOS builds.
+
+It is a UPM package port of [UniWindowController](https://github.com/kirurobo/UniWindowController) by Kirurobo.
+
+## Usage
+
+Add the `UniWindowController` component to any GameObject in your scene. Access it via:
+
+```csharp
+var winc = UniWindowController.current;
+winc.isTransparent = true;
+winc.isTopmost = true;
+winc.windowSize = new Vector2(1280, 720);
+```
+
+### Properties
+
+| Property | Type | Description |
+|----------|------|-------------|
+| `isTransparent` | `bool` | Enable/disable window transparency |
+| `alphaValue` | `float` | Window opacity (0.0 ~ 1.0) |
+| `isTopmost` | `bool` | Keep window always on top |
+| `isBottommost` | `bool` | Keep window always on bottom |
+| `isZoomed` | `bool` | Maximize/restore window |
+| `isClickThrough` | `bool` | Enable/disable mouse click-through |
+| `windowPosition` | `Vector2Int` | Get/set window position (screen coordinates) |
+| `windowSize` | `Vector2Int` | Get/set window size (pixels) |
+| `clientSize` | `Vector2Int` | Get client area size (read-only) |
+| `allowDropFiles` | `bool` | Enable/disable file drag-and-drop |
+| `hitTestType` | `HitTestType` | Click-through detection mode |
+| `transparentType` | `TransparentType` | Transparency algorithm |
+| `shouldFitMonitor` | `bool` | Fit window to a specific monitor |
+| `monitorToFit` | `int` | Target monitor index |
+
+### Events
+
+| Event | Description |
+|-------|-------------|
+| `OnStateChanged` | Fired when window style, z-order, or size changes |
+| `OnMonitorChanged` | Fired when display configuration changes (resolution, monitor count) |
+| `OnDropFiles` | Fired when files are dragged and dropped onto the window |
+
+## Samples
+
+Import samples via **Package Manager > XUniWindowController > Samples**.
+
+The following samples are included:
+
+- **Menu** — Navigation menu for browsing all sample scenes
+- **SimpleSample** — Minimal setup demonstrating basic window control
+- **UiSample** — Complete UI with toggles, sliders, dropdowns for all window properties
+- **Fullscreen** — Fullscreen mode with right-click context menu and a 3D snowman scene
+- **FileDialog** — Native file open/save dialog integration
+
+## Technical Details
+
+### Windows Architecture
+
+The plugin uses `LibUniWinC.dll` (C++ Win32 DLL) to control window behavior through native Win32 API calls:
+
+- `SetWindowLong` / `GetWindowLong` — Window style modification (borderless, layered, click-through)
+- `SetWindowPos` — Position, size, and Z-order (topmost/bottommost)
+- `DwmExtendFrameIntoClientArea` — DWM alpha transparency
+- `SetLayeredWindowAttributes` — ColorKey transparency mode
+- `SetWindowsHookEx` / custom `WNDPROC` — Window message interception (file drop, display change, resize)
+- `DragAcceptFiles` — File drag-and-drop
+- `GetOpenFileNameW` / `GetSaveFileNameW` — Native file dialogs
+
+### macOS Architecture
+
+The plugin uses `LibUniWinC.bundle` (Swift / Cocoa) to control window behavior through Cocoa APIs:
+
+- `NSWindow.styleMask` — Borderless mode
+- `NSWindow.level` — Z-order (topmost/bottommost)
+- `NSWindow.isOpaque` / `backgroundColor` — Transparency
+- `NSWindow.ignoresMouseEvents` — Click-through
+- `NSDraggingDestination` protocol — File drag-and-drop
+- `NSOpenPanel` / `NSSavePanel` — Native file dialogs
+- `constrainFrameRect` method swizzling — Free window positioning
+- `NotificationCenter` — Window state change observation
+
+### Package Contents
+
+| Location | Description |
+|----------|-------------|
+| `Runtime/Scripts/` | Core C# scripts (UniWindowController, UniWinCore, FilePanel, etc.) |
+| `Runtime/Plugins/` | Native plugin binaries (.dll for Windows, .bundle for macOS) |
+| `Editor/Scripts/` | Editor extensions (Inspector UI, batch build, PlayerSettings validation) |
+| `Samples~/` | Sample scenes and scripts |
\ No newline at end of file
diff --git a/Documentation/XUniWindowController.md.meta b/Documentation/XUniWindowController.md.meta
new file mode 100644
index 0000000..12b4f37
--- /dev/null
+++ b/Documentation/XUniWindowController.md.meta
@@ -0,0 +1,7 @@
+fileFormatVersion: 2
+guid: 1c67695e4c6a6d24f9fcdc3374c61073
+TextScriptImporter:
+ externalObjects: {}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Documentation/images.meta b/Documentation/images.meta
new file mode 100644
index 0000000..944cb9b
--- /dev/null
+++ b/Documentation/images.meta
@@ -0,0 +1,8 @@
+fileFormatVersion: 2
+guid: f7d50d96d22abb249aa89d22ffeceb31
+folderAsset: yes
+DefaultImporter:
+ externalObjects: {}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Documentation/images/example.png b/Documentation/images/example.png
new file mode 100644
index 0000000..216328d
Binary files /dev/null and b/Documentation/images/example.png differ
diff --git a/Documentation/images/example.png.meta b/Documentation/images/example.png.meta
new file mode 100644
index 0000000..e30c998
--- /dev/null
+++ b/Documentation/images/example.png.meta
@@ -0,0 +1,114 @@
+fileFormatVersion: 2
+guid: 77aeb9a6b2955d14cbc743feb1a80851
+TextureImporter:
+ internalIDToNameTable: []
+ externalObjects: {}
+ serializedVersion: 13
+ mipmaps:
+ mipMapMode: 0
+ enableMipMap: 1
+ sRGBTexture: 1
+ linearTexture: 0
+ fadeOut: 0
+ borderMipMap: 0
+ mipMapsPreserveCoverage: 0
+ alphaTestReferenceValue: 0.5
+ mipMapFadeDistanceStart: 1
+ mipMapFadeDistanceEnd: 3
+ bumpmap:
+ convertToNormalMap: 0
+ externalNormalMap: 0
+ heightScale: 0.25
+ normalMapFilter: 0
+ flipGreenChannel: 0
+ isReadable: 0
+ streamingMipmaps: 0
+ streamingMipmapsPriority: 0
+ vTOnly: 0
+ ignoreMipmapLimit: 0
+ grayScaleToAlpha: 0
+ generateCubemap: 6
+ cubemapConvolution: 0
+ seamlessCubemap: 0
+ textureFormat: 1
+ maxTextureSize: 2048
+ textureSettings:
+ serializedVersion: 2
+ filterMode: 1
+ aniso: 1
+ mipBias: 0
+ wrapU: 0
+ wrapV: 0
+ wrapW: 0
+ nPOTScale: 1
+ lightmap: 0
+ compressionQuality: 50
+ spriteMode: 0
+ spriteExtrude: 1
+ spriteMeshType: 1
+ alignment: 0
+ spritePivot: {x: 0.5, y: 0.5}
+ spritePixelsToUnits: 100
+ spriteBorder: {x: 0, y: 0, z: 0, w: 0}
+ spriteGenerateFallbackPhysicsShape: 1
+ alphaUsage: 1
+ alphaIsTransparency: 0
+ spriteTessellationDetail: -1
+ textureType: 0
+ textureShape: 1
+ singleChannelComponent: 0
+ flipbookRows: 1
+ flipbookColumns: 1
+ maxTextureSizeSet: 0
+ compressionQualitySet: 0
+ textureFormatSet: 0
+ ignorePngGamma: 0
+ applyGammaDecoding: 0
+ swizzle: 50462976
+ cookieLightType: 0
+ platformSettings:
+ - serializedVersion: 3
+ buildTarget: DefaultTexturePlatform
+ maxTextureSize: 2048
+ resizeAlgorithm: 0
+ textureFormat: -1
+ textureCompression: 1
+ compressionQuality: 50
+ crunchedCompression: 0
+ allowsAlphaSplitting: 0
+ overridden: 0
+ ignorePlatformSupport: 0
+ androidETC2FallbackOverride: 0
+ forceMaximumCompressionQuality_BC6H_BC7: 0
+ - serializedVersion: 3
+ buildTarget: Standalone
+ maxTextureSize: 2048
+ resizeAlgorithm: 0
+ textureFormat: -1
+ textureCompression: 1
+ compressionQuality: 50
+ crunchedCompression: 0
+ allowsAlphaSplitting: 0
+ overridden: 0
+ ignorePlatformSupport: 0
+ androidETC2FallbackOverride: 0
+ forceMaximumCompressionQuality_BC6H_BC7: 0
+ spriteSheet:
+ serializedVersion: 2
+ sprites: []
+ outline: []
+ physicsShape: []
+ bones: []
+ spriteID:
+ internalID: 0
+ vertices: []
+ indices:
+ edges: []
+ weights: []
+ secondaryTextures: []
+ nameFileIdTable: {}
+ mipmapLimitGroupName:
+ pSDRemoveMatte: 0
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Editor.meta b/Editor.meta
new file mode 100644
index 0000000..353a322
--- /dev/null
+++ b/Editor.meta
@@ -0,0 +1,8 @@
+fileFormatVersion: 2
+guid: e98c5a3fed598e34c9be86e1c42c95a6
+folderAsset: yes
+DefaultImporter:
+ externalObjects: {}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Editor/Lrss3.Xuniwindowcontroller.Editor.asmdef b/Editor/Lrss3.Xuniwindowcontroller.Editor.asmdef
new file mode 100644
index 0000000..1deb423
--- /dev/null
+++ b/Editor/Lrss3.Xuniwindowcontroller.Editor.asmdef
@@ -0,0 +1,10 @@
+{
+ "name": "Lrss3.Xuniwindowcontroller.Editor",
+ "references": [
+ "Lrss3.Xuniwindowcontroller"
+ ],
+ "includePlatforms": [
+ "Editor"
+ ],
+ "excludePlatforms": []
+}
\ No newline at end of file
diff --git a/Editor/Lrss3.Xuniwindowcontroller.Editor.asmdef.meta b/Editor/Lrss3.Xuniwindowcontroller.Editor.asmdef.meta
new file mode 100644
index 0000000..5221d40
--- /dev/null
+++ b/Editor/Lrss3.Xuniwindowcontroller.Editor.asmdef.meta
@@ -0,0 +1,7 @@
+fileFormatVersion: 2
+guid: f2ccb850d779ff749a565c6e5d95eaff
+AssemblyDefinitionImporter:
+ externalObjects: {}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Editor/Scripts.meta b/Editor/Scripts.meta
new file mode 100644
index 0000000..c8dfd14
--- /dev/null
+++ b/Editor/Scripts.meta
@@ -0,0 +1,8 @@
+fileFormatVersion: 2
+guid: 136bc4b3fb1edb04a814503bea6b7ed5
+folderAsset: yes
+DefaultImporter:
+ externalObjects: {}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Editor/Scripts/UniWindowControllerBatch.cs b/Editor/Scripts/UniWindowControllerBatch.cs
new file mode 100644
index 0000000..f6a8de0
--- /dev/null
+++ b/Editor/Scripts/UniWindowControllerBatch.cs
@@ -0,0 +1,67 @@
+using UnityEngine;
+using UnityEditor;
+using UnityEditor.Build;
+using UnityEditor.Build.Reporting;
+// ReSharper disable UnusedMember.Local
+
+namespace Kirurobo
+{
+ class UniWindowControllerBatch
+ {
+ //[MenuItem("Build/Build OSX")]
+ static void PerformBuild()
+ {
+ // コマンドライン引数の最後が出力パスだとする
+ //string outputPath = System.Environment.GetCommandLineArgs().Last();
+
+ // var buildPlayerOptions = new BuildPlayerOptions();
+ // buildPlayerOptions.scenes = sceneList.ToArray();
+ // buildPlayerOptions.locationPathName = outputPath;
+ // buildPlayerOptions.target = BuildTarget.StandaloneOSX;
+ // buildPlayerOptions.options = BuildOptions.None;
+
+ // 事前にエディタから設定したビルド設定を利用
+ var scenes = EditorBuildSettings.scenes;
+ var buildTarget = EditorUserBuildSettings.activeBuildTarget;
+ var locationPath = EditorUserBuildSettings.GetBuildLocation(buildTarget);
+
+ // ビルド対象は環境に合わせて上書き
+#if UNITY_EDITOR_OSX || UNITY_STANDALONE_OSX
+ buildTarget = BuildTarget.StandaloneOSX;
+ locationPath = "Builds/macOS/" + Application.productName;
+#elif UNITY_EDITOR_WIN || UNITY_STANDALONE_WIN
+ buildTarget = BuildTarget.StandaloneWindows64;
+ locationPath = "Builds/Win64/" + Application.productName;
+#endif
+
+ var buildPlayerOptions = new BuildPlayerOptions
+ {
+ scenes = EditorBuildSettingsScene.GetActiveSceneList(scenes),
+ locationPathName = locationPath,
+ target = buildTarget,
+ options = BuildOptions.None
+ };
+
+ // // 内容チェック用
+ // foreach (var scene in buildPlayerOptions.scenes)
+ // {
+ // Debug.Log(scene);
+ // }
+ // Debug.Log(buildPlayerOptions.locationPathName);
+ // return;
+
+ var report = BuildPipeline.BuildPlayer(buildPlayerOptions);
+ var summary = report.summary;
+
+ if (summary.result == BuildResult.Succeeded)
+ {
+ Debug.Log("构建成功");
+ } else if (summary.result == BuildResult.Failed)
+ {
+ Debug.Log("构建失败");
+ //EditorApplication.Exit(1);
+ throw new BuildFailedException(report.summary.ToString());
+ }
+ }
+ }
+}
diff --git a/Editor/Scripts/UniWindowControllerBatch.cs.meta b/Editor/Scripts/UniWindowControllerBatch.cs.meta
new file mode 100644
index 0000000..004cd05
--- /dev/null
+++ b/Editor/Scripts/UniWindowControllerBatch.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: 9aa8110448ede05409f3ce652b3ad2d1
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Editor/Scripts/UniWindowControllerEditor.cs b/Editor/Scripts/UniWindowControllerEditor.cs
new file mode 100644
index 0000000..af9d339
--- /dev/null
+++ b/Editor/Scripts/UniWindowControllerEditor.cs
@@ -0,0 +1,591 @@
+/*
+ * UniWindowControllerEditor.cs
+ *
+ * Author: Kirurobo http://x.com/kirurobo
+ * License: MIT
+ */
+
+// Assembry Definition を有効にしてから、ビルド時に Editor クラスがないとエラーが出る。
+// そこで丸ごと UNITY_EDITOR が無い場合は無視するものとした
+#if UNITY_EDITOR
+
+using System.Linq;
+using UnityEngine;
+using UnityEditor;
+using System.Reflection;
+using UnityEngine.Rendering;
+
+namespace Kirurobo
+{
+ ///
+ /// UniWindowControllerのためのエディタカスタマイズ部分
+ ///
+ [CustomEditor(typeof(UniWindowController))]
+ public class UniWindowControllerEditor : Editor
+ {
+ ///
+ /// カーソル下の色を表示するためのプロパティ
+ ///
+ SerializedProperty pickedColor;
+
+ ///
+ /// ゲームビューのウィンドウ
+ ///
+ private EditorWindow gameViewWindow;
+
+ ///
+ /// プロジェクト設定に関する警告を閉じておくか
+ private bool isWarningDismissed = false;
+
+ ///
+ /// URP に関する警告を閉じておくか
+ ///
+ private bool isUrpWarningDismissed = true;
+
+ ///
+ /// URP が有効かどうか
+ ///
+ private bool hasUrp = false;
+
+ void OnEnable()
+ {
+ LoadSettings();
+
+ pickedColor = serializedObject.FindProperty("pickedColor");
+
+ // URP が有効か否かを判定
+ hasUrp = GetUrpSettings();
+ }
+
+ void OnDisable()
+ {
+ SaveSettings();
+ }
+
+ ///
+ /// URPが有効か否かを検出
+ ///
+ ///
+ private bool GetUrpSettings()
+ {
+ var renderPipelineAsset = GraphicsSettings.defaultRenderPipeline;
+ if (renderPipelineAsset == null || renderPipelineAsset.GetType().Name != "UniversalRenderPipelineAsset")
+ {
+ // URP が設定されていない
+ return false;
+ }
+ return true;
+ }
+
+ private void LoadSettings()
+ {
+ isWarningDismissed = EditorUserSettings.GetConfigValue("WindowController_IS_WARNING DISMISSED") == "1";
+ }
+
+ private void SaveSettings()
+ {
+ EditorUserSettings.SetConfigValue("WindowController_IS_WARNING DISMISSED", isWarningDismissed ? "1" : "0");
+ }
+
+ ///
+ /// インスペクタでの表示をカスタマイズ
+ ///
+ ///
+ /// 参考情報および、推奨設定の変更欄を表示します。
+ ///
+ public override void OnInspectorGUI()
+ {
+ base.OnInspectorGUI();
+
+ // カーソル下の色が得られていれば、その透明度を参考として表示
+ if (pickedColor != null)
+ {
+ EditorGUI.BeginDisabledGroup(true);
+ EditorGUILayout.LabelField("选取的Alpha值", pickedColor.colorValue.a.ToString("P0"));
+ EditorGUI.EndDisabledGroup();
+ }
+
+ // Project Settings の推奨設定を表示
+ isWarningDismissed = ShowPlayerSettingsValidation(isWarningDismissed);
+
+ // URP 関連の推奨設定を表示
+ isUrpWarningDismissed = ShowUrpSettingsValidation(isUrpWarningDismissed);
+ }
+
+ ///
+ /// Project Settings に関する推奨設定の自動設定欄を表示
+ ///
+ private bool ShowPlayerSettingsValidation(bool dismissed) {
+ // 以下は Project Settings 関連
+ EditorGUILayout.Space();
+
+ bool enableValidation = EditorGUILayout.Foldout(!dismissed, "播放器设置验证");
+
+ // チェックするかどうかを記憶
+ if (enableValidation == dismissed)
+ {
+ dismissed = !enableValidation;
+ }
+
+ // 推奨設定のチェック
+ //if (!isWarningDismissed)
+ if (enableValidation)
+ {
+ if (ValidateSettings(false))
+ {
+ // 应用所有推荐设置
+ GUI.backgroundColor = Color.green;
+ if (GUILayout.Button(
+ "✔ 将所有设置修复为推荐值",
+ GUILayout.MinHeight(25f)
+ ))
+ {
+ ValidateSettings(true);
+ }
+
+ // 关闭验证
+ GUI.backgroundColor = Color.yellow;
+ if (GUILayout.Button(
+ "✘ 关闭此验证",
+ GUILayout.MinHeight(25f)
+ ))
+ {
+ dismissed = true;
+
+ //SaveSettings(); // 如果需要立即保存,取消注释
+ }
+
+ EditorGUILayout.Space();
+ }
+ else
+ {
+ GUI.color = Color.green;
+ GUILayout.Label("OK!");
+ }
+
+ // 打开播放器设置页面
+ EditorGUILayout.BeginHorizontal();
+ GUILayout.FlexibleSpace();
+ GUI.color = Color.white;
+ GUI.backgroundColor = Color.white;
+ if (GUILayout.Button(
+ "打开播放器设置",
+ GUILayout.MinHeight(25f), GUILayout.Width(200f)
+ ))
+ {
+ SettingsService.OpenProjectSettings("Project/Player");
+ }
+ GUILayout.FlexibleSpace();
+ EditorGUILayout.EndHorizontal();
+
+ EditorGUILayout.Space();
+ }
+ return dismissed;
+ }
+
+ ///
+ /// URP に関する推奨設定の自動設定欄を表示
+ ///
+ private bool ShowUrpSettingsValidation(bool dismissed) {
+ // URP が無効ならば何もしない
+ if (!hasUrp) return dismissed;
+
+ // 以下は URP 関連の自動設定
+ EditorGUILayout.Space();
+
+ bool enableValidation = EditorGUILayout.Foldout(!dismissed, "URP 设置验证");
+ // チェックするかどうかを記憶
+ if (enableValidation == dismissed)
+ {
+ dismissed = !enableValidation;
+ }
+ // 推奨設定のチェック
+ //if (!isWarningDismissed)
+ if (enableValidation)
+ {
+ if (ValidateUrpSettings(false))
+ {
+ // 应用所有推荐设置
+ GUI.backgroundColor = Color.green;
+ if (GUILayout.Button(
+ "✔ 将所有设置修复为推荐值",
+ GUILayout.MinHeight(25f)
+ ))
+ {
+ ValidateUrpSettings(true);
+ }
+
+ // 关闭验证
+ GUI.backgroundColor = Color.yellow;
+ if (GUILayout.Button(
+ "✘ 关闭此验证",
+ GUILayout.MinHeight(25f)
+ ))
+ {
+ dismissed = true;
+ }
+
+ EditorGUILayout.Space();
+ }
+ else
+ {
+ GUI.color = Color.green;
+ GUILayout.Label("OK!");
+ }
+
+ EditorGUILayout.Space();
+ }
+ return dismissed;
+ }
+
+ private delegate void FixMethod();
+
+ ///
+ /// 显示或修复设置
+ ///
+ /// 警告消息
+ /// 修复操作
+ /// false: 显示警告和修复按钮, true: 静默修复
+ private void FixSetting(string message, FixMethod fixAction, bool silentFix = false)
+
+ {
+ if (silentFix)
+ {
+ // 修复
+ fixAction.Invoke();
+ }
+ else
+ {
+ // 显示消息和修复按钮
+ EditorGUILayout.BeginHorizontal();
+ EditorGUILayout.HelpBox(message, MessageType.Warning, true);
+ GUILayout.FlexibleSpace();
+
+ EditorGUILayout.BeginVertical();
+ EditorGUILayout.Space();
+ if (GUILayout.Button("修复", GUILayout.Width(60f))) { fixAction.Invoke(); }
+ //GUILayout.FlexibleSpace();
+ EditorGUILayout.EndVertical();
+
+ EditorGUILayout.EndHorizontal();
+ }
+ }
+
+ ///
+ /// 仅显示建议
+ ///
+ /// 警告消息
+ private void ShowInfo(string message, Object target = null)
+
+ {
+ // 显示消息和定位按钮
+ EditorGUILayout.BeginHorizontal();
+ EditorGUILayout.HelpBox(message, MessageType.Info, true);
+ GUILayout.FlexibleSpace();
+
+ // 自動設定できない対象は、プロジェクトウィンドウで示すのみ
+ if (target != null)
+ {
+ EditorGUILayout.BeginVertical();
+ EditorGUILayout.Space();
+ if (GUILayout.Button("定位", GUILayout.Width(60f))) { EditorGUIUtility.PingObject(target); }
+ //GUILayout.FlexibleSpace();
+ EditorGUILayout.EndVertical();
+ }
+
+ EditorGUILayout.EndHorizontal();
+ }
+
+ ///
+ /// 验证播放器设置
+ ///
+ /// false: 显示警告和修复按钮, true: 静默修复
+ /// 如果有无效项则返回 true
+ private bool ValidateSettings(bool silentFix = false)
+ {
+ bool invalid = false;
+
+ // バックグラウンドでも実行する。クリックスルー切替などで必要
+ if (!PlayerSettings.runInBackground)
+ {
+ invalid = true;
+ FixSetting(
+ "强烈建议启用'后台运行'。",
+ () => PlayerSettings.runInBackground = true,
+ silentFix
+ );
+ }
+
+ // サイズ変更可能なウィンドウとする。必須ではないがウィンドウ枠無効時にサイズも変わるので変更可能である方が自然
+ if (!PlayerSettings.resizableWindow)
+ {
+ invalid = true;
+ FixSetting(
+ "建议启用'可调整窗口大小'。",
+ () => PlayerSettings.resizableWindow = true,
+ silentFix
+ );
+ }
+
+ // フルスクリーンでなくウィンドウとする
+#if UNITY_2018_1_OR_NEWER
+ // Unity 2018 からはフルスクリーン指定の仕様が変わった
+ if (PlayerSettings.fullScreenMode != FullScreenMode.Windowed)
+ {
+ invalid = true;
+ FixSetting(
+ "在'全屏模式'中选择'窗口化'。",
+ () => PlayerSettings.fullScreenMode = FullScreenMode.Windowed,
+ silentFix
+ );
+
+ }
+#else
+ if (PlayerSettings.defaultIsFullScreen)
+ {
+ invalid = true;
+ FixSetting(
+ "不建议启用'默认全屏'。",
+ () => PlayerSettings.defaultIsFullScreen = false,
+ silentFix
+ );
+ }
+#endif
+
+ // フルスクリーンとウィンドウの切替を無効とする
+ if (PlayerSettings.allowFullscreenSwitch)
+ {
+ invalid = true;
+ FixSetting(
+ "禁止全屏切换。",
+ () => PlayerSettings.allowFullscreenSwitch = false,
+ silentFix
+ );
+ }
+
+ // Windowsでは Use DXGI Flip Mode Swapchain を無効にしないと透過できない
+ // ↓Unity 2019.1.6未満だと useFlipModelSwapchain は無いはず
+ // なので除外のため書き連ねてあるが、ここまでサポートしなくて良い気もする。
+#if UNITY_2019_1_6
+#elif UNITY_2019_1_5
+#elif UNITY_2019_1_4
+#elif UNITY_2019_1_3
+#elif UNITY_2019_1_2
+#elif UNITY_2019_1_1
+#elif UNITY_2019_1_0
+#elif UNITY_2019_1_OR_NEWER
+ // Unity 2019.1.7 以降であれば、Player 設定 の Use DXGI Flip... 無効化を推奨
+ if (PlayerSettings.useFlipModelSwapchain)
+ {
+ invalid = true;
+ FixSetting(
+ "禁用'使用 DXGI 翻转模式交换链'以使窗口透明。",
+ () => PlayerSettings.useFlipModelSwapchain = false,
+ silentFix
+ );
+ }
+
+ // Direct3D12 は透過ウィンドウに対応していないので、Graphics APIs for Windows から除外することを推奨
+ if (PlayerSettings.GetUseDefaultGraphicsAPIs(BuildTarget.StandaloneWindows))
+ {
+ // 自動の場合も警告を出す
+ ShowInfo(
+ "Direct3D12 不支持透明窗口。" +
+ "请考虑在播放器设置中使用 Direct3D11 替代'自动图形 API for Windows'设置。",
+ null
+ );
+ }
+ else if (PlayerSettings.GetGraphicsAPIs(BuildTarget.StandaloneWindows).Contains(GraphicsDeviceType.Direct3D12))
+ {
+ // Graphhics APIs for Windows に Direct3D12 が含まれている場合は警告を出す
+ ShowInfo(
+ "Direct3D12 不支持透明窗口。" +
+ "请从播放器设置的'图形 API for Windows'中移除 Direct3D12。",
+ null
+ );
+ }
+#endif
+
+ return invalid;
+ }
+
+ ///
+ /// 验证播放器设置
+ ///
+ /// false: 显示警告和修复按钮, true: 静默修复
+ /// 如果有无效项则返回 true
+ private bool ValidateUrpSettings(bool silentFix = false)
+ {
+ bool invalid = false;
+
+ // Universal Render Pipelineが有効ならば、HDRの無効化を推奨
+ foreach (var cam in Camera.allCameras)
+ {
+ if (cam.allowHDR) {
+ string name = cam.name;
+ invalid = true;
+ FixSetting(
+ $"{name}:禁用摄像机中的'HDR'以使窗口透明。",
+ () => cam.allowHDR = false,
+ silentFix
+ );
+ }
+ if (cam.allowMSAA) {
+ string name = cam.name;
+ invalid = true;
+ FixSetting(
+ $"{name}:禁用摄像机中的'MSAA'以使窗口透明。",
+ () => cam.allowMSAA = false,
+ silentFix
+ );
+ }
+ }
+
+ var urpAsset = GraphicsSettings.defaultRenderPipeline;
+ if (hasUrp && urpAsset != null)
+ {
+ // hasUrp == true の時点で urpAsset は UniversalRenderPipelineAsset であるはず。そのため allowPostProcessAlphaOutput があるはず
+ var alphaProcessingProperty = urpAsset.GetType().GetProperty("allowPostProcessAlphaOutput", BindingFlags.Public | BindingFlags.Instance);
+ if (alphaProcessingProperty != null)
+ {
+ var alphaProcessing = alphaProcessingProperty.GetValue(urpAsset);
+ if (!(bool)alphaProcessing)
+ {
+ invalid = true;
+ ShowInfo(
+ "在 URP 资源中启用'Alpha 处理'",
+ urpAsset
+ );
+ }
+ }
+ }
+
+ return invalid;
+ }
+ }
+
+
+ [CustomPropertyDrawer(typeof(ReadOnlyAttribute))]
+ public class UniWindowControllerReadOnlyDrawer : PropertyDrawer
+ {
+ public override void OnGUI(Rect position, SerializedProperty property, GUIContent label)
+ {
+ GUI.enabled = false;
+ EditorGUI.PropertyField(position, property, label, true);
+ GUI.enabled = true;
+ }
+ }
+
+ ///
+ /// 设置布尔属性为可编辑
+ /// 参考: http://ponkotsu-hiyorin.hateblo.jp/entry/2015/10/20/003042
+ /// 参考: https://forum.unity.com/threads/c-class-property-with-reflection-in-propertydrawer-not-saving-to-prefab.473942/
+ ///
+ [CustomPropertyDrawer(typeof(EditablePropertyAttribute))]
+ public class UniWindowControllerDrawer : PropertyDrawer
+ {
+ public override void OnGUI(Rect position, SerializedProperty property, GUIContent label)
+ {
+ //base.OnGUI(position, property, label);
+
+ Object obj = property.serializedObject.targetObject;
+
+ // Range(min, max) が設定されていれば取得
+ FieldInfo fieldInfo = obj.GetType().GetField(
+ property.name,
+ BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance | BindingFlags.Static
+ );
+ var rangeAttrs = fieldInfo?.GetCustomAttributes(typeof(RangeAttribute), true) as RangeAttribute[];
+ RangeAttribute range = (rangeAttrs?.Length > 0 ? rangeAttrs.First() : null);
+
+ if (EditorApplication.isPlayingOrWillChangePlaymode)
+ {
+ // 変数の先頭が '_' であることが動作の条件
+ if (property.name[0] == '_')
+ {
+ string propertyName = property.name.Substring(1); // '_' なしをプロパティ名として取得
+ PropertyInfo info = obj.GetType().GetProperty(propertyName);
+ MethodInfo getMethod = default(MethodInfo);
+ MethodInfo setMethod = default(MethodInfo);
+ if (info.CanRead) { getMethod = info.GetGetMethod(); }
+ if (info.CanWrite) { setMethod = info.GetSetMethod(); }
+
+ if (property.type == "bool")
+ { var oldValue = property.boolValue;
+ if (getMethod != null)
+ {
+ oldValue = (bool)getMethod.Invoke(obj, null);
+ }
+ GUI.enabled = (setMethod != null);
+ EditorGUI.PropertyField(position, property, label, true);
+ GUI.enabled = true;
+ var newValue = property.boolValue;
+ if ((setMethod != null) && (oldValue != newValue))
+ {
+ setMethod.Invoke(obj, new[] { (object)newValue });
+ }
+ }
+ else if (property.type == "float")
+ {
+
+ var oldValue = property.floatValue;
+ if (getMethod != null)
+ {
+ oldValue = (float) getMethod.Invoke(obj, null);
+ }
+
+ GUI.enabled = (setMethod != null);
+ if (range != null)
+ {
+ EditorGUI.Slider(position, property, range.min, range.max, label);
+ }
+ else
+ {
+ EditorGUI.PropertyField(position, property, label, true);
+ }
+ GUI.enabled = true;
+
+ var newValue = property.floatValue;
+ if ((setMethod != null) && (oldValue != newValue))
+ {
+ setMethod.Invoke(obj, new[] {(object) newValue});
+ }
+ }
+ else
+ {
+ // bool, float 以外は今のところ非対応で Readonly とする
+ GUI.enabled = false;
+ EditorGUI.PropertyField(position, property, label, true);
+ GUI.enabled = true;
+ }
+ }
+ else
+ {
+ // 只读
+ GUI.enabled = false;
+ EditorGUI.PropertyField(position, property, label, true);
+ GUI.enabled = true;
+ }
+ }
+ else
+ {
+ // Range 指定があればスライダー
+ if (range != null)
+ {
+ EditorGUI.Slider(position, property, range.min, range.max, label);
+ }
+ else
+ {
+ EditorGUI.PropertyField(position, property, label, true);
+ }
+ }
+
+ }
+
+ public override float GetPropertyHeight(SerializedProperty property, GUIContent label)
+ {
+ return EditorGUI.GetPropertyHeight(property, label, true);
+ }
+ }
+}
+#endif
\ No newline at end of file
diff --git a/Editor/Scripts/UniWindowControllerEditor.cs.meta b/Editor/Scripts/UniWindowControllerEditor.cs.meta
new file mode 100644
index 0000000..b739b4e
--- /dev/null
+++ b/Editor/Scripts/UniWindowControllerEditor.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: 4132cf6e84b9d6e4488bce4df8f1bb67
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..e2b8e27
--- /dev/null
+++ b/README.md
@@ -0,0 +1,86 @@
+# XUniWindowController
+
+**XUniWindowController** is a Unity native plugin that provides comprehensive **standalone application window control** for Windows and macOS builds.
+
+It allows you to control window transparency, click-through, topmost/bottommost z-order, maximize, file drop, native file dialogs, and multi-monitor window fitting — all from C# scripts through a simple Unity component.
+
+## Features
+
+- **Window Transparency** — Alpha blending or ColorKey-based transparency
+- **Click-Through** — Make the window ignore mouse events
+- **Z-Order Control** — Set window topmost, bottommost, or normal
+- **Maximize / Restore** — Themed maximize and restore
+- **Borderless Mode** — Hide the title bar and border
+- **Window Position & Size** — Get/set window position and size
+- **Multi-Monitor Support** — Fit window to any connected display
+- **File Drop** — Receive file paths from drag-and-drop
+- **Native File Dialogs** — Open and save file dialogs (Windows/macOS native)
+- **Drag Move** — Drag the window by any UI element
+
+## Requirements
+
+- Unity 2022.3 or later
+- Windows or macOS standalone build target
+
+## Installation
+
+### Via Package Manager
+
+1. Open **Window > Package Manager**
+2. Click the **+** button > **Add package from git URL**
+3. Enter the repository URL
+
+### Via disk (local package)
+
+1. Copy the `com.lrss3.xuniwindowcontroller` folder to your project's `Packages/` directory
+2. Package Manager will automatically pick it up
+
+## Getting Started
+
+1. Add a **UniWindowController** component to any GameObject in your scene (or use the prefab from samples)
+2. Configure the Inspector properties:
+ - **Is Transparent** — Enable window transparency
+ - **Is Topmost** — Keep window on top
+ - **Hit Test Type** — Choose opacity-based or raycast-based click-through detection
+3. Call methods or toggle properties at runtime:
+
+```csharp
+var winc = UniWindowController.current;
+winc.isTransparent = true; // Enable transparency
+winc.isTopmost = true; // Keep on top
+winc.isClickThrough = false; // Disable click-through
+```
+
+## Samples
+
+The package includes 5 sample scenes:
+
+| Sample | Description |
+|--------|-------------|
+| **Menu** | Navigation menu for browsing all samples |
+| **SimpleSample** | Minimal window control setup |
+| **UiSample** | Full UI with toggles, sliders, dropdowns for all features |
+| **Fullscreen** | Fullscreen mode + right-click context menu + 3D scene |
+| **FileDialog** | Native open/save file dialog demonstration |
+
+Import samples via **Package Manager > XUniWindowController > Samples**.
+
+## How It Works
+
+On **Windows**, the plugin uses `LibUniWinC.dll` (C++ Win32 API) to call:
+- `SetWindowLong` — modify window styles
+- `SetWindowPos` — control z-order and position
+- `DwmExtendFrameIntoClientArea` — DWM transparency
+- `SetLayeredWindowAttributes` — layered window transparency
+- `DragAcceptFiles` / window subclassing — file drop handling
+
+On **macOS**, the plugin uses `LibUniWinC.bundle` (Swift / Cocoa) to call:
+- `NSWindow.styleMask` — borderless mode
+- `NSWindow.level` — z-order control
+- `NSWindow.isOpaque` / `backgroundColor` — transparency
+- `NSDraggingDestination` protocol — file drop
+- `NSOpenPanel` / `NSSavePanel` — native dialogs
+
+## License
+
+This package is based on [UniWindowController](https://github.com/kirurobo/UniWindowController) by Kirurobo, licensed under the MIT License.
\ No newline at end of file
diff --git a/README.md.meta b/README.md.meta
new file mode 100644
index 0000000..9bcb797
--- /dev/null
+++ b/README.md.meta
@@ -0,0 +1,7 @@
+fileFormatVersion: 2
+guid: 288347fd9d4e9a2488d0b8cc74fb4da2
+TextScriptImporter:
+ externalObjects: {}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Runtime.meta b/Runtime.meta
new file mode 100644
index 0000000..9d13265
--- /dev/null
+++ b/Runtime.meta
@@ -0,0 +1,8 @@
+fileFormatVersion: 2
+guid: f24a9f4fa29049144bf79a526b2bb586
+folderAsset: yes
+DefaultImporter:
+ externalObjects: {}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Runtime/Lrss3.Xuniwindowcontroller.asmdef b/Runtime/Lrss3.Xuniwindowcontroller.asmdef
new file mode 100644
index 0000000..ae3efa5
--- /dev/null
+++ b/Runtime/Lrss3.Xuniwindowcontroller.asmdef
@@ -0,0 +1,6 @@
+{
+ "name": "Lrss3.Xuniwindowcontroller",
+ "references": [],
+ "includePlatforms": [],
+ "excludePlatforms": []
+}
\ No newline at end of file
diff --git a/Runtime/Lrss3.Xuniwindowcontroller.asmdef.meta b/Runtime/Lrss3.Xuniwindowcontroller.asmdef.meta
new file mode 100644
index 0000000..7ca3670
--- /dev/null
+++ b/Runtime/Lrss3.Xuniwindowcontroller.asmdef.meta
@@ -0,0 +1,7 @@
+fileFormatVersion: 2
+guid: 4df3d67771614d24192762dbffd67d98
+AssemblyDefinitionImporter:
+ externalObjects: {}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Runtime/Plugins.meta b/Runtime/Plugins.meta
new file mode 100644
index 0000000..5f41354
--- /dev/null
+++ b/Runtime/Plugins.meta
@@ -0,0 +1,8 @@
+fileFormatVersion: 2
+guid: b9161ad40887a5746afa1d4eb780f60a
+folderAsset: yes
+DefaultImporter:
+ externalObjects: {}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Runtime/Plugins/MacOS.meta b/Runtime/Plugins/MacOS.meta
new file mode 100644
index 0000000..640da9b
--- /dev/null
+++ b/Runtime/Plugins/MacOS.meta
@@ -0,0 +1,8 @@
+fileFormatVersion: 2
+guid: 186ab6f8e4a960342b3bac311f6b2eb5
+folderAsset: yes
+DefaultImporter:
+ externalObjects: {}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Runtime/Plugins/MacOS/LibUniWinC.bundle.meta b/Runtime/Plugins/MacOS/LibUniWinC.bundle.meta
new file mode 100644
index 0000000..4c5a432
--- /dev/null
+++ b/Runtime/Plugins/MacOS/LibUniWinC.bundle.meta
@@ -0,0 +1,33 @@
+fileFormatVersion: 2
+guid: 04ad9f4fa34d2ed43a2c2a2b15c9959e
+PluginImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ iconMap: {}
+ executionOrder: {}
+ defineConstraints: []
+ isPreloaded: 0
+ isOverridable: 1
+ isExplicitlyReferenced: 0
+ validateReferences: 1
+ platformData:
+ - first:
+ Any:
+ second:
+ enabled: 0
+ settings: {}
+ - first:
+ Editor: Editor
+ second:
+ enabled: 1
+ settings:
+ DefaultValueInitialized: true
+ - first:
+ Standalone: OSXUniversal
+ second:
+ enabled: 1
+ settings:
+ CPU: AnyCPU
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Runtime/Plugins/MacOS/LibUniWinC.bundle/Contents/Info.plist b/Runtime/Plugins/MacOS/LibUniWinC.bundle/Contents/Info.plist
new file mode 100644
index 0000000..04de770
--- /dev/null
+++ b/Runtime/Plugins/MacOS/LibUniWinC.bundle/Contents/Info.plist
@@ -0,0 +1,48 @@
+
+
+
+
+ BuildMachineOSBuild
+ 25C56
+ CFBundleDevelopmentRegion
+ en
+ CFBundleExecutable
+ LibUniWinC
+ CFBundleIdentifier
+ com.kirurobo.LibUniWinC
+ CFBundleInfoDictionaryVersion
+ 6.0
+ CFBundleName
+ LibUniWinC
+ CFBundlePackageType
+ BNDL
+ CFBundleShortVersionString
+ 0.9.8
+ CFBundleSupportedPlatforms
+
+ MacOSX
+
+ CFBundleVersion
+ 1
+ DTCompiler
+ com.apple.compilers.llvm.clang.1_0
+ DTPlatformBuild
+ 25B74
+ DTPlatformName
+ macosx
+ DTPlatformVersion
+ 26.1
+ DTSDKBuild
+ 25B74
+ DTSDKName
+ macosx26.1
+ DTXcode
+ 2610
+ DTXcodeBuild
+ 17B55
+ LSMinimumSystemVersion
+ 11.0
+ NSHumanReadableCopyright
+ Copyright © 2019-2025 kirurobo. All rights reserved.
+
+
diff --git a/Runtime/Plugins/MacOS/LibUniWinC.bundle/Contents/MacOS/LibUniWinC b/Runtime/Plugins/MacOS/LibUniWinC.bundle/Contents/MacOS/LibUniWinC
new file mode 100644
index 0000000..ac4603e
Binary files /dev/null and b/Runtime/Plugins/MacOS/LibUniWinC.bundle/Contents/MacOS/LibUniWinC differ
diff --git a/Runtime/Plugins/Windows.meta b/Runtime/Plugins/Windows.meta
new file mode 100644
index 0000000..4ce064f
--- /dev/null
+++ b/Runtime/Plugins/Windows.meta
@@ -0,0 +1,8 @@
+fileFormatVersion: 2
+guid: 5d40a6da1308b51499d69d09998a1672
+folderAsset: yes
+DefaultImporter:
+ externalObjects: {}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Runtime/Plugins/Windows/x64.meta b/Runtime/Plugins/Windows/x64.meta
new file mode 100644
index 0000000..f41eb0d
--- /dev/null
+++ b/Runtime/Plugins/Windows/x64.meta
@@ -0,0 +1,8 @@
+fileFormatVersion: 2
+guid: 52438bdad5ba3524daae6d7c7050491e
+folderAsset: yes
+DefaultImporter:
+ externalObjects: {}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Runtime/Plugins/Windows/x64/LibUniWinC.dll b/Runtime/Plugins/Windows/x64/LibUniWinC.dll
new file mode 100644
index 0000000..fa8b8f5
Binary files /dev/null and b/Runtime/Plugins/Windows/x64/LibUniWinC.dll differ
diff --git a/Runtime/Plugins/Windows/x64/LibUniWinC.dll.meta b/Runtime/Plugins/Windows/x64/LibUniWinC.dll.meta
new file mode 100644
index 0000000..07d0511
--- /dev/null
+++ b/Runtime/Plugins/Windows/x64/LibUniWinC.dll.meta
@@ -0,0 +1,27 @@
+fileFormatVersion: 2
+guid: 2587e857c903c7648bb243f26d8388c5
+PluginImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ iconMap: {}
+ executionOrder: {}
+ defineConstraints: []
+ isPreloaded: 0
+ isOverridable: 1
+ isExplicitlyReferenced: 0
+ validateReferences: 1
+ platformData:
+ - first:
+ Any:
+ second:
+ enabled: 1
+ settings: {}
+ - first:
+ Editor: Editor
+ second:
+ enabled: 0
+ settings:
+ DefaultValueInitialized: true
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Runtime/Plugins/Windows/x86.meta b/Runtime/Plugins/Windows/x86.meta
new file mode 100644
index 0000000..8d1deeb
--- /dev/null
+++ b/Runtime/Plugins/Windows/x86.meta
@@ -0,0 +1,8 @@
+fileFormatVersion: 2
+guid: 1afe0de787d9c9b419c0083741340611
+folderAsset: yes
+DefaultImporter:
+ externalObjects: {}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Runtime/Plugins/Windows/x86/LibUniWinC.dll b/Runtime/Plugins/Windows/x86/LibUniWinC.dll
new file mode 100644
index 0000000..94773aa
Binary files /dev/null and b/Runtime/Plugins/Windows/x86/LibUniWinC.dll differ
diff --git a/Runtime/Plugins/Windows/x86/LibUniWinC.dll.meta b/Runtime/Plugins/Windows/x86/LibUniWinC.dll.meta
new file mode 100644
index 0000000..ace3bae
--- /dev/null
+++ b/Runtime/Plugins/Windows/x86/LibUniWinC.dll.meta
@@ -0,0 +1,27 @@
+fileFormatVersion: 2
+guid: 94d4ed4ccee04184c93f70e00c6f442c
+PluginImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ iconMap: {}
+ executionOrder: {}
+ defineConstraints: []
+ isPreloaded: 0
+ isOverridable: 1
+ isExplicitlyReferenced: 0
+ validateReferences: 1
+ platformData:
+ - first:
+ Any:
+ second:
+ enabled: 1
+ settings: {}
+ - first:
+ Editor: Editor
+ second:
+ enabled: 0
+ settings:
+ DefaultValueInitialized: true
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Runtime/Scripts.meta b/Runtime/Scripts.meta
new file mode 100644
index 0000000..553df4f
--- /dev/null
+++ b/Runtime/Scripts.meta
@@ -0,0 +1,8 @@
+fileFormatVersion: 2
+guid: 5807c8581d7c4be4ca838592a3a5ce8e
+folderAsset: yes
+DefaultImporter:
+ externalObjects: {}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Runtime/Scripts/LowLevel.meta b/Runtime/Scripts/LowLevel.meta
new file mode 100644
index 0000000..b9f6de3
--- /dev/null
+++ b/Runtime/Scripts/LowLevel.meta
@@ -0,0 +1,8 @@
+fileFormatVersion: 2
+guid: 4ecd974a2286b994b8432ec73c8e5bd2
+folderAsset: yes
+DefaultImporter:
+ externalObjects: {}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Runtime/Scripts/LowLevel/FilePanel.cs b/Runtime/Scripts/LowLevel/FilePanel.cs
new file mode 100644
index 0000000..dfd827c
--- /dev/null
+++ b/Runtime/Scripts/LowLevel/FilePanel.cs
@@ -0,0 +1,209 @@
+using AOT;
+using System;
+using System.Runtime.InteropServices;
+using System.Text;
+
+namespace Kirurobo
+{
+ ///
+ /// 提供打开原生文件对话框的静态方法
+ ///
+ public class FilePanel
+ {
+ protected class LibUniWinC
+ {
+ [DllImport("LibUniWinC", CharSet = CharSet.Unicode)]
+ [return: MarshalAs(UnmanagedType.Bool)]
+ public static extern bool OpenFilePanel(in PanelSettings settings, [MarshalAs(UnmanagedType.LPWStr), Out] StringBuilder buffer, UInt32 bufferSize);
+
+ [DllImport("LibUniWinC", CharSet = CharSet.Unicode)]
+ [return: MarshalAs(UnmanagedType.Bool)]
+ public static extern bool OpenSavePanel(in PanelSettings settings, [MarshalAs(UnmanagedType.LPWStr), Out] StringBuilder buffer, UInt32 bufferSize);
+
+
+ [StructLayout(LayoutKind.Sequential, Pack = 1)]
+ public struct PanelSettings : IDisposable {
+ public Int32 structSize;
+ public Int32 flags;
+ public IntPtr lpszTitle;
+ public IntPtr lpszFilter;
+ public IntPtr lpszInitialFile;
+ public IntPtr lpszInitialDir;
+ public IntPtr lpszDefaultExt;
+
+ public PanelSettings(Settings settings)
+ {
+ this.structSize = 0;
+ //this.structSize = 4 * 2 + Marshal.SizeOf() * 3;
+ this.flags = (Int32)settings.flags;
+
+ //this.lpTitleText = IntPtr.Zero;
+ //this.lpFilterText = IntPtr.Zero;
+ //this.lpDefaultPath = IntPtr.Zero;
+ this.lpszTitle = Marshal.StringToHGlobalUni(settings.title);
+ this.lpszFilter = Marshal.StringToHGlobalUni(Filter.Join(settings.filters));
+ this.lpszInitialFile = Marshal.StringToHGlobalUni(settings.initialFile);
+ this.lpszInitialDir = Marshal.StringToHGlobalUni(settings.initialDirectory);
+ //this.lpszDefaultExt = Marshal.StringToHGlobalUni(settings.defaultExtension);
+ this.lpszDefaultExt = IntPtr.Zero;
+
+ //this.structSize = Marshal.SizeOf(this);
+ this.structSize = Marshal.SizeOf(this);
+ }
+
+ public void Dispose()
+ {
+ if (this.lpszTitle != IntPtr.Zero)
+ {
+ Marshal.FreeHGlobal(lpszTitle);
+ this.lpszTitle = IntPtr.Zero;
+ }
+
+ if (this.lpszFilter!= IntPtr.Zero)
+ {
+ Marshal.FreeHGlobal(lpszFilter);
+ this.lpszFilter= IntPtr.Zero;
+ }
+
+ if (this.lpszInitialFile!= IntPtr.Zero)
+ {
+ Marshal.FreeHGlobal(lpszInitialFile);
+ this.lpszInitialFile= IntPtr.Zero;
+ }
+
+ if (this.lpszInitialDir != IntPtr.Zero)
+ {
+ Marshal.FreeHGlobal(lpszInitialDir);
+ this.lpszInitialDir = IntPtr.Zero;
+ }
+
+ if (this.lpszDefaultExt != IntPtr.Zero)
+ {
+ Marshal.FreeHGlobal(lpszDefaultExt);
+ this.lpszDefaultExt = IntPtr.Zero;
+ }
+ }
+ }
+
+ }
+
+ ///
+ /// 对话框的设置标志
+ ///
+ [Flags]
+ public enum Flag
+ {
+ None = 0,
+ FileMustExist = 1, // 仅 Windows
+ FolderMustExist = 2, // 仅 Windows
+ AllowMultipleSelection = 4,
+ CanCreateDirectories = 16,
+ OverwritePrompt = 256, // macOS 上始终启用
+ CreatePrompt = 512, // macOS 上始终启用
+ ShowHiddenFiles = 4096,
+ RetrieveLink = 8192,
+ }
+
+ ///
+ /// 文件对话框的参数
+ ///
+ public struct Settings
+ {
+ public string title;
+ public Filter[] filters;
+ public string initialDirectory;
+ public string initialFile;
+ public string defaultExtension; // 未实现
+ public Flag flags;
+ }
+
+ ///
+ /// 文件过滤器
+ ///
+ public class Filter
+ {
+ protected string title;
+ protected string[] extensions;
+
+ ///
+ ///
+ ///
+ /// 过滤器标题(macOS 上暂不可用)
+ /// 扩展名数组,如 ["png", "jpg", "txt"]
+ public Filter(string title, params string[] extensions)
+ {
+ this.title = title;
+ this.extensions = extensions;
+ }
+
+ public override string ToString()
+ {
+ return title + "\t" + String.Join("\t", extensions);
+ }
+
+ ///
+ /// 返回由 Filter 数组转换后的字符串
+ ///
+ ///
+ ///
+ public static string Join(Filter[] filters)
+ {
+ if (filters == null) return "";
+
+ string result = "";
+ bool isFirstItem = true;
+ foreach (var filter in filters) {
+ if (!isFirstItem) result += "\n";
+ result += filter.ToString();
+ isFirstItem = false;
+ }
+ return result;
+ }
+ }
+
+ ///
+ /// 用于传递文件或文件夹路径的 UTF-16 缓冲区字符数
+ /// 因为多个路径以换行符分隔,260 字符不够用。
+ ///
+ private const int pathBufferSize = 2560;
+
+
+ ///
+ /// 打开文件选择对话框
+ ///
+ ///
+ ///
+ public static void OpenFilePanel(Settings settings, Action action)
+ {
+ LibUniWinC.PanelSettings ps = new LibUniWinC.PanelSettings(settings);
+ StringBuilder sb = new StringBuilder(pathBufferSize);
+
+ if (LibUniWinC.OpenFilePanel(in ps, sb, (uint)sb.Capacity))
+ {
+ string[] files = UniWinCore.parsePaths(sb.ToString());
+ action.Invoke(files);
+ }
+
+ ps.Dispose(); // 通过传入 Settings 的构造函数分配了内存,因此需要释放
+ }
+
+ ///
+ /// 打开保存文件选择对话框
+ ///
+ ///
+ ///
+ public static void SaveFilePanel(Settings settings, Action action)
+ {
+ LibUniWinC.PanelSettings ps = new LibUniWinC.PanelSettings(settings);
+ StringBuilder sb = new StringBuilder(pathBufferSize);
+
+ if (LibUniWinC.OpenSavePanel(in ps, sb, (uint)sb.Capacity))
+ {
+ string[] files = UniWinCore.parsePaths(sb.ToString());
+ action.Invoke(files);
+ }
+
+ ps.Dispose(); // 通过传入 Settings 的构造函数分配了内存,因此需要释放
+ }
+ }
+}
diff --git a/Runtime/Scripts/LowLevel/FilePanel.cs.meta b/Runtime/Scripts/LowLevel/FilePanel.cs.meta
new file mode 100644
index 0000000..7795525
--- /dev/null
+++ b/Runtime/Scripts/LowLevel/FilePanel.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: ade63dbb28ba23c40bfc1795ae2b605c
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Runtime/Scripts/LowLevel/UniWinCore.cs b/Runtime/Scripts/LowLevel/UniWinCore.cs
new file mode 100644
index 0000000..eda3a42
--- /dev/null
+++ b/Runtime/Scripts/LowLevel/UniWinCore.cs
@@ -0,0 +1,926 @@
+/*
+ * UniWinCore.cs
+ *
+ * Author: Kirurobo http://twitter.com/kirurobo
+ * License: MIT 许可证
+ */
+
+using System;
+using System.Runtime.InteropServices;
+using AOT;
+using UnityEngine;
+using System.Text;
+#if UNITY_EDITOR
+using UnityEditor;
+#endif
+
+namespace Kirurobo
+{
+ ///
+ /// LibUniWinC 的原生插件包装
+ ///
+ internal class UniWinCore : IDisposable
+ {
+ ///
+ /// 仅 Windows 下的透明方法类型
+ ///
+ public enum TransparentType : int
+ {
+ None = 0,
+ Alpha = 1,
+ ColorKey = 2,
+ }
+
+
+ ///
+ /// 状态变更事件类型(实验性)
+ ///
+ [Flags]
+ public enum WindowStateEventType : int
+ {
+ None = 0,
+ StyleChanged = 1,
+ Resized = 2,
+
+ // 后续规格可能会有变更
+ TopMostEnabled = 16 + 1 + 8,
+ TopMostDisabled = 16 + 1,
+ BottomMostEnabled = 32 + 1 + 8,
+ BottomMostDisabled = 32 + 1,
+ WallpaperModeEnabled = 64 + 1 + 8,
+ WallpaperModeDisabled = 64 + 1,
+ };
+
+ #region Native functions
+ protected class LibUniWinC
+ {
+ [UnmanagedFunctionPointer(CallingConvention.Winapi)]
+ public delegate void StringCallback([MarshalAs(UnmanagedType.LPWStr)] string returnString);
+
+ [UnmanagedFunctionPointer((CallingConvention.Winapi))]
+ public delegate void IntCallback([MarshalAs(UnmanagedType.I4)] int value);
+
+
+ [DllImport("LibUniWinC",CallingConvention=CallingConvention.Winapi)]
+ [return: MarshalAs(UnmanagedType.Bool)]
+ public static extern bool IsActive();
+
+ [DllImport("LibUniWinC",CallingConvention=CallingConvention.Winapi)]
+ [return: MarshalAs(UnmanagedType.Bool)]
+ public static extern bool IsTransparent();
+
+ [DllImport("LibUniWinC",CallingConvention=CallingConvention.Winapi)]
+ [return: MarshalAs(UnmanagedType.Bool)]
+ public static extern bool IsBorderless();
+
+ [DllImport("LibUniWinC",CallingConvention=CallingConvention.Winapi)]
+ [return: MarshalAs(UnmanagedType.Bool)]
+ public static extern bool IsTopmost();
+
+ [DllImport("LibUniWinC",CallingConvention=CallingConvention.Winapi)]
+ [return: MarshalAs(UnmanagedType.Bool)]
+ public static extern bool IsBottommost();
+
+ [DllImport("LibUniWinC", CallingConvention=CallingConvention.Winapi)]
+ [return: MarshalAs(UnmanagedType.Bool)]
+ public static extern bool IsMaximized();
+
+ [DllImport("LibUniWinC", CallingConvention=CallingConvention.Winapi)]
+ [return: MarshalAs(UnmanagedType.Bool)]
+ public static extern bool IsFreePositioningEnabled();
+
+ [DllImport("LibUniWinC",CallingConvention=CallingConvention.Winapi)]
+ [return: MarshalAs(UnmanagedType.Bool)]
+ public static extern bool AttachMyWindow();
+
+ [DllImport("LibUniWinC",CallingConvention=CallingConvention.Winapi)]
+ [return: MarshalAs(UnmanagedType.Bool)]
+ public static extern bool AttachMyOwnerWindow();
+
+ [DllImport("LibUniWinC",CallingConvention=CallingConvention.Winapi)]
+ [return: MarshalAs(UnmanagedType.Bool)]
+ public static extern bool AttachMyActiveWindow();
+
+ [DllImport("LibUniWinC",CallingConvention=CallingConvention.Winapi)]
+ [return: MarshalAs(UnmanagedType.Bool)]
+ public static extern bool DetachWindow();
+
+ [DllImport("LibUniWinC",CallingConvention=CallingConvention.Winapi)]
+ public static extern void Update();
+
+ [DllImport("LibUniWinC",CallingConvention=CallingConvention.Winapi)]
+ public static extern void SetTransparent([MarshalAs(UnmanagedType.U1)] bool bEnabled);
+
+ [DllImport("LibUniWinC",CallingConvention=CallingConvention.Winapi)]
+ public static extern void SetBorderless([MarshalAs(UnmanagedType.U1)] bool bEnabled);
+
+ [DllImport("LibUniWinC",CallingConvention=CallingConvention.Winapi)]
+ public static extern void SetAlphaValue(float alpha);
+
+ [DllImport("LibUniWinC",CallingConvention=CallingConvention.Winapi)]
+ public static extern void SetClickThrough([MarshalAs(UnmanagedType.U1)] bool bEnabled);
+
+ [DllImport("LibUniWinC",CallingConvention=CallingConvention.Winapi)]
+ public static extern void SetTopmost([MarshalAs(UnmanagedType.U1)] bool bEnabled);
+
+ [DllImport("LibUniWinC",CallingConvention=CallingConvention.Winapi)]
+ public static extern void SetBottommost([MarshalAs(UnmanagedType.U1)] bool bEnabled);
+
+ [DllImport("LibUniWinC", CallingConvention = CallingConvention.Winapi)]
+ public static extern void SetMaximized([MarshalAs(UnmanagedType.U1)] bool bZoomed);
+
+ [DllImport("LibUniWinC", CallingConvention = CallingConvention.Winapi)]
+ public static extern void EnableFreePositioning([MarshalAs(UnmanagedType.U1)] bool bEnabled);
+
+ [DllImport("LibUniWinC",CallingConvention=CallingConvention.Winapi)]
+ public static extern void SetPosition(float x, float y);
+
+ [DllImport("LibUniWinC",CallingConvention=CallingConvention.Winapi)]
+ [return: MarshalAs(UnmanagedType.Bool)]
+ public static extern bool GetPosition(out float x, out float y);
+
+ [DllImport("LibUniWinC",CallingConvention=CallingConvention.Winapi)]
+ public static extern void SetSize(float x, float y);
+
+ [DllImport("LibUniWinC",CallingConvention=CallingConvention.Winapi)]
+ [return: MarshalAs(UnmanagedType.Bool)]
+ public static extern bool GetSize(out float x, out float y);
+
+ [DllImport("LibUniWinC",CallingConvention=CallingConvention.Winapi)]
+ [return: MarshalAs(UnmanagedType.Bool)]
+ public static extern bool GetClientSize(out float width, out float height);
+
+ [DllImport("LibUniWinC",CallingConvention=CallingConvention.Winapi)]
+ [return: MarshalAs(UnmanagedType.Bool)]
+ public static extern bool GetClientRectangle(out float x, out float y, out float width, out float height);
+
+ [DllImport("LibUniWinC",CallingConvention=CallingConvention.Winapi)]
+ [return: MarshalAs(UnmanagedType.Bool)]
+ public static extern bool RegisterDropFilesCallback([MarshalAs(UnmanagedType.FunctionPtr)] StringCallback callback);
+
+ [DllImport("LibUniWinC",CallingConvention=CallingConvention.Winapi)]
+ [return: MarshalAs(UnmanagedType.Bool)]
+ public static extern bool UnregisterDropFilesCallback();
+
+ [DllImport("LibUniWinC",CallingConvention=CallingConvention.Winapi)]
+ [return: MarshalAs(UnmanagedType.Bool)]
+ public static extern bool RegisterMonitorChangedCallback([MarshalAs(UnmanagedType.FunctionPtr)] IntCallback callback);
+
+ [DllImport("LibUniWinC",CallingConvention=CallingConvention.Winapi)]
+ [return: MarshalAs(UnmanagedType.Bool)]
+ public static extern bool UnregisterMonitorChangedCallback();
+
+ [DllImport("LibUniWinC",CallingConvention=CallingConvention.Winapi)]
+ [return: MarshalAs(UnmanagedType.Bool)]
+ public static extern bool RegisterWindowStyleChangedCallback([MarshalAs(UnmanagedType.FunctionPtr)] IntCallback callback);
+
+ [DllImport("LibUniWinC",CallingConvention=CallingConvention.Winapi)]
+ [return: MarshalAs(UnmanagedType.Bool)]
+ public static extern bool UnregisterWindowStyleChangedCallback();
+
+ [DllImport("LibUniWinC",CallingConvention=CallingConvention.Winapi)]
+ [return: MarshalAs(UnmanagedType.Bool)]
+ public static extern bool SetAllowDrop([MarshalAs(UnmanagedType.U1)] bool enabled);
+
+ [DllImport("LibUniWinC",CallingConvention=CallingConvention.Winapi)]
+ public static extern int GetCurrentMonitor();
+
+ [DllImport("LibUniWinC",CallingConvention=CallingConvention.Winapi)]
+ public static extern int GetMonitorCount();
+
+ [DllImport("LibUniWinC",CallingConvention=CallingConvention.Winapi)]
+ [return: MarshalAs(UnmanagedType.Bool)]
+ public static extern bool GetMonitorRectangle(int index, out float x, out float y, out float width, out float height);
+
+ [DllImport("LibUniWinC",CallingConvention=CallingConvention.Winapi)]
+ public static extern void SetCursorPosition(float x, float y);
+
+ [DllImport("LibUniWinC",CallingConvention=CallingConvention.Winapi)]
+ [return: MarshalAs(UnmanagedType.Bool)]
+ public static extern bool GetCursorPosition(out float x, out float y);
+
+ [DllImport("LibUniWinC",CallingConvention=CallingConvention.Winapi)]
+ public static extern int GetMouseButtons();
+
+ [DllImport("LibUniWinC",CallingConvention=CallingConvention.Winapi)]
+ public static extern int GetModifierKeys();
+
+
+ #region 仅适用于 Windows
+ [DllImport("LibUniWinC",CallingConvention=CallingConvention.Winapi)]
+ public static extern void SetTransparentType(int type);
+
+ [DllImport("LibUniWinC",CallingConvention=CallingConvention.Winapi)]
+ public static extern void SetKeyColor(uint colorref);
+
+ [DllImport("LibUniWinC",CallingConvention=CallingConvention.Winapi)]
+ public static extern int GetDebugInfo();
+
+ [DllImport("LibUniWinC",CallingConvention=CallingConvention.Winapi)]
+ [return: MarshalAs(UnmanagedType.Bool)]
+ public static extern bool AttachWindowHandle(IntPtr hWnd);
+ #endregion
+ }
+ #endregion
+
+ static string[] lastDroppedFiles;
+ static bool wasDropped = false;
+ static bool wasMonitorChanged = false;
+ static bool wasWindowStyleChanged = false;
+ static WindowStateEventType windowStateEventType = WindowStateEventType.None;
+
+#if UNITY_EDITOR
+ ///
+ /// 获取 Unity 编辑器窗口
+ ///
+ ///
+ ///
+ public static EditorWindow GetGameView()
+ {
+ var assembly = typeof(EditorWindow).Assembly;
+ var type = assembly.GetType("UnityEditor.GameView");
+ var gameView = EditorWindow.GetWindow(type);
+ return gameView;
+ }
+#endif
+
+ ///
+ /// 判断窗口是否已附加且可用
+ ///
+ /// true 如果此实例处于活动状态;否则为 false。
+ public bool IsActive { get; private set; } = false;
+
+ ///
+ /// 判断附加窗口是否始终置顶
+ ///
+ public bool IsTopmost { get { return (IsActive && _isTopmost); } }
+ private bool _isTopmost = false;
+
+ ///
+ /// 判断附加窗口是否始终置底
+ ///
+ public bool IsBottommost { get { return (IsActive && _isBottommost); } }
+ private bool _isBottommost = false;
+
+ ///
+ /// 判断附加窗口是否透明
+ ///
+ public bool IsTransparent { get { return (IsActive && _isTransparent); } }
+ private bool _isTransparent = false;
+
+ ///
+ /// 判断附加窗口是否点击穿透(即不接收任何鼠标操作)
+ ///
+ public bool IsClickThrough { get { return (IsActive && _isClickThrough); } }
+ private bool _isClickThrough = false;
+
+ ///
+ /// 判断附加窗口是否无边框(无标题栏和边框)
+ ///
+ public bool IsBorderless { get { return (IsActive && _isBorderless); } }
+ private bool _isBorderless = false;
+
+ ///
+ /// 判断附加窗口是否可以自由定位(仅 macOS)
+ ///
+ public bool IsFreePositioningEnabled { get { return (IsActive && _isFreePositioningEnabled); } }
+ private bool _isFreePositioningEnabled = false;
+
+ ///
+ /// Windows 下的透明方法类型
+ ///
+ private TransparentType transparentType = TransparentType.Alpha;
+
+ ///
+ /// 当 transparentType 为 ColorKey 时用于透明的颜色
+ ///
+ private Color32 keyColor = new Color32(1, 0, 1, 0);
+
+
+ #region Constructor or destructor
+ ///
+ /// 窗口控制构造函数
+ ///
+ public UniWinCore()
+ {
+ IsActive = false;
+ }
+
+ ///
+ /// 析构函数
+ ///
+ ~UniWinCore()
+ {
+ Dispose();
+ }
+
+ ///
+ /// 结束时的处理
+ ///
+ public void Dispose()
+ {
+ // 由于最后恢复窗口状态会引起注意,所以特意不恢复,因此注释掉
+ //DetachWindow();
+
+ // 替代 DetachWindow()
+ LibUniWinC.UnregisterDropFilesCallback();
+ LibUniWinC.UnregisterMonitorChangedCallback();
+ LibUniWinC.UnregisterWindowStyleChangedCallback();
+ }
+ #endregion
+
+
+ #region Callbacks
+
+ ///
+ /// 显示器或分辨率变化时的回调
+ /// 此处的处理保持最低限度,仅设置标志
+ ///
+ ///
+ [MonoPInvokeCallback(typeof(LibUniWinC.IntCallback))]
+ private static void _monitorChangedCallback([MarshalAs(UnmanagedType.I4)] int monitorCount)
+ {
+ wasMonitorChanged = true;
+ }
+
+ ///
+ /// 窗口样式、最大化、最小化等调用的回调
+ /// 此处的处理保持最低限度,仅设置标志
+ ///
+ ///
+ [MonoPInvokeCallback(typeof(LibUniWinC.IntCallback))]
+ private static void _windowStyleChangedCallback([MarshalAs(UnmanagedType.I4)] int e)
+ {
+ wasWindowStyleChanged = true;
+ windowStateEventType = (WindowStateEventType)e;
+ }
+
+ ///
+ /// ファイル、フォルダがドロップされた時に呼ばれるコールバック
+ /// 文字列を配列に直すことと、フラグを立てるまで行う
+ ///
+ ///
+ [MonoPInvokeCallback(typeof(LibUniWinC.StringCallback))]
+ private static void _dropFilesCallback([MarshalAs(UnmanagedType.LPWStr)] string paths)
+ {
+ // 将以 LF 分隔的字符串分割为路径数组
+ //char[] delimiters = { '\n', '\0' };
+ //string[] files = paths.Split(delimiters).Where(s => s != "").ToArray();
+ string[] files = parsePaths(paths);
+
+ if (files.Length > 0)
+ {
+ lastDroppedFiles = new string[files.Length];
+ files.CopyTo(lastDroppedFiles, 0);
+
+ wasDropped = true;
+ }
+ }
+
+ ///
+ /// 将双引号包围、LF(或null)分隔的字符串转换为数组并返回
+ ///
+ ///
+ ///
+ internal static string[] parsePaths(string text)
+ {
+ System.Collections.Generic.List list = new System.Collections.Generic.List();
+ bool inEscaped = false;
+ int len = text.Length;
+ StringBuilder sb = new StringBuilder();
+ for (int i = 0; i < len; i++)
+ {
+ char c = text[i];
+ if (c == '"')
+ {
+ if (inEscaped)
+ {
+ if (((i + 1) < len) && text[i + 1] == '"')
+ {
+ i++;
+ sb.Append(c); // 连续双引号视为一个双引号
+ continue;
+ }
+ }
+ inEscaped = !inEscaped; // 非连续则切换是否在引号内
+ }
+ else if (c == '\n')
+ {
+ if (inEscaped)
+ {
+ // 如果在引号内,则作为路径的一部分
+ sb.Append(c);
+ }
+ else
+ {
+ // 如果不在引号内,则作为分隔符,移到下一个路径
+ if (sb.Length > 0)
+ {
+ list.Add(sb.ToString());
+ //sb.Clear(); // for .NET 4 or later
+ sb.Length = 0; // for .NET 2
+ }
+ }
+ }
+ else if (c == '\0')
+ {
+ // 空字符始终作为分隔符,移到下一个路径
+ if (sb.Length > 0)
+ {
+ list.Add(sb.ToString());
+ //sb.Clear(); // for .NET 4 or later
+ sb.Length = 0; // for .NET 2
+ }
+ }
+ else
+ {
+ sb.Append(c);
+ }
+ }
+ if (sb.Length > 0)
+ {
+ list.Add(sb.ToString());
+ }
+
+ // 移除空字符串元素
+ list.RemoveAll(v => v.Length == 0);
+ return list.ToArray();
+ }
+
+ #endregion
+
+ #region Find, attach or detach
+
+ ///
+ /// 将窗口状态恢复至最初并从操作对象中解除
+ ///
+ public void DetachWindow()
+ {
+#if UNITY_EDITOR
+ // エディタの場合、ウィンドウスタイルでは常に最前面と得られていない可能性があるため、
+ // 最前面ではないのが本来と決め打ちで、デタッチ時無効化する
+ EnableTopmost(false);
+#endif
+ LibUniWinC.DetachWindow();
+ }
+
+ ///
+ /// 查找自己的窗口(如果游戏视图是独立窗口则查找它)并作为操作对象
+ ///
+ ///
+ public bool AttachMyWindow()
+ {
+#if UNITY_EDITOR_WIN
+ // 似乎没有可靠的方法获取游戏视图,因此给予焦点后立即获取活动窗口
+ var gameView = GetGameView();
+ if (gameView)
+ {
+ gameView.Focus();
+ LibUniWinC.AttachMyActiveWindow();
+ }
+#else
+ LibUniWinC.AttachMyWindow();
+#endif
+ // 添加事件处理程序
+ LibUniWinC.RegisterDropFilesCallback(_dropFilesCallback);
+ LibUniWinC.RegisterMonitorChangedCallback(_monitorChangedCallback);
+ LibUniWinC.RegisterWindowStyleChangedCallback(_windowStyleChangedCallback);
+
+ IsActive = LibUniWinC.IsActive();
+ return IsActive;
+ }
+
+ public bool AttachWindowHandle(IntPtr hWnd)
+ {
+ LibUniWinC.AttachWindowHandle(hWnd);
+ IsActive = LibUniWinC.IsActive();
+ return IsActive;
+ }
+
+ ///
+ /// 选择自己进程中当前活动的窗口
+ /// 编辑器情况下,窗口会关闭或停靠,因此在聚焦时调用
+ ///
+ ///
+ public bool AttachMyActiveWindow()
+ {
+ LibUniWinC.AttachMyActiveWindow();
+ IsActive = LibUniWinC.IsActive();
+ return IsActive;
+ }
+
+ #endregion
+
+ #region About window status
+ ///
+ /// 定期调用以维持窗口样式
+ ///
+ public void Update()
+ {
+ LibUniWinC.Update();
+ }
+
+ string GetDebubgWindowSizeInfo()
+ {
+ float x, y, cx, cy;
+ LibUniWinC.GetSize(out x, out y);
+ LibUniWinC.GetClientSize(out cx, out cy);
+ return $"W:{x},H:{y} CW:{cx},CH:{cy}";
+ }
+
+ ///
+ /// 设置/取消透明
+ ///
+ ///
+ public void EnableTransparent(bool isTransparent)
+ {
+ // 编辑器无法透明或边框与正常不同,因此跳过
+#if !UNITY_EDITOR
+ LibUniWinC.SetTransparent(isTransparent);
+ LibUniWinC.SetBorderless(isTransparent);
+#endif
+ this._isTransparent = isTransparent;
+ }
+
+ ///
+ /// 设置窗口透明度
+ ///
+ /// 0.0 - 1.0
+ public void SetAlphaValue(float alpha)
+ {
+ // Windows 编辑器下,一旦半透明化后显示不会更新,因此禁用。Mac 则没问题
+#if !UNITY_EDITOR_WIN
+ LibUniWinC.SetAlphaValue(alpha);
+#endif
+ }
+
+ ///
+ /// 设置窗口 Z 顺序(是否置顶)。
+ ///
+ /// 如果设为 true 则置顶。
+ public void EnableTopmost(bool isTopmost)
+ {
+ LibUniWinC.SetTopmost(isTopmost);
+ this._isTopmost = isTopmost;
+ this._isBottommost = false; // 互斥
+ }
+
+ ///
+ /// 设置窗口 Z 顺序(是否置底)。
+ ///
+ /// 如果设为 true 则置底。
+ public void EnableBottommost(bool isBottommost)
+ {
+ LibUniWinC.SetBottommost(isBottommost);
+ this._isBottommost = isBottommost;
+ this._isTopmost = false; // 互斥
+ }
+
+ ///
+ /// 设置/取消点击穿透
+ ///
+ ///
+ public void EnableClickThrough(bool isThrough)
+ {
+ // 编辑器下点击穿透可能导致无法操作,因此跳过
+#if !UNITY_EDITOR
+ LibUniWinC.SetClickThrough(isThrough);
+#endif
+ this._isClickThrough = isThrough;
+ }
+
+ ///
+ /// 最大化窗口(Mac 上为缩放)
+ /// 最大化后可能还会调整大小,目前可能无法可靠工作
+ ///
+ public void SetZoomed(bool isZoomed)
+ {
+ LibUniWinC.SetMaximized(isZoomed);
+ }
+
+ ///
+ /// 获取窗口是否已最大化(Mac 上为缩放)
+ /// 最大化后可能还会调整大小,目前可能无法可靠工作
+ ///
+ public bool GetZoomed()
+ {
+ return LibUniWinC.IsMaximized();
+ }
+
+ ///
+ /// 设置窗口位置。
+ ///
+ /// 位置。
+ public void SetWindowPosition(Vector2 position)
+ {
+ LibUniWinC.SetPosition(position.x, position.y);
+ }
+
+ ///
+ /// 获取窗口位置。
+ ///
+ /// 位置。
+ public Vector2 GetWindowPosition()
+ {
+ Vector2 pos = Vector2.zero;
+ LibUniWinC.GetPosition(out pos.x, out pos.y);
+ return pos;
+ }
+
+ ///
+ /// 设置窗口大小。
+ ///
+ /// x 为宽度,y 为高度
+ public void SetWindowSize(Vector2 size)
+ {
+ LibUniWinC.SetSize(size.x, size.y);
+ }
+
+ ///
+ /// 获取窗口大小。
+ ///
+ /// x 为宽度,y 为高度
+ public Vector2 GetWindowSize()
+ {
+ Vector2 size = Vector2.zero;
+ LibUniWinC.GetSize(out size.x, out size.y);
+ return size;
+ }
+
+ ///
+ /// 获取客户区大小。
+ ///
+ /// x 为宽度,y 为高度
+ public Vector2 GetClientSize()
+ {
+ Vector2 size = Vector2.zero;
+ LibUniWinC.GetClientSize(out size.x, out size.y);
+ return size;
+ }
+
+ ///
+ /// 获取客户区矩形。
+ ///
+ /// x 为宽度,y 为高度
+ public Rect GetClientRectangle()
+ {
+ Vector2 pos = Vector2.zero;
+ Vector2 size = Vector2.zero;
+ LibUniWinC.GetClientRectangle(out pos.x, out pos.y, out size.x, out size.y);
+ return new Rect(pos.x, pos.y, size.x, size.y);
+ }
+
+#endregion
+
+ #region File opening
+ public void SetAllowDrop(bool enabled)
+ {
+ LibUniWinC.SetAllowDrop(enabled);
+ }
+
+#endregion
+
+#region Event observers
+
+ ///
+ /// 检查文件拖放并取消拖放标志
+ ///
+ ///
+ /// 如果文件被拖放则返回 true
+ public bool ObserveDroppedFiles(out string[] files)
+ {
+ files = lastDroppedFiles;
+
+ if (!wasDropped || files == null) return false;
+
+ wasDropped = false;
+ return true;
+ }
+
+ ///
+ /// 检查显示器数量或分辨率变化,并取消标志
+ ///
+ /// 如果已变化则返回 true
+ public bool ObserveMonitorChanged()
+ {
+ if (!wasMonitorChanged) return false;
+
+ wasMonitorChanged = false;
+ return true;
+ }
+
+ ///
+ /// 检查窗口样式是否已变更,并取消标志
+ ///
+ /// 如果窗口样式已变更则返回 true
+ public bool ObserveWindowStyleChanged()
+ {
+ if (!wasWindowStyleChanged) return false;
+
+ windowStateEventType = WindowStateEventType.None;
+ wasWindowStyleChanged = false;
+ return true;
+ }
+
+ ///
+ /// 检查窗口样式是否已变更,并取消标志
+ ///
+ /// 如果窗口样式已变更则返回 true
+ public bool ObserveWindowStyleChanged(out WindowStateEventType type)
+ {
+ if (!wasWindowStyleChanged)
+ {
+ type = WindowStateEventType.None;
+ return false;
+ }
+
+ type = windowStateEventType;
+ windowStateEventType = WindowStateEventType.None;
+ wasWindowStyleChanged = false;
+ return true;
+ }
+
+#endregion
+
+#region About mouse cursor
+ ///
+ /// 设置鼠标指针位置。
+ ///
+ /// 位置。
+ public static void SetCursorPosition(Vector2 position)
+ {
+ LibUniWinC.SetCursorPosition(position.x, position.y);
+ }
+
+ ///
+ /// 获取鼠标指针位置。
+ ///
+ /// 位置。
+ public static Vector2 GetCursorPosition()
+ {
+ Vector2 pos = Vector2.zero;
+ LibUniWinC.GetCursorPosition(out pos.x, out pos.y);
+ return pos;
+ }
+
+ ///
+ /// Get pressed mouse buttons.
+ ///
+ /// Bit flags of pressed buttons
+ public static int GetMouseButtons()
+ {
+ return LibUniWinC.GetMouseButtons();
+ }
+
+ ///
+ /// 获取按下的修饰键。
+ ///
+ /// 按下键的位标志
+ public static int GetModifierKeys()
+ {
+ return LibUniWinC.GetModifierKeys();
+ }
+
+ // 未实现
+ public static bool GetCursorVisible()
+ {
+ return true;
+ }
+#endregion
+
+#region for Windows only
+ ///
+ /// 指定透明方法(仅 Windows 支持)
+ ///
+ ///
+ public void SetTransparentType(TransparentType type)
+ {
+ LibUniWinC.SetTransparentType((Int32)type);
+ transparentType = type;
+ }
+
+ ///
+ /// 单色透明时指定透明色(仅 Windows 支持)
+ ///
+ ///
+ public void SetKeyColor(Color32 color)
+ {
+ LibUniWinC.SetKeyColor((UInt32)(color.b * 0x10000 + color.g * 0x100 + color.r));
+ keyColor = color;
+ }
+ #endregion
+
+ #region for macOS only
+ ///
+ /// 设置/取消窗口的自由配置(仅 macOS 支持)
+ ///
+ ///
+ public void EnableFreePositioning(bool enabled)
+ {
+ LibUniWinC.EnableFreePositioning(enabled);
+ _isFreePositioningEnabled = LibUniWinC.IsFreePositioningEnabled();
+ }
+ #endregion
+
+ #region About monitors
+ ///
+ /// 获取窗口所在显示器的索引
+ ///
+ /// 显示器索引
+ public int GetCurrentMonitor()
+ {
+ return LibUniWinC.GetCurrentMonitor();
+ }
+
+ ///
+ /// 获取已连接显示器的数量
+ ///
+ /// 数量
+ public static int GetMonitorCount()
+ {
+ return LibUniWinC.GetMonitorCount();
+ }
+
+ ///
+ /// 获取显示器的位置和大小
+ ///
+ ///
+ ///
+ ///
+ ///
+ public static bool GetMonitorRectangle(int index, out Vector2 position, out Vector2 size)
+ {
+ return LibUniWinC.GetMonitorRectangle(index, out position.x, out position.y, out size.x, out size.y);
+ }
+
+ ///
+ /// 将窗口适配到指定显示器
+ ///
+ ///
+ ///
+ public bool FitToMonitor(int monitorIndex)
+ {
+ float dx, dy, dw, dh;
+ if (LibUniWinC.GetMonitorRectangle(monitorIndex, out dx, out dy, out dw, out dh))
+ {
+ // 如果处于最大化状态则先恢复
+ if (LibUniWinC.IsMaximized()) LibUniWinC.SetMaximized(false);
+
+ // 指定显示器的中心坐标
+ float cx = dx + (dw / 2);
+ float cy = dy + (dh / 2);
+
+ // 将窗口中心移动到指定显示器中心
+ float ww, wh;
+ LibUniWinC.GetSize(out ww, out wh);
+ float wx = cx - (ww / 2);
+ float wy = cy - (wh / 2);
+ LibUniWinC.SetPosition(wx, wy);
+
+ // 最大化
+ LibUniWinC.SetMaximized(true);
+
+ //Debug.Log(String.Format("显示器 {4} : {0},{1} - {2},{3}", dx, dy, dw, dh, monitorIndex));
+ return true;
+ }
+ return false;
+ }
+
+ ///
+ /// 打印显示器列表
+ ///
+ [Obsolete]
+ public static void DebugMonitorInfo()
+ {
+ int monitors = LibUniWinC.GetMonitorCount();
+
+ int currentMonitorIndex = LibUniWinC.GetCurrentMonitor();
+
+ string message = "当前显示器: " + currentMonitorIndex + "\r\n";
+
+ for (int i = 0; i < monitors; i++)
+ {
+ float x, y, w, h;
+ bool result = LibUniWinC.GetMonitorRectangle(i, out x, out y, out w, out h);
+ message += String.Format(
+ "显示器 {0}: X:{1}, Y:{2} - W:{3}, H:{4}\r\n",
+ i, x, y, w, h
+ );
+ }
+ Debug.Log(message);
+ }
+
+
+ ///
+ /// 获取用于调试的信息
+ ///
+ ///
+ [Obsolete]
+ public static int GetDebugInfo()
+ {
+ return LibUniWinC.GetDebugInfo();
+ }
+#endregion
+
+ }
+}
\ No newline at end of file
diff --git a/Runtime/Scripts/LowLevel/UniWinCore.cs.meta b/Runtime/Scripts/LowLevel/UniWinCore.cs.meta
new file mode 100644
index 0000000..486b78f
--- /dev/null
+++ b/Runtime/Scripts/LowLevel/UniWinCore.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: 4930552cf3596b040954b14d8b7c47e6
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Runtime/Scripts/UniWindowController.cs b/Runtime/Scripts/UniWindowController.cs
new file mode 100644
index 0000000..51da8fa
--- /dev/null
+++ b/Runtime/Scripts/UniWindowController.cs
@@ -0,0 +1,1227 @@
+/*
+ * UniWindowController.cs
+ *
+ * Author: Kirurobo http://twitter.com/kirurobo
+ * License: MIT
+ */
+
+using System;
+using System.Collections;
+using System.Collections.Generic;
+using UnityEngine;
+using UnityEngine.EventSystems;
+#if UNITY_EDITOR
+using UnityEditor;
+using System.Reflection;
+using UnityEngine.Events;
+using System.Linq;
+
+#endif
+#if ENABLE_INPUT_SYSTEM
+using UnityEngine.InputSystem;
+#endif
+
+namespace Kirurobo
+{
+ /// @cond DOXYGEN_SHOW_INTERNAL_CLASSES
+
+ ///
+ /// 使布尔属性可编辑
+ ///
+ [System.AttributeUsage(System.AttributeTargets.Field, Inherited = true, AllowMultiple = false)]
+ public class EditablePropertyAttribute : UnityEngine.PropertyAttribute { }
+
+ ///
+ /// 将属性设置为只读
+ ///
+ [System.AttributeUsage(System.AttributeTargets.Field, Inherited = true, AllowMultiple = false)]
+ public class ReadOnlyAttribute : UnityEngine.PropertyAttribute { }
+
+ /// @endcond
+
+
+ ///
+ /// Windows/Mac 统一窗口控制器
+ ///
+ public class UniWindowController : MonoBehaviour
+ {
+ ///
+ /// 与 UniWinCore.TransparentType 相同
+ ///
+ public enum TransparentType : int
+ {
+ None = 0,
+ Alpha = 1,
+ ColorKey = 2,
+ }
+
+ ///
+ /// 指定点击测试方法(即切换点击穿透)
+ ///
+ public enum HitTestType : int
+ {
+ None = 0,
+ Opacity = 1,
+ Raycast = 2,
+ }
+
+ ///
+ /// 标识 OnStateChanged 事件发生时的类型
+ ///
+ [Flags]
+ public enum WindowStateEventType : int
+ {
+ None = 0,
+ StyleChanged = 1,
+ Resized = 2,
+
+ // 以下规格可能会有变化
+ TopMostEnabled = 16 + 1 + 8,
+ TopMostDisabled = 16 + 1,
+ BottomMostEnabled = 32 + 1 + 8,
+ BottomMostDisabled = 32 + 1,
+ WallpaperModeEnabled = 64 + 1 + 8,
+ WallpaperModeDisabled = 64 + 1,
+ };
+
+ ///
+ /// 鼠标按键
+ ///
+ [Flags]
+ public enum MouseButton : int
+ {
+ None = 0,
+ Left = 1,
+ Right = 2,
+ Middle = 4,
+ }
+
+ ///
+ /// 修饰键
+ ///
+ [Flags]
+ public enum ModifierKey : int
+ {
+ None = 0,
+ Alt = 1,
+ Control = 2,
+ Shift = 4,
+ Command = 8,
+ }
+
+ ///
+ /// 获取当前 UniWindowController 实例
+ ///
+ public static UniWindowController current => _current ? _current : FindOrCreateInstance();
+ private static UniWindowController _current;
+
+ ///
+ /// 底层类
+ ///
+ private UniWinCore _uniWinCore = null;
+
+ ///
+ /// 此窗口是否接收鼠标事件
+ ///
+ public bool isClickThrough
+ {
+ get { return _isClickThrough; }
+ set { SetClickThrough(value); }
+ }
+ private bool _isClickThrough = false;
+
+ ///
+ /// 此窗口是否透明
+ ///
+ public bool isTransparent
+ {
+ get { return _isTransparent; }
+ set { SetTransparent(value); }
+ }
+ [SerializeField, EditableProperty, Tooltip("选中后启动时设置为透明")]
+ private bool _isTransparent = false;
+
+ ///
+ /// 窗口透明度(0.0 到 1.0)
+ ///
+ public float alphaValue
+ {
+ get { return _alphaValue; }
+ set { SetAlphaValue(value); }
+ }
+ [SerializeField, EditableProperty, Tooltip("窗口透明度"), Range(0f, 1f)]
+ private float _alphaValue = 1.0f;
+
+ ///
+ /// 此窗口是否置顶
+ ///
+ public bool isTopmost
+ {
+ get { return ((_uniWinCore == null) ? _isTopmost : _isTopmost = _uniWinCore.IsTopmost); }
+ set { SetTopmost(value); }
+ }
+ [SerializeField, EditableProperty, Tooltip("选中后启动时置顶")]
+ private bool _isTopmost = false;
+
+ ///
+ /// 此窗口是否置底
+ ///
+ public bool isBottommost
+ {
+ get { return ((_uniWinCore == null) ? _isBottommost : _isBottommost = _uniWinCore.IsBottommost); }
+ set { SetBottommost(value); }
+ }
+ [SerializeField, EditableProperty, Tooltip("选中后启动时置底")]
+ private bool _isBottommost = false;
+
+ ///
+ /// 此窗口是否最大化
+ ///
+ public bool isZoomed
+ {
+ get { return ((_uniWinCore == null) ? _isZoomed : _isZoomed = _uniWinCore.GetZoomed()); }
+ set { SetZoomed(value); }
+ }
+ [SerializeField, EditableProperty, Tooltip("选中后启动时最大化")]
+ private bool _isZoomed = false;
+
+ ///
+ /// 此窗口是否适配到显示器
+ ///
+ public bool shouldFitMonitor
+ {
+ get { return _shouldFitMonitor; }
+ set { FitToMonitor(value, _monitorToFit); }
+ }
+ [SerializeField, EditableProperty, Tooltip("选中后将窗口适配到显示器")]
+ private bool _shouldFitMonitor = false;
+
+ ///
+ /// 适配窗口的目标显示器索引(0, 1, ...)
+ ///
+ public int monitorToFit
+ {
+ get { return _monitorToFit; }
+ set { FitToMonitor(_shouldFitMonitor, value); }
+ }
+ private int _monitorToFit = 0;
+
+ ///
+ /// 启用/禁用接受文件拖放
+ ///
+ public bool allowDropFiles
+ {
+ get { return _allowDropFiles; }
+ set { SetAllowDrop(value); }
+ }
+ [SerializeField, EditableProperty, Tooltip("启用文件或文件夹拖放")]
+ private bool _allowDropFiles = false;
+
+ ///
+ /// 是否启用点击穿透自动判定
+ /// 如果禁用,可以手动修改 isClickThrough
+ ///
+ public bool isHitTestEnabled = true;
+
+ ///
+ /// 点击穿透自动判定的方法
+ ///
+ [Tooltip("选择方法")]
+ public HitTestType hitTestType = HitTestType.Opacity;
+
+ ///
+ /// 点击穿透判定方法为不透明度时使用的阈值
+ /// 鼠标下方像素的 alpha 达到此值时判定为命中
+ ///
+ [Tooltip("点击测试类型为 Opacity 时可用"), RangeAttribute(0f, 1f)]
+ public float opacityThreshold = 0.1f;
+
+ ///
+ /// 点击穿透判定方法为 raycast 时的最远距离
+ ///
+ private float raycastMaxDepth = 100.0f;
+
+ ///
+ /// 启用后,窗口透明时会自动将相机背景改为单色黑色透明
+ ///
+ [Header("高级设置")]
+ [Tooltip("窗口透明时更改相机背景")]
+ public bool autoSwitchCameraBackground = true;
+
+ ///
+ /// 启用后,启动时如果是全屏则会强制退出全屏
+ ///
+ /// 用于即使启动对话框设置了全屏,也能切换为窗口模式
+ /// 仅在启动时生效
+ /// 在 Mac 上,即使强制退出全屏,似乎仍会变成另一个画面,效果不大
+ ///
+ [Tooltip("启动时强制窗口模式")]
+ public bool forceWindowed = false;
+
+ ///
+ /// 相机实例
+ ///
+ [Tooltip("未设置时使用主相机")]
+ public Camera currentCamera;
+
+ ///
+ /// 透明方式的指定
+ ///
+ [Header("仅限 Windows")]
+ [Tooltip("选择透明方式。*仅 Windows 可用")]
+ public TransparentType transparentType = TransparentType.Alpha;
+
+ ///
+ /// 当透明类型为 ColorKey 时使用的键色
+ ///
+ [Tooltip("将在窗口下次变为透明时使用")]
+ public Color32 keyColor = new Color32(0x01, 0x00, 0x01, 0x00);
+
+ ///
+ /// 在 macOS 上,是否允许将窗口放置在菜单栏上方
+ ///
+ public bool isFreePositioningEnabled
+ {
+ get { return ((_uniWinCore == null) ? _isFreePositioningEnabled : _isFreePositioningEnabled = _uniWinCore.IsFreePositioningEnabled); }
+ set { SetFreePositioning(value); }
+ }
+ [Header("仅限 macOS")]
+ [Tooltip("禁用 constrainFrameRect() *仅 macOS 可用")]
+ [SerializeField, EditableProperty]
+ private bool _isFreePositioningEnabled = false;
+
+ ///
+ /// 鼠标指针是否在不透明像素或物体上
+ ///
+ [Header("状态")]
+ [SerializeField, ReadOnly, Tooltip("鼠标指针是否在不透明像素上?(只读)")]
+ private bool onObject = true;
+
+ ///
+ /// 鼠标指针下方的像素颜色。(只读)
+ ///
+ [SerializeField, ReadOnly, Tooltip("鼠标指针下方的像素颜色。(只读)")]
+ public Color pickedColor;
+
+ ///
+ /// 获取/设置窗口坐标
+ ///
+ public Vector2 windowPosition
+ {
+ get { return (_uniWinCore != null ? _uniWinCore.GetWindowPosition() : Vector2.zero); }
+ set { _uniWinCore?.SetWindowPosition(value); }
+ }
+
+ ///
+ /// 获取/设置窗口大小
+ ///
+ public Vector2 windowSize
+ {
+ get { return (_uniWinCore != null ? _uniWinCore.GetWindowSize() : Vector2.zero); }
+ set { _uniWinCore?.SetWindowSize(value); }
+ }
+
+ ///
+ /// 获取客户区域大小
+ ///
+ public Vector2 clientSize
+ {
+ get { return (_uniWinCore != null ? _uniWinCore.GetClientSize() : Vector2.zero); }
+ }
+
+ ///
+ /// 获取/设置鼠标光标坐标
+ ///
+ public Vector2 cursorPosition
+ {
+ get { return UniWinCore.GetCursorPosition(); }
+ set { UniWinCore.SetCursorPosition(value); }
+ }
+
+ ///
+ /// 初始状态的窗口位置和大小
+ ///
+ private Rect originalWindowRectangle;
+
+ // 存储相机原有背景,以便在窗口透明时替换为 alpha 为零的黑色
+ private CameraClearFlags originalCameraClearFlags;
+ private Color originalCameraBackground;
+
+ ///
+ /// 存储光标下方 1 像素颜色的纹理
+ ///
+ private Texture2D colorPickerTexture = null;
+
+ ///
+ /// Raycast 使用的鼠标事件信息
+ ///
+ private PointerEventData pointerEventData;
+
+ ///
+ /// Raycast 时的图层遮罩
+ ///
+ private int hitTestLayerMask;
+
+ ///
+ /// 窗口样式改变时发生
+ ///
+ public event OnStateChangedDelegate OnStateChanged;
+ public delegate void OnStateChangedDelegate(WindowStateEventType type);
+
+ public delegate void FilesDelegate(string[] files);
+
+ ///
+ /// 文件或文件夹被拖放后发生
+ ///
+ public event FilesDelegate OnDropFiles;
+
+ ///
+ /// 显示器设置或分辨率改变时发生
+ ///
+ public event OnMonitorChangedDelegate OnMonitorChanged;
+ public delegate void OnMonitorChangedDelegate();
+
+
+ // 用于初始化
+ void Awake()
+ {
+ // 用作单例。如果已有实例,则销毁自身
+ if (this != current)
+ {
+ Destroy(this.gameObject);
+ return;
+ }
+ else
+ {
+ _current = this;
+ }
+
+ // 强制退出全屏。在编辑器中不做任何操作
+#if !UNITY_EDITOR
+ if (forceWindowed && Screen.fullScreen)
+ {
+ Screen.fullScreen = false;
+ }
+#endif
+
+ if (!currentCamera)
+ {
+ // 寻找主相机
+ currentCamera = Camera.main;
+
+ // 如果主相机未找到,则使用 Find 查找
+ //if (!currentCamera)
+ //{
+ // currentCamera = GameObject.FindAnyObjectByType();
+ //}
+ }
+
+ // 记录相机原始背景
+ if (currentCamera)
+ {
+ originalCameraClearFlags = currentCamera.clearFlags;
+ originalCameraBackground = currentCamera.backgroundColor;
+
+ }
+
+ // 鼠标事件信息
+ pointerEventData = new PointerEventData(EventSystem.current);
+
+ // 使用 Ignore Raycast 之外的图层作为有效遮罩
+ hitTestLayerMask = ~LayerMask.GetMask("Ignore Raycast");
+
+ // 准备用于提取鼠标下方像素颜色的纹理
+ colorPickerTexture = new Texture2D(1, 1, TextureFormat.ARGB32, false);
+
+ // 创建窗口控制实例
+ _uniWinCore = new UniWinCore();
+ }
+
+ ///
+ /// 适配到指定显示器
+ ///
+ private void UpdateMonitorFitting()
+ {
+ if (!_shouldFitMonitor) return;
+
+ int monitors = UniWinCore.GetMonitorCount();
+ int targetMonitorIndex = _monitorToFit;
+
+ if (targetMonitorIndex < 0)
+ {
+ targetMonitorIndex = 0;
+ }
+ if (monitors <= targetMonitorIndex)
+ {
+ targetMonitorIndex = monitors - 1;
+ }
+
+ if (targetMonitorIndex >= 0)
+ {
+ _uniWinCore.FitToMonitor(targetMonitorIndex);
+ }
+ }
+
+ ///
+ /// 查找现有实例或创建新实例
+ ///
+ ///
+ private static UniWindowController FindOrCreateInstance()
+ {
+ var instance = GameObject.FindAnyObjectByType();
+
+ // 目前禁止自动创建
+ // // 场景中未找到时创建新实例
+ // if (!instance)
+ // {
+ // var obj = new GameObject(nameof(UniWindowController));
+ // obj.AddComponent();
+ // }
+
+ return instance;
+ }
+
+ void Start()
+ {
+ //// New Input System 存在兼容性问题,用于验证输出
+// #if ENABLE_LEGACY_INPUT_MANAGER
+// Debug.Log("使用旧版输入管理器。");
+// #elif ENABLE_INPUT_SYSTEM
+// Debug.Log("使用新版输入系统。");
+// Debug.Log("后台运行 " + Mouse.current.canRunInBackground);
+// #else
+// Debug.Log("鼠标位置不可用。");
+// #endif
+
+ // 启动获取鼠标光标下颜色的协程
+ StartCoroutine(HitTestCoroutine());
+
+ // 获取初始窗口大小和位置
+ StoreOriginalWindowRectangle();
+
+ // 适配到所选显示器
+ OnMonitorChanged += UpdateMonitorFitting;
+ UpdateMonitorFitting();
+ }
+
+ void OnDestroy()
+ {
+ if (_uniWinCore != null)
+ {
+ _uniWinCore.Dispose();
+ }
+
+ // 同时销毁实例
+ if (this == current)
+ {
+ _current = null;
+ }
+ }
+
+ void StoreOriginalWindowRectangle()
+ {
+ if (_uniWinCore != null)
+ {
+ var size = _uniWinCore.GetWindowSize();
+ var pos = _uniWinCore.GetWindowPosition();
+ originalWindowRectangle = new Rect(pos, size);
+ }
+ }
+
+ // 每一帧调用 Update
+ void Update()
+ {
+ // 如果尚未获取自身窗口,则获取
+ if (_uniWinCore == null || !_uniWinCore.IsActive)
+ {
+ UpdateTargetWindow();
+ } else
+ {
+ _uniWinCore.Update();
+ }
+
+ // 处理事件
+ UpdateEvents();
+
+ // 更新键盘、鼠标操作对下方窗口的穿透状态
+ UpdateClickThrough();
+ }
+
+ ///
+ /// 检查并处理 UniWinCore 事件
+ ///
+ private void UpdateEvents()
+ {
+ if (_uniWinCore == null) return;
+
+ if (_uniWinCore.ObserveDroppedFiles(out var droppedFiles))
+ {
+ OnDropFiles?.Invoke(droppedFiles);
+ }
+
+ if (_uniWinCore.ObserveMonitorChanged())
+ {
+ OnMonitorChanged?.Invoke();
+ }
+
+ if (_uniWinCore.ObserveWindowStyleChanged(out var type))
+ {
+ // // 指定了适配显示器时,最大化被取消的情况下
+ // if (shouldFitMonitor && !uniWinCore.GetZoomed())
+ // {
+ // //StartCoroutine("ForceZoomed"); // 延迟强制最大化
+ // //SetZoomed(true); // 强制最大化 ←不一定生效
+ // //shouldFitMonitor = false; // 禁用适配
+ // }
+ if (_shouldFitMonitor) StartCoroutine("ForceZoomed"); // 延迟强制最大化
+
+ OnStateChanged?.Invoke((WindowStateEventType)type);
+ }
+ }
+
+ IEnumerator ForceZoomed()
+ {
+ yield return new WaitForSeconds(0.5f);
+ if (_shouldFitMonitor && !_uniWinCore.GetZoomed()) SetZoomed(true);
+ yield return null;
+ }
+
+ ///
+ /// 指定相机。如果之前有相机,则恢复其背景
+ ///
+ ///
+ public void SetCamera(Camera newCamera)
+ {
+ // 如果相机已更改,恢复其设置
+ if (newCamera != currentCamera)
+ {
+ SetCameraBackground(false);
+ }
+
+ currentCamera = newCamera;
+
+ // 记录相机的原始背景
+ if (currentCamera)
+ {
+ originalCameraClearFlags = currentCamera.clearFlags;
+ originalCameraBackground = currentCamera.backgroundColor;
+
+ SetCameraBackground(_isTransparent);
+ }
+ }
+
+ ///
+ /// 将鼠标/触摸操作穿透到下方窗口
+ ///
+ ///
+ void SetClickThrough(bool isThrough)
+ {
+ _uniWinCore?.EnableClickThrough(isThrough);
+ _isClickThrough = isThrough;
+ }
+
+ ///
+ /// 根据像素颜色切换操作接收状态
+ ///
+ void UpdateClickThrough()
+ {
+ // 没有自动点击测试则结束
+ if (!isHitTestEnabled || hitTestType == HitTestType.None) return;
+
+ // 鼠标光标隐藏状态视为在透明像素上
+ bool hit = (onObject);
+
+ if (_isClickThrough)
+ {
+ // 如果当前是点击穿透状态,仅在命中时取消穿透
+ if (hit)
+ {
+ SetClickThrough(false);
+ }
+ }
+ else
+ {
+ // 如果当前不是穿透状态,仅在透明且未命中时启用穿透
+ if (isTransparent && !hit)
+ {
+ SetClickThrough(true);
+ }
+ }
+ }
+
+ ///
+ /// 在协程中重复进行光标下颜色或 Raycast 的点击测试
+ /// 使用 WaitForEndOfFrame() 所以采用协程
+ ///
+ ///
+ private IEnumerator HitTestCoroutine()
+ {
+ while (Application.isPlaying)
+ {
+ yield return new WaitForEndOfFrame();
+
+ // Windows 下,如果是单色透明则点击测试由 OS 负责,所以始终为命中
+#if UNITY_EDITOR_WIN || UNITY_STANDALONE_WIN
+ if (transparentType == TransparentType.ColorKey)
+ {
+ onObject = true;
+ }
+ else
+#endif
+ if (hitTestType == HitTestType.Opacity)
+ {
+ HitTestByOpaquePixel();
+ }
+ else if (hitTestType == HitTestType.Raycast)
+ {
+ HitTestByRaycast();
+ }
+ else
+ {
+ // 无点击测试时始终为 true
+ onObject = true;
+ }
+ }
+ yield return null;
+ }
+
+ ///
+ /// 将屏幕上的鼠标坐标换算为 Unity 的屏幕坐标系
+ ///
+ private Vector2 GetClientCursorPosition()
+ {
+
+ // New Input System 在没有焦点时无法获取鼠标坐标,因此自行计算
+ Vector2 mousePos = UniWinCore.GetCursorPosition();
+ Vector2 winPos = windowPosition;
+ Rect clientRect = _uniWinCore.GetClientRectangle();
+ Vector2 unityPos = new Vector2(
+ (mousePos.x - winPos.x - clientRect.x) * Screen.width / clientRect.width,
+ (mousePos.y - winPos.y - clientRect.y) * Screen.height / clientRect.height
+ );
+
+// // 调试用
+// // 与 Unity 获取的值进行比较
+// #if ENABLE_LEGACY_INPUT_MANAGER
+// Vector2 position = Input.mousePosition;
+// #elif ENABLE_INPUT_SYSTEM
+// Vector2 position = Mouse.current.position.ReadValue();
+// #endif
+// if (!position.Equals(unityPos))
+// {
+// Debug.LogWarning("鼠标位置差异 : " + position + " / " + unityPos);
+// }
+
+ // 在编辑器中始终使用 Unity 功能获取鼠标坐标
+ // Game 窗口可能不是唯一窗口,或 Scale 不同,无法简单计算
+#if UNITY_EDITOR
+ #if ENABLE_LEGACY_INPUT_MANAGER
+ return Input.mousePosition;
+ #elif UNITY_EDITOR && ENABLE_INPUT_SYSTEM
+ return Mouse.current.position.ReadValue();
+ #else
+ return unityPos;
+ #endif
+#else
+ return unityPos;
+#endif
+ }
+
+ ///
+ /// 检查鼠标下方是否有不透明像素
+ ///
+ private void HitTestByOpaquePixel()
+ {
+ Vector2 mousePos = GetClientCursorPosition();
+
+ // 检查鼠标坐标
+ if (GetOnOpaquePixel(mousePos))
+ {
+ //Debug.Log("鼠标 " + mousePos);
+ onObject = true;
+ //activeFingerId = -1; // 取消触摸追踪
+ return;
+ }
+ else
+ {
+ onObject = false;
+ }
+ }
+
+ ///
+ /// 返回指定坐标的像素是否透明
+ ///
+ /// 坐标[px]。必须在绘制范围内。
+ ///
+ private bool GetOnOpaquePixel(Vector2 mousePos)
+ {
+ float w = Screen.width;
+ float h = Screen.height;
+ //Debug.Log(w + ", " + h);
+
+ // 在屏幕外则视为透明
+ if (
+ mousePos.x < 0 || mousePos.x >= w
+ || mousePos.y < 0 || mousePos.y >= h
+ )
+ {
+ return false;
+ }
+
+ // 如果不是透明状态,在范围内则视为不透明
+ if (!_isTransparent) return true;
+
+ // 如果是 LayeredWindow,点击测试由 OS 负责,窗口内返回true
+ if (transparentType == TransparentType.ColorKey) return true;
+
+ // 根据指定坐标的绘制结果进行判断
+ try // 在 WaitForEndOfFrame 时机执行的话,不需要 try 应该也没问题
+ {
+ // 参考 http://tsubakit1.hateblo.jp/entry/20131203/1386000440
+ colorPickerTexture.ReadPixels(new Rect(mousePos, Vector2.one), 0, 0);
+ Color color = colorPickerTexture.GetPixels32()[0];
+ pickedColor = color;
+
+ return (color.a >= opacityThreshold); // alpha 达到阈值则视为不透明
+ }
+ catch (System.Exception ex)
+ {
+ Debug.LogError(ex.Message);
+ return false;
+ }
+ }
+
+ ///
+ /// 检查鼠标下方是否有对象
+ ///
+ private void HitTestByRaycast()
+ {
+ Vector2 position = GetClientCursorPosition();
+
+ // // 判断是否在 uGUI 上
+ var raycastResults = new List();
+ pointerEventData.position = position;
+ EventSystem.current.RaycastAll(pointerEventData, raycastResults);
+ foreach (var result in raycastResults)
+ {
+ // 考虑图层遮罩(Ignore Raycast 以外的命中)
+ if (((1 << result.gameObject.layer) & hitTestLayerMask) > 0)
+ {
+ onObject = true;
+ return;
+ }
+ }
+ // 如果忽略图层限制直接命中,使用下面代码
+ // // 如果判定为在 uGUI 上,则结束
+ // if (EventSystem.current.IsPointerOverGameObject())
+ // {
+ // onObject = true;
+ // return;
+ // }
+
+ if (currentCamera && currentCamera.isActiveAndEnabled)
+ {
+ Ray ray = currentCamera.ScreenPointToRay(position);
+
+ // 判断是否在 3D 对象上
+ if (Physics.Raycast(ray, out _, raycastMaxDepth))
+ {
+ onObject = true;
+ return;
+ }
+
+ // 判断是否在 2D 对象上
+ var rayHit2D = Physics2D.GetRayIntersection(ray);
+ Debug.DrawRay(ray.origin, ray.direction, Color.blue, 2f, false);
+ if (rayHit2D.collider != null)
+ {
+ onObject = true;
+ return;
+ }
+ } else
+ {
+ // 如果相机无效,则获取主相机
+ currentCamera = Camera.main;
+ }
+
+ // 若均未命中,则判定为不在对象上
+ onObject = false;
+ }
+
+ ///
+ /// 如果自己的窗口句柄不确定,则重新查找
+ ///
+ private void UpdateTargetWindow()
+ {
+ if (_uniWinCore == null)
+ {
+ _uniWinCore = new UniWinCore();
+ }
+
+ // 如果尚未获取窗口,则执行获取处理
+ if (!_uniWinCore.IsActive)
+ {
+ _uniWinCore.AttachMyWindow();
+
+ // 获取到窗口后设置初始值
+ if (_uniWinCore.IsActive)
+ {
+ _uniWinCore.SetTransparentType((UniWinCore.TransparentType)transparentType);
+ _uniWinCore.SetKeyColor(keyColor);
+ _uniWinCore.SetAlphaValue(_alphaValue);
+ SetTransparent(_isTransparent);
+ if (_isBottommost)
+ {
+ SetBottommost(_isBottommost);
+ }
+ else
+ {
+ SetTopmost(_isTopmost);
+ }
+ SetZoomed(_isZoomed);
+ SetClickThrough(_isClickThrough);
+ SetAllowDrop(_allowDropFiles);
+ SetFreePositioning(_isFreePositioningEnabled);
+
+ // 获取窗口时执行与显示器更改相同的处理
+ OnMonitorChanged?.Invoke();
+ }
+ }
+ else
+ {
+ #if UNITY_EDITOR
+ // 在编辑器中,由于 Game 视图可能被关闭或停靠,如果发生变化则更改目标窗口
+ // 如果活动窗口与当前目标相同,则不执行任何操作
+ _uniWinCore.AttachMyActiveWindow();
+ #endif
+ }
+ }
+
+ ///
+ /// 窗口焦点变化时调用
+ ///
+ ///
+ private void OnApplicationFocus(bool focus)
+ {
+ if (focus)
+ {
+ UpdateTargetWindow();
+
+ // 获取焦点的瞬间,强制关闭点击穿透
+ if (_isTransparent && isHitTestEnabled && transparentType != TransparentType.ColorKey)
+ {
+ SetClickThrough(false);
+ }
+ }
+ }
+
+ ///
+ /// 窗口变为透明状态时,自动将背景改为透明单色
+ ///
+ ///
+ void SetCameraBackground(bool transparent)
+ {
+ // 如果未指定相机或未启用自动切换,则不执行任何操作
+ if (!currentCamera || !autoSwitchCameraBackground) return;
+
+ // 如果需要透明,则将相机背景改为透明色
+ if (transparent)
+ {
+ // 如果尚未透明化,则记忆当前相机信息
+ if (!isTransparent)
+ {
+ originalCameraClearFlags = currentCamera.clearFlags;
+ originalCameraBackground = currentCamera.backgroundColor;
+ }
+
+ currentCamera.clearFlags = CameraClearFlags.SolidColor;
+ if (transparentType == TransparentType.ColorKey)
+ {
+ currentCamera.backgroundColor = keyColor;
+ }
+ else
+ {
+ currentCamera.backgroundColor = Color.clear;
+ }
+ }
+ else
+ {
+ currentCamera.clearFlags = originalCameraClearFlags;
+ currentCamera.backgroundColor = originalCameraBackground;
+ }
+ }
+
+ ///
+ /// 切换透明化状态
+ ///
+ ///
+ private void SetTransparent(bool transparent)
+ {
+ SetCameraBackground(transparent);
+ _isTransparent = transparent;
+#if !UNITY_EDITOR
+ if (_uniWinCore != null)
+ {
+ _uniWinCore.EnableTransparent(transparent);
+ }
+#endif
+ UpdateClickThrough();
+ }
+
+ ///
+ /// 更改透明方式
+ ///
+ ///
+ public void SetTransparentType(TransparentType type)
+ {
+ if (_uniWinCore != null) {
+ // 如果正在透明中,则先解除再重新透明
+ if (_isTransparent)
+ {
+ SetTransparent(false);
+ _uniWinCore.SetTransparentType((UniWinCore.TransparentType)type);
+ transparentType = type;
+ SetTransparent(true);
+ }
+ else
+ {
+ _uniWinCore.SetTransparentType((UniWinCore.TransparentType)type);
+ transparentType = type;
+ }
+ }
+ }
+
+ ///
+ /// 设置窗口透明度
+ ///
+ /// 0.0 到 1.0
+ private void SetAlphaValue(float alpha)
+ {
+ _alphaValue = alpha;
+ _uniWinCore?.SetAlphaValue(_alphaValue);
+ }
+
+ ///
+ /// 切换置顶
+ ///
+ ///
+ private void SetTopmost(bool topmost)
+ {
+ //if (_isTopmost == topmost) return;
+ if (_uniWinCore == null) return;
+
+ _uniWinCore.EnableTopmost(topmost);
+ _isTopmost = _uniWinCore.IsTopmost;
+ _isBottommost = _uniWinCore.IsBottommost;
+ }
+
+ ///
+ /// 切换始终置底
+ ///
+ ///
+ private void SetBottommost(bool bottommost)
+ {
+ if (_uniWinCore == null) return;
+
+ _uniWinCore.EnableBottommost(bottommost);
+ _isBottommost = _uniWinCore.IsBottommost;
+ _isTopmost = _uniWinCore.IsTopmost;
+ }
+
+ ///
+ /// 最大化/还原
+ ///
+ ///
+ private void SetZoomed(bool zoomed)
+ {
+ if (_uniWinCore == null) return;
+
+ _uniWinCore.SetZoomed(zoomed);
+ _isZoomed = _uniWinCore.GetZoomed();
+ }
+
+ private void SetAllowDrop(bool enabled)
+ {
+ if (_uniWinCore == null) return;
+
+ _uniWinCore.SetAllowDrop(enabled);
+ _allowDropFiles = enabled;
+ }
+
+ ///
+ /// 在 macOS 上,允许将窗口放置在包含菜单栏上方在内的任意位置
+ ///
+ ///
+ private void SetFreePositioning(bool enabled)
+ {
+ if (_uniWinCore == null) return;
+
+ _uniWinCore.EnableFreePositioning(enabled);
+ _isFreePositioningEnabled = _uniWinCore.IsFreePositioningEnabled;
+ }
+
+ ///
+ /// 获取连接的显示器数量
+ ///
+ ///
+ public static int GetMonitorCount()
+ {
+ //if (uniWinCore == null) return 0;
+ return UniWinCore.GetMonitorCount();
+ }
+
+ ///
+ /// 获取显示器的位置和大小
+ ///
+ ///
+ ///
+ public static Rect GetMonitorRect(int index)
+ {
+ if (UniWinCore.GetMonitorRectangle(index, out Vector2 position, out Vector2 size))
+ {
+ return new Rect(position, size);
+ }
+ return Rect.zero;
+ }
+
+ ///
+ /// 适配到指定显示器
+ ///
+ ///
+ private bool FitToMonitor(bool shouldFit, int monitorIndex)
+ {
+ if (_uniWinCore == null)
+ {
+ _shouldFitMonitor = shouldFit;
+ _monitorToFit = monitorIndex;
+ return false;
+ }
+
+ if (shouldFit)
+ {
+ if (!_shouldFitMonitor)
+ {
+ // 之前未适配的情况
+ _monitorToFit = monitorIndex;
+ _shouldFitMonitor = shouldFit;
+ UpdateMonitorFitting();
+ }
+ else
+ {
+ if (_monitorToFit != monitorIndex)
+ {
+ // 适配的显示器发生变化的情况
+ _monitorToFit = monitorIndex;
+ UpdateMonitorFitting();
+ }
+ }
+ }
+ else
+ {
+ if (_shouldFitMonitor)
+ {
+ // 之前是适配状态,现在被取消的情况
+ _monitorToFit = monitorIndex;
+ _shouldFitMonitor = shouldFit;
+ UpdateMonitorFitting();
+
+ _uniWinCore.SetZoomed(false);
+ //uniWinCore.SetWindowSize(originalWindowRectangle.size);
+ //uniWinCore.SetWindowPosition(originalWindowRectangle.position);
+ }
+ else
+ {
+ // 未在适配中时,仅更改选择
+ _monitorToFit = monitorIndex;
+ }
+ }
+
+ return true;
+ }
+
+ ///
+ /// 获取鼠标光标位置
+ ///
+ /// 光标位置
+ public static Vector2 GetCursorPosition()
+ {
+ return UniWinCore.GetCursorPosition();
+ }
+
+ ///
+ /// 设置鼠标光标位置
+ ///
+ ///
+ public static void SetCursorPosition(Vector2 position)
+ {
+ UniWinCore.SetCursorPosition(position);
+ }
+
+ ///
+ /// 获取鼠标按键状态
+ ///
+ ///
+ public static MouseButton GetMouseButtons()
+ {
+ int buttons = UniWinCore.GetMouseButtons();
+ return (MouseButton)buttons;
+ }
+
+ ///
+ /// 获取按下的修饰键
+ ///
+ ///
+ public static ModifierKey GetModifierKeys()
+ {
+ int mod = UniWinCore.GetModifierKeys();
+ return (ModifierKey)mod;
+ }
+
+ ///
+ /// 退出时需要恢复窗口状态
+ ///
+ void OnApplicationQuit()
+ {
+ if (Application.isPlaying)
+ {
+ if (_uniWinCore != null)
+ {
+ // 在编辑器中恢复窗口状态
+ // 在独立构建中会看到恢复过程,因此跳过
+#if UNITY_EDITOR
+ _uniWinCore.SetWindowSize(originalWindowRectangle.size);
+ _uniWinCore.SetWindowPosition(originalWindowRectangle.position);
+
+ _uniWinCore.DetachWindow();
+#endif
+ _uniWinCore.Dispose();
+ }
+ }
+ }
+
+ ///
+ /// 将焦点给予自身窗口
+ ///
+ public void Focus()
+ {
+ if (_uniWinCore != null)
+ {
+ //uniWin.SetFocus();
+ }
+ }
+
+
+ ///
+ /// 仅供调试用。用于获取各阶段参考信息的函数
+ ///
+ ///
+ [Obsolete]
+ public int GetDebugInfo()
+ {
+ if (_uniWinCore != null) {
+ return UniWinCore.GetDebugInfo();
+ }
+ return 0;
+ }
+ }
+}
diff --git a/Runtime/Scripts/UniWindowController.cs.meta b/Runtime/Scripts/UniWindowController.cs.meta
new file mode 100644
index 0000000..141b3ca
--- /dev/null
+++ b/Runtime/Scripts/UniWindowController.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: d327b245537480646bd85e511002d6ce
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Runtime/Scripts/UniWindowMoveHandle.cs b/Runtime/Scripts/UniWindowMoveHandle.cs
new file mode 100644
index 0000000..9da36a2
--- /dev/null
+++ b/Runtime/Scripts/UniWindowMoveHandle.cs
@@ -0,0 +1,206 @@
+/*
+ * UniWindowDragMove.cs
+ *
+ * 作者: Kirurobo http://twitter.com/kirurobo
+ * 许可证: MIT
+ */
+
+using System.Collections;
+using System.Collections.Generic;
+using UnityEditor;
+using UnityEngine;
+using UnityEngine.EventSystems;
+#if ENABLE_LEGACY_INPUT_MANAGER
+#elif ENABLE_INPUT_SYSTEM
+using UnityEngine.InputSystem;
+#endif
+
+namespace Kirurobo
+{
+ public class UniWindowMoveHandle : MonoBehaviour, IDragHandler, IBeginDragHandler, IEndDragHandler, IPointerUpHandler
+ {
+ private UniWindowController _uniwinc;
+
+ ///
+ /// 窗口最大化时是否禁用移动
+ ///
+ [Tooltip("窗口已最大化(缩放)时禁用拖拽移动。")]
+ public bool disableOnZoomed = true;
+
+ ///
+ /// 拖动中则为 true
+ ///
+ public bool IsDragging
+ {
+ get { return _isDragging; }
+ }
+ private bool _isDragging = false;
+
+ ///
+ /// 是否进行拖动
+ ///
+ private bool IsEnabled
+ {
+ get { return enabled && (!disableOnZoomed || !IsZoomed); }
+ }
+
+ ///
+ /// 是否适配显示器或最大化
+ ///
+ private bool IsZoomed
+ {
+ get { return (_uniwinc && (_uniwinc.shouldFitMonitor || _uniwinc.isZoomed)); }
+ }
+
+ ///
+ /// 记录拖动前自动命中测试是否启用
+ ///
+ private bool _isHitTestEnabled;
+
+ ///
+ /// 拖动开始时窗口内坐标[像素]
+ ///
+ private Vector2 _dragStartedPosition;
+
+ // 首次帧更新前调用 Start
+ void Start()
+ {
+ // 获取场景中的 UniWindowController
+ _uniwinc = GameObject.FindAnyObjectByType();
+ if (_uniwinc) _isHitTestEnabled = _uniwinc.isHitTestEnabled;
+
+ //// 下面的代码似乎不需要,所以注释掉以免擅自更改
+ //Input.simulateMouseWithTouches = false;
+ }
+
+ ///
+ /// 拖动开始时的处理
+ ///
+ public void OnBeginDrag(PointerEventData eventData)
+ {
+ if (!IsEnabled)
+ {
+ return;
+ }
+
+ // 仅通过鼠标左键拖动
+ if (eventData.button != PointerEventData.InputButton.Left) return;
+
+ // Mac 上行为会有所不同
+ // 实际上仅在 Retina 支持启用时,但 eventData.position 的坐标系与窗口坐标系的缩放会不一致
+#if UNITY_EDITOR_OSX || UNITY_STANDALONE_OSX
+ _dragStartedPosition = _uniwinc.windowPosition - _uniwinc.cursorPosition;
+#else
+ _dragStartedPosition = eventData.position;
+#endif
+
+ // 如果 _isDragging 为 false,则判断即将开始拖动
+ if (!_isDragging)
+ {
+ // 拖动期间禁用命中测试
+ _isHitTestEnabled = _uniwinc.isHitTestEnabled;
+ _uniwinc.isHitTestEnabled = false;
+ _uniwinc.isClickThrough = false;
+ }
+
+ _isDragging = true;
+ }
+
+ ///
+ /// 拖动结束时的处理
+ ///
+ public void OnEndDrag(PointerEventData eventData)
+ {
+ EndDragging();
+ }
+
+ ///
+ /// 鼠标抬起时也视为拖动结束
+ ///
+ ///
+ public void OnPointerUp(PointerEventData eventData)
+ {
+ EndDragging();
+ }
+
+ ///
+ /// 结束拖动
+ ///
+ private void EndDragging()
+ {
+ if (_isDragging)
+ {
+ _uniwinc.isHitTestEnabled = _isHitTestEnabled;
+ }
+ _isDragging = false;
+ }
+
+ ///
+ /// 非最大化时,通过鼠标拖动移动窗口
+ ///
+ public void OnDrag(PointerEventData eventData)
+ {
+ if (!_uniwinc || !_isDragging) return;
+
+ // 如果拖动移动已被禁用,则结束拖动
+ if (!IsEnabled)
+ {
+ EndDragging();
+ return;
+ }
+
+ // // 如果鼠标左键未按下,则结束拖动
+ // if (eventData.button != PointerEventData.InputButton.Left) return;
+
+ // [Shift]、[Ctrl]、[Alt]、[Command] 键按下期间不视为拖动
+ var modifiers = UniWindowController.GetModifierKeys();
+ if (modifiers != UniWindowController.ModifierKey.None) return;
+
+ // 如果鼠标按钮已松开,则结束拖动
+ var buttons = UniWindowController.GetMouseButtons();
+ if ((buttons & UniWindowController.MouseButton.Left) == UniWindowController.MouseButton.None) {
+ EndDragging();
+ return;
+ }
+// #if ENABLE_LEGACY_INPUT_MANAGER
+// // 在 Mac 上,如果在多显示器之间移动,EventSystem 的 OnEndDrag 可能无法正确调用,因此始终监控鼠标按钮
+// if (!Input.Mouse.Button(0).IsPressed) {
+// EndDragging();
+// return;
+// }
+// if (Input.GetKey(KeyCode.LeftShift) || Input.GetKey(KeyCode.RightShift)
+// || Input.GetKey(KeyCode.LeftControl) || Input.GetKey(KeyCode.RightControl)
+// || Input.GetKey(KeyCode.LeftAlt) || Input.GetKey(KeyCode.RightAlt)) return;
+// #elif ENABLE_INPUT_SYSTEM
+// // 在 Mac 上,如果在多显示器之间移动,EventSystem 的 OnEndDrag 可能无法正确调用,因此始终监控鼠标按钮
+// if (!Mouse.current.leftButton.isPressed) {
+// EndDragging();
+// return;
+// }
+// if (Keyboard.current[Key.LeftShift].isPressed || Keyboard.current[Key.RightShift].isPressed
+// || Keyboard.current[Key.LeftCtrl].isPressed || Keyboard.current[Key.RightCtrl].isPressed
+// || Keyboard.current[Key.LeftAlt].isPressed || Keyboard.current[Key.RightAlt].isPressed) return;
+// #endif
+
+ // 如果是全屏则不移动窗口
+ // 在编辑器中可能会变为 true,因此仅在非编辑器环境下确认
+#if !UNITY_EDITOR
+ if (Screen.fullScreen)
+ {
+ EndDragging();
+ return;
+ }
+#endif
+
+#if UNITY_EDITOR_OSX || UNITY_STANDALONE_OSX
+ // 在 Mac 上,通过原生插件获取/设置光标位置
+ _uniwinc.windowPosition = _uniwinc.cursorPosition + _dragStartedPosition;
+ //Debug.Log("Drag start: " + _dragStartedPosition);
+#else
+ // 在 Windows 上,为支持触控操作而使用 eventData.position
+ // 将窗口移动与起始位置一致的屏幕位置偏移量
+ _uniwinc.windowPosition += eventData.position - _dragStartedPosition;
+#endif
+ }
+ }
+}
diff --git a/Runtime/Scripts/UniWindowMoveHandle.cs.meta b/Runtime/Scripts/UniWindowMoveHandle.cs.meta
new file mode 100644
index 0000000..d59a347
--- /dev/null
+++ b/Runtime/Scripts/UniWindowMoveHandle.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: dd641513c2924f7488734c8cac43310f
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Samples.meta b/Samples.meta
new file mode 100644
index 0000000..c2dfa62
--- /dev/null
+++ b/Samples.meta
@@ -0,0 +1,8 @@
+fileFormatVersion: 2
+guid: 326ddcba926f5e849bde9a0e0fb87ee1
+folderAsset: yes
+DefaultImporter:
+ externalObjects: {}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Samples~/Common/AutoRotator.cs b/Samples~/Common/AutoRotator.cs
new file mode 100644
index 0000000..f331214
--- /dev/null
+++ b/Samples~/Common/AutoRotator.cs
@@ -0,0 +1,35 @@
+using UnityEngine;
+
+namespace Kirurobo {
+ ///
+ /// 使附加的对象以恒定速度进行偏航旋转
+ ///
+ public class AutoRotator : MonoBehaviour {
+ ///
+ /// 旋转速度 [度/秒]
+ ///
+ public float angularVelocity = 90f;
+
+ ///
+ /// 旋转轴(偏航旋转,方向向上)
+ ///
+ Vector3 rotationAxis = Vector3.up;
+
+ ///
+ /// 初始姿态
+ ///
+ Quaternion initialLocalRotation;
+
+ // 用于初始化
+ void Start () {
+ // 记录初始姿态
+ initialLocalRotation = transform.localRotation;
+ }
+
+ // 每帧调用 Update
+ void Update () {
+ var rotation = Quaternion.Euler(0f, Time.time * angularVelocity, 0f);
+ transform.localRotation = initialLocalRotation * rotation;
+ }
+ }
+}
diff --git a/Samples~/Common/AutoRotator.cs.meta b/Samples~/Common/AutoRotator.cs.meta
new file mode 100644
index 0000000..4d630da
--- /dev/null
+++ b/Samples~/Common/AutoRotator.cs.meta
@@ -0,0 +1,12 @@
+fileFormatVersion: 2
+guid: f985bf036f5416a45b9dd4e31bc85075
+timeCreated: 1545989238
+licenseType: Pro
+MonoImporter:
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Samples~/Common/CollisionBorder.png b/Samples~/Common/CollisionBorder.png
new file mode 100644
index 0000000..94e5e16
Binary files /dev/null and b/Samples~/Common/CollisionBorder.png differ
diff --git a/Samples~/Common/CollisionBorder.png.meta b/Samples~/Common/CollisionBorder.png.meta
new file mode 100644
index 0000000..1b64805
--- /dev/null
+++ b/Samples~/Common/CollisionBorder.png.meta
@@ -0,0 +1,88 @@
+fileFormatVersion: 2
+guid: 2b5d2690e20d6584e909fd2bdfd93579
+TextureImporter:
+ fileIDToRecycleName: {}
+ externalObjects: {}
+ serializedVersion: 9
+ mipmaps:
+ mipMapMode: 0
+ enableMipMap: 0
+ sRGBTexture: 1
+ linearTexture: 0
+ fadeOut: 0
+ borderMipMap: 0
+ mipMapsPreserveCoverage: 0
+ alphaTestReferenceValue: 0.5
+ mipMapFadeDistanceStart: 1
+ mipMapFadeDistanceEnd: 3
+ bumpmap:
+ convertToNormalMap: 0
+ externalNormalMap: 0
+ heightScale: 0.25
+ normalMapFilter: 0
+ isReadable: 0
+ streamingMipmaps: 0
+ streamingMipmapsPriority: 0
+ grayScaleToAlpha: 0
+ generateCubemap: 6
+ cubemapConvolution: 0
+ seamlessCubemap: 0
+ textureFormat: 1
+ maxTextureSize: 2048
+ textureSettings:
+ serializedVersion: 2
+ filterMode: -1
+ aniso: -1
+ mipBias: -100
+ wrapU: 1
+ wrapV: 1
+ wrapW: -1
+ nPOTScale: 0
+ lightmap: 0
+ compressionQuality: 50
+ spriteMode: 1
+ spriteExtrude: 1
+ spriteMeshType: 0
+ alignment: 0
+ spritePivot: {x: 0.5, y: 0.5}
+ spritePixelsToUnits: 100
+ spriteBorder: {x: 8, y: 8, z: 8, w: 8}
+ spriteGenerateFallbackPhysicsShape: 1
+ alphaUsage: 1
+ alphaIsTransparency: 1
+ spriteTessellationDetail: -1
+ textureType: 8
+ textureShape: 1
+ singleChannelComponent: 0
+ maxTextureSizeSet: 0
+ compressionQualitySet: 0
+ textureFormatSet: 0
+ platformSettings:
+ - serializedVersion: 2
+ buildTarget: DefaultTexturePlatform
+ maxTextureSize: 2048
+ resizeAlgorithm: 0
+ textureFormat: -1
+ textureCompression: 1
+ compressionQuality: 50
+ crunchedCompression: 0
+ allowsAlphaSplitting: 0
+ overridden: 0
+ androidETC2FallbackOverride: 0
+ spriteSheet:
+ serializedVersion: 2
+ sprites: []
+ outline: []
+ physicsShape: []
+ bones: []
+ spriteID: 533df9bf30503d349b91598d325d5fcd
+ vertices: []
+ indices:
+ edges: []
+ weights: []
+ spritePackingTag:
+ pSDRemoveMatte: 0
+ pSDShowRemoveMatteOption: 0
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Samples~/Common/GreenBorder.png b/Samples~/Common/GreenBorder.png
new file mode 100644
index 0000000..c060683
Binary files /dev/null and b/Samples~/Common/GreenBorder.png differ
diff --git a/Samples~/Common/GreenBorder.png.meta b/Samples~/Common/GreenBorder.png.meta
new file mode 100644
index 0000000..3e0a0e3
--- /dev/null
+++ b/Samples~/Common/GreenBorder.png.meta
@@ -0,0 +1,88 @@
+fileFormatVersion: 2
+guid: 4713fc586389c694f9e384c7f3a02289
+TextureImporter:
+ fileIDToRecycleName: {}
+ externalObjects: {}
+ serializedVersion: 9
+ mipmaps:
+ mipMapMode: 0
+ enableMipMap: 0
+ sRGBTexture: 1
+ linearTexture: 0
+ fadeOut: 0
+ borderMipMap: 0
+ mipMapsPreserveCoverage: 0
+ alphaTestReferenceValue: 0.5
+ mipMapFadeDistanceStart: 1
+ mipMapFadeDistanceEnd: 3
+ bumpmap:
+ convertToNormalMap: 0
+ externalNormalMap: 0
+ heightScale: 0.25
+ normalMapFilter: 0
+ isReadable: 0
+ streamingMipmaps: 0
+ streamingMipmapsPriority: 0
+ grayScaleToAlpha: 0
+ generateCubemap: 6
+ cubemapConvolution: 0
+ seamlessCubemap: 0
+ textureFormat: 1
+ maxTextureSize: 2048
+ textureSettings:
+ serializedVersion: 2
+ filterMode: -1
+ aniso: -1
+ mipBias: -100
+ wrapU: 1
+ wrapV: 1
+ wrapW: -1
+ nPOTScale: 0
+ lightmap: 0
+ compressionQuality: 50
+ spriteMode: 1
+ spriteExtrude: 1
+ spriteMeshType: 0
+ alignment: 0
+ spritePivot: {x: 0.5, y: 0.5}
+ spritePixelsToUnits: 100
+ spriteBorder: {x: 8, y: 8, z: 8, w: 8}
+ spriteGenerateFallbackPhysicsShape: 1
+ alphaUsage: 1
+ alphaIsTransparency: 1
+ spriteTessellationDetail: -1
+ textureType: 8
+ textureShape: 1
+ singleChannelComponent: 0
+ maxTextureSizeSet: 0
+ compressionQualitySet: 0
+ textureFormatSet: 0
+ platformSettings:
+ - serializedVersion: 2
+ buildTarget: DefaultTexturePlatform
+ maxTextureSize: 2048
+ resizeAlgorithm: 0
+ textureFormat: -1
+ textureCompression: 1
+ compressionQuality: 50
+ crunchedCompression: 0
+ allowsAlphaSplitting: 0
+ overridden: 0
+ androidETC2FallbackOverride: 0
+ spriteSheet:
+ serializedVersion: 2
+ sprites: []
+ outline: []
+ physicsShape: []
+ bones: []
+ spriteID: 47fdf1b4c9bb7764d916b229e9a2d98c
+ vertices: []
+ indices:
+ edges: []
+ weights: []
+ spritePackingTag:
+ pSDRemoveMatte: 0
+ pSDShowRemoveMatteOption: 0
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Samples~/Common/InputModuleProxy.cs b/Samples~/Common/InputModuleProxy.cs
new file mode 100644
index 0000000..adc84af
--- /dev/null
+++ b/Samples~/Common/InputModuleProxy.cs
@@ -0,0 +1,27 @@
+using System.Collections;
+using System.Collections.Generic;
+using UnityEngine;
+#if ENABLE_LEGACY_INPUT_MANAGER
+#elif ENABLE_INPUT_SYSTEM
+using UnityEngine.InputSystem;
+#endif
+
+namespace Kirurobo {
+
+ ///
+ /// 为快速兼容 Legacy InputManager 和 InputSystem 而准备的类
+ ///
+#if ENABLE_LEGACY_INPUT_MANAGER
+ public class InputModuleProxy : UnityEngine.EventSystems.StandaloneInputModule
+ {
+ }
+#elif ENABLE_INPUT_SYSTEM
+ public class InputModuleProxy : UnityEngine.InputSystem.UI.InputSystemUIInputModule
+ {
+ }
+#else
+ public class InputModuleProxy
+ {
+ }
+#endif
+}
\ No newline at end of file
diff --git a/Samples~/Common/InputModuleProxy.cs.meta b/Samples~/Common/InputModuleProxy.cs.meta
new file mode 100644
index 0000000..5c852fd
--- /dev/null
+++ b/Samples~/Common/InputModuleProxy.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: ce6b387a66b0e654d9eb8712d70fff48
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Samples~/Common/InputProxy.cs b/Samples~/Common/InputProxy.cs
new file mode 100644
index 0000000..eff4d4c
--- /dev/null
+++ b/Samples~/Common/InputProxy.cs
@@ -0,0 +1,138 @@
+/**
+ * UniWindowController 的示例脚本
+ *
+ * 作者: Kirurobo http://twitter.com/kirurobo
+ * 许可证: MIT
+ */
+
+using System;
+using UnityEngine;
+#if ENABLE_LEGACY_INPUT_MANAGER
+// Don't use InputSystem in this script to prevent TouchPhase duplication
+#elif ENABLE_INPUT_SYSTEM
+using UnityEngine.InputSystem;
+#endif
+
+namespace Kirurobo {
+ ///
+ /// Input System と Input Manager の違いを吸収するためのプロキシ
+ ///
+ public class InputProxy
+ {
+ public static Vector3 mousePosition {
+ get {
+ return GetMousePosition();
+ }
+ }
+
+ ///
+ /// Input System の利用に合わせてキーアップを取得
+ ///
+ ///
+ public static bool GetKeyUp(String key)
+ {
+ #if ENABLE_LEGACY_INPUT_MANAGER
+ return Input.GetKeyUp(key);
+ #elif ENABLE_INPUT_SYSTEM
+ // 簡易的な実装。keyが1文字で、かつアルファベットか数字に対応
+ // 1文字以外は escape, space のみ対応
+ if (key.Length == 1) {
+ Key k = Key.None;
+ char c = key[0];
+ if (c >= '0' && c <= '9') {
+ // 数字の場合はDigit0~Digit9とNumpad0~Numpad9の両方に反応
+ k = (Key)Enum.ToObject(typeof(Key), (int)Key.Numpad0 + (int)(c - '0'));
+ if (Keyboard.current[k].wasReleasedThisFrame) return true;
+
+ // Digitの場合はDigit0の値が最大
+ k = (Key)Enum.ToObject(typeof(Key), (int)Key.Digit1 + (int)((c == '0' ? 9 : c - '1')));
+ if (Keyboard.current[k].wasReleasedThisFrame) return true;
+ }
+ if ((c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z')) {
+ // アルファベットの場合は大文字・小文字どちらでも可とする
+ k = (Key)Enum.ToObject(typeof(Key), (int)Key.A + (int)(Char.ToUpper(c) - 'A'));
+ if (Keyboard.current[k].wasReleasedThisFrame) return true;
+ }
+ } else if (key == "escape") {
+ return Keyboard.current.escapeKey.wasReleasedThisFrame;
+ } else if (key == "space") {
+ return Keyboard.current.spaceKey.wasReleasedThisFrame;
+ }
+ return false;
+ #else
+ return false;
+ #endif
+ }
+
+ ///
+ /// Input System の利用に合わせてマウス座標を取得
+ ///
+ ///
+ private static Vector3 GetMousePosition()
+ {
+ #if ENABLE_LEGACY_INPUT_MANAGER
+ return Input.mousePosition;
+ #elif ENABLE_INPUT_SYSTEM
+ return Mouse.current.position.ReadValue();
+ #else
+ return Vector3.zero;
+ #endif
+ }
+
+ ///
+ /// 判断鼠标按钮当前是否被按下
+ ///
+ ///
+ ///
+ public static bool GetMouseButton(int button)
+ {
+ #if ENABLE_LEGACY_INPUT_MANAGER
+ return Input.GetMouseButton(button);
+ #elif ENABLE_INPUT_SYSTEM
+ if (button == 0) return Mouse.current.leftButton.isPressed;
+ if (button == 1) return Mouse.current.rightButton.isPressed;
+ if (button == 2) return Mouse.current.middleButton.isPressed;
+ return false;
+ #else
+ return false;
+ #endif
+ }
+
+ ///
+ /// このフレームでマウスボタンが押されたか判定
+ ///
+ ///
+ ///
+ public static bool GetMouseButtonDown(int button)
+ {
+ #if ENABLE_LEGACY_INPUT_MANAGER
+ return Input.GetMouseButtonDown(button);
+ #elif ENABLE_INPUT_SYSTEM
+ if (button == 0) return Mouse.current.leftButton.wasPressedThisFrame;
+ if (button == 1) return Mouse.current.rightButton.wasPressedThisFrame;
+ if (button == 2) return Mouse.current.middleButton.wasPressedThisFrame;
+ return false;
+ #else
+ return false;
+ #endif
+ }
+
+ ///
+ /// 判断本帧是否松开了鼠标按钮
+ ///
+ ///
+ ///
+ public static bool GetMouseButtonUp(int button) {
+ #if ENABLE_LEGACY_INPUT_MANAGER
+ return Input.GetMouseButtonUp(button);
+ #elif ENABLE_INPUT_SYSTEM
+ if (button == 0) return Mouse.current.leftButton.wasReleasedThisFrame;
+ if (button == 1) return Mouse.current.rightButton.wasReleasedThisFrame;
+ if (button == 2) return Mouse.current.middleButton.wasReleasedThisFrame;
+ return false;
+ #else
+ return false;
+ #endif
+ }
+ }
+}
\ No newline at end of file
diff --git a/Samples~/Common/InputProxy.cs.meta b/Samples~/Common/InputProxy.cs.meta
new file mode 100644
index 0000000..bf70d1c
--- /dev/null
+++ b/Samples~/Common/InputProxy.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: 93a3055c4733041a1a83f6c90996f3ee
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Samples~/Common/ModelController.cs b/Samples~/Common/ModelController.cs
new file mode 100644
index 0000000..bc9324e
--- /dev/null
+++ b/Samples~/Common/ModelController.cs
@@ -0,0 +1,282 @@
+/*
+ * ModelController
+ *
+ * 旋转、平移和缩放对象
+ *
+ * 作者: Kirurobo http://twitter.com/kirurobo
+ * 许可证: MIT
+ */
+
+using System;
+using UnityEngine;
+
+namespace Kirurobo
+{
+ public class ModelController : MonoBehaviour
+ {
+ [Flags]
+ public enum RotationAxes : int
+ {
+ None = 0,
+ Pitch = 1,
+ Yaw = 2,
+ PitchAndYaw = 3
+ }
+
+ [Flags]
+ public enum DragState
+ {
+ None,
+ Rotating,
+ Translating,
+ }
+
+ public RotationAxes axes = RotationAxes.PitchAndYaw;
+ public float yawSensitivity = 1f;
+ public float pitchSensitvity = 1f;
+ public float scaleSensitivity = 0.5f;
+
+ public Vector2 minimumAngles = new Vector2(-90f, -360f);
+ public Vector2 maximumAngles = new Vector2(90f, 360f);
+
+ [Tooltip("Restrict to move out from screen")]
+ public bool confineTranslation = true; // 並進移動をウィンドウ(Screen)の範囲に制限するか
+
+ [Tooltip("Default is the parent transform")]
+ public Transform centerTransform; // 回転中心
+
+ [Tooltip("Default is the main camera")]
+ public Camera currentCamera;
+
+ internal GameObject centerObject = null; // 当未指定旋转中心Transform时创建的对象
+
+ internal Vector3 rotation;
+ internal Vector3 translation;
+ internal Vector3 lastMousePosition; // 上一帧的鼠标坐标
+ internal DragState dragState; // 拖动时根据开始时的按钮设置对应状态
+
+ internal Vector3 relativePosition;
+ internal Quaternion relativeRotation;
+ internal Vector3 originalLocalScale;
+ internal float zoom;
+
+
+ void Start()
+ {
+ Initialize();
+ SetupTransform();
+ }
+
+ void OnDestroy()
+ {
+ // 回転中心を独自に作成していれば、削除
+ if (centerObject) GameObject.Destroy(centerObject);
+ }
+
+ void Update()
+ {
+ if (!currentCamera.isActiveAndEnabled) return;
+ {
+ HandleMouse();
+ }
+ }
+
+ ///
+ /// 必要なオブジェクトを取得・準備
+ ///
+ internal void Initialize()
+ {
+ if (!centerTransform)
+ {
+ centerTransform = this.transform.parent;
+ if (!centerTransform || centerTransform == this.transform)
+ {
+ centerObject = new GameObject();
+ centerTransform = centerObject.transform;
+ centerTransform.position = Vector3.zero;
+ }
+ }
+
+ if (!currentCamera)
+ {
+ currentCamera = Camera.main;
+ }
+
+ lastMousePosition = InputProxy.mousePosition;
+ }
+
+ ///
+ /// 初期位置・姿勢の設定
+ /// 対象となるオブジェクトがそろった後で実行する
+ ///
+ internal void SetupTransform()
+ {
+ relativePosition = transform.position- centerTransform.position; // 从对象到中心坐标的向量
+ relativeRotation = transform.rotation * Quaternion.Inverse(centerTransform.rotation);
+ originalLocalScale = transform.localScale;
+
+ ResetTransform();
+ }
+
+ ///
+ /// Reset rotation and translation.
+ ///
+ public void ResetTransform()
+ {
+ rotation = relativeRotation.eulerAngles;
+ translation = relativePosition;
+ zoom = 0f;
+
+ UpdateTransform();
+ }
+
+ ///
+ /// 应用旋转和平移
+ ///
+ internal void UpdateTransform()
+ {
+ Quaternion rot = Quaternion.Euler(rotation);
+ transform.rotation = rot;
+ transform.position = centerTransform.position + translation;
+
+ transform.localScale = originalLocalScale * Mathf.Pow(10f, zoom);
+ }
+
+ internal virtual void HandleMouse()
+ {
+ Vector3 mousePos = InputProxy.mousePosition;
+
+ if (InputProxy.GetMouseButtonDown(0))
+ {
+ // 左键(0)拖动时进行平移
+ if (dragState == DragState.None && IsHit(mousePos))
+ {
+ dragState = DragState.Translating;
+
+ // 限制在屏幕范围内
+ if (confineTranslation)
+ {
+ Vector3 screenMax = new Vector3(Screen.width, Screen.height);
+ mousePos = Vector3.Max(Vector3.Min(mousePos, screenMax), Vector3.zero);
+ }
+
+ lastMousePosition = mousePos; // ドラッグ開始時にはリセット
+ }
+ }
+ else if (InputProxy.GetMouseButtonDown(1))
+ {
+ // 右ボタン(1)ドラッグでは回転を行う
+ if (dragState == DragState.None && IsHit(mousePos))
+ {
+ dragState = DragState.Rotating;
+ lastMousePosition = mousePos; // ドラッグ開始時にはリセット
+ }
+ }
+
+ // 通过拖动旋转
+ if (dragState == DragState.Rotating)
+ {
+ // 仅在按下按钮时操作
+ if (InputProxy.GetMouseButton(1))
+ {
+ // 通过拖动旋转
+ if ((axes & RotationAxes.Yaw) > RotationAxes.None)
+ {
+ rotation.y -= (mousePos.x - lastMousePosition.x) * 360f / Screen.width * yawSensitivity;
+ rotation.y = ClampAngle(rotation.y, minimumAngles.y, maximumAngles.y);
+ }
+
+ if ((axes & RotationAxes.Pitch) > RotationAxes.None)
+ {
+ rotation.x += (mousePos.y - lastMousePosition.y) * 360f / Screen.height * pitchSensitvity;
+ rotation.x = ClampAngle(rotation.x, minimumAngles.x, maximumAngles.x);
+ }
+
+ UpdateTransform();
+ }
+ else
+ {
+ // 如果右键已松开则结束旋转
+ dragState = DragState.None;
+ }
+ }
+
+ // 通过拖动平移
+ if (dragState == DragState.Translating)
+ {
+ // 仅在按下按钮时操作
+ if (InputProxy.GetMouseButton(0))
+ {
+ // 限制在屏幕范围内
+ if (confineTranslation)
+ {
+ Vector3 screenMax = new Vector3(Screen.width, Screen.height);
+ mousePos = Vector3.Max(Vector3.Min(mousePos, screenMax), Vector3.zero);
+ }
+
+ Vector3 screenPos = currentCamera.WorldToScreenPoint(transform.position);
+ Vector3 deltaPos = mousePos - lastMousePosition;
+ deltaPos.z = 0f;
+ Vector3 worldPos = currentCamera.ScreenToWorldPoint(screenPos + deltaPos);
+ translation = worldPos - centerTransform.position;
+
+ UpdateTransform();
+ }
+ else
+ {
+ // ボタンが離されていれば並進は終了
+ dragState = DragState.None;
+ }
+ }
+
+ // 暂时仅在使用 Legacy Input Manager 时接受滚轮操作
+ #if ENABLE_LEGACY_INPUT_MANAGER
+ // 如果滚轮转动,则进行缩放
+ if (!Mathf.Approximately(Input.GetAxis("Mouse ScrollWheel"), 0f) && IsHit(mousePos))
+ {
+ // 滚轮操作量
+ float wheelDelta = Input.GetAxis("Mouse ScrollWheel") * scaleSensitivity;
+
+ // 更改缩放倍率
+ zoom -= wheelDelta;
+ zoom = Mathf.Clamp(zoom, -1f, 2f); // 视场角的对数范围 [度]
+
+ UpdateTransform();
+ }
+ #endif
+
+ lastMousePosition = mousePos;
+ }
+
+ ///
+ /// 判断鼠标操作时是否点击到对象
+ ///
+ ///
+ internal bool IsHit(Vector3 screenPosition)
+ {
+ RaycastHit hit;
+ Ray ray = currentCamera.ScreenPointToRay(screenPosition);
+
+ if (Physics.Raycast(ray, out hit))
+ {
+ if (hit.transform.IsChildOf(transform)) return true;
+ }
+
+ return false;
+ }
+
+ ///
+ /// 若角度超出指定范围,则进行修正
+ ///
+ ///
+ ///
+ ///
+ ///
+ public static float ClampAngle(float angle, float min, float max)
+ {
+ if (angle < -min) angle = -((-angle) % 360f);
+ if (angle > max) angle = angle % 360f;
+ return Mathf.Clamp(angle, min, max);
+ }
+ }
+}
\ No newline at end of file
diff --git a/Samples~/Common/ModelController.cs.meta b/Samples~/Common/ModelController.cs.meta
new file mode 100644
index 0000000..c758ce4
--- /dev/null
+++ b/Samples~/Common/ModelController.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: 035ad1913e9c28f4492641ca36127790
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Samples~/Common/UiMaterial.mat b/Samples~/Common/UiMaterial.mat
new file mode 100644
index 0000000..14dc3fb
--- /dev/null
+++ b/Samples~/Common/UiMaterial.mat
@@ -0,0 +1,84 @@
+%YAML 1.1
+%TAG !u! tag:unity3d.com,2011:
+--- !u!21 &2100000
+Material:
+ serializedVersion: 6
+ m_ObjectHideFlags: 0
+ m_CorrespondingSourceObject: {fileID: 0}
+ m_PrefabInstance: {fileID: 0}
+ m_PrefabAsset: {fileID: 0}
+ m_Name: UiMaterial
+ m_Shader: {fileID: 10760, guid: 0000000000000000f000000000000000, type: 0}
+ m_ShaderKeywords:
+ m_LightmapFlags: 4
+ m_EnableInstancingVariants: 0
+ m_DoubleSidedGI: 0
+ m_CustomRenderQueue: -1
+ stringTagMap: {}
+ disabledShaderPasses: []
+ m_SavedProperties:
+ serializedVersion: 3
+ m_TexEnvs:
+ - _BumpMap:
+ m_Texture: {fileID: 0}
+ m_Scale: {x: 1, y: 1}
+ m_Offset: {x: 0, y: 0}
+ - _DetailAlbedoMap:
+ m_Texture: {fileID: 0}
+ m_Scale: {x: 1, y: 1}
+ m_Offset: {x: 0, y: 0}
+ - _DetailMask:
+ m_Texture: {fileID: 0}
+ m_Scale: {x: 1, y: 1}
+ m_Offset: {x: 0, y: 0}
+ - _DetailNormalMap:
+ m_Texture: {fileID: 0}
+ m_Scale: {x: 1, y: 1}
+ m_Offset: {x: 0, y: 0}
+ - _EmissionMap:
+ m_Texture: {fileID: 0}
+ m_Scale: {x: 1, y: 1}
+ m_Offset: {x: 0, y: 0}
+ - _MainTex:
+ m_Texture: {fileID: 0}
+ m_Scale: {x: 1, y: 1}
+ m_Offset: {x: 0, y: 0}
+ - _MetallicGlossMap:
+ m_Texture: {fileID: 0}
+ m_Scale: {x: 1, y: 1}
+ m_Offset: {x: 0, y: 0}
+ - _OcclusionMap:
+ m_Texture: {fileID: 0}
+ m_Scale: {x: 1, y: 1}
+ m_Offset: {x: 0, y: 0}
+ - _ParallaxMap:
+ m_Texture: {fileID: 0}
+ m_Scale: {x: 1, y: 1}
+ m_Offset: {x: 0, y: 0}
+ m_Floats:
+ - _BumpScale: 1
+ - _ColorMask: 15
+ - _Cutoff: 0.5
+ - _DetailNormalMapScale: 1
+ - _DstBlend: 0
+ - _GlossMapScale: 1
+ - _Glossiness: 0.5
+ - _GlossyReflections: 1
+ - _Metallic: 0
+ - _Mode: 0
+ - _OcclusionStrength: 1
+ - _Parallax: 0.02
+ - _SmoothnessTextureChannel: 0
+ - _SpecularHighlights: 1
+ - _SrcBlend: 1
+ - _Stencil: 0
+ - _StencilComp: 8
+ - _StencilOp: 0
+ - _StencilReadMask: 255
+ - _StencilWriteMask: 255
+ - _UVSec: 0
+ - _UseUIAlphaClip: 0
+ - _ZWrite: 1
+ m_Colors:
+ - _Color: {r: 1, g: 1, b: 1, a: 0.78431374}
+ - _EmissionColor: {r: 0, g: 0, b: 0, a: 1}
diff --git a/Samples~/Common/UiMaterial.mat.meta b/Samples~/Common/UiMaterial.mat.meta
new file mode 100644
index 0000000..7524ace
--- /dev/null
+++ b/Samples~/Common/UiMaterial.mat.meta
@@ -0,0 +1,8 @@
+fileFormatVersion: 2
+guid: 57c048a21c6552643bb464f9bcd0cf1a
+NativeFormatImporter:
+ externalObjects: {}
+ mainObjectFileID: 2100000
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Samples~/FileDialog/.sample.json b/Samples~/FileDialog/.sample.json
new file mode 100644
index 0000000..c9dc99b
--- /dev/null
+++ b/Samples~/FileDialog/.sample.json
@@ -0,0 +1,5 @@
+{
+ "displayName": "FileDialog",
+ "description": "Demonstrates native file open/save dialog integration.",
+ "createSeparatePackage": false
+}
\ No newline at end of file
diff --git a/Samples~/FileDialog/FileDialogSample.cs b/Samples~/FileDialog/FileDialogSample.cs
new file mode 100644
index 0000000..49db3f5
--- /dev/null
+++ b/Samples~/FileDialog/FileDialogSample.cs
@@ -0,0 +1,97 @@
+using System.Collections;
+using System.Collections.Generic;
+using UnityEngine;
+using UnityEngine.UI;
+
+namespace Kirurobo
+{
+ ///
+ /// 基础文件面板示例
+ ///
+ public class FileDialogSample : MonoBehaviour
+ {
+ public Button openFileButton;
+ public Button openMultipleFilesButton;
+ public Button saveFileButton;
+ public Text messageText;
+
+ // 首次更新前调用 Start
+ void Start()
+ {
+ openFileButton.onClick.AddListener(OpenSingleFile);
+ openMultipleFilesButton.onClick.AddListener(OpenMultipleFiles);
+ saveFileButton.onClick.AddListener(OpenSaveFile);
+ messageText.text = "点击按钮!";
+ }
+
+ // 每帧调用 Update
+ void Update()
+ {
+
+ }
+
+ ///
+ /// 打开单个文件的对话框。
+ ///
+ private void OpenSingleFile() {
+ FilePanel.Settings settings = new FilePanel.Settings();
+ settings.filters = new FilePanel.Filter[]
+ {
+ new FilePanel.Filter("所有文件", "*"),
+ new FilePanel.Filter("图片文件 (*.png;*.jpg;*.jpeg;*.tiff;*.gif;*.tga)", "png", "jpg", "jpeg", "tiff", "gif", "tga"),
+ new FilePanel.Filter("文档 (*.txt;*.rtf;*.doc;*.docx)", "txt", "rtf", "doc", "docx"),
+ };
+ settings.title = "打开文件!";
+ settings.initialDirectory = System.Environment.GetFolderPath(System.Environment.SpecialFolder.MyPictures);
+
+ messageText.text = "";
+ FilePanel.OpenFilePanel(settings, (files) =>
+ {
+ messageText.text = "打开文件\n" + string.Join("\n", files);
+ });
+ }
+
+ ///
+ /// 打开多个文件的对话框。
+ ///
+ private void OpenMultipleFiles() {
+ FilePanel.Settings settings = new FilePanel.Settings();
+ settings.filters = new FilePanel.Filter[]
+ {
+ new FilePanel.Filter("图片文件 (*.png;*.jpg;*.jpeg;*.tiff;*.gif;*.tga)", "png", "jpg", "jpeg", "tiff", "gif", "tga"),
+ new FilePanel.Filter("文档 (*.txt;*.rtf;*.doc;*.docx)", "txt", "rtf", "doc", "docx"),
+ new FilePanel.Filter("所有文件", "*"),
+ };
+ settings.flags = FilePanel.Flag.AllowMultipleSelection;
+ settings.title = "打开多个文件!";
+ settings.initialDirectory = System.Environment.GetFolderPath(System.Environment.SpecialFolder.MyDocuments);
+
+ messageText.text = "";
+ FilePanel.OpenFilePanel(settings, (files) =>
+ {
+ messageText.text = "打开多个文件\n" + string.Join("\n", files);
+ });
+ }
+
+ ///
+ /// 打开保存文件对话框。
+ ///
+ private void OpenSaveFile() {
+ FilePanel.Settings settings = new FilePanel.Settings();
+ settings.filters = new FilePanel.Filter[]
+ {
+ new FilePanel.Filter("文本文件 (*.txt;*.log)", "txt", "log"),
+ new FilePanel.Filter("图片文件 (*.png;*.jpg;*.jpeg;*.tiff;*.gif;*.tga)", "png", "jpg", "jpeg", "tiff", "gif", "tga"),
+ new FilePanel.Filter("所有文件", "*"),
+ };
+ settings.title = "实际上不会执行保存操作";
+ settings.initialFile = "Test.txt";
+
+ messageText.text = "";
+ FilePanel.SaveFilePanel(settings, (files) =>
+ {
+ messageText.text = "选中的文件\n" + string.Join("\n", files);
+ });
+ }
+ }
+}
\ No newline at end of file
diff --git a/Samples~/FileDialog/FileDialogSample.unity b/Samples~/FileDialog/FileDialogSample.unity
new file mode 100644
index 0000000..d87717b
--- /dev/null
+++ b/Samples~/FileDialog/FileDialogSample.unity
@@ -0,0 +1,2063 @@
+%YAML 1.1
+%TAG !u! tag:unity3d.com,2011:
+--- !u!29 &1
+OcclusionCullingSettings:
+ m_ObjectHideFlags: 0
+ serializedVersion: 2
+ m_OcclusionBakeSettings:
+ smallestOccluder: 5
+ smallestHole: 0.25
+ backfaceThreshold: 100
+ m_SceneGUID: 00000000000000000000000000000000
+ m_OcclusionCullingData: {fileID: 0}
+--- !u!104 &2
+RenderSettings:
+ m_ObjectHideFlags: 0
+ serializedVersion: 9
+ m_Fog: 0
+ m_FogColor: {r: 0.5, g: 0.5, b: 0.5, a: 1}
+ m_FogMode: 3
+ m_FogDensity: 0.01
+ m_LinearFogStart: 0
+ m_LinearFogEnd: 300
+ m_AmbientSkyColor: {r: 0.212, g: 0.227, b: 0.259, a: 1}
+ m_AmbientEquatorColor: {r: 0.114, g: 0.125, b: 0.133, a: 1}
+ m_AmbientGroundColor: {r: 0.047, g: 0.043, b: 0.035, a: 1}
+ m_AmbientIntensity: 1
+ m_AmbientMode: 0
+ m_SubtractiveShadowColor: {r: 0.42, g: 0.478, b: 0.627, a: 1}
+ m_SkyboxMaterial: {fileID: 10304, guid: 0000000000000000f000000000000000, type: 0}
+ m_HaloStrength: 0.5
+ m_FlareStrength: 1
+ m_FlareFadeSpeed: 3
+ m_HaloTexture: {fileID: 0}
+ m_SpotCookie: {fileID: 10001, guid: 0000000000000000e000000000000000, type: 0}
+ m_DefaultReflectionMode: 0
+ m_DefaultReflectionResolution: 128
+ m_ReflectionBounces: 1
+ m_ReflectionIntensity: 1
+ m_CustomReflection: {fileID: 0}
+ m_Sun: {fileID: 0}
+ m_IndirectSpecularColor: {r: 0.44657844, g: 0.49641222, b: 0.57481676, a: 1}
+ m_UseRadianceAmbientProbe: 0
+--- !u!157 &3
+LightmapSettings:
+ m_ObjectHideFlags: 0
+ serializedVersion: 12
+ m_GIWorkflowMode: 0
+ m_GISettings:
+ serializedVersion: 2
+ m_BounceScale: 1
+ m_IndirectOutputScale: 1
+ m_AlbedoBoost: 1
+ m_EnvironmentLightingMode: 0
+ m_EnableBakedLightmaps: 1
+ m_EnableRealtimeLightmaps: 1
+ m_LightmapEditorSettings:
+ serializedVersion: 12
+ m_Resolution: 2
+ m_BakeResolution: 40
+ m_AtlasSize: 1024
+ m_AO: 0
+ m_AOMaxDistance: 1
+ m_CompAOExponent: 1
+ m_CompAOExponentDirect: 0
+ m_ExtractAmbientOcclusion: 0
+ m_Padding: 2
+ m_LightmapParameters: {fileID: 0}
+ m_LightmapsBakeMode: 1
+ m_TextureCompression: 1
+ m_FinalGather: 0
+ m_FinalGatherFiltering: 1
+ m_FinalGatherRayCount: 256
+ m_ReflectionCompression: 2
+ m_MixedBakeMode: 2
+ m_BakeBackend: 1
+ m_PVRSampling: 1
+ m_PVRDirectSampleCount: 32
+ m_PVRSampleCount: 500
+ m_PVRBounces: 2
+ m_PVREnvironmentSampleCount: 500
+ m_PVREnvironmentReferencePointCount: 2048
+ m_PVRFilteringMode: 2
+ m_PVRDenoiserTypeDirect: 0
+ m_PVRDenoiserTypeIndirect: 0
+ m_PVRDenoiserTypeAO: 0
+ m_PVRFilterTypeDirect: 0
+ m_PVRFilterTypeIndirect: 0
+ m_PVRFilterTypeAO: 0
+ m_PVREnvironmentMIS: 0
+ m_PVRCulling: 1
+ m_PVRFilteringGaussRadiusDirect: 1
+ m_PVRFilteringGaussRadiusIndirect: 5
+ m_PVRFilteringGaussRadiusAO: 2
+ m_PVRFilteringAtrousPositionSigmaDirect: 0.5
+ m_PVRFilteringAtrousPositionSigmaIndirect: 2
+ m_PVRFilteringAtrousPositionSigmaAO: 1
+ m_ExportTrainingData: 0
+ m_TrainingDataDestination: TrainingData
+ m_LightProbeSampleCountMultiplier: 4
+ m_LightingDataAsset: {fileID: 0}
+ m_LightingSettings: {fileID: 4890085278179872738, guid: 24c3b38da5d7645cca546e4a61bf8980,
+ type: 2}
+--- !u!196 &4
+NavMeshSettings:
+ serializedVersion: 2
+ m_ObjectHideFlags: 0
+ m_BuildSettings:
+ serializedVersion: 3
+ agentTypeID: 0
+ agentRadius: 0.5
+ agentHeight: 2
+ agentSlope: 45
+ agentClimb: 0.4
+ ledgeDropHeight: 0
+ maxJumpAcrossDistance: 0
+ minRegionArea: 2
+ manualCellSize: 0
+ cellSize: 0.16666667
+ manualTileSize: 0
+ tileSize: 256
+ buildHeightMesh: 0
+ maxJobWorkers: 0
+ preserveTilesOutsideBounds: 0
+ debug:
+ m_Flags: 0
+ m_NavMeshData: {fileID: 0}
+--- !u!1 &30811436
+GameObject:
+ m_ObjectHideFlags: 0
+ m_CorrespondingSourceObject: {fileID: 0}
+ m_PrefabInstance: {fileID: 0}
+ m_PrefabAsset: {fileID: 0}
+ serializedVersion: 6
+ m_Component:
+ - component: {fileID: 30811437}
+ - component: {fileID: 30811440}
+ - component: {fileID: 30811439}
+ - component: {fileID: 30811438}
+ m_Layer: 5
+ m_Name: Scroll View
+ m_TagString: Untagged
+ m_Icon: {fileID: 0}
+ m_NavMeshLayer: 0
+ m_StaticEditorFlags: 0
+ m_IsActive: 1
+--- !u!224 &30811437
+RectTransform:
+ m_ObjectHideFlags: 0
+ m_CorrespondingSourceObject: {fileID: 0}
+ m_PrefabInstance: {fileID: 0}
+ m_PrefabAsset: {fileID: 0}
+ m_GameObject: {fileID: 30811436}
+ m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
+ m_LocalPosition: {x: 0, y: 0, z: 0}
+ m_LocalScale: {x: 1, y: 1, z: 1}
+ m_ConstrainProportionsScale: 0
+ m_Children:
+ - {fileID: 246320738}
+ - {fileID: 691758582}
+ - {fileID: 2082900859}
+ m_Father: {fileID: 1115002725}
+ m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
+ m_AnchorMin: {x: 0, y: 1}
+ m_AnchorMax: {x: 1, y: 1}
+ m_AnchoredPosition: {x: 260, y: -10}
+ m_SizeDelta: {x: -270, y: 180}
+ m_Pivot: {x: 0, y: 1}
+--- !u!114 &30811438
+MonoBehaviour:
+ m_ObjectHideFlags: 0
+ m_CorrespondingSourceObject: {fileID: 0}
+ m_PrefabInstance: {fileID: 0}
+ m_PrefabAsset: {fileID: 0}
+ m_GameObject: {fileID: 30811436}
+ m_Enabled: 1
+ m_EditorHideFlags: 0
+ m_Script: {fileID: 11500000, guid: 1aa08ab6e0800fa44ae55d278d1423e3, type: 3}
+ m_Name:
+ m_EditorClassIdentifier:
+ m_Content: {fileID: 1209789489}
+ m_Horizontal: 1
+ m_Vertical: 1
+ m_MovementType: 1
+ m_Elasticity: 0.1
+ m_Inertia: 1
+ m_DecelerationRate: 0.135
+ m_ScrollSensitivity: 1
+ m_Viewport: {fileID: 246320738}
+ m_HorizontalScrollbar: {fileID: 691758583}
+ m_VerticalScrollbar: {fileID: 2082900860}
+ m_HorizontalScrollbarVisibility: 2
+ m_VerticalScrollbarVisibility: 2
+ m_HorizontalScrollbarSpacing: -3
+ m_VerticalScrollbarSpacing: -3
+ m_OnValueChanged:
+ m_PersistentCalls:
+ m_Calls: []
+--- !u!114 &30811439
+MonoBehaviour:
+ m_ObjectHideFlags: 0
+ m_CorrespondingSourceObject: {fileID: 0}
+ m_PrefabInstance: {fileID: 0}
+ m_PrefabAsset: {fileID: 0}
+ m_GameObject: {fileID: 30811436}
+ m_Enabled: 1
+ m_EditorHideFlags: 0
+ m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3}
+ m_Name:
+ m_EditorClassIdentifier:
+ m_Material: {fileID: 0}
+ m_Color: {r: 1, g: 1, b: 1, a: 0.392}
+ m_RaycastTarget: 1
+ m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0}
+ m_Maskable: 1
+ m_OnCullStateChanged:
+ m_PersistentCalls:
+ m_Calls: []
+ m_Sprite: {fileID: 10907, guid: 0000000000000000f000000000000000, type: 0}
+ m_Type: 1
+ m_PreserveAspect: 0
+ m_FillCenter: 1
+ m_FillMethod: 4
+ m_FillAmount: 1
+ m_FillClockwise: 1
+ m_FillOrigin: 0
+ m_UseSpriteMesh: 0
+ m_PixelsPerUnitMultiplier: 1
+--- !u!222 &30811440
+CanvasRenderer:
+ m_ObjectHideFlags: 0
+ m_CorrespondingSourceObject: {fileID: 0}
+ m_PrefabInstance: {fileID: 0}
+ m_PrefabAsset: {fileID: 0}
+ m_GameObject: {fileID: 30811436}
+ m_CullTransparentMesh: 1
+--- !u!1 &223023792
+GameObject:
+ m_ObjectHideFlags: 0
+ m_CorrespondingSourceObject: {fileID: 0}
+ m_PrefabInstance: {fileID: 0}
+ m_PrefabAsset: {fileID: 0}
+ serializedVersion: 6
+ m_Component:
+ - component: {fileID: 223023793}
+ m_Layer: 5
+ m_Name: Sliding Area
+ m_TagString: Untagged
+ m_Icon: {fileID: 0}
+ m_NavMeshLayer: 0
+ m_StaticEditorFlags: 0
+ m_IsActive: 1
+--- !u!224 &223023793
+RectTransform:
+ m_ObjectHideFlags: 0
+ m_CorrespondingSourceObject: {fileID: 0}
+ m_PrefabInstance: {fileID: 0}
+ m_PrefabAsset: {fileID: 0}
+ m_GameObject: {fileID: 223023792}
+ m_LocalRotation: {x: -0, y: -0, z: -0, w: 1}
+ m_LocalPosition: {x: 0, y: 0, z: 0}
+ m_LocalScale: {x: 1, y: 1, z: 1}
+ m_ConstrainProportionsScale: 0
+ m_Children:
+ - {fileID: 1486794694}
+ m_Father: {fileID: 691758582}
+ m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
+ m_AnchorMin: {x: 0, y: 0}
+ m_AnchorMax: {x: 1, y: 1}
+ m_AnchoredPosition: {x: 0, y: 0}
+ m_SizeDelta: {x: -20, y: -20}
+ m_Pivot: {x: 0.5, y: 0.5}
+--- !u!1 &246320737
+GameObject:
+ m_ObjectHideFlags: 0
+ m_CorrespondingSourceObject: {fileID: 0}
+ m_PrefabInstance: {fileID: 0}
+ m_PrefabAsset: {fileID: 0}
+ serializedVersion: 6
+ m_Component:
+ - component: {fileID: 246320738}
+ - component: {fileID: 246320741}
+ - component: {fileID: 246320740}
+ - component: {fileID: 246320739}
+ m_Layer: 5
+ m_Name: Viewport
+ m_TagString: Untagged
+ m_Icon: {fileID: 0}
+ m_NavMeshLayer: 0
+ m_StaticEditorFlags: 0
+ m_IsActive: 1
+--- !u!224 &246320738
+RectTransform:
+ m_ObjectHideFlags: 0
+ m_CorrespondingSourceObject: {fileID: 0}
+ m_PrefabInstance: {fileID: 0}
+ m_PrefabAsset: {fileID: 0}
+ m_GameObject: {fileID: 246320737}
+ m_LocalRotation: {x: -0, y: -0, z: -0, w: 1}
+ m_LocalPosition: {x: 0, y: 0, z: 0}
+ m_LocalScale: {x: 1, y: 1, z: 1}
+ m_ConstrainProportionsScale: 0
+ m_Children:
+ - {fileID: 1209789489}
+ m_Father: {fileID: 30811437}
+ m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
+ m_AnchorMin: {x: 0, y: 0}
+ m_AnchorMax: {x: 0, y: 0}
+ m_AnchoredPosition: {x: 0, y: 0}
+ m_SizeDelta: {x: 0, y: 0}
+ m_Pivot: {x: 0, y: 1}
+--- !u!114 &246320739
+MonoBehaviour:
+ m_ObjectHideFlags: 0
+ m_CorrespondingSourceObject: {fileID: 0}
+ m_PrefabInstance: {fileID: 0}
+ m_PrefabAsset: {fileID: 0}
+ m_GameObject: {fileID: 246320737}
+ m_Enabled: 1
+ m_EditorHideFlags: 0
+ m_Script: {fileID: 11500000, guid: 31a19414c41e5ae4aae2af33fee712f6, type: 3}
+ m_Name:
+ m_EditorClassIdentifier:
+ m_ShowMaskGraphic: 0
+--- !u!114 &246320740
+MonoBehaviour:
+ m_ObjectHideFlags: 0
+ m_CorrespondingSourceObject: {fileID: 0}
+ m_PrefabInstance: {fileID: 0}
+ m_PrefabAsset: {fileID: 0}
+ m_GameObject: {fileID: 246320737}
+ m_Enabled: 1
+ m_EditorHideFlags: 0
+ m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3}
+ m_Name:
+ m_EditorClassIdentifier:
+ m_Material: {fileID: 0}
+ m_Color: {r: 1, g: 1, b: 1, a: 1}
+ m_RaycastTarget: 1
+ m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0}
+ m_Maskable: 1
+ m_OnCullStateChanged:
+ m_PersistentCalls:
+ m_Calls: []
+ m_Sprite: {fileID: 10917, guid: 0000000000000000f000000000000000, type: 0}
+ m_Type: 1
+ m_PreserveAspect: 0
+ m_FillCenter: 1
+ m_FillMethod: 4
+ m_FillAmount: 1
+ m_FillClockwise: 1
+ m_FillOrigin: 0
+ m_UseSpriteMesh: 0
+ m_PixelsPerUnitMultiplier: 1
+--- !u!222 &246320741
+CanvasRenderer:
+ m_ObjectHideFlags: 0
+ m_CorrespondingSourceObject: {fileID: 0}
+ m_PrefabInstance: {fileID: 0}
+ m_PrefabAsset: {fileID: 0}
+ m_GameObject: {fileID: 246320737}
+ m_CullTransparentMesh: 1
+--- !u!1 &474919455
+GameObject:
+ m_ObjectHideFlags: 0
+ m_CorrespondingSourceObject: {fileID: 0}
+ m_PrefabInstance: {fileID: 0}
+ m_PrefabAsset: {fileID: 0}
+ serializedVersion: 6
+ m_Component:
+ - component: {fileID: 474919456}
+ - component: {fileID: 474919458}
+ - component: {fileID: 474919457}
+ m_Layer: 5
+ m_Name: Handle
+ m_TagString: Untagged
+ m_Icon: {fileID: 0}
+ m_NavMeshLayer: 0
+ m_StaticEditorFlags: 0
+ m_IsActive: 1
+--- !u!224 &474919456
+RectTransform:
+ m_ObjectHideFlags: 0
+ m_CorrespondingSourceObject: {fileID: 0}
+ m_PrefabInstance: {fileID: 0}
+ m_PrefabAsset: {fileID: 0}
+ m_GameObject: {fileID: 474919455}
+ m_LocalRotation: {x: -0, y: -0, z: -0, w: 1}
+ m_LocalPosition: {x: 0, y: 0, z: 0}
+ m_LocalScale: {x: 1, y: 1, z: 1}
+ m_ConstrainProportionsScale: 0
+ m_Children: []
+ m_Father: {fileID: 651359272}
+ m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
+ m_AnchorMin: {x: 0, y: 0}
+ m_AnchorMax: {x: 0, y: 0}
+ m_AnchoredPosition: {x: 0, y: 0}
+ m_SizeDelta: {x: 20, y: 20}
+ m_Pivot: {x: 0.5, y: 0.5}
+--- !u!114 &474919457
+MonoBehaviour:
+ m_ObjectHideFlags: 0
+ m_CorrespondingSourceObject: {fileID: 0}
+ m_PrefabInstance: {fileID: 0}
+ m_PrefabAsset: {fileID: 0}
+ m_GameObject: {fileID: 474919455}
+ m_Enabled: 1
+ m_EditorHideFlags: 0
+ m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3}
+ m_Name:
+ m_EditorClassIdentifier:
+ m_Material: {fileID: 0}
+ m_Color: {r: 1, g: 1, b: 1, a: 1}
+ m_RaycastTarget: 1
+ m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0}
+ m_Maskable: 1
+ m_OnCullStateChanged:
+ m_PersistentCalls:
+ m_Calls: []
+ m_Sprite: {fileID: 10905, guid: 0000000000000000f000000000000000, type: 0}
+ m_Type: 1
+ m_PreserveAspect: 0
+ m_FillCenter: 1
+ m_FillMethod: 4
+ m_FillAmount: 1
+ m_FillClockwise: 1
+ m_FillOrigin: 0
+ m_UseSpriteMesh: 0
+ m_PixelsPerUnitMultiplier: 1
+--- !u!222 &474919458
+CanvasRenderer:
+ m_ObjectHideFlags: 0
+ m_CorrespondingSourceObject: {fileID: 0}
+ m_PrefabInstance: {fileID: 0}
+ m_PrefabAsset: {fileID: 0}
+ m_GameObject: {fileID: 474919455}
+ m_CullTransparentMesh: 1
+--- !u!1 &482449624
+GameObject:
+ m_ObjectHideFlags: 0
+ m_CorrespondingSourceObject: {fileID: 0}
+ m_PrefabInstance: {fileID: 0}
+ m_PrefabAsset: {fileID: 0}
+ serializedVersion: 6
+ m_Component:
+ - component: {fileID: 482449625}
+ - component: {fileID: 482449628}
+ - component: {fileID: 482449627}
+ - component: {fileID: 482449626}
+ m_Layer: 5
+ m_Name: Button01
+ m_TagString: Untagged
+ m_Icon: {fileID: 0}
+ m_NavMeshLayer: 0
+ m_StaticEditorFlags: 0
+ m_IsActive: 1
+--- !u!224 &482449625
+RectTransform:
+ m_ObjectHideFlags: 0
+ m_CorrespondingSourceObject: {fileID: 0}
+ m_PrefabInstance: {fileID: 0}
+ m_PrefabAsset: {fileID: 0}
+ m_GameObject: {fileID: 482449624}
+ m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
+ m_LocalPosition: {x: 0, y: 0, z: 0}
+ m_LocalScale: {x: 1, y: 1, z: 1}
+ m_ConstrainProportionsScale: 0
+ m_Children:
+ - {fileID: 1987906028}
+ m_Father: {fileID: 1115002725}
+ m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
+ m_AnchorMin: {x: 0, y: 1}
+ m_AnchorMax: {x: 0, y: 1}
+ m_AnchoredPosition: {x: 10, y: -10}
+ m_SizeDelta: {x: 240, y: 40}
+ m_Pivot: {x: 0, y: 1}
+--- !u!114 &482449626
+MonoBehaviour:
+ m_ObjectHideFlags: 0
+ m_CorrespondingSourceObject: {fileID: 0}
+ m_PrefabInstance: {fileID: 0}
+ m_PrefabAsset: {fileID: 0}
+ m_GameObject: {fileID: 482449624}
+ m_Enabled: 1
+ m_EditorHideFlags: 0
+ m_Script: {fileID: 11500000, guid: 4e29b1a8efbd4b44bb3f3716e73f07ff, type: 3}
+ m_Name:
+ m_EditorClassIdentifier:
+ m_Navigation:
+ m_Mode: 3
+ m_WrapAround: 0
+ m_SelectOnUp: {fileID: 0}
+ m_SelectOnDown: {fileID: 0}
+ m_SelectOnLeft: {fileID: 0}
+ m_SelectOnRight: {fileID: 0}
+ m_Transition: 1
+ m_Colors:
+ m_NormalColor: {r: 1, g: 1, b: 1, a: 1}
+ m_HighlightedColor: {r: 0.9607843, g: 0.9607843, b: 0.9607843, a: 1}
+ m_PressedColor: {r: 0.78431374, g: 0.78431374, b: 0.78431374, a: 1}
+ m_SelectedColor: {r: 0.9607843, g: 0.9607843, b: 0.9607843, a: 1}
+ m_DisabledColor: {r: 0.78431374, g: 0.78431374, b: 0.78431374, a: 0.5019608}
+ m_ColorMultiplier: 1
+ m_FadeDuration: 0.1
+ m_SpriteState:
+ m_HighlightedSprite: {fileID: 0}
+ m_PressedSprite: {fileID: 0}
+ m_SelectedSprite: {fileID: 0}
+ m_DisabledSprite: {fileID: 0}
+ m_AnimationTriggers:
+ m_NormalTrigger: Normal
+ m_HighlightedTrigger: Highlighted
+ m_PressedTrigger: Pressed
+ m_SelectedTrigger: Selected
+ m_DisabledTrigger: Disabled
+ m_Interactable: 1
+ m_TargetGraphic: {fileID: 482449627}
+ m_OnClick:
+ m_PersistentCalls:
+ m_Calls:
+ - m_Target: {fileID: 0}
+ m_TargetAssemblyTypeName: Kirurobo.SampleManager, Assembly-CSharp
+ m_MethodName: LoadScene
+ m_Mode: 5
+ m_Arguments:
+ m_ObjectArgument: {fileID: 0}
+ m_ObjectArgumentAssemblyTypeName: UnityEngine.Object, UnityEngine
+ m_IntArgument: 0
+ m_FloatArgument: 0
+ m_StringArgument: SimpleSample
+ m_BoolArgument: 0
+ m_CallState: 2
+--- !u!114 &482449627
+MonoBehaviour:
+ m_ObjectHideFlags: 0
+ m_CorrespondingSourceObject: {fileID: 0}
+ m_PrefabInstance: {fileID: 0}
+ m_PrefabAsset: {fileID: 0}
+ m_GameObject: {fileID: 482449624}
+ m_Enabled: 1
+ m_EditorHideFlags: 0
+ m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3}
+ m_Name:
+ m_EditorClassIdentifier:
+ m_Material: {fileID: 0}
+ m_Color: {r: 1, g: 1, b: 1, a: 1}
+ m_RaycastTarget: 1
+ m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0}
+ m_Maskable: 1
+ m_OnCullStateChanged:
+ m_PersistentCalls:
+ m_Calls: []
+ m_Sprite: {fileID: 10905, guid: 0000000000000000f000000000000000, type: 0}
+ m_Type: 1
+ m_PreserveAspect: 0
+ m_FillCenter: 1
+ m_FillMethod: 4
+ m_FillAmount: 1
+ m_FillClockwise: 1
+ m_FillOrigin: 0
+ m_UseSpriteMesh: 0
+ m_PixelsPerUnitMultiplier: 1
+--- !u!222 &482449628
+CanvasRenderer:
+ m_ObjectHideFlags: 0
+ m_CorrespondingSourceObject: {fileID: 0}
+ m_PrefabInstance: {fileID: 0}
+ m_PrefabAsset: {fileID: 0}
+ m_GameObject: {fileID: 482449624}
+ m_CullTransparentMesh: 1
+--- !u!1 &590190060
+GameObject:
+ m_ObjectHideFlags: 0
+ m_CorrespondingSourceObject: {fileID: 0}
+ m_PrefabInstance: {fileID: 0}
+ m_PrefabAsset: {fileID: 0}
+ serializedVersion: 6
+ m_Component:
+ - component: {fileID: 590190063}
+ - component: {fileID: 590190062}
+ - component: {fileID: 590190064}
+ m_Layer: 0
+ m_Name: EventSystem
+ m_TagString: Untagged
+ m_Icon: {fileID: 0}
+ m_NavMeshLayer: 0
+ m_StaticEditorFlags: 0
+ m_IsActive: 1
+--- !u!114 &590190062
+MonoBehaviour:
+ m_ObjectHideFlags: 0
+ m_CorrespondingSourceObject: {fileID: 0}
+ m_PrefabInstance: {fileID: 0}
+ m_PrefabAsset: {fileID: 0}
+ m_GameObject: {fileID: 590190060}
+ m_Enabled: 1
+ m_EditorHideFlags: 0
+ m_Script: {fileID: 11500000, guid: 76c392e42b5098c458856cdf6ecaaaa1, type: 3}
+ m_Name:
+ m_EditorClassIdentifier:
+ m_FirstSelected: {fileID: 0}
+ m_sendNavigationEvents: 1
+ m_DragThreshold: 10
+--- !u!4 &590190063
+Transform:
+ m_ObjectHideFlags: 0
+ m_CorrespondingSourceObject: {fileID: 0}
+ m_PrefabInstance: {fileID: 0}
+ m_PrefabAsset: {fileID: 0}
+ m_GameObject: {fileID: 590190060}
+ serializedVersion: 2
+ m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
+ m_LocalPosition: {x: 0, y: 0, z: 0}
+ m_LocalScale: {x: 1, y: 1, z: 1}
+ m_ConstrainProportionsScale: 0
+ m_Children: []
+ m_Father: {fileID: 0}
+ m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
+--- !u!114 &590190064
+MonoBehaviour:
+ m_ObjectHideFlags: 0
+ m_CorrespondingSourceObject: {fileID: 0}
+ m_PrefabInstance: {fileID: 0}
+ m_PrefabAsset: {fileID: 0}
+ m_GameObject: {fileID: 590190060}
+ m_Enabled: 1
+ m_EditorHideFlags: 0
+ m_Script: {fileID: 11500000, guid: ce6b387a66b0e654d9eb8712d70fff48, type: 3}
+ m_Name:
+ m_EditorClassIdentifier:
+ m_SendPointerHoverToParent: 1
+ m_MoveRepeatDelay: 0.5
+ m_MoveRepeatRate: 0.1
+ m_XRTrackingOrigin: {fileID: 0}
+ m_ActionsAsset: {fileID: -944628639613478452, guid: ca9f5fa95ffab41fb9a615ab714db018,
+ type: 3}
+ m_PointAction: {fileID: -1654692200621890270, guid: ca9f5fa95ffab41fb9a615ab714db018,
+ type: 3}
+ m_MoveAction: {fileID: -8784545083839296357, guid: ca9f5fa95ffab41fb9a615ab714db018,
+ type: 3}
+ m_SubmitAction: {fileID: 392368643174621059, guid: ca9f5fa95ffab41fb9a615ab714db018,
+ type: 3}
+ m_CancelAction: {fileID: 7727032971491509709, guid: ca9f5fa95ffab41fb9a615ab714db018,
+ type: 3}
+ m_LeftClickAction: {fileID: 3001919216989983466, guid: ca9f5fa95ffab41fb9a615ab714db018,
+ type: 3}
+ m_MiddleClickAction: {fileID: -2185481485913320682, guid: ca9f5fa95ffab41fb9a615ab714db018,
+ type: 3}
+ m_RightClickAction: {fileID: -4090225696740746782, guid: ca9f5fa95ffab41fb9a615ab714db018,
+ type: 3}
+ m_ScrollWheelAction: {fileID: 6240969308177333660, guid: ca9f5fa95ffab41fb9a615ab714db018,
+ type: 3}
+ m_TrackedDevicePositionAction: {fileID: 6564999863303420839, guid: ca9f5fa95ffab41fb9a615ab714db018,
+ type: 3}
+ m_TrackedDeviceOrientationAction: {fileID: 7970375526676320489, guid: ca9f5fa95ffab41fb9a615ab714db018,
+ type: 3}
+ m_DeselectOnBackgroundClick: 1
+ m_PointerBehavior: 0
+ m_CursorLockBehavior: 0
+--- !u!1 &651359271
+GameObject:
+ m_ObjectHideFlags: 0
+ m_CorrespondingSourceObject: {fileID: 0}
+ m_PrefabInstance: {fileID: 0}
+ m_PrefabAsset: {fileID: 0}
+ serializedVersion: 6
+ m_Component:
+ - component: {fileID: 651359272}
+ m_Layer: 5
+ m_Name: Sliding Area
+ m_TagString: Untagged
+ m_Icon: {fileID: 0}
+ m_NavMeshLayer: 0
+ m_StaticEditorFlags: 0
+ m_IsActive: 1
+--- !u!224 &651359272
+RectTransform:
+ m_ObjectHideFlags: 0
+ m_CorrespondingSourceObject: {fileID: 0}
+ m_PrefabInstance: {fileID: 0}
+ m_PrefabAsset: {fileID: 0}
+ m_GameObject: {fileID: 651359271}
+ m_LocalRotation: {x: -0, y: -0, z: -0, w: 1}
+ m_LocalPosition: {x: 0, y: 0, z: 0}
+ m_LocalScale: {x: 1, y: 1, z: 1}
+ m_ConstrainProportionsScale: 0
+ m_Children:
+ - {fileID: 474919456}
+ m_Father: {fileID: 2082900859}
+ m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
+ m_AnchorMin: {x: 0, y: 0}
+ m_AnchorMax: {x: 1, y: 1}
+ m_AnchoredPosition: {x: 0, y: 0}
+ m_SizeDelta: {x: -20, y: -20}
+ m_Pivot: {x: 0.5, y: 0.5}
+--- !u!1 &691758581
+GameObject:
+ m_ObjectHideFlags: 0
+ m_CorrespondingSourceObject: {fileID: 0}
+ m_PrefabInstance: {fileID: 0}
+ m_PrefabAsset: {fileID: 0}
+ serializedVersion: 6
+ m_Component:
+ - component: {fileID: 691758582}
+ - component: {fileID: 691758585}
+ - component: {fileID: 691758584}
+ - component: {fileID: 691758583}
+ m_Layer: 5
+ m_Name: Scrollbar Horizontal
+ m_TagString: Untagged
+ m_Icon: {fileID: 0}
+ m_NavMeshLayer: 0
+ m_StaticEditorFlags: 0
+ m_IsActive: 1
+--- !u!224 &691758582
+RectTransform:
+ m_ObjectHideFlags: 0
+ m_CorrespondingSourceObject: {fileID: 0}
+ m_PrefabInstance: {fileID: 0}
+ m_PrefabAsset: {fileID: 0}
+ m_GameObject: {fileID: 691758581}
+ m_LocalRotation: {x: -0, y: -0, z: -0, w: 1}
+ m_LocalPosition: {x: 0, y: 0, z: 0}
+ m_LocalScale: {x: 1, y: 1, z: 1}
+ m_ConstrainProportionsScale: 0
+ m_Children:
+ - {fileID: 223023793}
+ m_Father: {fileID: 30811437}
+ m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
+ m_AnchorMin: {x: 0, y: 0}
+ m_AnchorMax: {x: 0, y: 0}
+ m_AnchoredPosition: {x: 0, y: 0}
+ m_SizeDelta: {x: 0, y: 20}
+ m_Pivot: {x: 0, y: 0}
+--- !u!114 &691758583
+MonoBehaviour:
+ m_ObjectHideFlags: 0
+ m_CorrespondingSourceObject: {fileID: 0}
+ m_PrefabInstance: {fileID: 0}
+ m_PrefabAsset: {fileID: 0}
+ m_GameObject: {fileID: 691758581}
+ m_Enabled: 1
+ m_EditorHideFlags: 0
+ m_Script: {fileID: 11500000, guid: 2a4db7a114972834c8e4117be1d82ba3, type: 3}
+ m_Name:
+ m_EditorClassIdentifier:
+ m_Navigation:
+ m_Mode: 3
+ m_WrapAround: 0
+ m_SelectOnUp: {fileID: 0}
+ m_SelectOnDown: {fileID: 0}
+ m_SelectOnLeft: {fileID: 0}
+ m_SelectOnRight: {fileID: 0}
+ m_Transition: 1
+ m_Colors:
+ m_NormalColor: {r: 1, g: 1, b: 1, a: 1}
+ m_HighlightedColor: {r: 0.9607843, g: 0.9607843, b: 0.9607843, a: 1}
+ m_PressedColor: {r: 0.78431374, g: 0.78431374, b: 0.78431374, a: 1}
+ m_SelectedColor: {r: 0.9607843, g: 0.9607843, b: 0.9607843, a: 1}
+ m_DisabledColor: {r: 0.78431374, g: 0.78431374, b: 0.78431374, a: 0.5019608}
+ m_ColorMultiplier: 1
+ m_FadeDuration: 0.1
+ m_SpriteState:
+ m_HighlightedSprite: {fileID: 0}
+ m_PressedSprite: {fileID: 0}
+ m_SelectedSprite: {fileID: 0}
+ m_DisabledSprite: {fileID: 0}
+ m_AnimationTriggers:
+ m_NormalTrigger: Normal
+ m_HighlightedTrigger: Highlighted
+ m_PressedTrigger: Pressed
+ m_SelectedTrigger: Selected
+ m_DisabledTrigger: Disabled
+ m_Interactable: 1
+ m_TargetGraphic: {fileID: 1486794695}
+ m_HandleRect: {fileID: 1486794694}
+ m_Direction: 0
+ m_Value: 0
+ m_Size: 1
+ m_NumberOfSteps: 0
+ m_OnValueChanged:
+ m_PersistentCalls:
+ m_Calls: []
+--- !u!114 &691758584
+MonoBehaviour:
+ m_ObjectHideFlags: 0
+ m_CorrespondingSourceObject: {fileID: 0}
+ m_PrefabInstance: {fileID: 0}
+ m_PrefabAsset: {fileID: 0}
+ m_GameObject: {fileID: 691758581}
+ m_Enabled: 1
+ m_EditorHideFlags: 0
+ m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3}
+ m_Name:
+ m_EditorClassIdentifier:
+ m_Material: {fileID: 0}
+ m_Color: {r: 1, g: 1, b: 1, a: 1}
+ m_RaycastTarget: 1
+ m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0}
+ m_Maskable: 1
+ m_OnCullStateChanged:
+ m_PersistentCalls:
+ m_Calls: []
+ m_Sprite: {fileID: 10907, guid: 0000000000000000f000000000000000, type: 0}
+ m_Type: 1
+ m_PreserveAspect: 0
+ m_FillCenter: 1
+ m_FillMethod: 4
+ m_FillAmount: 1
+ m_FillClockwise: 1
+ m_FillOrigin: 0
+ m_UseSpriteMesh: 0
+ m_PixelsPerUnitMultiplier: 1
+--- !u!222 &691758585
+CanvasRenderer:
+ m_ObjectHideFlags: 0
+ m_CorrespondingSourceObject: {fileID: 0}
+ m_PrefabInstance: {fileID: 0}
+ m_PrefabAsset: {fileID: 0}
+ m_GameObject: {fileID: 691758581}
+ m_CullTransparentMesh: 1
+--- !u!1 &925578655
+GameObject:
+ m_ObjectHideFlags: 0
+ m_CorrespondingSourceObject: {fileID: 0}
+ m_PrefabInstance: {fileID: 0}
+ m_PrefabAsset: {fileID: 0}
+ serializedVersion: 6
+ m_Component:
+ - component: {fileID: 925578656}
+ - component: {fileID: 925578659}
+ - component: {fileID: 925578658}
+ - component: {fileID: 925578657}
+ m_Layer: 5
+ m_Name: Button02
+ m_TagString: Untagged
+ m_Icon: {fileID: 0}
+ m_NavMeshLayer: 0
+ m_StaticEditorFlags: 0
+ m_IsActive: 1
+--- !u!224 &925578656
+RectTransform:
+ m_ObjectHideFlags: 0
+ m_CorrespondingSourceObject: {fileID: 0}
+ m_PrefabInstance: {fileID: 0}
+ m_PrefabAsset: {fileID: 0}
+ m_GameObject: {fileID: 925578655}
+ m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
+ m_LocalPosition: {x: 0, y: 0, z: 0}
+ m_LocalScale: {x: 1, y: 1, z: 1}
+ m_ConstrainProportionsScale: 0
+ m_Children:
+ - {fileID: 2062578109}
+ m_Father: {fileID: 1115002725}
+ m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
+ m_AnchorMin: {x: 0, y: 1}
+ m_AnchorMax: {x: 0, y: 1}
+ m_AnchoredPosition: {x: 10, y: -50}
+ m_SizeDelta: {x: 240, y: 40}
+ m_Pivot: {x: 0, y: 1}
+--- !u!114 &925578657
+MonoBehaviour:
+ m_ObjectHideFlags: 0
+ m_CorrespondingSourceObject: {fileID: 0}
+ m_PrefabInstance: {fileID: 0}
+ m_PrefabAsset: {fileID: 0}
+ m_GameObject: {fileID: 925578655}
+ m_Enabled: 1
+ m_EditorHideFlags: 0
+ m_Script: {fileID: 11500000, guid: 4e29b1a8efbd4b44bb3f3716e73f07ff, type: 3}
+ m_Name:
+ m_EditorClassIdentifier:
+ m_Navigation:
+ m_Mode: 3
+ m_WrapAround: 0
+ m_SelectOnUp: {fileID: 0}
+ m_SelectOnDown: {fileID: 0}
+ m_SelectOnLeft: {fileID: 0}
+ m_SelectOnRight: {fileID: 0}
+ m_Transition: 1
+ m_Colors:
+ m_NormalColor: {r: 1, g: 1, b: 1, a: 1}
+ m_HighlightedColor: {r: 0.9607843, g: 0.9607843, b: 0.9607843, a: 1}
+ m_PressedColor: {r: 0.78431374, g: 0.78431374, b: 0.78431374, a: 1}
+ m_SelectedColor: {r: 0.9607843, g: 0.9607843, b: 0.9607843, a: 1}
+ m_DisabledColor: {r: 0.78431374, g: 0.78431374, b: 0.78431374, a: 0.5019608}
+ m_ColorMultiplier: 1
+ m_FadeDuration: 0.1
+ m_SpriteState:
+ m_HighlightedSprite: {fileID: 0}
+ m_PressedSprite: {fileID: 0}
+ m_SelectedSprite: {fileID: 0}
+ m_DisabledSprite: {fileID: 0}
+ m_AnimationTriggers:
+ m_NormalTrigger: Normal
+ m_HighlightedTrigger: Highlighted
+ m_PressedTrigger: Pressed
+ m_SelectedTrigger: Selected
+ m_DisabledTrigger: Disabled
+ m_Interactable: 1
+ m_TargetGraphic: {fileID: 925578658}
+ m_OnClick:
+ m_PersistentCalls:
+ m_Calls:
+ - m_Target: {fileID: 0}
+ m_TargetAssemblyTypeName: Kirurobo.SampleManager, Assembly-CSharp
+ m_MethodName: LoadScene
+ m_Mode: 5
+ m_Arguments:
+ m_ObjectArgument: {fileID: 0}
+ m_ObjectArgumentAssemblyTypeName: UnityEngine.Object, UnityEngine
+ m_IntArgument: 0
+ m_FloatArgument: 0
+ m_StringArgument: UiSample
+ m_BoolArgument: 0
+ m_CallState: 2
+--- !u!114 &925578658
+MonoBehaviour:
+ m_ObjectHideFlags: 0
+ m_CorrespondingSourceObject: {fileID: 0}
+ m_PrefabInstance: {fileID: 0}
+ m_PrefabAsset: {fileID: 0}
+ m_GameObject: {fileID: 925578655}
+ m_Enabled: 1
+ m_EditorHideFlags: 0
+ m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3}
+ m_Name:
+ m_EditorClassIdentifier:
+ m_Material: {fileID: 0}
+ m_Color: {r: 1, g: 1, b: 1, a: 1}
+ m_RaycastTarget: 1
+ m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0}
+ m_Maskable: 1
+ m_OnCullStateChanged:
+ m_PersistentCalls:
+ m_Calls: []
+ m_Sprite: {fileID: 10905, guid: 0000000000000000f000000000000000, type: 0}
+ m_Type: 1
+ m_PreserveAspect: 0
+ m_FillCenter: 1
+ m_FillMethod: 4
+ m_FillAmount: 1
+ m_FillClockwise: 1
+ m_FillOrigin: 0
+ m_UseSpriteMesh: 0
+ m_PixelsPerUnitMultiplier: 1
+--- !u!222 &925578659
+CanvasRenderer:
+ m_ObjectHideFlags: 0
+ m_CorrespondingSourceObject: {fileID: 0}
+ m_PrefabInstance: {fileID: 0}
+ m_PrefabAsset: {fileID: 0}
+ m_GameObject: {fileID: 925578655}
+ m_CullTransparentMesh: 1
+--- !u!1 &989311917
+GameObject:
+ m_ObjectHideFlags: 0
+ m_CorrespondingSourceObject: {fileID: 0}
+ m_PrefabInstance: {fileID: 0}
+ m_PrefabAsset: {fileID: 0}
+ serializedVersion: 6
+ m_Component:
+ - component: {fileID: 989311918}
+ - component: {fileID: 989311921}
+ - component: {fileID: 989311920}
+ - component: {fileID: 989311919}
+ m_Layer: 5
+ m_Name: Button03
+ m_TagString: Untagged
+ m_Icon: {fileID: 0}
+ m_NavMeshLayer: 0
+ m_StaticEditorFlags: 0
+ m_IsActive: 1
+--- !u!224 &989311918
+RectTransform:
+ m_ObjectHideFlags: 0
+ m_CorrespondingSourceObject: {fileID: 0}
+ m_PrefabInstance: {fileID: 0}
+ m_PrefabAsset: {fileID: 0}
+ m_GameObject: {fileID: 989311917}
+ m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
+ m_LocalPosition: {x: 0, y: 0, z: 0}
+ m_LocalScale: {x: 1, y: 1, z: 1}
+ m_ConstrainProportionsScale: 0
+ m_Children:
+ - {fileID: 1161899926}
+ m_Father: {fileID: 1115002725}
+ m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
+ m_AnchorMin: {x: 0, y: 1}
+ m_AnchorMax: {x: 0, y: 1}
+ m_AnchoredPosition: {x: 10, y: -100}
+ m_SizeDelta: {x: 240, y: 40}
+ m_Pivot: {x: 0, y: 1}
+--- !u!114 &989311919
+MonoBehaviour:
+ m_ObjectHideFlags: 0
+ m_CorrespondingSourceObject: {fileID: 0}
+ m_PrefabInstance: {fileID: 0}
+ m_PrefabAsset: {fileID: 0}
+ m_GameObject: {fileID: 989311917}
+ m_Enabled: 1
+ m_EditorHideFlags: 0
+ m_Script: {fileID: 11500000, guid: 4e29b1a8efbd4b44bb3f3716e73f07ff, type: 3}
+ m_Name:
+ m_EditorClassIdentifier:
+ m_Navigation:
+ m_Mode: 3
+ m_WrapAround: 0
+ m_SelectOnUp: {fileID: 0}
+ m_SelectOnDown: {fileID: 0}
+ m_SelectOnLeft: {fileID: 0}
+ m_SelectOnRight: {fileID: 0}
+ m_Transition: 1
+ m_Colors:
+ m_NormalColor: {r: 1, g: 1, b: 1, a: 1}
+ m_HighlightedColor: {r: 0.9607843, g: 0.9607843, b: 0.9607843, a: 1}
+ m_PressedColor: {r: 0.78431374, g: 0.78431374, b: 0.78431374, a: 1}
+ m_SelectedColor: {r: 0.9607843, g: 0.9607843, b: 0.9607843, a: 1}
+ m_DisabledColor: {r: 0.78431374, g: 0.78431374, b: 0.78431374, a: 0.5019608}
+ m_ColorMultiplier: 1
+ m_FadeDuration: 0.1
+ m_SpriteState:
+ m_HighlightedSprite: {fileID: 0}
+ m_PressedSprite: {fileID: 0}
+ m_SelectedSprite: {fileID: 0}
+ m_DisabledSprite: {fileID: 0}
+ m_AnimationTriggers:
+ m_NormalTrigger: Normal
+ m_HighlightedTrigger: Highlighted
+ m_PressedTrigger: Pressed
+ m_SelectedTrigger: Selected
+ m_DisabledTrigger: Disabled
+ m_Interactable: 1
+ m_TargetGraphic: {fileID: 989311920}
+ m_OnClick:
+ m_PersistentCalls:
+ m_Calls:
+ - m_Target: {fileID: 0}
+ m_TargetAssemblyTypeName: Kirurobo.SampleManager, Assembly-CSharp
+ m_MethodName: LoadScene
+ m_Mode: 5
+ m_Arguments:
+ m_ObjectArgument: {fileID: 0}
+ m_ObjectArgumentAssemblyTypeName: UnityEngine.Object, UnityEngine
+ m_IntArgument: 0
+ m_FloatArgument: 0
+ m_StringArgument: FullScreenSample
+ m_BoolArgument: 0
+ m_CallState: 2
+--- !u!114 &989311920
+MonoBehaviour:
+ m_ObjectHideFlags: 0
+ m_CorrespondingSourceObject: {fileID: 0}
+ m_PrefabInstance: {fileID: 0}
+ m_PrefabAsset: {fileID: 0}
+ m_GameObject: {fileID: 989311917}
+ m_Enabled: 1
+ m_EditorHideFlags: 0
+ m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3}
+ m_Name:
+ m_EditorClassIdentifier:
+ m_Material: {fileID: 0}
+ m_Color: {r: 1, g: 1, b: 1, a: 1}
+ m_RaycastTarget: 1
+ m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0}
+ m_Maskable: 1
+ m_OnCullStateChanged:
+ m_PersistentCalls:
+ m_Calls: []
+ m_Sprite: {fileID: 10905, guid: 0000000000000000f000000000000000, type: 0}
+ m_Type: 1
+ m_PreserveAspect: 0
+ m_FillCenter: 1
+ m_FillMethod: 4
+ m_FillAmount: 1
+ m_FillClockwise: 1
+ m_FillOrigin: 0
+ m_UseSpriteMesh: 0
+ m_PixelsPerUnitMultiplier: 1
+--- !u!222 &989311921
+CanvasRenderer:
+ m_ObjectHideFlags: 0
+ m_CorrespondingSourceObject: {fileID: 0}
+ m_PrefabInstance: {fileID: 0}
+ m_PrefabAsset: {fileID: 0}
+ m_GameObject: {fileID: 989311917}
+ m_CullTransparentMesh: 1
+--- !u!1 &1115002724
+GameObject:
+ m_ObjectHideFlags: 0
+ m_CorrespondingSourceObject: {fileID: 0}
+ m_PrefabInstance: {fileID: 0}
+ m_PrefabAsset: {fileID: 0}
+ serializedVersion: 6
+ m_Component:
+ - component: {fileID: 1115002725}
+ - component: {fileID: 1115002727}
+ - component: {fileID: 1115002726}
+ m_Layer: 5
+ m_Name: Panel
+ m_TagString: Untagged
+ m_Icon: {fileID: 0}
+ m_NavMeshLayer: 0
+ m_StaticEditorFlags: 0
+ m_IsActive: 1
+--- !u!224 &1115002725
+RectTransform:
+ m_ObjectHideFlags: 0
+ m_CorrespondingSourceObject: {fileID: 0}
+ m_PrefabInstance: {fileID: 0}
+ m_PrefabAsset: {fileID: 0}
+ m_GameObject: {fileID: 1115002724}
+ m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
+ m_LocalPosition: {x: 0, y: 0, z: 0}
+ m_LocalScale: {x: 1, y: 1, z: 1}
+ m_ConstrainProportionsScale: 0
+ m_Children:
+ - {fileID: 482449625}
+ - {fileID: 925578656}
+ - {fileID: 989311918}
+ - {fileID: 30811437}
+ m_Father: {fileID: 1721279633}
+ m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
+ m_AnchorMin: {x: 0.5, y: 0.5}
+ m_AnchorMax: {x: 0.5, y: 0.5}
+ m_AnchoredPosition: {x: 90, y: 70}
+ m_SizeDelta: {x: 480, y: 200}
+ m_Pivot: {x: 0.5, y: 0.5}
+--- !u!114 &1115002726
+MonoBehaviour:
+ m_ObjectHideFlags: 0
+ m_CorrespondingSourceObject: {fileID: 0}
+ m_PrefabInstance: {fileID: 0}
+ m_PrefabAsset: {fileID: 0}
+ m_GameObject: {fileID: 1115002724}
+ m_Enabled: 1
+ m_EditorHideFlags: 0
+ m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3}
+ m_Name:
+ m_EditorClassIdentifier:
+ m_Material: {fileID: 0}
+ m_Color: {r: 1, g: 1, b: 1, a: 0.392}
+ m_RaycastTarget: 1
+ m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0}
+ m_Maskable: 1
+ m_OnCullStateChanged:
+ m_PersistentCalls:
+ m_Calls: []
+ m_Sprite: {fileID: 10907, guid: 0000000000000000f000000000000000, type: 0}
+ m_Type: 1
+ m_PreserveAspect: 0
+ m_FillCenter: 1
+ m_FillMethod: 4
+ m_FillAmount: 1
+ m_FillClockwise: 1
+ m_FillOrigin: 0
+ m_UseSpriteMesh: 0
+ m_PixelsPerUnitMultiplier: 1
+--- !u!222 &1115002727
+CanvasRenderer:
+ m_ObjectHideFlags: 0
+ m_CorrespondingSourceObject: {fileID: 0}
+ m_PrefabInstance: {fileID: 0}
+ m_PrefabAsset: {fileID: 0}
+ m_GameObject: {fileID: 1115002724}
+ m_CullTransparentMesh: 1
+--- !u!1 &1161899925
+GameObject:
+ m_ObjectHideFlags: 0
+ m_CorrespondingSourceObject: {fileID: 0}
+ m_PrefabInstance: {fileID: 0}
+ m_PrefabAsset: {fileID: 0}
+ serializedVersion: 6
+ m_Component:
+ - component: {fileID: 1161899926}
+ - component: {fileID: 1161899928}
+ - component: {fileID: 1161899927}
+ m_Layer: 5
+ m_Name: Text
+ m_TagString: Untagged
+ m_Icon: {fileID: 0}
+ m_NavMeshLayer: 0
+ m_StaticEditorFlags: 0
+ m_IsActive: 1
+--- !u!224 &1161899926
+RectTransform:
+ m_ObjectHideFlags: 0
+ m_CorrespondingSourceObject: {fileID: 0}
+ m_PrefabInstance: {fileID: 0}
+ m_PrefabAsset: {fileID: 0}
+ m_GameObject: {fileID: 1161899925}
+ m_LocalRotation: {x: -0, y: -0, z: -0, w: 1}
+ m_LocalPosition: {x: 0, y: 0, z: 0}
+ m_LocalScale: {x: 1, y: 1, z: 1}
+ m_ConstrainProportionsScale: 0
+ m_Children: []
+ m_Father: {fileID: 989311918}
+ m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
+ m_AnchorMin: {x: 0, y: 0}
+ m_AnchorMax: {x: 1, y: 1}
+ m_AnchoredPosition: {x: 0, y: 0}
+ m_SizeDelta: {x: 0, y: 0}
+ m_Pivot: {x: 0.5, y: 0.5}
+--- !u!114 &1161899927
+MonoBehaviour:
+ m_ObjectHideFlags: 0
+ m_CorrespondingSourceObject: {fileID: 0}
+ m_PrefabInstance: {fileID: 0}
+ m_PrefabAsset: {fileID: 0}
+ m_GameObject: {fileID: 1161899925}
+ m_Enabled: 1
+ m_EditorHideFlags: 0
+ m_Script: {fileID: 11500000, guid: 5f7201a12d95ffc409449d95f23cf332, type: 3}
+ m_Name:
+ m_EditorClassIdentifier:
+ m_Material: {fileID: 0}
+ m_Color: {r: 0.19607843, g: 0.19607843, b: 0.19607843, a: 1}
+ m_RaycastTarget: 1
+ m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0}
+ m_Maskable: 1
+ m_OnCullStateChanged:
+ m_PersistentCalls:
+ m_Calls: []
+ m_FontData:
+ m_Font: {fileID: 10102, guid: 0000000000000000e000000000000000, type: 0}
+ m_FontSize: 14
+ m_FontStyle: 0
+ m_BestFit: 0
+ m_MinSize: 10
+ m_MaxSize: 40
+ m_Alignment: 4
+ m_AlignByGeometry: 0
+ m_RichText: 1
+ m_HorizontalOverflow: 0
+ m_VerticalOverflow: 0
+ m_LineSpacing: 1
+ m_Text: Open Save File Dialog
+--- !u!222 &1161899928
+CanvasRenderer:
+ m_ObjectHideFlags: 0
+ m_CorrespondingSourceObject: {fileID: 0}
+ m_PrefabInstance: {fileID: 0}
+ m_PrefabAsset: {fileID: 0}
+ m_GameObject: {fileID: 1161899925}
+ m_CullTransparentMesh: 1
+--- !u!1 &1162323843
+GameObject:
+ m_ObjectHideFlags: 0
+ m_CorrespondingSourceObject: {fileID: 0}
+ m_PrefabInstance: {fileID: 0}
+ m_PrefabAsset: {fileID: 0}
+ serializedVersion: 6
+ m_Component:
+ - component: {fileID: 1162323844}
+ - component: {fileID: 1162323846}
+ - component: {fileID: 1162323845}
+ m_Layer: 5
+ m_Name: MessageText
+ m_TagString: Untagged
+ m_Icon: {fileID: 0}
+ m_NavMeshLayer: 0
+ m_StaticEditorFlags: 0
+ m_IsActive: 1
+--- !u!224 &1162323844
+RectTransform:
+ m_ObjectHideFlags: 0
+ m_CorrespondingSourceObject: {fileID: 0}
+ m_PrefabInstance: {fileID: 0}
+ m_PrefabAsset: {fileID: 0}
+ m_GameObject: {fileID: 1162323843}
+ m_LocalRotation: {x: -0, y: -0, z: -0, w: 1}
+ m_LocalPosition: {x: 0, y: 0, z: 0}
+ m_LocalScale: {x: 1, y: 1, z: 1}
+ m_ConstrainProportionsScale: 0
+ m_Children: []
+ m_Father: {fileID: 1209789489}
+ m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
+ m_AnchorMin: {x: 0, y: 0}
+ m_AnchorMax: {x: 1, y: 1}
+ m_AnchoredPosition: {x: 0, y: 2.5}
+ m_SizeDelta: {x: -10, y: -5}
+ m_Pivot: {x: 0.5, y: 0.5}
+--- !u!114 &1162323845
+MonoBehaviour:
+ m_ObjectHideFlags: 0
+ m_CorrespondingSourceObject: {fileID: 0}
+ m_PrefabInstance: {fileID: 0}
+ m_PrefabAsset: {fileID: 0}
+ m_GameObject: {fileID: 1162323843}
+ m_Enabled: 1
+ m_EditorHideFlags: 0
+ m_Script: {fileID: 11500000, guid: 5f7201a12d95ffc409449d95f23cf332, type: 3}
+ m_Name:
+ m_EditorClassIdentifier:
+ m_Material: {fileID: 0}
+ m_Color: {r: 0.19607843, g: 0.19607843, b: 0.19607843, a: 1}
+ m_RaycastTarget: 1
+ m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0}
+ m_Maskable: 1
+ m_OnCullStateChanged:
+ m_PersistentCalls:
+ m_Calls: []
+ m_FontData:
+ m_Font: {fileID: 10102, guid: 0000000000000000e000000000000000, type: 0}
+ m_FontSize: 14
+ m_FontStyle: 0
+ m_BestFit: 0
+ m_MinSize: 10
+ m_MaxSize: 40
+ m_Alignment: 0
+ m_AlignByGeometry: 0
+ m_RichText: 1
+ m_HorizontalOverflow: 0
+ m_VerticalOverflow: 0
+ m_LineSpacing: 1
+ m_Text: Message
+--- !u!222 &1162323846
+CanvasRenderer:
+ m_ObjectHideFlags: 0
+ m_CorrespondingSourceObject: {fileID: 0}
+ m_PrefabInstance: {fileID: 0}
+ m_PrefabAsset: {fileID: 0}
+ m_GameObject: {fileID: 1162323843}
+ m_CullTransparentMesh: 1
+--- !u!1 &1209789488
+GameObject:
+ m_ObjectHideFlags: 0
+ m_CorrespondingSourceObject: {fileID: 0}
+ m_PrefabInstance: {fileID: 0}
+ m_PrefabAsset: {fileID: 0}
+ serializedVersion: 6
+ m_Component:
+ - component: {fileID: 1209789489}
+ m_Layer: 5
+ m_Name: Content
+ m_TagString: Untagged
+ m_Icon: {fileID: 0}
+ m_NavMeshLayer: 0
+ m_StaticEditorFlags: 0
+ m_IsActive: 1
+--- !u!224 &1209789489
+RectTransform:
+ m_ObjectHideFlags: 0
+ m_CorrespondingSourceObject: {fileID: 0}
+ m_PrefabInstance: {fileID: 0}
+ m_PrefabAsset: {fileID: 0}
+ m_GameObject: {fileID: 1209789488}
+ m_LocalRotation: {x: -0, y: -0, z: -0, w: 1}
+ m_LocalPosition: {x: 0, y: 0, z: 0}
+ m_LocalScale: {x: 1, y: 1, z: 1}
+ m_ConstrainProportionsScale: 0
+ m_Children:
+ - {fileID: 1162323844}
+ m_Father: {fileID: 246320738}
+ m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
+ m_AnchorMin: {x: 0, y: 1}
+ m_AnchorMax: {x: 1, y: 1}
+ m_AnchoredPosition: {x: 0, y: 0}
+ m_SizeDelta: {x: 0, y: 300}
+ m_Pivot: {x: 0, y: 1}
+--- !u!1 &1434002365
+GameObject:
+ m_ObjectHideFlags: 0
+ m_CorrespondingSourceObject: {fileID: 0}
+ m_PrefabInstance: {fileID: 0}
+ m_PrefabAsset: {fileID: 0}
+ serializedVersion: 6
+ m_Component:
+ - component: {fileID: 1434002368}
+ - component: {fileID: 1434002367}
+ - component: {fileID: 1434002366}
+ m_Layer: 0
+ m_Name: Main Camera
+ m_TagString: MainCamera
+ m_Icon: {fileID: 0}
+ m_NavMeshLayer: 0
+ m_StaticEditorFlags: 0
+ m_IsActive: 1
+--- !u!81 &1434002366
+AudioListener:
+ m_ObjectHideFlags: 0
+ m_CorrespondingSourceObject: {fileID: 0}
+ m_PrefabInstance: {fileID: 0}
+ m_PrefabAsset: {fileID: 0}
+ m_GameObject: {fileID: 1434002365}
+ m_Enabled: 1
+--- !u!20 &1434002367
+Camera:
+ m_ObjectHideFlags: 0
+ m_CorrespondingSourceObject: {fileID: 0}
+ m_PrefabInstance: {fileID: 0}
+ m_PrefabAsset: {fileID: 0}
+ m_GameObject: {fileID: 1434002365}
+ m_Enabled: 1
+ serializedVersion: 2
+ m_ClearFlags: 1
+ m_BackGroundColor: {r: 0.19215687, g: 0.3019608, b: 0.4745098, a: 0}
+ m_projectionMatrixMode: 1
+ m_GateFitMode: 2
+ m_FOVAxisMode: 0
+ m_Iso: 200
+ m_ShutterSpeed: 0.005
+ m_Aperture: 16
+ m_FocusDistance: 10
+ m_FocalLength: 50
+ m_BladeCount: 5
+ m_Curvature: {x: 2, y: 11}
+ m_BarrelClipping: 0.25
+ m_Anamorphism: 0
+ m_SensorSize: {x: 36, y: 24}
+ m_LensShift: {x: 0, y: 0}
+ m_NormalizedViewPortRect:
+ serializedVersion: 2
+ x: 0
+ y: 0
+ width: 1
+ height: 1
+ near clip plane: 0.3
+ far clip plane: 1000
+ field of view: 60
+ orthographic: 0
+ orthographic size: 5
+ m_Depth: -1
+ m_CullingMask:
+ serializedVersion: 2
+ m_Bits: 4294967295
+ m_RenderingPath: -1
+ m_TargetTexture: {fileID: 0}
+ m_TargetDisplay: 0
+ m_TargetEye: 3
+ m_HDR: 1
+ m_AllowMSAA: 1
+ m_AllowDynamicResolution: 0
+ m_ForceIntoRT: 0
+ m_OcclusionCulling: 1
+ m_StereoConvergence: 10
+ m_StereoSeparation: 0.022
+--- !u!4 &1434002368
+Transform:
+ m_ObjectHideFlags: 0
+ m_CorrespondingSourceObject: {fileID: 0}
+ m_PrefabInstance: {fileID: 0}
+ m_PrefabAsset: {fileID: 0}
+ m_GameObject: {fileID: 1434002365}
+ serializedVersion: 2
+ m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
+ m_LocalPosition: {x: 0, y: 1, z: -10}
+ m_LocalScale: {x: 1, y: 1, z: 1}
+ m_ConstrainProportionsScale: 0
+ m_Children: []
+ m_Father: {fileID: 0}
+ m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
+--- !u!1 &1486794693
+GameObject:
+ m_ObjectHideFlags: 0
+ m_CorrespondingSourceObject: {fileID: 0}
+ m_PrefabInstance: {fileID: 0}
+ m_PrefabAsset: {fileID: 0}
+ serializedVersion: 6
+ m_Component:
+ - component: {fileID: 1486794694}
+ - component: {fileID: 1486794696}
+ - component: {fileID: 1486794695}
+ m_Layer: 5
+ m_Name: Handle
+ m_TagString: Untagged
+ m_Icon: {fileID: 0}
+ m_NavMeshLayer: 0
+ m_StaticEditorFlags: 0
+ m_IsActive: 1
+--- !u!224 &1486794694
+RectTransform:
+ m_ObjectHideFlags: 0
+ m_CorrespondingSourceObject: {fileID: 0}
+ m_PrefabInstance: {fileID: 0}
+ m_PrefabAsset: {fileID: 0}
+ m_GameObject: {fileID: 1486794693}
+ m_LocalRotation: {x: -0, y: -0, z: -0, w: 1}
+ m_LocalPosition: {x: 0, y: 0, z: 0}
+ m_LocalScale: {x: 1, y: 1, z: 1}
+ m_ConstrainProportionsScale: 0
+ m_Children: []
+ m_Father: {fileID: 223023793}
+ m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
+ m_AnchorMin: {x: 0, y: 0}
+ m_AnchorMax: {x: 0, y: 0}
+ m_AnchoredPosition: {x: 0, y: 0}
+ m_SizeDelta: {x: 20, y: 20}
+ m_Pivot: {x: 0.5, y: 0.5}
+--- !u!114 &1486794695
+MonoBehaviour:
+ m_ObjectHideFlags: 0
+ m_CorrespondingSourceObject: {fileID: 0}
+ m_PrefabInstance: {fileID: 0}
+ m_PrefabAsset: {fileID: 0}
+ m_GameObject: {fileID: 1486794693}
+ m_Enabled: 1
+ m_EditorHideFlags: 0
+ m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3}
+ m_Name:
+ m_EditorClassIdentifier:
+ m_Material: {fileID: 0}
+ m_Color: {r: 1, g: 1, b: 1, a: 1}
+ m_RaycastTarget: 1
+ m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0}
+ m_Maskable: 1
+ m_OnCullStateChanged:
+ m_PersistentCalls:
+ m_Calls: []
+ m_Sprite: {fileID: 10905, guid: 0000000000000000f000000000000000, type: 0}
+ m_Type: 1
+ m_PreserveAspect: 0
+ m_FillCenter: 1
+ m_FillMethod: 4
+ m_FillAmount: 1
+ m_FillClockwise: 1
+ m_FillOrigin: 0
+ m_UseSpriteMesh: 0
+ m_PixelsPerUnitMultiplier: 1
+--- !u!222 &1486794696
+CanvasRenderer:
+ m_ObjectHideFlags: 0
+ m_CorrespondingSourceObject: {fileID: 0}
+ m_PrefabInstance: {fileID: 0}
+ m_PrefabAsset: {fileID: 0}
+ m_GameObject: {fileID: 1486794693}
+ m_CullTransparentMesh: 1
+--- !u!1 &1610488909
+GameObject:
+ m_ObjectHideFlags: 0
+ m_CorrespondingSourceObject: {fileID: 0}
+ m_PrefabInstance: {fileID: 0}
+ m_PrefabAsset: {fileID: 0}
+ serializedVersion: 6
+ m_Component:
+ - component: {fileID: 1610488910}
+ - component: {fileID: 1610488911}
+ m_Layer: 0
+ m_Name: FileDialogSample
+ m_TagString: Untagged
+ m_Icon: {fileID: 0}
+ m_NavMeshLayer: 0
+ m_StaticEditorFlags: 0
+ m_IsActive: 1
+--- !u!4 &1610488910
+Transform:
+ m_ObjectHideFlags: 0
+ m_CorrespondingSourceObject: {fileID: 0}
+ m_PrefabInstance: {fileID: 0}
+ m_PrefabAsset: {fileID: 0}
+ m_GameObject: {fileID: 1610488909}
+ serializedVersion: 2
+ m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
+ m_LocalPosition: {x: 0, y: 0, z: -15}
+ m_LocalScale: {x: 1, y: 1, z: 1}
+ m_ConstrainProportionsScale: 0
+ m_Children:
+ - {fileID: 1721279633}
+ m_Father: {fileID: 0}
+ m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
+--- !u!114 &1610488911
+MonoBehaviour:
+ m_ObjectHideFlags: 0
+ m_CorrespondingSourceObject: {fileID: 0}
+ m_PrefabInstance: {fileID: 0}
+ m_PrefabAsset: {fileID: 0}
+ m_GameObject: {fileID: 1610488909}
+ m_Enabled: 1
+ m_EditorHideFlags: 0
+ m_Script: {fileID: 11500000, guid: eb6dba400744842c1b9025c020a1dd4e, type: 3}
+ m_Name:
+ m_EditorClassIdentifier:
+ openFileButton: {fileID: 482449626}
+ openMultipleFilesButton: {fileID: 925578657}
+ saveFileButton: {fileID: 989311919}
+ messageText: {fileID: 1162323845}
+--- !u!1 &1721279632
+GameObject:
+ m_ObjectHideFlags: 0
+ m_CorrespondingSourceObject: {fileID: 0}
+ m_PrefabInstance: {fileID: 0}
+ m_PrefabAsset: {fileID: 0}
+ serializedVersion: 6
+ m_Component:
+ - component: {fileID: 1721279633}
+ - component: {fileID: 1721279636}
+ - component: {fileID: 1721279635}
+ - component: {fileID: 1721279634}
+ m_Layer: 5
+ m_Name: Canvas
+ m_TagString: Untagged
+ m_Icon: {fileID: 0}
+ m_NavMeshLayer: 0
+ m_StaticEditorFlags: 0
+ m_IsActive: 1
+--- !u!224 &1721279633
+RectTransform:
+ m_ObjectHideFlags: 0
+ m_CorrespondingSourceObject: {fileID: 0}
+ m_PrefabInstance: {fileID: 0}
+ m_PrefabAsset: {fileID: 0}
+ m_GameObject: {fileID: 1721279632}
+ m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
+ m_LocalPosition: {x: 0, y: 0, z: 0}
+ m_LocalScale: {x: 0, y: 0, z: 0}
+ m_ConstrainProportionsScale: 0
+ m_Children:
+ - {fileID: 1115002725}
+ m_Father: {fileID: 1610488910}
+ m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
+ m_AnchorMin: {x: 0, y: 0}
+ m_AnchorMax: {x: 0, y: 0}
+ m_AnchoredPosition: {x: 0, y: 0}
+ m_SizeDelta: {x: 0, y: 0}
+ m_Pivot: {x: 0, y: 0}
+--- !u!114 &1721279634
+MonoBehaviour:
+ m_ObjectHideFlags: 0
+ m_CorrespondingSourceObject: {fileID: 0}
+ m_PrefabInstance: {fileID: 0}
+ m_PrefabAsset: {fileID: 0}
+ m_GameObject: {fileID: 1721279632}
+ m_Enabled: 1
+ m_EditorHideFlags: 0
+ m_Script: {fileID: 11500000, guid: dc42784cf147c0c48a680349fa168899, type: 3}
+ m_Name:
+ m_EditorClassIdentifier:
+ m_IgnoreReversedGraphics: 1
+ m_BlockingObjects: 0
+ m_BlockingMask:
+ serializedVersion: 2
+ m_Bits: 4294967295
+--- !u!114 &1721279635
+MonoBehaviour:
+ m_ObjectHideFlags: 0
+ m_CorrespondingSourceObject: {fileID: 0}
+ m_PrefabInstance: {fileID: 0}
+ m_PrefabAsset: {fileID: 0}
+ m_GameObject: {fileID: 1721279632}
+ m_Enabled: 1
+ m_EditorHideFlags: 0
+ m_Script: {fileID: 11500000, guid: 0cd44c1031e13a943bb63640046fad76, type: 3}
+ m_Name:
+ m_EditorClassIdentifier:
+ m_UiScaleMode: 0
+ m_ReferencePixelsPerUnit: 100
+ m_ScaleFactor: 1
+ m_ReferenceResolution: {x: 800, y: 600}
+ m_ScreenMatchMode: 0
+ m_MatchWidthOrHeight: 0
+ m_PhysicalUnit: 3
+ m_FallbackScreenDPI: 96
+ m_DefaultSpriteDPI: 96
+ m_DynamicPixelsPerUnit: 1
+ m_PresetInfoIsWorld: 0
+--- !u!223 &1721279636
+Canvas:
+ m_ObjectHideFlags: 0
+ m_CorrespondingSourceObject: {fileID: 0}
+ m_PrefabInstance: {fileID: 0}
+ m_PrefabAsset: {fileID: 0}
+ m_GameObject: {fileID: 1721279632}
+ m_Enabled: 1
+ serializedVersion: 3
+ m_RenderMode: 0
+ m_Camera: {fileID: 0}
+ m_PlaneDistance: 100
+ m_PixelPerfect: 0
+ m_ReceivesEvents: 1
+ m_OverrideSorting: 0
+ m_OverridePixelPerfect: 0
+ m_SortingBucketNormalizedSize: 0
+ m_VertexColorAlwaysGammaSpace: 0
+ m_AdditionalShaderChannelsFlag: 0
+ m_UpdateRectTransformForStandalone: 0
+ m_SortingLayerID: 0
+ m_SortingOrder: 0
+ m_TargetDisplay: 0
+--- !u!1 &1853089148
+GameObject:
+ m_ObjectHideFlags: 0
+ m_CorrespondingSourceObject: {fileID: 0}
+ m_PrefabInstance: {fileID: 0}
+ m_PrefabAsset: {fileID: 0}
+ serializedVersion: 6
+ m_Component:
+ - component: {fileID: 1853089150}
+ - component: {fileID: 1853089149}
+ m_Layer: 0
+ m_Name: Directional Light
+ m_TagString: Untagged
+ m_Icon: {fileID: 0}
+ m_NavMeshLayer: 0
+ m_StaticEditorFlags: 0
+ m_IsActive: 1
+--- !u!108 &1853089149
+Light:
+ m_ObjectHideFlags: 0
+ m_CorrespondingSourceObject: {fileID: 0}
+ m_PrefabInstance: {fileID: 0}
+ m_PrefabAsset: {fileID: 0}
+ m_GameObject: {fileID: 1853089148}
+ m_Enabled: 1
+ serializedVersion: 10
+ m_Type: 1
+ m_Shape: 0
+ m_Color: {r: 1, g: 0.95686275, b: 0.8392157, a: 1}
+ m_Intensity: 1
+ m_Range: 10
+ m_SpotAngle: 30
+ m_InnerSpotAngle: 21.802082
+ m_CookieSize: 10
+ m_Shadows:
+ m_Type: 2
+ m_Resolution: -1
+ m_CustomResolution: -1
+ m_Strength: 1
+ m_Bias: 0.05
+ m_NormalBias: 0.4
+ m_NearPlane: 0.2
+ m_CullingMatrixOverride:
+ e00: 1
+ e01: 0
+ e02: 0
+ e03: 0
+ e10: 0
+ e11: 1
+ e12: 0
+ e13: 0
+ e20: 0
+ e21: 0
+ e22: 1
+ e23: 0
+ e30: 0
+ e31: 0
+ e32: 0
+ e33: 1
+ m_UseCullingMatrixOverride: 0
+ m_Cookie: {fileID: 0}
+ m_DrawHalo: 0
+ m_Flare: {fileID: 0}
+ m_RenderMode: 0
+ m_CullingMask:
+ serializedVersion: 2
+ m_Bits: 4294967295
+ m_RenderingLayerMask: 1
+ m_Lightmapping: 4
+ m_LightShadowCasterMode: 0
+ m_AreaSize: {x: 1, y: 1}
+ m_BounceIntensity: 1
+ m_ColorTemperature: 6570
+ m_UseColorTemperature: 0
+ m_BoundingSphereOverride: {x: 0, y: 0, z: 0, w: 0}
+ m_UseBoundingSphereOverride: 0
+ m_UseViewFrustumForShadowCasterCull: 1
+ m_ShadowRadius: 0
+ m_ShadowAngle: 0
+--- !u!4 &1853089150
+Transform:
+ m_ObjectHideFlags: 0
+ m_CorrespondingSourceObject: {fileID: 0}
+ m_PrefabInstance: {fileID: 0}
+ m_PrefabAsset: {fileID: 0}
+ m_GameObject: {fileID: 1853089148}
+ serializedVersion: 2
+ m_LocalRotation: {x: 0.40821788, y: -0.23456968, z: 0.10938163, w: 0.8754261}
+ m_LocalPosition: {x: 0, y: 3, z: 0}
+ m_LocalScale: {x: 1, y: 1, z: 1}
+ m_ConstrainProportionsScale: 0
+ m_Children: []
+ m_Father: {fileID: 0}
+ m_LocalEulerAnglesHint: {x: 50, y: -30, z: 0}
+--- !u!1 &1987906027
+GameObject:
+ m_ObjectHideFlags: 0
+ m_CorrespondingSourceObject: {fileID: 0}
+ m_PrefabInstance: {fileID: 0}
+ m_PrefabAsset: {fileID: 0}
+ serializedVersion: 6
+ m_Component:
+ - component: {fileID: 1987906028}
+ - component: {fileID: 1987906030}
+ - component: {fileID: 1987906029}
+ m_Layer: 5
+ m_Name: Text
+ m_TagString: Untagged
+ m_Icon: {fileID: 0}
+ m_NavMeshLayer: 0
+ m_StaticEditorFlags: 0
+ m_IsActive: 1
+--- !u!224 &1987906028
+RectTransform:
+ m_ObjectHideFlags: 0
+ m_CorrespondingSourceObject: {fileID: 0}
+ m_PrefabInstance: {fileID: 0}
+ m_PrefabAsset: {fileID: 0}
+ m_GameObject: {fileID: 1987906027}
+ m_LocalRotation: {x: -0, y: -0, z: -0, w: 1}
+ m_LocalPosition: {x: 0, y: 0, z: 0}
+ m_LocalScale: {x: 1, y: 1, z: 1}
+ m_ConstrainProportionsScale: 0
+ m_Children: []
+ m_Father: {fileID: 482449625}
+ m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
+ m_AnchorMin: {x: 0, y: 0}
+ m_AnchorMax: {x: 1, y: 1}
+ m_AnchoredPosition: {x: 0, y: 0}
+ m_SizeDelta: {x: 0, y: 0}
+ m_Pivot: {x: 0.5, y: 0.5}
+--- !u!114 &1987906029
+MonoBehaviour:
+ m_ObjectHideFlags: 0
+ m_CorrespondingSourceObject: {fileID: 0}
+ m_PrefabInstance: {fileID: 0}
+ m_PrefabAsset: {fileID: 0}
+ m_GameObject: {fileID: 1987906027}
+ m_Enabled: 1
+ m_EditorHideFlags: 0
+ m_Script: {fileID: 11500000, guid: 5f7201a12d95ffc409449d95f23cf332, type: 3}
+ m_Name:
+ m_EditorClassIdentifier:
+ m_Material: {fileID: 0}
+ m_Color: {r: 0.19607843, g: 0.19607843, b: 0.19607843, a: 1}
+ m_RaycastTarget: 1
+ m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0}
+ m_Maskable: 1
+ m_OnCullStateChanged:
+ m_PersistentCalls:
+ m_Calls: []
+ m_FontData:
+ m_Font: {fileID: 10102, guid: 0000000000000000e000000000000000, type: 0}
+ m_FontSize: 14
+ m_FontStyle: 0
+ m_BestFit: 0
+ m_MinSize: 10
+ m_MaxSize: 40
+ m_Alignment: 4
+ m_AlignByGeometry: 0
+ m_RichText: 1
+ m_HorizontalOverflow: 0
+ m_VerticalOverflow: 0
+ m_LineSpacing: 1
+ m_Text: Open Single FileSelection Dialog
+--- !u!222 &1987906030
+CanvasRenderer:
+ m_ObjectHideFlags: 0
+ m_CorrespondingSourceObject: {fileID: 0}
+ m_PrefabInstance: {fileID: 0}
+ m_PrefabAsset: {fileID: 0}
+ m_GameObject: {fileID: 1987906027}
+ m_CullTransparentMesh: 1
+--- !u!1 &2062578108
+GameObject:
+ m_ObjectHideFlags: 0
+ m_CorrespondingSourceObject: {fileID: 0}
+ m_PrefabInstance: {fileID: 0}
+ m_PrefabAsset: {fileID: 0}
+ serializedVersion: 6
+ m_Component:
+ - component: {fileID: 2062578109}
+ - component: {fileID: 2062578111}
+ - component: {fileID: 2062578110}
+ m_Layer: 5
+ m_Name: Text
+ m_TagString: Untagged
+ m_Icon: {fileID: 0}
+ m_NavMeshLayer: 0
+ m_StaticEditorFlags: 0
+ m_IsActive: 1
+--- !u!224 &2062578109
+RectTransform:
+ m_ObjectHideFlags: 0
+ m_CorrespondingSourceObject: {fileID: 0}
+ m_PrefabInstance: {fileID: 0}
+ m_PrefabAsset: {fileID: 0}
+ m_GameObject: {fileID: 2062578108}
+ m_LocalRotation: {x: -0, y: -0, z: -0, w: 1}
+ m_LocalPosition: {x: 0, y: 0, z: 0}
+ m_LocalScale: {x: 1, y: 1, z: 1}
+ m_ConstrainProportionsScale: 0
+ m_Children: []
+ m_Father: {fileID: 925578656}
+ m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
+ m_AnchorMin: {x: 0, y: 0}
+ m_AnchorMax: {x: 1, y: 1}
+ m_AnchoredPosition: {x: 0, y: 0}
+ m_SizeDelta: {x: 0, y: 0}
+ m_Pivot: {x: 0.5, y: 0.5}
+--- !u!114 &2062578110
+MonoBehaviour:
+ m_ObjectHideFlags: 0
+ m_CorrespondingSourceObject: {fileID: 0}
+ m_PrefabInstance: {fileID: 0}
+ m_PrefabAsset: {fileID: 0}
+ m_GameObject: {fileID: 2062578108}
+ m_Enabled: 1
+ m_EditorHideFlags: 0
+ m_Script: {fileID: 11500000, guid: 5f7201a12d95ffc409449d95f23cf332, type: 3}
+ m_Name:
+ m_EditorClassIdentifier:
+ m_Material: {fileID: 0}
+ m_Color: {r: 0.19607843, g: 0.19607843, b: 0.19607843, a: 1}
+ m_RaycastTarget: 1
+ m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0}
+ m_Maskable: 1
+ m_OnCullStateChanged:
+ m_PersistentCalls:
+ m_Calls: []
+ m_FontData:
+ m_Font: {fileID: 10102, guid: 0000000000000000e000000000000000, type: 0}
+ m_FontSize: 14
+ m_FontStyle: 0
+ m_BestFit: 0
+ m_MinSize: 10
+ m_MaxSize: 40
+ m_Alignment: 4
+ m_AlignByGeometry: 0
+ m_RichText: 1
+ m_HorizontalOverflow: 0
+ m_VerticalOverflow: 0
+ m_LineSpacing: 1
+ m_Text: Open Multiple File Selection Dialog
+--- !u!222 &2062578111
+CanvasRenderer:
+ m_ObjectHideFlags: 0
+ m_CorrespondingSourceObject: {fileID: 0}
+ m_PrefabInstance: {fileID: 0}
+ m_PrefabAsset: {fileID: 0}
+ m_GameObject: {fileID: 2062578108}
+ m_CullTransparentMesh: 1
+--- !u!1 &2082900858
+GameObject:
+ m_ObjectHideFlags: 0
+ m_CorrespondingSourceObject: {fileID: 0}
+ m_PrefabInstance: {fileID: 0}
+ m_PrefabAsset: {fileID: 0}
+ serializedVersion: 6
+ m_Component:
+ - component: {fileID: 2082900859}
+ - component: {fileID: 2082900862}
+ - component: {fileID: 2082900861}
+ - component: {fileID: 2082900860}
+ m_Layer: 5
+ m_Name: Scrollbar Vertical
+ m_TagString: Untagged
+ m_Icon: {fileID: 0}
+ m_NavMeshLayer: 0
+ m_StaticEditorFlags: 0
+ m_IsActive: 1
+--- !u!224 &2082900859
+RectTransform:
+ m_ObjectHideFlags: 0
+ m_CorrespondingSourceObject: {fileID: 0}
+ m_PrefabInstance: {fileID: 0}
+ m_PrefabAsset: {fileID: 0}
+ m_GameObject: {fileID: 2082900858}
+ m_LocalRotation: {x: -0, y: -0, z: -0, w: 1}
+ m_LocalPosition: {x: 0, y: 0, z: 0}
+ m_LocalScale: {x: 1, y: 1, z: 1}
+ m_ConstrainProportionsScale: 0
+ m_Children:
+ - {fileID: 651359272}
+ m_Father: {fileID: 30811437}
+ m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
+ m_AnchorMin: {x: 1, y: 0}
+ m_AnchorMax: {x: 1, y: 0}
+ m_AnchoredPosition: {x: 0, y: 0}
+ m_SizeDelta: {x: 20, y: 0}
+ m_Pivot: {x: 1, y: 1}
+--- !u!114 &2082900860
+MonoBehaviour:
+ m_ObjectHideFlags: 0
+ m_CorrespondingSourceObject: {fileID: 0}
+ m_PrefabInstance: {fileID: 0}
+ m_PrefabAsset: {fileID: 0}
+ m_GameObject: {fileID: 2082900858}
+ m_Enabled: 1
+ m_EditorHideFlags: 0
+ m_Script: {fileID: 11500000, guid: 2a4db7a114972834c8e4117be1d82ba3, type: 3}
+ m_Name:
+ m_EditorClassIdentifier:
+ m_Navigation:
+ m_Mode: 3
+ m_WrapAround: 0
+ m_SelectOnUp: {fileID: 0}
+ m_SelectOnDown: {fileID: 0}
+ m_SelectOnLeft: {fileID: 0}
+ m_SelectOnRight: {fileID: 0}
+ m_Transition: 1
+ m_Colors:
+ m_NormalColor: {r: 1, g: 1, b: 1, a: 1}
+ m_HighlightedColor: {r: 0.9607843, g: 0.9607843, b: 0.9607843, a: 1}
+ m_PressedColor: {r: 0.78431374, g: 0.78431374, b: 0.78431374, a: 1}
+ m_SelectedColor: {r: 0.9607843, g: 0.9607843, b: 0.9607843, a: 1}
+ m_DisabledColor: {r: 0.78431374, g: 0.78431374, b: 0.78431374, a: 0.5019608}
+ m_ColorMultiplier: 1
+ m_FadeDuration: 0.1
+ m_SpriteState:
+ m_HighlightedSprite: {fileID: 0}
+ m_PressedSprite: {fileID: 0}
+ m_SelectedSprite: {fileID: 0}
+ m_DisabledSprite: {fileID: 0}
+ m_AnimationTriggers:
+ m_NormalTrigger: Normal
+ m_HighlightedTrigger: Highlighted
+ m_PressedTrigger: Pressed
+ m_SelectedTrigger: Selected
+ m_DisabledTrigger: Disabled
+ m_Interactable: 1
+ m_TargetGraphic: {fileID: 474919457}
+ m_HandleRect: {fileID: 474919456}
+ m_Direction: 2
+ m_Value: 1
+ m_Size: 0.54333335
+ m_NumberOfSteps: 0
+ m_OnValueChanged:
+ m_PersistentCalls:
+ m_Calls: []
+--- !u!114 &2082900861
+MonoBehaviour:
+ m_ObjectHideFlags: 0
+ m_CorrespondingSourceObject: {fileID: 0}
+ m_PrefabInstance: {fileID: 0}
+ m_PrefabAsset: {fileID: 0}
+ m_GameObject: {fileID: 2082900858}
+ m_Enabled: 1
+ m_EditorHideFlags: 0
+ m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3}
+ m_Name:
+ m_EditorClassIdentifier:
+ m_Material: {fileID: 0}
+ m_Color: {r: 1, g: 1, b: 1, a: 1}
+ m_RaycastTarget: 1
+ m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0}
+ m_Maskable: 1
+ m_OnCullStateChanged:
+ m_PersistentCalls:
+ m_Calls: []
+ m_Sprite: {fileID: 10907, guid: 0000000000000000f000000000000000, type: 0}
+ m_Type: 1
+ m_PreserveAspect: 0
+ m_FillCenter: 1
+ m_FillMethod: 4
+ m_FillAmount: 1
+ m_FillClockwise: 1
+ m_FillOrigin: 0
+ m_UseSpriteMesh: 0
+ m_PixelsPerUnitMultiplier: 1
+--- !u!222 &2082900862
+CanvasRenderer:
+ m_ObjectHideFlags: 0
+ m_CorrespondingSourceObject: {fileID: 0}
+ m_PrefabInstance: {fileID: 0}
+ m_PrefabAsset: {fileID: 0}
+ m_GameObject: {fileID: 2082900858}
+ m_CullTransparentMesh: 1
+--- !u!1660057539 &9223372036854775807
+SceneRoots:
+ m_ObjectHideFlags: 0
+ m_Roots:
+ - {fileID: 1434002368}
+ - {fileID: 1853089150}
+ - {fileID: 1610488910}
+ - {fileID: 590190063}
diff --git a/Samples~/FileDialog/FileDialogSampleSettings.lighting b/Samples~/FileDialog/FileDialogSampleSettings.lighting
new file mode 100644
index 0000000..321c436
--- /dev/null
+++ b/Samples~/FileDialog/FileDialogSampleSettings.lighting
@@ -0,0 +1,63 @@
+%YAML 1.1
+%TAG !u! tag:unity3d.com,2011:
+--- !u!850595691 &4890085278179872738
+LightingSettings:
+ m_ObjectHideFlags: 0
+ m_CorrespondingSourceObject: {fileID: 0}
+ m_PrefabInstance: {fileID: 0}
+ m_PrefabAsset: {fileID: 0}
+ m_Name: FileDialogSampleSettings
+ serializedVersion: 3
+ m_GIWorkflowMode: 0
+ m_EnableBakedLightmaps: 1
+ m_EnableRealtimeLightmaps: 1
+ m_RealtimeEnvironmentLighting: 1
+ m_BounceScale: 1
+ m_AlbedoBoost: 1
+ m_IndirectOutputScale: 1
+ m_UsingShadowmask: 1
+ m_BakeBackend: 1
+ m_LightmapMaxSize: 1024
+ m_BakeResolution: 40
+ m_Padding: 2
+ m_TextureCompression: 1
+ m_AO: 0
+ m_AOMaxDistance: 1
+ m_CompAOExponent: 1
+ m_CompAOExponentDirect: 0
+ m_ExtractAO: 0
+ m_MixedBakeMode: 2
+ m_LightmapsBakeMode: 1
+ m_FilterMode: 1
+ m_LightmapParameters: {fileID: 15204, guid: 0000000000000000f000000000000000, type: 0}
+ m_ExportTrainingData: 0
+ m_TrainingDataDestination: TrainingData
+ m_RealtimeResolution: 2
+ m_ForceWhiteAlbedo: 0
+ m_ForceUpdates: 0
+ m_FinalGather: 0
+ m_FinalGatherRayCount: 256
+ m_FinalGatherFiltering: 1
+ m_PVRCulling: 1
+ m_PVRSampling: 1
+ m_PVRDirectSampleCount: 32
+ m_PVRSampleCount: 500
+ m_PVREnvironmentSampleCount: 500
+ m_PVREnvironmentReferencePointCount: 2048
+ m_LightProbeSampleCountMultiplier: 4
+ m_PVRBounces: 2
+ m_PVRMinBounces: 2
+ m_PVREnvironmentMIS: 0
+ m_PVRFilteringMode: 2
+ m_PVRDenoiserTypeDirect: 0
+ m_PVRDenoiserTypeIndirect: 0
+ m_PVRDenoiserTypeAO: 0
+ m_PVRFilterTypeDirect: 0
+ m_PVRFilterTypeIndirect: 0
+ m_PVRFilterTypeAO: 0
+ m_PVRFilteringGaussRadiusDirect: 1
+ m_PVRFilteringGaussRadiusIndirect: 5
+ m_PVRFilteringGaussRadiusAO: 2
+ m_PVRFilteringAtrousPositionSigmaDirect: 0.5
+ m_PVRFilteringAtrousPositionSigmaIndirect: 2
+ m_PVRFilteringAtrousPositionSigmaAO: 1
diff --git a/Samples~/Fullscreen/.sample.json b/Samples~/Fullscreen/.sample.json
new file mode 100644
index 0000000..4fce493
--- /dev/null
+++ b/Samples~/Fullscreen/.sample.json
@@ -0,0 +1,5 @@
+{
+ "displayName": "Fullscreen",
+ "description": "Fullscreen mode example with right-click context menu and 3D snowman scene.",
+ "createSeparatePackage": false
+}
\ No newline at end of file
diff --git a/Samples~/Fullscreen/FullscreenSample.cs b/Samples~/Fullscreen/FullscreenSample.cs
new file mode 100644
index 0000000..c04272e
--- /dev/null
+++ b/Samples~/Fullscreen/FullscreenSample.cs
@@ -0,0 +1,304 @@
+ /**
+* 全屏示例的 UI 控制器
+*
+* Author: Kirurobo http://twitter.com/kirurobo
+* License: MIT
+*/
+
+using UnityEngine;
+using UnityEngine.UI;
+
+namespace Kirurobo
+{
+ ///
+ /// 使用 Toggle 开关 WindowController 设置的示例
+ ///
+ public class FullscreenSample : MonoBehaviour
+ {
+ private UniWindowController uniwinc;
+ private RectTransform canvasRect;
+
+ private float mouseMoveSS = 0f; // 鼠标轨迹平方和。[px^2]
+ private float mouseMoveSSThreshold = 36f; // 点击(非拖拽)阈值。[px^2]
+ private Vector3 lastMousePosition; // 右键点击位置。
+ private float touchDuration = 0f;
+ private float touchDurationThreshold = 0.5f; // 长按时间阈值。[s]
+
+ public Toggle transparentToggle;
+ public Toggle topmostToggle;
+ public Toggle bottommostToggle;
+ public Dropdown fitWindowDropdown;
+ public Button quitButton;
+ public Button menuCloseButton;
+ public RectTransform menuPanel;
+
+ ///
+ /// 设置
+ ///
+ void Start()
+ {
+ // 查找 UniWindowController
+ uniwinc = GameObject.FindAnyObjectByType();
+
+ // 获取 Canvas 的 RectTransform
+ if (menuPanel) canvasRect = menuPanel.GetComponentInParent