diff --git a/Editor/Inspector/UXUIEditor.cs b/Editor/Inspector/UXUIEditor.cs index 12ee068..ad45c80 100644 --- a/Editor/Inspector/UXUIEditor.cs +++ b/Editor/Inspector/UXUIEditor.cs @@ -70,4 +70,16 @@ internal class UXUIEditor : Editor PrefabUtility.UnpackPrefabInstance(instance, PrefabUnpackMode.Completely, InteractionMode.UserAction); Selection.activeGameObject = instance; } + + [MenuItem("GameObject/UI/UXTemplateWindow")] + private static void CreateTemplateWindow() + { + GameObject selectionObject = Selection.activeGameObject; + if (selectionObject == null) return; + const string prefabPath = "Packages/com.alicizax.unity.ui.extension/Editor/Res/Template/UITemplateWindow.prefab"; + GameObject prefab = AssetDatabase.LoadAssetAtPath(prefabPath); + GameObject instance = (GameObject)PrefabUtility.InstantiatePrefab(prefab, selectionObject.transform); + PrefabUtility.UnpackPrefabInstance(instance, PrefabUnpackMode.Completely, InteractionMode.UserAction); + Selection.activeGameObject = instance; + } } diff --git a/Runtime/Extension.meta b/Editor/Res/Template.meta similarity index 77% rename from Runtime/Extension.meta rename to Editor/Res/Template.meta index c6baa56..cd71ae5 100644 --- a/Runtime/Extension.meta +++ b/Editor/Res/Template.meta @@ -1,5 +1,5 @@ fileFormatVersion: 2 -guid: dc3fb1c1caf6fbd40a900ca46f204e07 +guid: 1d15142d99e161d48a8a592c799a7f60 folderAsset: yes DefaultImporter: externalObjects: {} diff --git a/Editor/Res/Template/UITemplateWindow.prefab b/Editor/Res/Template/UITemplateWindow.prefab new file mode 100644 index 0000000..3c68931 --- /dev/null +++ b/Editor/Res/Template/UITemplateWindow.prefab @@ -0,0 +1,79 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!1 &391155014370552000 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 907499237110470932} + - component: {fileID: 1560093894229825085} + - component: {fileID: 4731840468700438029} + m_Layer: 5 + m_Name: UITemplateWindow + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &907499237110470932 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 391155014370552000} + 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} + 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!223 &1560093894229825085 +Canvas: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 391155014370552000} + 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: 1 + m_AdditionalShaderChannelsFlag: 7 + m_UpdateRectTransformForStandalone: 0 + m_SortingLayerID: 0 + m_SortingOrder: 0 + m_TargetDisplay: 0 +--- !u!114 &4731840468700438029 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 391155014370552000} + 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: 55 diff --git a/Editor/Res/Template/UITemplateWindow.prefab.meta b/Editor/Res/Template/UITemplateWindow.prefab.meta new file mode 100644 index 0000000..0276782 --- /dev/null +++ b/Editor/Res/Template/UITemplateWindow.prefab.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 4581faa155df5854cab0d579934a0c40 +PrefabImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Runtime/AlicizaX.UI.Extension.asmdef b/Runtime/AlicizaX.UI.Extension.asmdef index c518311..1d461fa 100644 --- a/Runtime/AlicizaX.UI.Extension.asmdef +++ b/Runtime/AlicizaX.UI.Extension.asmdef @@ -3,14 +3,8 @@ "rootNamespace": "AlicizaX.UI.Extension", "references": [ "GUID:6055be8ebefd69e48b49212b09b47b2f", - "GUID:5553d74549d54e74cb548b3ab58a8483", "GUID:75b6f2078d190f14dbda4a5b747d709c", - "GUID:a19b414bea3b97240a91aeab9a8eab36", - "GUID:198eb6af143bbc4488e2779d96697e06", - "GUID:80ecb87cae9c44d19824e70ea7229748", - "GUID:f51ebe6a0ceec4240a699833d6309b23", - "GUID:33661e06c33d31b4c9223810bf503247", - "GUID:e9c35c8938f782649bb7e670099ca425" + "GUID:80ecb87cae9c44d19824e70ea7229748" ], "includePlatforms": [], "excludePlatforms": [], diff --git a/Runtime/Extension/ZeroGCTypewriterPro.cs b/Runtime/Extension/ZeroGCTypewriterPro.cs deleted file mode 100644 index 84631bb..0000000 --- a/Runtime/Extension/ZeroGCTypewriterPro.cs +++ /dev/null @@ -1,236 +0,0 @@ -// using UnityEngine; -// -// using System; -// using System.Collections.Generic; -// using Cysharp.Threading.Tasks; -// using Cysharp.Threading.Tasks.Triggers; -// using TMPro; -// using UnityEngine; -// using UnityEngine.Pool; -// using System.Threading; -// using System.Runtime.CompilerServices; -// using Cysharp.Text; -// -// namespace text -// { -// public static class ZeroGCTypewriterPro -// { -// #region 核心结构体 -// -// private struct TypewriterHandle : IEquatable -// { -// public int InstanceID; -// public int Version; -// -// public bool Equals(TypewriterHandle other) => -// InstanceID == other.InstanceID && Version == other.Version; -// } -// -// private struct TypewriterJob -// { -// public TypewriterHandle Handle; -// public TMP_Text Target; -// public string Content; -// public float Speed; -// public int LoopCount; -// public Action OnUpdate; -// public Action OnComplete; -// public CancellationToken ExternalToken; -// } -// -// #endregion -// -// #region 状态管理 -// -// private static readonly Dictionary activeJobs = -// new Dictionary(32); -// -// private struct ActiveJob -// { -// public int Version; -// public CancellationTokenSource Cts; -// } -// -// private static readonly ObjectPool ctsPool = -// ObjectPool( -// createFunc: () => new CancellationTokenSource(), -// actionOnRelease: cts => cts.Cancel(), -// collectionCheck: false -// ); -// -// #endregion -// -// #region 公开接口 -// -// [MethodImpl(MethodImplOptions.AggressiveInlining)] -// public static void Play( -// this TMP_Text text, -// string content, -// float charsPerSecond = 30, -// int loopCount = 0, -// Action onUpdate = null, -// Action onComplete = null, -// CancellationToken externalToken = default) -// { -// var instanceID = text.GetInstanceID(); -// -// // 停止当前任务(如果有) -// if (activeJobs.TryGetValue(instanceID, out var existingJob)) -// { -// ctsPool.Release(existingJob.Cts); -// activeJobs.Remove(instanceID); -// } -// -// // 从对象池获取CTS -// var cts = ctsPool.Get(); -// var linkedToken = CombineTokens( -// text.GetCancellationTokenOnDestroy(), -// externalToken, -// cts.Token -// ); -// -// // 创建新任务 -// var newVersion = activeJobs.TryGetValue(instanceID, out var job) ? job.Version + 1 : 1; -// -// activeJobs[instanceID] = new ActiveJob -// { -// Version = newVersion, -// Cts = cts -// }; -// -// RunJob(new TypewriterJob -// { -// Handle = new TypewriterHandle -// { -// InstanceID = instanceID, -// Version = newVersion -// }, -// Target = text, -// Content = content, -// Speed = Mathf.Max(0.01f, charsPerSecond), -// LoopCount = loopCount, -// OnUpdate = onUpdate, -// OnComplete = onComplete, -// ExternalToken = linkedToken -// }).Forget(); -// } -// -// [MethodImpl(MethodImplOptions.AggressiveInlining)] -// public static void Stop(this TMP_Text text) -// { -// var instanceID = text.GetInstanceID(); -// if (activeJobs.TryGetValue(instanceID, out var job)) -// { -// ctsPool.Release(job.Cts); -// activeJobs.Remove(instanceID); -// ResetTextState(text); -// } -// } -// -// #endregion -// -// #region 核心逻辑 -// -// private static async UniTaskVoid RunJob(TypewriterJob job) -// { -// try -// { -// var target = job.Target; -// using (var sb = ZString.CreateStringBuilder()) -// { -// sb.Append(job.Content); -// target.text = sb.ToString(); -// target.ForceMeshUpdate(); -// -// int currentLoop = 0; -// var chars = sb.AsSpan(); -// var interval = 1f / job.Speed; -// var timer = 0f; -// -// while (IsLoopValid(currentLoop, job.LoopCount)) -// { -// target.maxVisibleCharacters = 0; -// -// for (int i = 0; i < chars.Length; i++) -// { -// // 版本校验 -// if (!IsHandleValid(job.Handle)) return; -// -// // 基于时间的更新 -// timer += Time.deltaTime; -// var required = (int)(timer * job.Speed); -// -// if (required > i) -// { -// target.maxVisibleCharacters = required; -// job.OnUpdate?.Invoke(required); -// } -// -// await UniTask.Yield(PlayerLoopTiming.Update, job.ExternalToken); -// } -// -// currentLoop++; -// timer = 0f; -// job.OnComplete?.Invoke(); -// } -// } -// } -// finally -// { -// if (IsHandleValid(job.Handle)) -// { -// activeJobs.Remove(job.Handle.InstanceID); -// ResetTextState(job.Target); -// } -// } -// } -// -// #endregion -// -// #region 工具方法 -// -// [MethodImpl(MethodImplOptions.AggressiveInlining)] -// private static bool IsHandleValid(TypewriterHandle handle) -// { -// return activeJobs.TryGetValue(handle.InstanceID, out var job) && -// job.Version == handle.Version; -// } -// -// [MethodImpl(MethodImplOptions.AggressiveInlining)] -// private static bool IsLoopValid(int current, int max) => -// max < 0 || current <= max; -// -// private static CancellationToken CombineTokens( -// CancellationToken token1, -// CancellationToken token2, -// CancellationToken token3) -// { -// if (token1.CanBeCanceled && token2.CanBeCanceled && token3.CanBeCanceled) -// return CancellationTokenSource.CreateLinkedTokenSource( -// token1, token2, token3).Token; -// -// if (token1.CanBeCanceled && token2.CanBeCanceled) -// return CancellationTokenSource.CreateLinkedTokenSource( -// token1, token2).Token; -// -// return token1.CanBeCanceled ? token1 : token2; -// } -// -// private static void ResetTextState(TMP_Text text) -// { -// if (text != null) -// { -// text.maxVisibleCharacters = int.MaxValue; -// text.SetVerticesDirty(); -// } -// } -// -// private static CancellationToken GetCancellationTokenOnDestroy(this TMP_Text text) -// { -// return text.gameObject.GetCancellationTokenOnDestroy(); -// } -// -// #endregion -// } -// -// } diff --git a/Runtime/Extension/ZeroGCTypewriterPro.cs.meta b/Runtime/Extension/ZeroGCTypewriterPro.cs.meta deleted file mode 100644 index 80bda8c..0000000 --- a/Runtime/Extension/ZeroGCTypewriterPro.cs.meta +++ /dev/null @@ -1,2 +0,0 @@ -fileFormatVersion: 2 -guid: dd18a7ac84917984dbbf48f71872add9 \ No newline at end of file diff --git a/Runtime/UXComponent/IUXLocalizationHelper.cs b/Runtime/UXComponent/IUXLocalizationHelper.cs deleted file mode 100644 index 4559a1b..0000000 --- a/Runtime/UXComponent/IUXLocalizationHelper.cs +++ /dev/null @@ -1,14 +0,0 @@ -public static class UXLocalizationComponent -{ - internal static IUXLocalizationHelper Helper; - - public static void SetLocalizationHelper(IUXLocalizationHelper helper) - { - Helper = helper; - } -} - -public interface IUXLocalizationHelper -{ - public string GetString(string key); -} diff --git a/Runtime/UXComponent/Text/UXTextMeshPro.cs b/Runtime/UXComponent/Text/UXTextMeshPro.cs index 5f1c125..da39d82 100644 --- a/Runtime/UXComponent/Text/UXTextMeshPro.cs +++ b/Runtime/UXComponent/Text/UXTextMeshPro.cs @@ -16,9 +16,9 @@ namespace UnityEngine.UI protected void ChangeLanguage() { - if (!string.IsNullOrEmpty(m_localizationID) && !"None".Equals(m_localizationID) && UXLocalizationComponent.Helper != null) + if (!string.IsNullOrEmpty(m_localizationID) && !"None".Equals(m_localizationID) && UXComponentExtensionsHelper.LocalizationHelper != null) { - text = UXLocalizationComponent.Helper.GetString(m_localizationID); + text = UXComponentExtensionsHelper.LocalizationHelper.GetString(m_localizationID); } } diff --git a/Runtime/UXComponent/UX/UXButton.cs b/Runtime/UXComponent/UX/UXButton.cs index 562224d..e7ad692 100644 --- a/Runtime/UXComponent/UX/UXButton.cs +++ b/Runtime/UXComponent/UX/UXButton.cs @@ -7,7 +7,6 @@ using UnityEngine; using UnityEngine.Events; using UnityEngine.EventSystems; using UnityEngine.UI; -using AudioType = AlicizaX.Audio.Runtime.AudioType; [Serializable] public enum ButtonModeType @@ -403,8 +402,8 @@ public class UXButton : UIBehaviour, IButton, private void PlayButtonSound(AudioClip clip) { - if (clip == null || GameApp.Audio == null) return; - GameApp.Audio.Play(AudioType.UISound, clip, false, GameApp.Audio.UISoundVolume); + if (clip == null || UXComponentExtensionsHelper.AudioHelper == null) return; + UXComponentExtensionsHelper.AudioHelper.PlayAudio(clip); } private IEnumerator OnFinishSubmit() diff --git a/Runtime/UXComponent/UXHelper.cs b/Runtime/UXComponent/UXHelper.cs new file mode 100644 index 0000000..9b24f6e --- /dev/null +++ b/Runtime/UXComponent/UXHelper.cs @@ -0,0 +1,29 @@ +using UnityEngine; + +public static class UXComponentExtensionsHelper +{ + internal static IUXLocalizationHelper LocalizationHelper; + internal static IUXAudioHelper AudioHelper; + + public static void SetLocalizationHelper(IUXLocalizationHelper helper) + { + LocalizationHelper = helper; + } + + public static void SetAudioHelper(IUXAudioHelper helper) + { + AudioHelper = helper; + } +} + +public interface IUXLocalizationHelper +{ + public string GetString(string key); +} + + +public interface IUXAudioHelper +{ + void PlayAudio(AudioClip clip); + void PlayAudio(string clipName); +} diff --git a/Runtime/UXComponent/IUXLocalizationHelper.cs.meta b/Runtime/UXComponent/UXHelper.cs.meta similarity index 100% rename from Runtime/UXComponent/IUXLocalizationHelper.cs.meta rename to Runtime/UXComponent/UXHelper.cs.meta