【m】1111
This commit is contained in:
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: f6e218215da269c45b6b578b4eb0da12
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,268 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
using UnityEngine.Events;
|
||||
using UnityEngine.UI;
|
||||
|
||||
namespace Stary.Evo
|
||||
{
|
||||
|
||||
public enum AnchorPresets
|
||||
{
|
||||
TopLeft,
|
||||
TopCenter,
|
||||
TopRight,
|
||||
|
||||
MiddleLeft,
|
||||
MiddleCenter,
|
||||
MiddleRight,
|
||||
|
||||
BottomLeft,
|
||||
BottonCenter,
|
||||
BottomRight,
|
||||
BottomStretch,
|
||||
|
||||
VertStretchLeft,
|
||||
VertStretchRight,
|
||||
VertStretchCenter,
|
||||
|
||||
HorStretchTop,
|
||||
HorStretchMiddle,
|
||||
HorStretchBottom,
|
||||
|
||||
StretchAll
|
||||
}
|
||||
|
||||
public enum PivotPresets
|
||||
{
|
||||
TopLeft,
|
||||
TopCenter,
|
||||
TopRight,
|
||||
|
||||
MiddleLeft,
|
||||
MiddleCenter,
|
||||
MiddleRight,
|
||||
|
||||
BottomLeft,
|
||||
BottomCenter,
|
||||
BottomRight,
|
||||
}
|
||||
|
||||
public static class UIExtension
|
||||
{
|
||||
public static void SetAnchor(this RectTransform source, AnchorPresets allign, int offsetX = 0, int offsetY = 0)
|
||||
{
|
||||
source.anchoredPosition = new Vector3(offsetX, offsetY, 0);
|
||||
|
||||
switch (allign)
|
||||
{
|
||||
case (AnchorPresets.TopLeft):
|
||||
{
|
||||
source.anchorMin = new Vector2(0, 1);
|
||||
source.anchorMax = new Vector2(0, 1);
|
||||
break;
|
||||
}
|
||||
case (AnchorPresets.TopCenter):
|
||||
{
|
||||
source.anchorMin = new Vector2(0.5f, 1);
|
||||
source.anchorMax = new Vector2(0.5f, 1);
|
||||
break;
|
||||
}
|
||||
case (AnchorPresets.TopRight):
|
||||
{
|
||||
source.anchorMin = new Vector2(1, 1);
|
||||
source.anchorMax = new Vector2(1, 1);
|
||||
break;
|
||||
}
|
||||
|
||||
case (AnchorPresets.MiddleLeft):
|
||||
{
|
||||
source.anchorMin = new Vector2(0, 0.5f);
|
||||
source.anchorMax = new Vector2(0, 0.5f);
|
||||
break;
|
||||
}
|
||||
case (AnchorPresets.MiddleCenter):
|
||||
{
|
||||
source.anchorMin = new Vector2(0.5f, 0.5f);
|
||||
source.anchorMax = new Vector2(0.5f, 0.5f);
|
||||
break;
|
||||
}
|
||||
case (AnchorPresets.MiddleRight):
|
||||
{
|
||||
source.anchorMin = new Vector2(1, 0.5f);
|
||||
source.anchorMax = new Vector2(1, 0.5f);
|
||||
break;
|
||||
}
|
||||
|
||||
case (AnchorPresets.BottomLeft):
|
||||
{
|
||||
source.anchorMin = new Vector2(0, 0);
|
||||
source.anchorMax = new Vector2(0, 0);
|
||||
break;
|
||||
}
|
||||
case (AnchorPresets.BottonCenter):
|
||||
{
|
||||
source.anchorMin = new Vector2(0.5f, 0);
|
||||
source.anchorMax = new Vector2(0.5f, 0);
|
||||
break;
|
||||
}
|
||||
case (AnchorPresets.BottomRight):
|
||||
{
|
||||
source.anchorMin = new Vector2(1, 0);
|
||||
source.anchorMax = new Vector2(1, 0);
|
||||
break;
|
||||
}
|
||||
|
||||
case (AnchorPresets.HorStretchTop):
|
||||
{
|
||||
source.anchorMin = new Vector2(0, 1);
|
||||
source.anchorMax = new Vector2(1, 1);
|
||||
break;
|
||||
}
|
||||
case (AnchorPresets.HorStretchMiddle):
|
||||
{
|
||||
source.anchorMin = new Vector2(0, 0.5f);
|
||||
source.anchorMax = new Vector2(1, 0.5f);
|
||||
break;
|
||||
}
|
||||
case (AnchorPresets.HorStretchBottom):
|
||||
{
|
||||
source.anchorMin = new Vector2(0, 0);
|
||||
source.anchorMax = new Vector2(1, 0);
|
||||
break;
|
||||
}
|
||||
|
||||
case (AnchorPresets.VertStretchLeft):
|
||||
{
|
||||
source.anchorMin = new Vector2(0, 0);
|
||||
source.anchorMax = new Vector2(0, 1);
|
||||
break;
|
||||
}
|
||||
case (AnchorPresets.VertStretchCenter):
|
||||
{
|
||||
source.anchorMin = new Vector2(0.5f, 0);
|
||||
source.anchorMax = new Vector2(0.5f, 1);
|
||||
break;
|
||||
}
|
||||
case (AnchorPresets.VertStretchRight):
|
||||
{
|
||||
source.anchorMin = new Vector2(1, 0);
|
||||
source.anchorMax = new Vector2(1, 1);
|
||||
break;
|
||||
}
|
||||
|
||||
case (AnchorPresets.StretchAll):
|
||||
{
|
||||
source.anchorMin = new Vector2(0, 0);
|
||||
source.anchorMax = new Vector2(1, 1);
|
||||
source.sizeDelta = Vector2.zero;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static void SetPivot(this RectTransform source, PivotPresets preset)
|
||||
{
|
||||
|
||||
switch (preset)
|
||||
{
|
||||
case (PivotPresets.TopLeft):
|
||||
{
|
||||
source.pivot = new Vector2(0, 1);
|
||||
break;
|
||||
}
|
||||
case (PivotPresets.TopCenter):
|
||||
{
|
||||
source.pivot = new Vector2(0.5f, 1);
|
||||
break;
|
||||
}
|
||||
case (PivotPresets.TopRight):
|
||||
{
|
||||
source.pivot = new Vector2(1, 1);
|
||||
break;
|
||||
}
|
||||
|
||||
case (PivotPresets.MiddleLeft):
|
||||
{
|
||||
source.pivot = new Vector2(0, 0.5f);
|
||||
break;
|
||||
}
|
||||
case (PivotPresets.MiddleCenter):
|
||||
{
|
||||
source.pivot = new Vector2(0.5f, 0.5f);
|
||||
break;
|
||||
}
|
||||
case (PivotPresets.MiddleRight):
|
||||
{
|
||||
source.pivot = new Vector2(1, 0.5f);
|
||||
break;
|
||||
}
|
||||
|
||||
case (PivotPresets.BottomLeft):
|
||||
{
|
||||
source.pivot = new Vector2(0, 0);
|
||||
break;
|
||||
}
|
||||
case (PivotPresets.BottomCenter):
|
||||
{
|
||||
source.pivot = new Vector2(0.5f, 0);
|
||||
break;
|
||||
}
|
||||
case (PivotPresets.BottomRight):
|
||||
{
|
||||
source.pivot = new Vector2(1, 0);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static CanvasGroup CreateBlackMask(Transform parent, float alpha = 0, string name = null)
|
||||
{
|
||||
GameObject maskGo = new GameObject("Black Mask");
|
||||
RectTransform rectTransform = maskGo.AddComponent<RectTransform>();
|
||||
rectTransform.SetParentEx(parent);
|
||||
rectTransform.anchorMin = Vector2.zero;
|
||||
rectTransform.anchorMax = Vector2.one;
|
||||
Image image = maskGo.AddComponent<Image>();
|
||||
image.color = Color.black;
|
||||
image.raycastTarget = false;
|
||||
CanvasGroup canvasGroup = maskGo.AddComponent<CanvasGroup>();
|
||||
canvasGroup.alpha = alpha;
|
||||
if(name != null)
|
||||
canvasGroup.name = name;
|
||||
return canvasGroup;
|
||||
}
|
||||
|
||||
public static Canvas CreateLayerCanvas(UILayer layer, bool is3D, Transform parent, Camera camera, float width, float height)
|
||||
{
|
||||
GameObject canvasGo = new GameObject(layer.ToString());
|
||||
RectTransform rectTransform = canvasGo.AddComponent<RectTransform>();
|
||||
rectTransform.SetParentEx(parent);
|
||||
rectTransform.anchorMin = Vector2.zero;
|
||||
rectTransform.anchorMax = Vector2.one;
|
||||
canvasGo.layer = is3D ? Layer.Default : Layer.UI;
|
||||
Canvas canvas = canvasGo.AddComponent<Canvas>();
|
||||
canvas.renderMode = is3D ? RenderMode.WorldSpace : RenderMode.ScreenSpaceCamera;
|
||||
canvas.overrideSorting = true;
|
||||
canvas.sortingOrder = (int)layer;
|
||||
canvas.worldCamera = camera;
|
||||
canvas.pixelPerfect = false;
|
||||
CanvasScaler canvasScaler = canvasGo.AddComponent<CanvasScaler>();
|
||||
canvasScaler.uiScaleMode = CanvasScaler.ScaleMode.ScaleWithScreenSize;
|
||||
canvasScaler.referenceResolution = new Vector2(height,width);
|
||||
canvasScaler.screenMatchMode = CanvasScaler.ScreenMatchMode.Expand;
|
||||
|
||||
canvasGo.AddComponent<GraphicRaycaster>();
|
||||
|
||||
return canvas;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 为方便统一处理点击音效等
|
||||
/// </summary>
|
||||
public static void AddClick(this Button button, UnityAction callback)
|
||||
{
|
||||
button.onClick.AddListener(callback);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: b521dcf8e49760e4fa28db6a6436ebc3
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: ab9e1d815209d5e469824bfa1bbc399c
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,15 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Stary.Evo
|
||||
{
|
||||
public static class Layer
|
||||
{
|
||||
public const int Default = 0;
|
||||
public const int TransparentFX = 1;
|
||||
public const int IgnoreRaycast = 2;
|
||||
public const int Water = 4;
|
||||
public const int UI = 5;
|
||||
public const int UIRenderToTarget = 6;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: f57fecb20b667bb45a6240fd6b16fc80
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,65 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Stary.Evo
|
||||
{
|
||||
public static class ObjectExtension
|
||||
{
|
||||
private static readonly List<Transform> s_CachedTransforms = new List<Transform>();
|
||||
|
||||
public static T GetOrAddComponent<T>(this Component obj) where T : Component
|
||||
{
|
||||
return obj.gameObject.GetOrAddComponent<T>();
|
||||
}
|
||||
|
||||
public static T GetOrAddComponent<T>(this GameObject gameObject) where T : Component
|
||||
{
|
||||
T t = gameObject.GetComponent<T>();
|
||||
if (t == null)
|
||||
t = gameObject.AddComponent<T>();
|
||||
return t;
|
||||
}
|
||||
|
||||
public static Component GetOrAddComponent(this Component obj, Type type)
|
||||
{
|
||||
return obj.gameObject.GetOrAddComponent(type);
|
||||
}
|
||||
|
||||
public static Component GetOrAddComponent(this GameObject gameObject, Type type)
|
||||
{
|
||||
if (gameObject == null) return null;
|
||||
|
||||
Component component = gameObject.GetComponent(type);
|
||||
if (component == null)
|
||||
component = gameObject.AddComponent(type);
|
||||
return component;
|
||||
}
|
||||
|
||||
public static void SetParentEx(this Transform transform, Transform parent)
|
||||
{
|
||||
transform.SetParent(parent);
|
||||
transform.localPosition = Vector3.zero;
|
||||
transform.localRotation = Quaternion.identity;
|
||||
transform.localScale = Vector3.one;
|
||||
}
|
||||
|
||||
public static void SetLayerRecursively(this GameObject gameObject, int layer)
|
||||
{
|
||||
gameObject.GetComponentsInChildren(true, s_CachedTransforms);
|
||||
for (int i = 0; i < s_CachedTransforms.Count; i++)
|
||||
{
|
||||
s_CachedTransforms[i].gameObject.layer = layer;
|
||||
}
|
||||
s_CachedTransforms.Clear();
|
||||
}
|
||||
|
||||
public static void AddOrUpdate<TKey, TValue>(this IDictionary<TKey, TValue> dict, TKey key, TValue value)
|
||||
{
|
||||
if (dict.ContainsKey(key))
|
||||
dict[key] = value;
|
||||
else
|
||||
dict.Add(key, value);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 1255735e746b217478dc63262723567a
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,194 @@
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Stary.Evo
|
||||
{
|
||||
public static class Pool
|
||||
{
|
||||
public readonly static List<PoolBase> AllPool = new List<PoolBase>();
|
||||
|
||||
public static void ReleaseAll()
|
||||
{
|
||||
foreach (var pool in AllPool)
|
||||
{
|
||||
pool.Dispose();
|
||||
}
|
||||
AllPool.Clear();
|
||||
}
|
||||
}
|
||||
|
||||
public interface IObject
|
||||
{
|
||||
void OnRelease();
|
||||
}
|
||||
|
||||
public interface PoolBase
|
||||
{
|
||||
void Dispose();
|
||||
}
|
||||
|
||||
public class ObjectPool<T> : PoolBase where T : new()
|
||||
{
|
||||
private static ObjectPool<T> Instance;
|
||||
|
||||
private Stack<T> _pool;
|
||||
|
||||
private ObjectPool() { }
|
||||
|
||||
|
||||
private static void Init()
|
||||
{
|
||||
if (Instance == null)
|
||||
{
|
||||
Instance = new ObjectPool<T>();
|
||||
Instance._pool = new Stack<T>();
|
||||
Pool.AllPool.Add(Instance);
|
||||
}
|
||||
}
|
||||
|
||||
public static T Get()
|
||||
{
|
||||
Init();
|
||||
|
||||
if (Instance._pool.Count > 0)
|
||||
{
|
||||
return Instance._pool.Pop();
|
||||
}
|
||||
else
|
||||
{
|
||||
return new T();
|
||||
}
|
||||
}
|
||||
|
||||
public static void Release(T obj)
|
||||
{
|
||||
if (obj == null || Instance == null) return;
|
||||
|
||||
if (obj is IObject interfac)
|
||||
{
|
||||
interfac.OnRelease();
|
||||
}
|
||||
Instance._pool.Push(obj);
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
if (Instance != null)
|
||||
{
|
||||
if (Instance._pool != null)
|
||||
{
|
||||
Instance._pool.Clear();
|
||||
Instance._pool = null;
|
||||
}
|
||||
Instance = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public class ListPool<T> : PoolBase
|
||||
{
|
||||
private static ListPool<T> Instance;
|
||||
|
||||
private Stack<List<T>> _pool;
|
||||
|
||||
private ListPool() { }
|
||||
|
||||
private static void Init()
|
||||
{
|
||||
if (Instance == null)
|
||||
{
|
||||
Instance = new ListPool<T>();
|
||||
Instance._pool = new Stack<List<T>>();
|
||||
Pool.AllPool.Add(Instance);
|
||||
}
|
||||
}
|
||||
|
||||
public static List<T> Get()
|
||||
{
|
||||
Init();
|
||||
|
||||
if (Instance._pool.Count > 0)
|
||||
{
|
||||
return Instance._pool.Pop();
|
||||
}
|
||||
else
|
||||
{
|
||||
return new List<T>();
|
||||
}
|
||||
}
|
||||
|
||||
public static void Release(List<T> list)
|
||||
{
|
||||
if (list == null || Instance == null) return;
|
||||
list.Clear();
|
||||
Instance._pool.Push(list);
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
if (Instance != null)
|
||||
{
|
||||
if (Instance._pool != null)
|
||||
{
|
||||
Instance._pool.Clear();
|
||||
Instance._pool = null;
|
||||
}
|
||||
Instance = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public class DictionaryPool<Key, Value> : PoolBase
|
||||
{
|
||||
private static DictionaryPool<Key, Value> Instance;
|
||||
|
||||
private Stack<Dictionary<Key, Value>> _pool;
|
||||
|
||||
private DictionaryPool() { }
|
||||
|
||||
private static void Init()
|
||||
{
|
||||
if (Instance == null)
|
||||
{
|
||||
Instance = new DictionaryPool<Key, Value>();
|
||||
Instance._pool = new Stack<Dictionary<Key, Value>>();
|
||||
Pool.AllPool.Add(Instance);
|
||||
}
|
||||
}
|
||||
|
||||
public static Dictionary<Key, Value> Get()
|
||||
{
|
||||
Init();
|
||||
|
||||
if (Instance._pool.Count > 0)
|
||||
{
|
||||
return Instance._pool.Pop();
|
||||
}
|
||||
else
|
||||
{
|
||||
return new Dictionary<Key, Value>();
|
||||
}
|
||||
}
|
||||
|
||||
public static void Release(Dictionary<Key, Value> dict)
|
||||
{
|
||||
if (dict == null || Instance == null) return;
|
||||
dict.Clear();
|
||||
Instance._pool.Push(dict);
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
if (Instance != null)
|
||||
{
|
||||
if (Instance._pool != null)
|
||||
{
|
||||
Instance._pool.Clear();
|
||||
Instance._pool = null;
|
||||
}
|
||||
Instance = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 59e9f74cfa6aa344c91bcdcc6db78ac6
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,140 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Stary.Evo
|
||||
{
|
||||
public class PrefabPool
|
||||
{
|
||||
/// <summary>
|
||||
/// 如果名字一样,则使用同一个池子
|
||||
/// </summary>
|
||||
public static Dictionary<string, PrefabPool> s_Pools = new Dictionary<string, PrefabPool>();
|
||||
|
||||
private string _poolName;
|
||||
private GameObject _prefab;
|
||||
private List<GameObject> _pool;
|
||||
private List<GameObject> _useList;
|
||||
|
||||
public GameObject Prefab => _prefab;
|
||||
public List<GameObject> UseList => _useList;
|
||||
|
||||
private PrefabPool() { }
|
||||
|
||||
private void Init(string poolName, GameObject prefab)
|
||||
{
|
||||
_pool = ListPool<GameObject>.Get();
|
||||
_useList = ListPool<GameObject>.Get();
|
||||
_prefab = prefab;
|
||||
_poolName = poolName;
|
||||
}
|
||||
|
||||
public static PrefabPool Get(string poolName)
|
||||
{
|
||||
if (!string.IsNullOrEmpty(poolName))
|
||||
{
|
||||
if (s_Pools.TryGetValue(poolName, out var prefabPool))
|
||||
{
|
||||
return prefabPool;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public static PrefabPool Create(GameObject prefab, string poolName = null)
|
||||
{
|
||||
if (prefab == null) return null;
|
||||
if (!string.IsNullOrEmpty(poolName))
|
||||
{
|
||||
if (s_Pools.TryGetValue(poolName, out var prefabPool))
|
||||
{
|
||||
return prefabPool;
|
||||
}
|
||||
}
|
||||
var pool = new PrefabPool();
|
||||
pool.Init(poolName, prefab);
|
||||
if (!string.IsNullOrEmpty(poolName))
|
||||
{
|
||||
s_Pools.Add(poolName, pool);
|
||||
}
|
||||
return pool;
|
||||
}
|
||||
|
||||
public GameObject Get(Transform parent = null)
|
||||
{
|
||||
if (_prefab == null) return null;
|
||||
|
||||
GameObject go = null;
|
||||
if (_pool.Count > 0)
|
||||
{
|
||||
go = _pool[0];
|
||||
_pool.RemoveAt(0);
|
||||
}
|
||||
else
|
||||
{
|
||||
go = GameObject.Instantiate(_prefab);
|
||||
}
|
||||
go.transform.parent = parent;
|
||||
go.transform.localScale = Vector3.one;
|
||||
go.transform.localPosition = Vector3.zero;
|
||||
go.transform.localRotation = Quaternion.identity;
|
||||
go.SetActive(true);
|
||||
go.transform.SetAsLastSibling();
|
||||
_useList.Add(go);
|
||||
return go;
|
||||
}
|
||||
|
||||
public void Recycle(GameObject go)
|
||||
{
|
||||
if (go != null)
|
||||
{
|
||||
go.SetActive(false);
|
||||
_pool.Add(go);
|
||||
_useList.Remove(go);
|
||||
}
|
||||
}
|
||||
|
||||
public void RecycleUseList()
|
||||
{
|
||||
foreach (var go in _useList)
|
||||
{
|
||||
if (go != null)
|
||||
{
|
||||
go.SetActive(false);
|
||||
_pool.Add(go);
|
||||
}
|
||||
}
|
||||
_useList.Clear();
|
||||
}
|
||||
|
||||
public void Destroy()
|
||||
{
|
||||
foreach (var go in _pool)
|
||||
{
|
||||
if (go != null)
|
||||
{
|
||||
GameObject.Destroy(go);
|
||||
}
|
||||
}
|
||||
_pool.Clear();
|
||||
foreach (var go in _useList)
|
||||
{
|
||||
if (go != null)
|
||||
{
|
||||
GameObject.Destroy(go);
|
||||
}
|
||||
}
|
||||
_useList.Clear();
|
||||
|
||||
ListPool<GameObject>.Release(_pool);
|
||||
ListPool<GameObject>.Release(_useList);
|
||||
|
||||
s_Pools.Remove(_poolName);
|
||||
|
||||
_pool = null;
|
||||
_useList = null;
|
||||
_prefab = null;
|
||||
_poolName = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 02cdac12da067fa479f36e34fafd0987
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,71 @@
|
||||
using UnityEngine;
|
||||
|
||||
public abstract class Singleton<T> where T : new()
|
||||
{
|
||||
private static T _ServiceContext;
|
||||
private readonly static object lockObj = new object();
|
||||
|
||||
/// <summary>
|
||||
/// 禁止外部进行实例化
|
||||
/// </summary>
|
||||
protected Singleton()
|
||||
{
|
||||
OnInitialize();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取唯一实例,双锁定防止多线程并发时重复创建实例
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public static T Instance
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_ServiceContext == null)
|
||||
{
|
||||
lock (lockObj)
|
||||
{
|
||||
if (_ServiceContext == null)
|
||||
{
|
||||
_ServiceContext = new T();
|
||||
}
|
||||
}
|
||||
}
|
||||
return _ServiceContext;
|
||||
}
|
||||
}
|
||||
public virtual void OnInitialize() { }
|
||||
|
||||
public void Init() { }
|
||||
}
|
||||
|
||||
|
||||
public class SingletonMono<T> : MonoBehaviour where T : MonoBehaviour
|
||||
{
|
||||
private static T _instance;
|
||||
|
||||
public static T Instance
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_instance == null)
|
||||
{
|
||||
_instance = (T)FindObjectOfType(typeof(T));
|
||||
if (_instance == null)
|
||||
{
|
||||
GameObject singleton = new GameObject();
|
||||
_instance = singleton.AddComponent<T>();
|
||||
singleton.name = typeof(T).ToString();
|
||||
DontDestroyOnLoad(singleton);
|
||||
}
|
||||
}
|
||||
return _instance;
|
||||
}
|
||||
}
|
||||
|
||||
public virtual void OnDestroy()
|
||||
{
|
||||
_instance = null;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 26a0ecd7bd1fa9441a7229d39408180c
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,52 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Stary.Evo
|
||||
{
|
||||
public class TreeNode
|
||||
{
|
||||
public Dictionary<ulong, TreeNode> childs;
|
||||
public ulong id;
|
||||
public object data;
|
||||
|
||||
public TreeNode Get(ulong id)
|
||||
{
|
||||
if (childs == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
childs.TryGetValue(id, out var node);
|
||||
return node;
|
||||
}
|
||||
|
||||
public TreeNode GetOrAdd(ulong id)
|
||||
{
|
||||
if (childs == null)
|
||||
{
|
||||
childs = new Dictionary<ulong, TreeNode>();
|
||||
}
|
||||
if (!childs.TryGetValue(id, out var node))
|
||||
{
|
||||
node = ObjectPool<TreeNode>.Get();
|
||||
node.id = id;
|
||||
childs.Add(id, node);
|
||||
}
|
||||
return node;
|
||||
}
|
||||
|
||||
public void CleanUp()
|
||||
{
|
||||
if (childs != null)
|
||||
{
|
||||
foreach (var item in childs.Values)
|
||||
{
|
||||
item.CleanUp();
|
||||
ObjectPool<TreeNode>.Release(item);
|
||||
}
|
||||
childs.Clear();
|
||||
}
|
||||
id = 0;
|
||||
data = default;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: dc97d6286a198a946a032cc4fa7fe2cf
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: d1c08d26fe3fa4740b2a4398ea9ee65b
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,135 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Stary.Evo
|
||||
{
|
||||
public class InstancePool
|
||||
{
|
||||
private static string GameObjectName = "GameObjectPool";
|
||||
private static string RecycleName = "RecyclePool";
|
||||
private Dictionary<string, Stack<GameObject>> _allInstances = new Dictionary<string, Stack<GameObject>>();
|
||||
private Transform _instancePoolTransRoot = null;
|
||||
private Transform _recyclePoolTransRoot = null;
|
||||
|
||||
public InstancePool()
|
||||
{
|
||||
var go = new GameObject(GameObjectName);
|
||||
GameObject.DontDestroyOnLoad(go);
|
||||
|
||||
_instancePoolTransRoot = go.transform;
|
||||
go.SetActive(true);
|
||||
|
||||
_recyclePoolTransRoot = _instancePoolTransRoot.Find(RecycleName);
|
||||
if (_recyclePoolTransRoot == null)
|
||||
{
|
||||
_recyclePoolTransRoot = new GameObject(RecycleName).transform;
|
||||
_recyclePoolTransRoot.SetParent(_instancePoolTransRoot);
|
||||
}
|
||||
|
||||
_recyclePoolTransRoot.gameObject.SetActive(false);
|
||||
}
|
||||
|
||||
public GameObject Get(string key)
|
||||
{
|
||||
Stack<GameObject> objects = null;
|
||||
if (!_allInstances.TryGetValue(key, out objects))
|
||||
{
|
||||
return null;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (objects == null || objects.Count == 0)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
return objects.Pop();
|
||||
}
|
||||
}
|
||||
|
||||
public void Recycle(string key, GameObject obj, bool forceDestroy = false)
|
||||
{
|
||||
//强制删除
|
||||
if (forceDestroy)
|
||||
{
|
||||
if (Application.isPlaying)
|
||||
{
|
||||
GameObject.Destroy(obj);
|
||||
}
|
||||
else
|
||||
{
|
||||
GameObject.DestroyImmediate(obj);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
Stack<GameObject> objects = null;
|
||||
if (!_allInstances.TryGetValue(key, out objects))
|
||||
{
|
||||
objects = new Stack<GameObject>();
|
||||
_allInstances[key] = objects;
|
||||
}
|
||||
|
||||
InitInst(obj, false);
|
||||
objects.Push(obj);
|
||||
}
|
||||
|
||||
public void Clear(string key)
|
||||
{
|
||||
Stack<GameObject> objects = null;
|
||||
if (_allInstances.TryGetValue(key, out objects))
|
||||
{
|
||||
while (objects.Count > 0)
|
||||
{
|
||||
GameObject objToDestroy = objects.Pop();
|
||||
if (Application.isPlaying)
|
||||
{
|
||||
GameObject.Destroy(objToDestroy);
|
||||
}
|
||||
else
|
||||
{
|
||||
GameObject.DestroyImmediate(objToDestroy);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void ClearAll()
|
||||
{
|
||||
foreach (var item in _allInstances)
|
||||
{
|
||||
while (item.Value.Count > 0)
|
||||
{
|
||||
GameObject objToDestroy = item.Value.Pop();
|
||||
if (Application.isPlaying)
|
||||
{
|
||||
GameObject.Destroy(objToDestroy);
|
||||
}
|
||||
else
|
||||
{
|
||||
GameObject.DestroyImmediate(objToDestroy);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
_allInstances.Clear();
|
||||
}
|
||||
|
||||
public void InitInst(GameObject inst, bool active = true)
|
||||
{
|
||||
if (inst != null)
|
||||
{
|
||||
if (active)
|
||||
{
|
||||
inst.transform.SetParent(_instancePoolTransRoot, true);
|
||||
}
|
||||
else
|
||||
{
|
||||
inst.transform.SetParent(_recyclePoolTransRoot, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: b78b11e8c4a134f478ab61d5c6334deb
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 125226ccd07f47c5bf3b94157bf12fc3
|
||||
timeCreated: 1758179120
|
||||
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: ae09f872dbca2d84fa2a065b22315aef
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,5 @@
|
||||
fileFormatVersion: 2
|
||||
guid: a6bdd27938945f0449bc8fe7947f2bf2
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
userData:
|
||||
@@ -0,0 +1,135 @@
|
||||
using UnityEngine;
|
||||
|
||||
/// <summary>
|
||||
/// Tween the object's alpha. Works with both UI widgets as well as renderers.
|
||||
/// </summary>
|
||||
|
||||
[AddComponentMenu("Tween/Tween Alpha")]
|
||||
public class TweenAlpha : UITweener
|
||||
{
|
||||
[Range(0f, 1f)] public float from = 1f;
|
||||
[Range(0f, 1f)] public float to = 1f;
|
||||
|
||||
[Tooltip("If used on a renderer, the material should probably be cleaned up after this script gets destroyed...")]
|
||||
public bool autoCleanup = false;
|
||||
|
||||
[Tooltip("Color to adjust")]
|
||||
public string colorProperty;
|
||||
|
||||
[System.NonSerialized] bool mCached = false;
|
||||
[System.NonSerialized] CanvasGroup mRect;
|
||||
[System.NonSerialized] Material mShared;
|
||||
[System.NonSerialized] Material mMat;
|
||||
[System.NonSerialized] Light mLight;
|
||||
[System.NonSerialized] SpriteRenderer mSr;
|
||||
[System.NonSerialized] float mBaseIntensity = 1f;
|
||||
|
||||
[System.Obsolete("Use 'value' instead")]
|
||||
public float alpha { get { return this.value; } set { this.value = value; } }
|
||||
|
||||
void OnDestroy () { if (autoCleanup && mMat != null && mShared != mMat) { Destroy(mMat); mMat = null; } }
|
||||
|
||||
void Cache ()
|
||||
{
|
||||
mCached = true;
|
||||
mRect = GetComponent<CanvasGroup>();
|
||||
mSr = GetComponent<SpriteRenderer>();
|
||||
|
||||
if (mRect == null && mSr == null)
|
||||
{
|
||||
mLight = GetComponent<Light>();
|
||||
|
||||
if (mLight == null)
|
||||
{
|
||||
var ren = GetComponent<Renderer>();
|
||||
|
||||
if (ren != null)
|
||||
{
|
||||
mShared = ren.sharedMaterial;
|
||||
mMat = ren.material;
|
||||
}
|
||||
|
||||
if (mMat == null) mRect = GetComponentInChildren<CanvasGroup>();
|
||||
}
|
||||
else mBaseIntensity = mLight.intensity;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Tween's current value.
|
||||
/// </summary>
|
||||
|
||||
public float value
|
||||
{
|
||||
get
|
||||
{
|
||||
if (!mCached) Cache();
|
||||
if (mRect != null) return mRect.alpha;
|
||||
if (mSr != null) return mSr.color.a;
|
||||
if (mMat == null) return 1f;
|
||||
if (string.IsNullOrEmpty(colorProperty)) return mMat.color.a;
|
||||
return mMat.GetColor(colorProperty).a;
|
||||
}
|
||||
set
|
||||
{
|
||||
if (!mCached) Cache();
|
||||
|
||||
if (mRect != null)
|
||||
{
|
||||
mRect.alpha = value;
|
||||
}
|
||||
else if (mSr != null)
|
||||
{
|
||||
var c = mSr.color;
|
||||
c.a = value;
|
||||
mSr.color = c;
|
||||
}
|
||||
else if (mMat != null)
|
||||
{
|
||||
if (string.IsNullOrEmpty(colorProperty))
|
||||
{
|
||||
var c = mMat.color;
|
||||
c.a = value;
|
||||
mMat.color = c;
|
||||
}
|
||||
else
|
||||
{
|
||||
var c = mMat.GetColor(colorProperty);
|
||||
c.a = value;
|
||||
mMat.SetColor(colorProperty, c);
|
||||
}
|
||||
}
|
||||
else if (mLight != null)
|
||||
{
|
||||
mLight.intensity = mBaseIntensity * value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Tween the value.
|
||||
/// </summary>
|
||||
|
||||
protected override void OnUpdate (float factor, bool isFinished) { value = Mathf.Lerp(from, to, factor); }
|
||||
|
||||
/// <summary>
|
||||
/// Start the tweening operation.
|
||||
/// </summary>
|
||||
|
||||
static public TweenAlpha Begin (GameObject go, float duration, float alpha, float delay = 0f)
|
||||
{
|
||||
var comp = UITweener.Begin<TweenAlpha>(go, duration, delay);
|
||||
comp.from = comp.value;
|
||||
comp.to = alpha;
|
||||
|
||||
if (duration <= 0f)
|
||||
{
|
||||
comp.Sample(1f, true);
|
||||
comp.enabled = false;
|
||||
}
|
||||
return comp;
|
||||
}
|
||||
|
||||
public override void SetStartToCurrentValue () { from = value; }
|
||||
public override void SetEndToCurrentValue () { to = value; }
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 9e2747e3775af504da1a4d5a46c5a1ce
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
@@ -0,0 +1,118 @@
|
||||
using UnityEngine;
|
||||
using UnityEngine.UI;
|
||||
|
||||
/// <summary>
|
||||
/// Tween the object's color.
|
||||
/// </summary>
|
||||
|
||||
[AddComponentMenu("Tween/Tween Color")]
|
||||
public class TweenColor : UITweener
|
||||
{
|
||||
public Color from = Color.white;
|
||||
public Color to = Color.white;
|
||||
|
||||
bool mCached = false;
|
||||
Graphic mGraphic;
|
||||
Material mMat;
|
||||
Light mLight;
|
||||
SpriteRenderer mSr;
|
||||
|
||||
void Cache ()
|
||||
{
|
||||
mCached = true;
|
||||
mGraphic = GetComponent<Graphic>();
|
||||
if (mGraphic != null) return;
|
||||
|
||||
mSr = GetComponent<SpriteRenderer>();
|
||||
if (mSr != null) return;
|
||||
|
||||
#if UNITY_4_3 || UNITY_4_5 || UNITY_4_6 || UNITY_4_7
|
||||
Renderer ren = renderer;
|
||||
#else
|
||||
Renderer ren = GetComponent<Renderer>();
|
||||
#endif
|
||||
if (ren != null)
|
||||
{
|
||||
mMat = ren.material;
|
||||
return;
|
||||
}
|
||||
|
||||
#if UNITY_4_3 || UNITY_4_5 || UNITY_4_6 || UNITY_4_7
|
||||
mLight = light;
|
||||
#else
|
||||
mLight = GetComponent<Light>();
|
||||
#endif
|
||||
if (mLight == null) mGraphic = GetComponentInChildren<Graphic>();
|
||||
}
|
||||
|
||||
[System.Obsolete("Use 'value' instead")]
|
||||
public Color color { get { return this.value; } set { this.value = value; } }
|
||||
|
||||
/// <summary>
|
||||
/// Tween's current value.
|
||||
/// </summary>
|
||||
|
||||
public Color value
|
||||
{
|
||||
get
|
||||
{
|
||||
if (!mCached) Cache();
|
||||
if (mGraphic != null) return mGraphic.color;
|
||||
if (mMat != null) return mMat.color;
|
||||
if (mSr != null) return mSr.color;
|
||||
if (mLight != null) return mLight.color;
|
||||
return Color.black;
|
||||
}
|
||||
set
|
||||
{
|
||||
if (!mCached) Cache();
|
||||
if (mGraphic != null) mGraphic.color = value;
|
||||
else if (mMat != null) mMat.color = value;
|
||||
else if (mSr != null) mSr.color = value;
|
||||
else if (mLight != null)
|
||||
{
|
||||
mLight.color = value;
|
||||
mLight.enabled = (value.r + value.g + value.b) > 0.01f;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Tween the value.
|
||||
/// </summary>
|
||||
|
||||
protected override void OnUpdate (float factor, bool isFinished) { value = Color.Lerp(from, to, factor); }
|
||||
|
||||
/// <summary>
|
||||
/// Start the tweening operation.
|
||||
/// </summary>
|
||||
|
||||
static public TweenColor Begin (GameObject go, float duration, Color color)
|
||||
{
|
||||
#if UNITY_EDITOR
|
||||
if (!Application.isPlaying) return null;
|
||||
#endif
|
||||
TweenColor comp = UITweener.Begin<TweenColor>(go, duration);
|
||||
comp.from = comp.value;
|
||||
comp.to = color;
|
||||
|
||||
if (duration <= 0f)
|
||||
{
|
||||
comp.Sample(1f, true);
|
||||
comp.enabled = false;
|
||||
}
|
||||
return comp;
|
||||
}
|
||||
|
||||
[ContextMenu("Set 'From' to current value")]
|
||||
public override void SetStartToCurrentValue () { from = value; }
|
||||
|
||||
[ContextMenu("Set 'To' to current value")]
|
||||
public override void SetEndToCurrentValue () { to = value; }
|
||||
|
||||
[ContextMenu("Assume value of 'From'")]
|
||||
void SetCurrentValueToStart () { value = from; }
|
||||
|
||||
[ContextMenu("Assume value of 'To'")]
|
||||
void SetCurrentValueToEnd () { value = to; }
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: cfa4a4a103e4fed43a7e9e9df4a6915c
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
@@ -0,0 +1,66 @@
|
||||
using UnityEngine;
|
||||
|
||||
/// <summary>
|
||||
/// Tween the camera's field of view.
|
||||
/// </summary>
|
||||
|
||||
[RequireComponent(typeof(Camera))]
|
||||
[AddComponentMenu("Tween/Tween Field of View")]
|
||||
public class TweenFOV : UITweener
|
||||
{
|
||||
public float from = 45f;
|
||||
public float to = 45f;
|
||||
|
||||
Camera mCam;
|
||||
|
||||
#if UNITY_4_3 || UNITY_4_5 || UNITY_4_6 || UNITY_4_7
|
||||
public Camera cachedCamera { get { if (mCam == null) mCam = camera; return mCam; } }
|
||||
#else
|
||||
public Camera cachedCamera { get { if (mCam == null) mCam = GetComponent<Camera>(); return mCam; } }
|
||||
#endif
|
||||
|
||||
[System.Obsolete("Use 'value' instead")]
|
||||
public float fov { get { return this.value; } set { this.value = value; } }
|
||||
|
||||
/// <summary>
|
||||
/// Tween's current value.
|
||||
/// </summary>
|
||||
|
||||
public float value { get { return cachedCamera.fieldOfView; } set { cachedCamera.fieldOfView = value; } }
|
||||
|
||||
/// <summary>
|
||||
/// Tween the value.
|
||||
/// </summary>
|
||||
|
||||
protected override void OnUpdate (float factor, bool isFinished) { value = from * (1f - factor) + to * factor; }
|
||||
|
||||
/// <summary>
|
||||
/// Start the tweening operation.
|
||||
/// </summary>
|
||||
|
||||
static public TweenFOV Begin (GameObject go, float duration, float to)
|
||||
{
|
||||
TweenFOV comp = UITweener.Begin<TweenFOV>(go, duration);
|
||||
comp.from = comp.value;
|
||||
comp.to = to;
|
||||
|
||||
if (duration <= 0f)
|
||||
{
|
||||
comp.Sample(1f, true);
|
||||
comp.enabled = false;
|
||||
}
|
||||
return comp;
|
||||
}
|
||||
|
||||
[ContextMenu("Set 'From' to current value")]
|
||||
public override void SetStartToCurrentValue () { from = value; }
|
||||
|
||||
[ContextMenu("Set 'To' to current value")]
|
||||
public override void SetEndToCurrentValue () { to = value; }
|
||||
|
||||
[ContextMenu("Assume value of 'From'")]
|
||||
void SetCurrentValueToStart () { value = from; }
|
||||
|
||||
[ContextMenu("Assume value of 'To'")]
|
||||
void SetCurrentValueToEnd () { value = to; }
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 0153adb55685cee4d97c4ee2d52124e5
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
@@ -0,0 +1,69 @@
|
||||
using UnityEngine;
|
||||
using UnityEngine.UI;
|
||||
|
||||
/// <summary>
|
||||
/// Tween the Image fill.
|
||||
/// </summary>
|
||||
|
||||
[RequireComponent(typeof(Image))]
|
||||
[AddComponentMenu("Tween/Tween Fill")]
|
||||
public class TweenFill : UITweener
|
||||
{
|
||||
[Range(0f, 1f)] public float from = 1f;
|
||||
[Range(0f, 1f)] public float to = 1f;
|
||||
|
||||
bool mCached = false;
|
||||
Image mSprite;
|
||||
|
||||
void Cache ()
|
||||
{
|
||||
mCached = true;
|
||||
mSprite = GetComponent<Image>();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Tween's current value.
|
||||
/// </summary>
|
||||
|
||||
public float value
|
||||
{
|
||||
get
|
||||
{
|
||||
if (!mCached) Cache();
|
||||
if (mSprite != null) return mSprite.fillAmount;
|
||||
return 0f;
|
||||
}
|
||||
set
|
||||
{
|
||||
if (!mCached) Cache();
|
||||
if (mSprite != null) mSprite.fillAmount = value;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Tween the value.
|
||||
/// </summary>
|
||||
|
||||
protected override void OnUpdate (float factor, bool isFinished) { value = Mathf.Lerp(from, to, factor); }
|
||||
|
||||
/// <summary>
|
||||
/// Start the tweening operation.
|
||||
/// </summary>
|
||||
|
||||
static public TweenFill Begin (GameObject go, float duration, float fill)
|
||||
{
|
||||
TweenFill comp = UITweener.Begin<TweenFill>(go, duration);
|
||||
comp.from = comp.value;
|
||||
comp.to = fill;
|
||||
|
||||
if (duration <= 0f)
|
||||
{
|
||||
comp.Sample(1f, true);
|
||||
comp.enabled = false;
|
||||
}
|
||||
return comp;
|
||||
}
|
||||
|
||||
public override void SetStartToCurrentValue () { from = value; }
|
||||
public override void SetEndToCurrentValue () { to = value; }
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 6ba7f59a1f412544f85ac3e66f0b5227
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
@@ -0,0 +1,74 @@
|
||||
using UnityEngine;
|
||||
|
||||
/// <summary>
|
||||
/// Tween the widget's size.
|
||||
/// </summary>
|
||||
|
||||
[RequireComponent(typeof(RectTransform))]
|
||||
[AddComponentMenu("Tween/Tween Height")]
|
||||
public class TweenHeight : UITweener
|
||||
{
|
||||
public float from = 100;
|
||||
public float to = 100;
|
||||
|
||||
[Tooltip("If set, 'from' value will be set to match the specified rectangle")]
|
||||
public RectTransform fromTarget;
|
||||
|
||||
[Tooltip("If set, 'to' value will be set to match the specified rectangle")]
|
||||
public RectTransform toTarget;
|
||||
|
||||
RectTransform mWidget;
|
||||
|
||||
public RectTransform cachedWidget { get { if (mWidget == null) mWidget = GetComponent<RectTransform>(); return mWidget; } }
|
||||
|
||||
[System.Obsolete("Use 'value' instead")]
|
||||
public float height { get { return this.value; } set { this.value = value; } }
|
||||
|
||||
/// <summary>
|
||||
/// Tween's current value.
|
||||
/// </summary>
|
||||
|
||||
public float value { get { return cachedWidget.rect.height; } set { cachedWidget.SetSizeWithCurrentAnchors(RectTransform.Axis.Vertical, value); } }
|
||||
|
||||
/// <summary>
|
||||
/// Tween the value.
|
||||
/// </summary>
|
||||
|
||||
protected override void OnUpdate (float factor, bool isFinished)
|
||||
{
|
||||
if (fromTarget) from = fromTarget.rect.width;
|
||||
if (toTarget) to = toTarget.rect.width;
|
||||
|
||||
value = Mathf.RoundToInt(from * (1f - factor) + to * factor);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Start the tweening operation.
|
||||
/// </summary>
|
||||
|
||||
static public TweenHeight Begin (RectTransform widget, float duration, int height)
|
||||
{
|
||||
TweenHeight comp = UITweener.Begin<TweenHeight>(widget.gameObject, duration);
|
||||
comp.from = widget.rect.height;
|
||||
comp.to = height;
|
||||
|
||||
if (duration <= 0f)
|
||||
{
|
||||
comp.Sample(1f, true);
|
||||
comp.enabled = false;
|
||||
}
|
||||
return comp;
|
||||
}
|
||||
|
||||
[ContextMenu("Set 'From' to current value")]
|
||||
public override void SetStartToCurrentValue () { from = value; }
|
||||
|
||||
[ContextMenu("Set 'To' to current value")]
|
||||
public override void SetEndToCurrentValue () { to = value; }
|
||||
|
||||
[ContextMenu("Assume value of 'From'")]
|
||||
void SetCurrentValueToStart () { value = from; }
|
||||
|
||||
[ContextMenu("Assume value of 'To'")]
|
||||
void SetCurrentValueToEnd () { value = to; }
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 66a6ab21c5f860946ade65b47cc0270b
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: -92
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
@@ -0,0 +1,65 @@
|
||||
using UnityEngine;
|
||||
|
||||
/// <summary>
|
||||
/// Tween the camera's orthographic size.
|
||||
/// </summary>
|
||||
|
||||
[RequireComponent(typeof(Camera))]
|
||||
[AddComponentMenu("Tween/Tween Orthographic Size")]
|
||||
public class TweenOrthoSize : UITweener
|
||||
{
|
||||
public float from = 1f;
|
||||
public float to = 1f;
|
||||
|
||||
Camera mCam;
|
||||
|
||||
/// <summary>
|
||||
/// Camera that's being tweened.
|
||||
/// </summary>
|
||||
|
||||
#if UNITY_4_3 || UNITY_4_5 || UNITY_4_6 || UNITY_4_7
|
||||
public Camera cachedCamera { get { if (mCam == null) mCam = camera; return mCam; } }
|
||||
#else
|
||||
public Camera cachedCamera { get { if (mCam == null) mCam = GetComponent<Camera>(); return mCam; } }
|
||||
#endif
|
||||
|
||||
[System.Obsolete("Use 'value' instead")]
|
||||
public float orthoSize { get { return this.value; } set { this.value = value; } }
|
||||
|
||||
/// <summary>
|
||||
/// Tween's current value.
|
||||
/// </summary>
|
||||
|
||||
public float value
|
||||
{
|
||||
get { return cachedCamera.orthographicSize; }
|
||||
set { cachedCamera.orthographicSize = value; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Tween the value.
|
||||
/// </summary>
|
||||
|
||||
protected override void OnUpdate (float factor, bool isFinished) { value = from * (1f - factor) + to * factor; }
|
||||
|
||||
/// <summary>
|
||||
/// Start the tweening operation.
|
||||
/// </summary>
|
||||
|
||||
static public TweenOrthoSize Begin (GameObject go, float duration, float to)
|
||||
{
|
||||
TweenOrthoSize comp = UITweener.Begin<TweenOrthoSize>(go, duration);
|
||||
comp.from = comp.value;
|
||||
comp.to = to;
|
||||
|
||||
if (duration <= 0f)
|
||||
{
|
||||
comp.Sample(1f, true);
|
||||
comp.enabled = false;
|
||||
}
|
||||
return comp;
|
||||
}
|
||||
|
||||
public override void SetStartToCurrentValue () { from = value; }
|
||||
public override void SetEndToCurrentValue () { to = value; }
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 365827806a6dd8b4583deeefe6e483c9
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
@@ -0,0 +1,94 @@
|
||||
using UnityEngine;
|
||||
|
||||
/// <summary>
|
||||
/// Tween the object's position.
|
||||
/// </summary>
|
||||
|
||||
[AddComponentMenu("Tween/Tween Position")]
|
||||
public class TweenPosition : UITweener
|
||||
{
|
||||
public Vector3 from;
|
||||
public Vector3 to;
|
||||
|
||||
[HideInInspector]
|
||||
public bool worldSpace = false;
|
||||
|
||||
Transform mTrans;
|
||||
|
||||
public Transform cachedTransform { get { if (mTrans == null) mTrans = transform; return mTrans; } }
|
||||
|
||||
[System.Obsolete("Use 'value' instead")]
|
||||
public Vector3 position { get { return this.value; } set { this.value = value; } }
|
||||
|
||||
/// <summary>
|
||||
/// Tween's current value.
|
||||
/// </summary>
|
||||
|
||||
public Vector3 value
|
||||
{
|
||||
get
|
||||
{
|
||||
return worldSpace ? cachedTransform.position : cachedTransform.localPosition;
|
||||
}
|
||||
set
|
||||
{
|
||||
if (worldSpace) cachedTransform.position = value;
|
||||
else cachedTransform.localPosition = value;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Tween the value.
|
||||
/// </summary>
|
||||
|
||||
protected override void OnUpdate (float factor, bool isFinished) { value = from * (1f - factor) + to * factor; }
|
||||
|
||||
/// <summary>
|
||||
/// Start the tweening operation.
|
||||
/// </summary>
|
||||
|
||||
static public TweenPosition Begin (GameObject go, float duration, Vector3 pos)
|
||||
{
|
||||
TweenPosition comp = UITweener.Begin<TweenPosition>(go, duration);
|
||||
comp.from = comp.value;
|
||||
comp.to = pos;
|
||||
|
||||
if (duration <= 0f)
|
||||
{
|
||||
comp.Sample(1f, true);
|
||||
comp.enabled = false;
|
||||
}
|
||||
return comp;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Start the tweening operation.
|
||||
/// </summary>
|
||||
|
||||
static public TweenPosition Begin (GameObject go, float duration, Vector3 pos, bool worldSpace)
|
||||
{
|
||||
TweenPosition comp = UITweener.Begin<TweenPosition>(go, duration);
|
||||
comp.worldSpace = worldSpace;
|
||||
comp.from = comp.value;
|
||||
comp.to = pos;
|
||||
|
||||
if (duration <= 0f)
|
||||
{
|
||||
comp.Sample(1f, true);
|
||||
comp.enabled = false;
|
||||
}
|
||||
return comp;
|
||||
}
|
||||
|
||||
[ContextMenu("Set 'From' to current value")]
|
||||
public override void SetStartToCurrentValue () { from = value; }
|
||||
|
||||
[ContextMenu("Set 'To' to current value")]
|
||||
public override void SetEndToCurrentValue () { to = value; }
|
||||
|
||||
[ContextMenu("Assume value of 'From'")]
|
||||
void SetCurrentValueToStart () { value = from; }
|
||||
|
||||
[ContextMenu("Assume value of 'To'")]
|
||||
void SetCurrentValueToEnd () { value = to; }
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 3d166255cacf07b4292b8402b3ddefc5
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: -98
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
@@ -0,0 +1,69 @@
|
||||
using UnityEngine;
|
||||
|
||||
/// <summary>
|
||||
/// Tween the object's rotation.
|
||||
/// </summary>
|
||||
|
||||
[AddComponentMenu("Tween/Tween Rotation")]
|
||||
public class TweenRotation : UITweener
|
||||
{
|
||||
public Vector3 from;
|
||||
public Vector3 to;
|
||||
public bool quaternionLerp = false;
|
||||
|
||||
Transform mTrans;
|
||||
|
||||
public Transform cachedTransform { get { if (mTrans == null) mTrans = transform; return mTrans; } }
|
||||
|
||||
[System.Obsolete("Use 'value' instead")]
|
||||
public Quaternion rotation { get { return this.value; } set { this.value = value; } }
|
||||
|
||||
/// <summary>
|
||||
/// Tween's current value.
|
||||
/// </summary>
|
||||
|
||||
public Quaternion value { get { return cachedTransform.localRotation; } set { cachedTransform.localRotation = value; } }
|
||||
|
||||
/// <summary>
|
||||
/// Tween the value.
|
||||
/// </summary>
|
||||
|
||||
protected override void OnUpdate (float factor, bool isFinished)
|
||||
{
|
||||
value = quaternionLerp ? Quaternion.Slerp(Quaternion.Euler(from), Quaternion.Euler(to), factor) :
|
||||
Quaternion.Euler(new Vector3(
|
||||
Mathf.Lerp(from.x, to.x, factor),
|
||||
Mathf.Lerp(from.y, to.y, factor),
|
||||
Mathf.Lerp(from.z, to.z, factor)));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Start the tweening operation.
|
||||
/// </summary>
|
||||
|
||||
static public TweenRotation Begin (GameObject go, float duration, Quaternion rot)
|
||||
{
|
||||
TweenRotation comp = UITweener.Begin<TweenRotation>(go, duration);
|
||||
comp.from = comp.value.eulerAngles;
|
||||
comp.to = rot.eulerAngles;
|
||||
|
||||
if (duration <= 0f)
|
||||
{
|
||||
comp.Sample(1f, true);
|
||||
comp.enabled = false;
|
||||
}
|
||||
return comp;
|
||||
}
|
||||
|
||||
[ContextMenu("Set 'From' to current value")]
|
||||
public override void SetStartToCurrentValue () { from = value.eulerAngles; }
|
||||
|
||||
[ContextMenu("Set 'To' to current value")]
|
||||
public override void SetEndToCurrentValue () { to = value.eulerAngles; }
|
||||
|
||||
[ContextMenu("Assume value of 'From'")]
|
||||
void SetCurrentValueToStart () { value = Quaternion.Euler(from); }
|
||||
|
||||
[ContextMenu("Assume value of 'To'")]
|
||||
void SetCurrentValueToEnd () { value = Quaternion.Euler(to); }
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 04d1b7c9e9a19a24ab67123a43c6544b
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: -95
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
@@ -0,0 +1,60 @@
|
||||
using UnityEngine;
|
||||
|
||||
/// <summary>
|
||||
/// Tween the object's local scale.
|
||||
/// </summary>
|
||||
|
||||
[AddComponentMenu("Tween/Tween Scale")]
|
||||
public class TweenScale : UITweener
|
||||
{
|
||||
public Vector3 from = Vector3.one;
|
||||
public Vector3 to = Vector3.one;
|
||||
|
||||
Transform mTrans;
|
||||
|
||||
public Transform cachedTransform { get { if (mTrans == null) mTrans = transform; return mTrans; } }
|
||||
|
||||
public Vector3 value { get { return cachedTransform.localScale; } set { cachedTransform.localScale = value; } }
|
||||
|
||||
[System.Obsolete("Use 'value' instead")]
|
||||
public Vector3 scale { get { return this.value; } set { this.value = value; } }
|
||||
|
||||
/// <summary>
|
||||
/// Tween the value.
|
||||
/// </summary>
|
||||
|
||||
protected override void OnUpdate (float factor, bool isFinished)
|
||||
{
|
||||
value = from * (1f - factor) + to * factor;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Start the tweening operation.
|
||||
/// </summary>
|
||||
|
||||
static public TweenScale Begin (GameObject go, float duration, Vector3 scale)
|
||||
{
|
||||
TweenScale comp = UITweener.Begin<TweenScale>(go, duration);
|
||||
comp.from = comp.value;
|
||||
comp.to = scale;
|
||||
|
||||
if (duration <= 0f)
|
||||
{
|
||||
comp.Sample(1f, true);
|
||||
comp.enabled = false;
|
||||
}
|
||||
return comp;
|
||||
}
|
||||
|
||||
[ContextMenu("Set 'From' to current value")]
|
||||
public override void SetStartToCurrentValue () { from = value; }
|
||||
|
||||
[ContextMenu("Set 'To' to current value")]
|
||||
public override void SetEndToCurrentValue () { to = value; }
|
||||
|
||||
[ContextMenu("Assume value of 'From'")]
|
||||
void SetCurrentValueToStart () { value = from; }
|
||||
|
||||
[ContextMenu("Assume value of 'To'")]
|
||||
void SetCurrentValueToEnd () { value = to; }
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 75e7459110b9666449485c40f25362a5
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: -94
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
@@ -0,0 +1,76 @@
|
||||
using UnityEngine;
|
||||
|
||||
/// <summary>
|
||||
/// Tween the object's position, rotation and scale.
|
||||
/// </summary>
|
||||
|
||||
[AddComponentMenu("Tween/Tween Transform")]
|
||||
public class TweenTransform : UITweener
|
||||
{
|
||||
public Transform from;
|
||||
public Transform to;
|
||||
public bool parentWhenFinished = false;
|
||||
|
||||
Transform mTrans;
|
||||
Vector3 mPos;
|
||||
Quaternion mRot;
|
||||
Vector3 mScale;
|
||||
|
||||
/// <summary>
|
||||
/// Interpolate the position, scale, and rotation.
|
||||
/// </summary>
|
||||
|
||||
protected override void OnUpdate (float factor, bool isFinished)
|
||||
{
|
||||
if (to != null)
|
||||
{
|
||||
if (mTrans == null)
|
||||
{
|
||||
mTrans = transform;
|
||||
mPos = mTrans.position;
|
||||
mRot = mTrans.rotation;
|
||||
mScale = mTrans.localScale;
|
||||
}
|
||||
|
||||
if (from != null)
|
||||
{
|
||||
mTrans.position = from.position * (1f - factor) + to.position * factor;
|
||||
mTrans.localScale = from.localScale * (1f - factor) + to.localScale * factor;
|
||||
mTrans.rotation = Quaternion.Slerp(from.rotation, to.rotation, factor);
|
||||
}
|
||||
else
|
||||
{
|
||||
mTrans.position = mPos * (1f - factor) + to.position * factor;
|
||||
mTrans.localScale = mScale * (1f - factor) + to.localScale * factor;
|
||||
mTrans.rotation = Quaternion.Slerp(mRot, to.rotation, factor);
|
||||
}
|
||||
|
||||
// Change the parent when finished, if requested
|
||||
if (parentWhenFinished && isFinished) mTrans.parent = to;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Start the tweening operation from the current position/rotation/scale to the target transform.
|
||||
/// </summary>
|
||||
|
||||
static public TweenTransform Begin (GameObject go, float duration, Transform to) { return Begin(go, duration, null, to); }
|
||||
|
||||
/// <summary>
|
||||
/// Start the tweening operation.
|
||||
/// </summary>
|
||||
|
||||
static public TweenTransform Begin (GameObject go, float duration, Transform from, Transform to)
|
||||
{
|
||||
TweenTransform comp = UITweener.Begin<TweenTransform>(go, duration);
|
||||
comp.from = from;
|
||||
comp.to = to;
|
||||
|
||||
if (duration <= 0f)
|
||||
{
|
||||
comp.Sample(1f, true);
|
||||
comp.enabled = false;
|
||||
}
|
||||
return comp;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 1d805c79a1ab11643bfd9d91e10c195a
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
@@ -0,0 +1,89 @@
|
||||
using UnityEngine;
|
||||
|
||||
/// <summary>
|
||||
/// Tween the audio source's volume.
|
||||
/// </summary>
|
||||
|
||||
[RequireComponent(typeof(AudioSource))]
|
||||
[AddComponentMenu("Tween/Tween Volume")]
|
||||
public class TweenVolume : UITweener
|
||||
{
|
||||
[Range(0f, 1f)] public float from = 1f;
|
||||
[Range(0f, 1f)] public float to = 1f;
|
||||
|
||||
AudioSource mSource;
|
||||
|
||||
/// <summary>
|
||||
/// Cached version of 'audio', as it's always faster to cache.
|
||||
/// </summary>
|
||||
|
||||
public AudioSource audioSource
|
||||
{
|
||||
get
|
||||
{
|
||||
if (mSource == null)
|
||||
{
|
||||
mSource = GetComponent<AudioSource>();
|
||||
|
||||
if (mSource == null)
|
||||
{
|
||||
mSource = GetComponent<AudioSource>();
|
||||
|
||||
if (mSource == null)
|
||||
{
|
||||
Debug.LogError("TweenVolume needs an AudioSource to work with", this);
|
||||
enabled = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
return mSource;
|
||||
}
|
||||
}
|
||||
|
||||
[System.Obsolete("Use 'value' instead")]
|
||||
public float volume { get { return this.value; } set { this.value = value; } }
|
||||
|
||||
/// <summary>
|
||||
/// Audio source's current volume.
|
||||
/// </summary>
|
||||
|
||||
public float value
|
||||
{
|
||||
get
|
||||
{
|
||||
return audioSource != null ? mSource.volume : 0f;
|
||||
}
|
||||
set
|
||||
{
|
||||
if (audioSource != null) mSource.volume = value;
|
||||
}
|
||||
}
|
||||
|
||||
protected override void OnUpdate (float factor, bool isFinished)
|
||||
{
|
||||
value = from * (1f - factor) + to * factor;
|
||||
mSource.enabled = (mSource.volume > 0.01f);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Start the tweening operation.
|
||||
/// </summary>
|
||||
|
||||
static public TweenVolume Begin (GameObject go, float duration, float targetVolume)
|
||||
{
|
||||
TweenVolume comp = UITweener.Begin<TweenVolume>(go, duration);
|
||||
comp.from = comp.value;
|
||||
comp.to = targetVolume;
|
||||
|
||||
if (targetVolume > 0f)
|
||||
{
|
||||
var s = comp.audioSource;
|
||||
s.enabled = true;
|
||||
s.Play();
|
||||
}
|
||||
return comp;
|
||||
}
|
||||
|
||||
public override void SetStartToCurrentValue () { from = value; }
|
||||
public override void SetEndToCurrentValue () { to = value; }
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 17aeef7ce6c142344959e650cab20151
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
@@ -0,0 +1,75 @@
|
||||
using UnityEngine;
|
||||
|
||||
/// <summary>
|
||||
/// Tween the widget's size.
|
||||
/// </summary>
|
||||
|
||||
[RequireComponent(typeof(RectTransform))]
|
||||
[AddComponentMenu("Tween/Tween Width")]
|
||||
public class TweenWidth : UITweener
|
||||
{
|
||||
public float from = 100;
|
||||
public float to = 100;
|
||||
|
||||
[Tooltip("If set, 'from' value will be set to match the specified rectangle")]
|
||||
public RectTransform fromTarget;
|
||||
|
||||
[Tooltip("If set, 'to' value will be set to match the specified rectangle")]
|
||||
public RectTransform toTarget;
|
||||
|
||||
RectTransform mWidget;
|
||||
RectTransform mTable;
|
||||
|
||||
public RectTransform cachedWidget { get { if (mWidget == null) mWidget = GetComponent<RectTransform>(); return mWidget; } }
|
||||
|
||||
[System.Obsolete("Use 'value' instead")]
|
||||
public float width { get { return this.value; } set { this.value = value; } }
|
||||
|
||||
/// <summary>
|
||||
/// Tween's current value.
|
||||
/// </summary>
|
||||
|
||||
public float value { get { return cachedWidget.rect.width; } set { cachedWidget.SetSizeWithCurrentAnchors(RectTransform.Axis.Horizontal, value); } }
|
||||
|
||||
/// <summary>
|
||||
/// Tween the value.
|
||||
/// </summary>
|
||||
|
||||
protected override void OnUpdate (float factor, bool isFinished)
|
||||
{
|
||||
if (fromTarget) from = fromTarget.rect.width;
|
||||
if (toTarget) to = toTarget.rect.width;
|
||||
|
||||
value = Mathf.RoundToInt(from * (1f - factor) + to * factor);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Start the tweening operation.
|
||||
/// </summary>
|
||||
|
||||
static public TweenWidth Begin (RectTransform widget, float duration, int width)
|
||||
{
|
||||
var comp = UITweener.Begin<TweenWidth>(widget.gameObject, duration);
|
||||
comp.from = widget.rect.width;
|
||||
comp.to = width;
|
||||
|
||||
if (duration <= 0f)
|
||||
{
|
||||
comp.Sample(1f, true);
|
||||
comp.enabled = false;
|
||||
}
|
||||
return comp;
|
||||
}
|
||||
|
||||
[ContextMenu("Set 'From' to current value")]
|
||||
public override void SetStartToCurrentValue () { from = value; }
|
||||
|
||||
[ContextMenu("Set 'To' to current value")]
|
||||
public override void SetEndToCurrentValue () { to = value; }
|
||||
|
||||
[ContextMenu("Assume value of 'From'")]
|
||||
void SetCurrentValueToStart () { value = from; }
|
||||
|
||||
[ContextMenu("Assume value of 'To'")]
|
||||
void SetCurrentValueToEnd () { value = to; }
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 0fe5d396737f89f4ea1534bc147cad2e
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: -93
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
@@ -0,0 +1,531 @@
|
||||
using UnityEngine;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
|
||||
/// <summary>
|
||||
/// Base class for all tweening operations.
|
||||
/// </summary>
|
||||
|
||||
public abstract class UITweener : MonoBehaviour
|
||||
{
|
||||
/// <summary>
|
||||
/// Current tween that triggered the callback function.
|
||||
/// </summary>
|
||||
|
||||
static public UITweener current;
|
||||
|
||||
public enum Method
|
||||
{
|
||||
Linear,
|
||||
EaseIn,
|
||||
EaseOut,
|
||||
EaseInOut,
|
||||
BounceIn,
|
||||
BounceOut,
|
||||
}
|
||||
|
||||
public enum Style
|
||||
{
|
||||
Once,
|
||||
Loop,
|
||||
PingPong,
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Tweening method used.
|
||||
/// </summary>
|
||||
|
||||
[HideInInspector]
|
||||
public Method method = Method.Linear;
|
||||
|
||||
/// <summary>
|
||||
/// Does it play once? Does it loop?
|
||||
/// </summary>
|
||||
|
||||
[HideInInspector]
|
||||
public Style style = Style.Once;
|
||||
|
||||
/// <summary>
|
||||
/// Optional curve to apply to the tween's time factor value.
|
||||
/// </summary>
|
||||
|
||||
[HideInInspector]
|
||||
public AnimationCurve animationCurve = new AnimationCurve(new Keyframe(0f, 0f, 0f, 1f), new Keyframe(1f, 1f, 1f, 0f));
|
||||
|
||||
/// <summary>
|
||||
/// Whether the tween will ignore the timescale, making it work while the game is paused.
|
||||
/// </summary>
|
||||
|
||||
[HideInInspector]
|
||||
public bool ignoreTimeScale = true;
|
||||
|
||||
/// <summary>
|
||||
/// How long will the tweener wait before starting the tween?
|
||||
/// </summary>
|
||||
|
||||
[HideInInspector]
|
||||
public float delay = 0f;
|
||||
|
||||
public enum DelayAffects
|
||||
{
|
||||
Forward,
|
||||
Reverse,
|
||||
Both,
|
||||
}
|
||||
|
||||
[HideInInspector]
|
||||
public DelayAffects delayAffects = DelayAffects.Both;
|
||||
|
||||
/// <summary>
|
||||
/// How long is the duration of the tween?
|
||||
/// </summary>
|
||||
|
||||
[HideInInspector]
|
||||
public float duration = 1f;
|
||||
|
||||
/// <summary>
|
||||
/// Whether the tweener will use steeper curves for ease in / out style interpolation.
|
||||
/// </summary>
|
||||
|
||||
[HideInInspector]
|
||||
public bool steeperCurves = false;
|
||||
|
||||
/// <summary>
|
||||
/// Used by buttons and tween sequences. Group of '0' means not in a sequence.
|
||||
/// </summary>
|
||||
|
||||
[HideInInspector]
|
||||
public int tweenGroup = 0;
|
||||
|
||||
[Tooltip("By default, Update() will be used for tweening. Setting this to 'true' will make the tween happen in FixedUpdate() insted.")]
|
||||
public bool useFixedUpdate = false;
|
||||
|
||||
/// <summary>
|
||||
/// Event delegates called when the animation finishes.
|
||||
/// </summary>
|
||||
|
||||
//[HideInInspector]
|
||||
//public List<EventDelegate> onFinished = new List<EventDelegate>();
|
||||
|
||||
// Deprecated functionality, kept for backwards compatibility
|
||||
[HideInInspector] public GameObject eventReceiver;
|
||||
[HideInInspector] public string callWhenFinished;
|
||||
|
||||
/// <summary>
|
||||
/// Custom time scale for this tween, if desired. Can be used to slow down or speed up the animation.
|
||||
/// </summary>
|
||||
|
||||
[System.NonSerialized] public float timeScale = 1f;
|
||||
|
||||
bool mStarted = false;
|
||||
float mStartTime = 0f;
|
||||
float mDuration = 0f;
|
||||
float mAmountPerDelta = 1000f;
|
||||
float mFactor = 0f;
|
||||
|
||||
/// <summary>
|
||||
/// Amount advanced per delta time.
|
||||
/// </summary>
|
||||
|
||||
public float amountPerDelta
|
||||
{
|
||||
get
|
||||
{
|
||||
if (duration == 0f) return 1000f;
|
||||
|
||||
if (mDuration != duration)
|
||||
{
|
||||
mDuration = duration;
|
||||
mAmountPerDelta = Mathf.Abs(1f / duration) * Mathf.Sign(mAmountPerDelta);
|
||||
}
|
||||
return mAmountPerDelta;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Tween factor, 0-1 range.
|
||||
/// </summary>
|
||||
|
||||
public float tweenFactor { get { return mFactor; } set { mFactor = Mathf.Clamp01(value); } }
|
||||
|
||||
/// <summary>
|
||||
/// Direction that the tween is currently playing in.
|
||||
/// </summary>
|
||||
|
||||
//public AnimationOrTween.Direction direction { get { return amountPerDelta < 0f ? AnimationOrTween.Direction.Reverse : AnimationOrTween.Direction.Forward; } }
|
||||
|
||||
/// <summary>
|
||||
/// This function is called by Unity when you add a component. Automatically set the starting values for convenience.
|
||||
/// </summary>
|
||||
|
||||
void Reset ()
|
||||
{
|
||||
if (!mStarted)
|
||||
{
|
||||
SetStartToCurrentValue();
|
||||
SetEndToCurrentValue();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Update as soon as it's started so that there is no delay.
|
||||
/// </summary>
|
||||
|
||||
protected virtual void Start () { DoUpdate(); }
|
||||
protected void Update () { if (!useFixedUpdate) DoUpdate(); }
|
||||
protected void FixedUpdate () { if (useFixedUpdate) DoUpdate(); }
|
||||
|
||||
/// <summary>
|
||||
/// Update the tweening factor and call the virtual update function.
|
||||
/// </summary>
|
||||
|
||||
protected void DoUpdate ()
|
||||
{
|
||||
float delta = ignoreTimeScale && !useFixedUpdate ? Time.unscaledDeltaTime : Time.deltaTime;
|
||||
float time = ignoreTimeScale && !useFixedUpdate ? Time.unscaledTime : Time.time;
|
||||
|
||||
if (!mStarted)
|
||||
{
|
||||
delta = 0;
|
||||
mStarted = true;
|
||||
mStartTime = time;
|
||||
if (mAmountPerDelta > 0f && (delayAffects == DelayAffects.Both || delayAffects == DelayAffects.Forward)) mStartTime += delay;
|
||||
else if (mAmountPerDelta < 0f && (delayAffects == DelayAffects.Both || delayAffects == DelayAffects.Reverse)) mStartTime += delay;
|
||||
}
|
||||
|
||||
if (time < mStartTime) return;
|
||||
|
||||
// Advance the sampling factor
|
||||
mFactor += (duration == 0f) ? 1f : amountPerDelta * delta * timeScale;
|
||||
|
||||
// Loop style simply resets the play factor after it exceeds 1.
|
||||
if (style == Style.Loop)
|
||||
{
|
||||
if (mFactor > 1f)
|
||||
{
|
||||
mFactor -= Mathf.Floor(mFactor);
|
||||
}
|
||||
}
|
||||
else if (style == Style.PingPong)
|
||||
{
|
||||
// Ping-pong style reverses the direction
|
||||
if (mFactor > 1f)
|
||||
{
|
||||
mFactor = 1f - (mFactor - Mathf.Floor(mFactor));
|
||||
mAmountPerDelta = -mAmountPerDelta;
|
||||
}
|
||||
else if (mFactor < 0f)
|
||||
{
|
||||
mFactor = -mFactor;
|
||||
mFactor -= Mathf.Floor(mFactor);
|
||||
mAmountPerDelta = -mAmountPerDelta;
|
||||
}
|
||||
}
|
||||
|
||||
// If the factor goes out of range and this is a one-time tweening operation, disable the script
|
||||
if ((style == Style.Once) && (duration == 0f || mFactor > 1f || mFactor < 0f))
|
||||
{
|
||||
mFactor = Mathf.Clamp01(mFactor);
|
||||
Sample(mFactor, true);
|
||||
enabled = false;
|
||||
|
||||
if (current != this)
|
||||
{
|
||||
UITweener before = current;
|
||||
current = this;
|
||||
|
||||
//if (onFinished != null)
|
||||
//{
|
||||
// mTemp = onFinished;
|
||||
// onFinished = new List<EventDelegate>();
|
||||
|
||||
// // Notify the listener delegates
|
||||
// EventDelegate.Execute(mTemp);
|
||||
|
||||
// // Re-add the previous persistent delegates
|
||||
// for (int i = 0; i < mTemp.Count; ++i)
|
||||
// {
|
||||
// EventDelegate ed = mTemp[i];
|
||||
// if (ed != null && !ed.oneShot) EventDelegate.Add(onFinished, ed, ed.oneShot);
|
||||
// }
|
||||
// mTemp = null;
|
||||
//}
|
||||
|
||||
// Deprecated legacy functionality support
|
||||
if (eventReceiver != null && !string.IsNullOrEmpty(callWhenFinished))
|
||||
eventReceiver.SendMessage(callWhenFinished, this, SendMessageOptions.DontRequireReceiver);
|
||||
|
||||
current = before;
|
||||
}
|
||||
}
|
||||
else Sample(mFactor, false);
|
||||
}
|
||||
|
||||
//List<EventDelegate> mTemp = null;
|
||||
|
||||
/// <summary>
|
||||
/// Convenience function -- set a new OnFinished event delegate (here for to be consistent with RemoveOnFinished).
|
||||
/// </summary>
|
||||
|
||||
//public void SetOnFinished (EventDelegate.Callback del) { EventDelegate.Set(onFinished, del); }
|
||||
|
||||
///// <summary>
|
||||
///// Convenience function -- set a new OnFinished event delegate (here for to be consistent with RemoveOnFinished).
|
||||
///// </summary>
|
||||
|
||||
//public void SetOnFinished (EventDelegate del) { EventDelegate.Set(onFinished, del); }
|
||||
|
||||
///// <summary>
|
||||
///// Convenience function -- add a new OnFinished event delegate (here for to be consistent with RemoveOnFinished).
|
||||
///// </summary>
|
||||
|
||||
//public void AddOnFinished (EventDelegate.Callback del) { EventDelegate.Add(onFinished, del); }
|
||||
|
||||
///// <summary>
|
||||
///// Convenience function -- add a new OnFinished event delegate (here for to be consistent with RemoveOnFinished).
|
||||
///// </summary>
|
||||
|
||||
//public void AddOnFinished (EventDelegate del) { EventDelegate.Add(onFinished, del); }
|
||||
|
||||
///// <summary>
|
||||
///// Remove an OnFinished delegate. Will work even while iterating through the list when the tweener has finished its operation.
|
||||
///// </summary>
|
||||
|
||||
//public void RemoveOnFinished (EventDelegate del)
|
||||
//{
|
||||
// if (onFinished != null) onFinished.Remove(del);
|
||||
// if (mTemp != null) mTemp.Remove(del);
|
||||
//}
|
||||
|
||||
/// <summary>
|
||||
/// Mark as not started when finished to enable delay on next play.
|
||||
/// </summary>
|
||||
|
||||
protected virtual void OnDisable () { mStarted = false; }
|
||||
|
||||
/// <summary>
|
||||
/// Immediately finish the tween animation, if it's active.
|
||||
/// </summary>
|
||||
|
||||
public void Finish ()
|
||||
{
|
||||
if (enabled)
|
||||
{
|
||||
Sample(mAmountPerDelta > 0f ? 1f : 0f, true);
|
||||
enabled = false;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sample the tween at the specified factor.
|
||||
/// </summary>
|
||||
|
||||
public void Sample (float factor, bool isFinished)
|
||||
{
|
||||
// Calculate the sampling value
|
||||
float val = Mathf.Clamp01(factor);
|
||||
|
||||
if (method == Method.EaseIn)
|
||||
{
|
||||
val = 1f - Mathf.Sin(0.5f * Mathf.PI * (1f - val));
|
||||
if (steeperCurves) val *= val;
|
||||
}
|
||||
else if (method == Method.EaseOut)
|
||||
{
|
||||
val = Mathf.Sin(0.5f * Mathf.PI * val);
|
||||
|
||||
if (steeperCurves)
|
||||
{
|
||||
val = 1f - val;
|
||||
val = 1f - val * val;
|
||||
}
|
||||
}
|
||||
else if (method == Method.EaseInOut)
|
||||
{
|
||||
const float pi2 = Mathf.PI * 2f;
|
||||
val = val - Mathf.Sin(val * pi2) / pi2;
|
||||
|
||||
if (steeperCurves)
|
||||
{
|
||||
val = val * 2f - 1f;
|
||||
float sign = Mathf.Sign(val);
|
||||
val = 1f - Mathf.Abs(val);
|
||||
val = 1f - val * val;
|
||||
val = sign * val * 0.5f + 0.5f;
|
||||
}
|
||||
}
|
||||
else if (method == Method.BounceIn)
|
||||
{
|
||||
val = BounceLogic(val);
|
||||
}
|
||||
else if (method == Method.BounceOut)
|
||||
{
|
||||
val = 1f - BounceLogic(1f - val);
|
||||
}
|
||||
|
||||
// Call the virtual update
|
||||
OnUpdate((animationCurve != null) ? animationCurve.Evaluate(val) : val, isFinished);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Main Bounce logic to simplify the Sample function
|
||||
/// </summary>
|
||||
|
||||
float BounceLogic (float val)
|
||||
{
|
||||
if (val < 0.363636f) // 0.363636 = (1/ 2.75)
|
||||
{
|
||||
val = 7.5685f * val * val;
|
||||
}
|
||||
else if (val < 0.727272f) // 0.727272 = (2 / 2.75)
|
||||
{
|
||||
val = 7.5625f * (val -= 0.545454f) * val + 0.75f; // 0.545454f = (1.5 / 2.75)
|
||||
}
|
||||
else if (val < 0.909090f) // 0.909090 = (2.5 / 2.75)
|
||||
{
|
||||
val = 7.5625f * (val -= 0.818181f) * val + 0.9375f; // 0.818181 = (2.25 / 2.75)
|
||||
}
|
||||
else
|
||||
{
|
||||
val = 7.5625f * (val -= 0.9545454f) * val + 0.984375f; // 0.9545454 = (2.625 / 2.75)
|
||||
}
|
||||
return val;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Play the tween.
|
||||
/// </summary>
|
||||
|
||||
[System.Obsolete("Use PlayForward() instead")]
|
||||
public void Play () { Play(true); }
|
||||
|
||||
/// <summary>
|
||||
/// Play the tween forward.
|
||||
/// </summary>
|
||||
|
||||
[ContextMenu("Play forward")]
|
||||
public void PlayForward () { Play(true); }
|
||||
|
||||
/// <summary>
|
||||
/// Play the tween in reverse.
|
||||
/// </summary>
|
||||
|
||||
[ContextMenu("Play in reverse")]
|
||||
public void PlayReverse () { Play(false); }
|
||||
|
||||
/// <summary>
|
||||
/// Manually activate the tweening process, reversing it if necessary.
|
||||
/// </summary>
|
||||
|
||||
public virtual void Play (bool forward)
|
||||
{
|
||||
mAmountPerDelta = Mathf.Abs(amountPerDelta);
|
||||
if (!forward) mAmountPerDelta = -mAmountPerDelta;
|
||||
|
||||
if (!enabled)
|
||||
{
|
||||
enabled = true;
|
||||
mStarted = false;
|
||||
}
|
||||
|
||||
DoUpdate();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Manually reset the tweener's state to the beginning.
|
||||
/// If the tween is playing forward, this means the tween's start.
|
||||
/// If the tween is playing in reverse, this means the tween's end.
|
||||
/// </summary>
|
||||
|
||||
public void ResetToBeginning ()
|
||||
{
|
||||
mStarted = false;
|
||||
mFactor = (amountPerDelta < 0f) ? 1f : 0f;
|
||||
Sample(mFactor, false);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Manually start the tweening process, reversing its direction.
|
||||
/// </summary>
|
||||
|
||||
public void Toggle ()
|
||||
{
|
||||
if (mFactor > 0f)
|
||||
{
|
||||
mAmountPerDelta = -amountPerDelta;
|
||||
}
|
||||
else
|
||||
{
|
||||
mAmountPerDelta = Mathf.Abs(amountPerDelta);
|
||||
}
|
||||
enabled = true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Actual tweening logic should go here.
|
||||
/// </summary>
|
||||
|
||||
abstract protected void OnUpdate (float factor, bool isFinished);
|
||||
|
||||
/// <summary>
|
||||
/// Starts the tweening operation.
|
||||
/// </summary>
|
||||
|
||||
static public T Begin<T> (GameObject go, float duration, float delay = 0f) where T : UITweener
|
||||
{
|
||||
T comp = go.GetComponent<T>();
|
||||
#if UNITY_FLASH
|
||||
if ((object)comp == null) comp = (T)go.AddComponent<T>();
|
||||
#else
|
||||
// Find the tween with an unset group ID (group ID of 0).
|
||||
if (comp != null && comp.tweenGroup != 0)
|
||||
{
|
||||
comp = null;
|
||||
T[] comps = go.GetComponents<T>();
|
||||
for (int i = 0, imax = comps.Length; i < imax; ++i)
|
||||
{
|
||||
comp = comps[i];
|
||||
if (comp != null && comp.tweenGroup == 0) break;
|
||||
comp = null;
|
||||
}
|
||||
}
|
||||
|
||||
if (comp == null)
|
||||
{
|
||||
comp = go.AddComponent<T>();
|
||||
|
||||
if (comp == null)
|
||||
{
|
||||
//Debug.LogError("Unable to add " + typeof(T) + " to " + NGUITools.GetHierarchy(go), go);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
comp.mStarted = false;
|
||||
comp.mFactor = 0f;
|
||||
comp.duration = duration;
|
||||
comp.mDuration = duration;
|
||||
comp.delay = delay;
|
||||
comp.mAmountPerDelta = duration > 0f ? Mathf.Abs(1f / duration) : 1000f;
|
||||
comp.style = Style.Once;
|
||||
comp.animationCurve = new AnimationCurve(new Keyframe(0f, 0f, 0f, 1f), new Keyframe(1f, 1f, 1f, 0f));
|
||||
comp.eventReceiver = null;
|
||||
comp.callWhenFinished = null;
|
||||
//comp.onFinished.Clear();
|
||||
//if (comp.mTemp != null) comp.mTemp.Clear();
|
||||
comp.enabled = true;
|
||||
return comp;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Set the 'from' value to the current one.
|
||||
/// </summary>
|
||||
|
||||
public virtual void SetStartToCurrentValue () { }
|
||||
|
||||
/// <summary>
|
||||
/// Set the 'to' value to the current one.
|
||||
/// </summary>
|
||||
|
||||
public virtual void SetEndToCurrentValue () { }
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: c96860f5597f2494abb42d29cdca0bcc
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
@@ -0,0 +1,111 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Unity.VisualScripting;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Stary.Evo
|
||||
{
|
||||
public enum UIAdaptType
|
||||
{
|
||||
All,
|
||||
LeftOrTop,
|
||||
RightOrBottom,
|
||||
}
|
||||
|
||||
public class UIAdapter : MonoBehaviour
|
||||
{
|
||||
public UIAdaptType uIAdaptType = UIAdaptType.All;
|
||||
|
||||
private float cd;
|
||||
|
||||
private void Update()
|
||||
{
|
||||
// 为避免旋转屏幕,华为分屏机等导致分辨率变化,且安全区变化的问题,需要持续检测
|
||||
if (Time.time > cd)
|
||||
{
|
||||
InitAdapter();
|
||||
cd = Time.time + 1;
|
||||
}
|
||||
}
|
||||
|
||||
private void InitAdapter()
|
||||
{
|
||||
var safeArea = Screen.safeArea;
|
||||
if (UIManager.Instance != null)
|
||||
{
|
||||
safeArea = UIManager.Instance.GetSafeArea();
|
||||
}
|
||||
var orientation = Screen.orientation;
|
||||
RectTransform rectTransform = transform as RectTransform;
|
||||
rectTransform.sizeDelta = Vector2.zero;
|
||||
if (orientation == ScreenOrientation.LandscapeLeft || orientation == ScreenOrientation.LandscapeRight)
|
||||
{
|
||||
switch (uIAdaptType)
|
||||
{
|
||||
case UIAdaptType.All:
|
||||
rectTransform.anchorMin = new Vector2(safeArea.xMin / Screen.width, 0);
|
||||
rectTransform.anchorMax = new Vector2(safeArea.xMax / Screen.width, 1);
|
||||
break;
|
||||
case UIAdaptType.LeftOrTop:
|
||||
if (orientation == ScreenOrientation.LandscapeLeft)
|
||||
{
|
||||
rectTransform.anchorMin = new Vector2(safeArea.xMin / Screen.width, 0);
|
||||
rectTransform.anchorMax = new Vector2(1, 1);
|
||||
}
|
||||
else
|
||||
{
|
||||
rectTransform.anchorMin = new Vector2(0, 0);
|
||||
rectTransform.anchorMax = new Vector2(safeArea.xMax / Screen.width, 1);
|
||||
}
|
||||
break;
|
||||
case UIAdaptType.RightOrBottom:
|
||||
if (orientation == ScreenOrientation.LandscapeLeft)
|
||||
{
|
||||
rectTransform.anchorMin = new Vector2(0, 0);
|
||||
rectTransform.anchorMax = new Vector2(safeArea.xMax / Screen.width, 1);
|
||||
}
|
||||
else
|
||||
{
|
||||
rectTransform.anchorMin = new Vector2(safeArea.xMin / Screen.width, 0);
|
||||
rectTransform.anchorMax = new Vector2(1, 1);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
else if (orientation == ScreenOrientation.Portrait || orientation == ScreenOrientation.PortraitUpsideDown)
|
||||
{
|
||||
switch (uIAdaptType)
|
||||
{
|
||||
case UIAdaptType.All:
|
||||
rectTransform.anchorMin = new Vector2(0 , safeArea.yMin / Screen.height);
|
||||
rectTransform.anchorMax = new Vector2(1 , safeArea.yMax / Screen.height);
|
||||
break;
|
||||
case UIAdaptType.LeftOrTop:
|
||||
if (orientation == ScreenOrientation.Portrait)
|
||||
{
|
||||
rectTransform.anchorMin = new Vector2(0, 0);
|
||||
rectTransform.anchorMax = new Vector2(1, safeArea.yMax / Screen.height);
|
||||
}
|
||||
else
|
||||
{
|
||||
rectTransform.anchorMin = new Vector2(0, safeArea.yMin / Screen.height);
|
||||
rectTransform.anchorMax = new Vector2(1, 1);
|
||||
}
|
||||
break;
|
||||
case UIAdaptType.RightOrBottom:
|
||||
if (orientation == ScreenOrientation.Portrait)
|
||||
{
|
||||
rectTransform.anchorMin = new Vector2(0, safeArea.yMin / Screen.height);
|
||||
rectTransform.anchorMax = new Vector2(1, 1);
|
||||
}
|
||||
else
|
||||
{
|
||||
rectTransform.anchorMin = new Vector2(0, 0);
|
||||
rectTransform.anchorMax = new Vector2(1, safeArea.yMax / Screen.height);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: efc1aaf05b906ac48b36dd28888f9aac
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: dac5f0f85d3930749ac016d6ed29b9dd
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,9 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 957bc409a9e47584c9c0a315f5c05a0d
|
||||
folderAsset: yes
|
||||
timeCreated: 1525057340
|
||||
licenseType: Pro
|
||||
DefaultImporter:
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,10 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 40733aef832e3a84b84ae9a5b3f74895
|
||||
folderAsset: yes
|
||||
timeCreated: 1521786329
|
||||
licenseType: Pro
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
Binary file not shown.
+23
@@ -0,0 +1,23 @@
|
||||
fileFormatVersion: 2
|
||||
guid: cd170bc15e34a094c8609532aedcc7c9
|
||||
timeCreated: 1521786330
|
||||
licenseType: Pro
|
||||
TrueTypeFontImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 4
|
||||
fontSize: 16
|
||||
forceTextureCase: -2
|
||||
characterSpacing: 0
|
||||
characterPadding: 1
|
||||
includeFontData: 1
|
||||
fontName: Microsoft YaHei Mono
|
||||
fontNames:
|
||||
- Microsoft YaHei Mono
|
||||
fallbackFontReferences: []
|
||||
customCharacters:
|
||||
fontRenderingMode: 0
|
||||
ascentCalculationMode: 1
|
||||
useLegacyBoundsCalculation: 0
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
+1427
File diff suppressed because it is too large
Load Diff
+9
@@ -0,0 +1,9 @@
|
||||
fileFormatVersion: 2
|
||||
guid: e54e612c85cb2f0438f3fc6849b64d93
|
||||
timeCreated: 1525054737
|
||||
licenseType: Pro
|
||||
NativeFormatImporter:
|
||||
mainObjectFileID: 11400000
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
+1427
File diff suppressed because it is too large
Load Diff
+10
@@ -0,0 +1,10 @@
|
||||
fileFormatVersion: 2
|
||||
guid: bb2d64fbaaa8623488f623d8f26434cf
|
||||
timeCreated: 1521786517
|
||||
licenseType: Pro
|
||||
NativeFormatImporter:
|
||||
externalObjects: {}
|
||||
mainObjectFileID: 11400000
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 1020 B |
@@ -0,0 +1,68 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 086dc3a35eb33bb47af413530fc6ef08
|
||||
timeCreated: 1525056854
|
||||
licenseType: Pro
|
||||
TextureImporter:
|
||||
fileIDToRecycleName: {}
|
||||
serializedVersion: 4
|
||||
mipmaps:
|
||||
mipMapMode: 0
|
||||
enableMipMap: 1
|
||||
sRGBTexture: 1
|
||||
linearTexture: 0
|
||||
fadeOut: 0
|
||||
borderMipMap: 0
|
||||
mipMapFadeDistanceStart: 1
|
||||
mipMapFadeDistanceEnd: 3
|
||||
bumpmap:
|
||||
convertToNormalMap: 0
|
||||
externalNormalMap: 0
|
||||
heightScale: 0.25
|
||||
normalMapFilter: 0
|
||||
isReadable: 0
|
||||
grayScaleToAlpha: 0
|
||||
generateCubemap: 6
|
||||
cubemapConvolution: 0
|
||||
seamlessCubemap: 0
|
||||
textureFormat: 1
|
||||
maxTextureSize: 2048
|
||||
textureSettings:
|
||||
filterMode: -1
|
||||
aniso: -1
|
||||
mipBias: -1
|
||||
wrapMode: -1
|
||||
nPOTScale: 1
|
||||
lightmap: 0
|
||||
compressionQuality: 50
|
||||
spriteMode: 0
|
||||
spriteExtrude: 1
|
||||
spriteMeshType: 1
|
||||
alignment: 0
|
||||
spritePivot: {x: 0.5, y: 0.5}
|
||||
spriteBorder: {x: 0, y: 0, z: 0, w: 0}
|
||||
spritePixelsToUnits: 100
|
||||
alphaUsage: 1
|
||||
alphaIsTransparency: 0
|
||||
spriteTessellationDetail: -1
|
||||
textureType: 0
|
||||
textureShape: 1
|
||||
maxTextureSizeSet: 0
|
||||
compressionQualitySet: 0
|
||||
textureFormatSet: 0
|
||||
platformSettings:
|
||||
- buildTarget: DefaultTexturePlatform
|
||||
maxTextureSize: 2048
|
||||
textureFormat: -1
|
||||
textureCompression: 1
|
||||
compressionQuality: 50
|
||||
crunchedCompression: 0
|
||||
allowsAlphaSplitting: 0
|
||||
overridden: 0
|
||||
spriteSheet:
|
||||
serializedVersion: 2
|
||||
sprites: []
|
||||
outline: []
|
||||
spritePackingTag:
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 1022 B |
+68
@@ -0,0 +1,68 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 88cc2c445d716b24bbe3d9c0acb15a50
|
||||
timeCreated: 1525056966
|
||||
licenseType: Pro
|
||||
TextureImporter:
|
||||
fileIDToRecycleName: {}
|
||||
serializedVersion: 4
|
||||
mipmaps:
|
||||
mipMapMode: 0
|
||||
enableMipMap: 1
|
||||
sRGBTexture: 1
|
||||
linearTexture: 0
|
||||
fadeOut: 0
|
||||
borderMipMap: 0
|
||||
mipMapFadeDistanceStart: 1
|
||||
mipMapFadeDistanceEnd: 3
|
||||
bumpmap:
|
||||
convertToNormalMap: 0
|
||||
externalNormalMap: 0
|
||||
heightScale: 0.25
|
||||
normalMapFilter: 0
|
||||
isReadable: 0
|
||||
grayScaleToAlpha: 0
|
||||
generateCubemap: 6
|
||||
cubemapConvolution: 0
|
||||
seamlessCubemap: 0
|
||||
textureFormat: 1
|
||||
maxTextureSize: 2048
|
||||
textureSettings:
|
||||
filterMode: -1
|
||||
aniso: -1
|
||||
mipBias: -1
|
||||
wrapMode: -1
|
||||
nPOTScale: 1
|
||||
lightmap: 0
|
||||
compressionQuality: 50
|
||||
spriteMode: 0
|
||||
spriteExtrude: 1
|
||||
spriteMeshType: 1
|
||||
alignment: 0
|
||||
spritePivot: {x: 0.5, y: 0.5}
|
||||
spriteBorder: {x: 0, y: 0, z: 0, w: 0}
|
||||
spritePixelsToUnits: 100
|
||||
alphaUsage: 1
|
||||
alphaIsTransparency: 0
|
||||
spriteTessellationDetail: -1
|
||||
textureType: 0
|
||||
textureShape: 1
|
||||
maxTextureSizeSet: 0
|
||||
compressionQualitySet: 0
|
||||
textureFormatSet: 0
|
||||
platformSettings:
|
||||
- buildTarget: DefaultTexturePlatform
|
||||
maxTextureSize: 2048
|
||||
textureFormat: -1
|
||||
textureCompression: 1
|
||||
compressionQuality: 50
|
||||
crunchedCompression: 0
|
||||
allowsAlphaSplitting: 0
|
||||
overridden: 0
|
||||
spriteSheet:
|
||||
serializedVersion: 2
|
||||
sprites: []
|
||||
outline: []
|
||||
spritePackingTag:
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,9 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 257f5e1b9bfd2bc488d6eee4c486ed96
|
||||
folderAsset: yes
|
||||
timeCreated: 1525057347
|
||||
licenseType: Pro
|
||||
DefaultImporter:
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
+11
@@ -0,0 +1,11 @@
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Stary.Evo
|
||||
{
|
||||
public class ControlBindingAttribute : Attribute
|
||||
{
|
||||
}
|
||||
}
|
||||
+13
@@ -0,0 +1,13 @@
|
||||
fileFormatVersion: 2
|
||||
guid: dcc9a6b6a055f0641b7a35a2accd6a7b
|
||||
timeCreated: 1521661617
|
||||
licenseType: Pro
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,11 @@
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Stary.Evo
|
||||
{
|
||||
public interface IBindableUI
|
||||
{
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 658cc57fff0c29c40a634f2c5ac937cb
|
||||
timeCreated: 1525934273
|
||||
licenseType: Pro
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
+11
@@ -0,0 +1,11 @@
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Stary.Evo
|
||||
{
|
||||
public class SubUIBindingAttribute : Attribute
|
||||
{
|
||||
}
|
||||
}
|
||||
+11
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 745e76df505d0d3479057f4f389793de
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
+116
@@ -0,0 +1,116 @@
|
||||
#if UNITY_EDITOR
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
using System.Reflection;
|
||||
using UnityEditor;
|
||||
using UnityEditor.Experimental.SceneManagement;
|
||||
|
||||
#if UNITY_2019_1_OR_NEWER
|
||||
#if UNITY_2020_1_OR_NEWER
|
||||
using UnityEditor.SceneManagement;
|
||||
# else
|
||||
using UnityEditor.Experimental.SceneManagement;
|
||||
# endif
|
||||
#endif
|
||||
|
||||
namespace Stary.Evo
|
||||
{
|
||||
public class UIBindingPrefabSaveHelper : UnityEditor.AssetModificationProcessor
|
||||
{
|
||||
static UIBindingPrefabSaveHelper()
|
||||
{
|
||||
#if UNITY_2019_1_OR_NEWER
|
||||
PrefabStage.prefabSaving += OnPrefabStageSaving;
|
||||
#endif
|
||||
}
|
||||
|
||||
#if UNITY_2019_1_OR_NEWER
|
||||
/// <summary>
|
||||
/// 当点击Perfab编辑场景的Save按钮时修改数据不会立刻保存,因此需要在其执行前主动保存一下
|
||||
/// </summary>
|
||||
/// <param name="go"></param>
|
||||
static void OnPrefabStageSaving(GameObject go)
|
||||
{
|
||||
string path = AssetDatabase.GetAssetPath(go);
|
||||
OnWillSaveAssets(new string[] { path });
|
||||
AssetDatabase.SaveAssets();
|
||||
}
|
||||
#endif
|
||||
/// <summary>
|
||||
/// 保存资源时修正控件绑定数据
|
||||
/// </summary>
|
||||
/// <param name="paths"></param>
|
||||
/// <returns></returns>
|
||||
static string[] OnWillSaveAssets(string[] paths)
|
||||
{
|
||||
GameObject goInHierarchy = Selection.activeGameObject;
|
||||
if(goInHierarchy != null)
|
||||
{
|
||||
// 从根节点开始遍历,以免当前prefab有多个子UI修改时无法被全部修正
|
||||
var rootTran = goInHierarchy.transform;
|
||||
while (rootTran.parent != null)
|
||||
rootTran = rootTran.parent;
|
||||
|
||||
UIControlData[] uiControlData = rootTran.GetComponentsInChildren<UIControlData>();
|
||||
if (uiControlData != null)
|
||||
{
|
||||
foreach (var comp in uiControlData)
|
||||
{
|
||||
comp.CorrectComponents();
|
||||
comp.CheckSubUIs();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return paths;
|
||||
}
|
||||
|
||||
public static void SavePrefab(GameObject goInHierarchy)
|
||||
{
|
||||
Object goPrefab = null;
|
||||
GameObject objValid = null;
|
||||
GameObject objToCheck = goInHierarchy;
|
||||
string prefabPath = null;
|
||||
|
||||
do
|
||||
{
|
||||
#if UNITY_2019_1_OR_NEWER
|
||||
var currPrefab = PrefabUtility.GetCorrespondingObjectFromSource(objToCheck);
|
||||
#else
|
||||
var currPrefab = PrefabUtility.GetPrefabParent(objToCheck);
|
||||
#endif
|
||||
|
||||
if (currPrefab == null)
|
||||
break;
|
||||
|
||||
string currPath = AssetDatabase.GetAssetPath(currPrefab);
|
||||
if (prefabPath == null)
|
||||
prefabPath = currPath;
|
||||
|
||||
if (currPath != prefabPath) // 已经到root或者当前是嵌套prefab并且已经到达上一层prefab
|
||||
break;
|
||||
|
||||
goPrefab = currPrefab;
|
||||
objValid = objToCheck;
|
||||
|
||||
var t = objToCheck.transform.parent;
|
||||
if (t != null)
|
||||
objToCheck = t.gameObject;
|
||||
else
|
||||
break;
|
||||
} while (true);
|
||||
|
||||
if (objValid != null)
|
||||
#if UNITY_2019_1_OR_NEWER
|
||||
goPrefab = PrefabUtility.SaveAsPrefabAssetAndConnect(objValid, prefabPath, InteractionMode.AutomatedAction);
|
||||
#else
|
||||
PrefabUtility.ReplacePrefab(goInHierarchy, goPrefab, ReplacePrefabOptions.ConnectToPrefab);
|
||||
#endif
|
||||
else
|
||||
Debug.LogFormat("<color=red>当前对象不属于Prefab, 请将其保存为 Prefab</color>");
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
#endif
|
||||
+11
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 2d989bc73e59c344988d9b2d2e11acb7
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,740 @@
|
||||
/*
|
||||
URL: https://github.com/Misaka-Mikoto-Tech/UIControlBinding
|
||||
使用方法:
|
||||
UE: 将此脚本添加到UI根节点,与程序协商好需要绑定的控件及其变量名后,将需要绑定的控件拖到脚本上
|
||||
程序: 点此脚本右上角的齿轮,点 "复制代码到剪贴板" 按钮
|
||||
|
||||
UIManager 加载示例:
|
||||
`` C#
|
||||
IBindableUI uiA = Activator.CreateInstance(Type.GetType("UIA")) as IBindableUI;
|
||||
GameObject prefab = Resources.Load<GameObject>("UI/UIA"); // you can get ui config from config file
|
||||
GameObject go = Instantiate(prefab);
|
||||
UIControlData ctrlData = go.GetComponent<UIControlData>();
|
||||
if(ctrlData != null)
|
||||
{
|
||||
ctrlData.BindDataTo(uiA);
|
||||
}
|
||||
``
|
||||
|
||||
*/
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Reflection;
|
||||
using UnityEngine;
|
||||
using UnityEngine.UI;
|
||||
using System.Text;
|
||||
#if XLUA
|
||||
using XLua;
|
||||
#endif
|
||||
using UnityEngine.Profiling;
|
||||
|
||||
#if UNITY_EDITOR
|
||||
using UnityEditor;
|
||||
using UnityEngine.Playables;
|
||||
#endif
|
||||
|
||||
namespace Stary.Evo
|
||||
{
|
||||
/// <summary>
|
||||
/// 单个控件数据
|
||||
/// </summary>
|
||||
[Serializable]
|
||||
public class CtrlItemData
|
||||
{
|
||||
public string name = string.Empty;
|
||||
#if UNITY_EDITOR
|
||||
[HideInInspector]
|
||||
public string type = string.Empty;
|
||||
#endif
|
||||
public UnityEngine.Object[] targets = new UnityEngine.Object[1];
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return name;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 单个子UI数据
|
||||
/// </summary>
|
||||
[Serializable]
|
||||
public class SubUIItemData
|
||||
{
|
||||
public string name = string.Empty;
|
||||
public UIControlData subUIData = null;
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return name;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 被绑定的UI类字段信息
|
||||
/// </summary>
|
||||
public class UIFieldsInfo
|
||||
{
|
||||
public Type type;
|
||||
public List<FieldInfo> controls = new List<FieldInfo>(10);
|
||||
public List<FieldInfo> subUIs = new List<FieldInfo>();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 当前UI所有的绑定数据以及子UI指定
|
||||
/// </summary>
|
||||
[DisallowMultipleComponent]
|
||||
public class UIControlData : MonoBehaviour
|
||||
{
|
||||
/// <summary>
|
||||
/// 所有绑定的组件,不允许重名
|
||||
/// </summary>
|
||||
public List<CtrlItemData> ctrlItemDatas;
|
||||
/// <summary>
|
||||
/// 子UI数据
|
||||
/// </summary>
|
||||
public List<SubUIItemData> subUIItemDatas;
|
||||
|
||||
/// <summary>
|
||||
/// 被绑定的UI
|
||||
/// </summary>
|
||||
public List<WeakReference<IBindableUI>> bindUIRefs;
|
||||
|
||||
/// <summary>
|
||||
/// 缓存所有打开过的UI类型的字段数据(如果有需求可以在特定时机清理以节约内存)
|
||||
/// </summary>
|
||||
public static Dictionary<Type, UIFieldsInfo> s_uiFieldsCache = new Dictionary<Type, UIFieldsInfo>();
|
||||
|
||||
#region Editor
|
||||
#if UNITY_EDITOR
|
||||
/// <summary>
|
||||
/// 已知类型列表,自定义类型可以添加到下面指定区域
|
||||
/// </summary>
|
||||
private static Dictionary<string, Type> _typeMap = new Dictionary<string, Type>()
|
||||
{
|
||||
{ "TextMeshProUGUI", typeof(TMPro.TextMeshProUGUI) },
|
||||
{ "TextMeshPro", typeof(TMPro.TextMeshPro) },
|
||||
{ "TMP_InputField", typeof(TMPro.TMP_InputField) },
|
||||
{ "TMP_Dropdown", typeof(TMPro.TMP_Dropdown) },
|
||||
{ "Text", typeof(Text)},
|
||||
{ "RawImage", typeof(RawImage)},
|
||||
{ "Button", typeof(Button)},
|
||||
{ "Toggle", typeof(Toggle)},
|
||||
{ "Slider", typeof(Slider)},
|
||||
{ "Scrollbar", typeof(Scrollbar)},
|
||||
{ "Dropdown", typeof(Dropdown)},
|
||||
{ "InputField", typeof(InputField)},
|
||||
{ "Canvas", typeof(Canvas)},
|
||||
{ "UIScrollView", typeof(UIScrollView) },
|
||||
{ "ScrollRect", typeof(ScrollRect)},
|
||||
{ "SpriteRenderer", typeof(SpriteRenderer)},
|
||||
{ "GridLayoutGroup", typeof(GridLayoutGroup) },
|
||||
{ "Animation", typeof(Animation) },
|
||||
{ "VideoPlayer", typeof(UnityEngine.Video.VideoPlayer) },
|
||||
{ "CanvasGroup", typeof(CanvasGroup) },
|
||||
{ "PlayableDirector", typeof(PlayableDirector) },
|
||||
{ "UITweener", typeof(UITweener) },
|
||||
|
||||
////////自定义控件类型请放这里////////
|
||||
|
||||
|
||||
|
||||
//////////////////////////////////////
|
||||
|
||||
{ "Image", typeof(Image)},
|
||||
{ "RectTransform", typeof(RectTransform)},
|
||||
{ "Transform", typeof(Transform)},
|
||||
{ "GameObject", typeof(GameObject)},
|
||||
};
|
||||
|
||||
public static string[] GetAllTypeNames()
|
||||
{
|
||||
string[] keys = new string[_typeMap.Count + 1];
|
||||
keys[0] = "自动";
|
||||
_typeMap.Keys.CopyTo(keys, 1);
|
||||
return keys;
|
||||
}
|
||||
|
||||
public static Type[] GetAllTypes()
|
||||
{
|
||||
Type[] types = new Type[_typeMap.Count + 1];
|
||||
types[0] = typeof(UnityEngine.Object);
|
||||
_typeMap.Values.CopyTo(types, 1);
|
||||
return types;
|
||||
}
|
||||
#endif
|
||||
#endregion
|
||||
|
||||
#region BindDataToC#UI
|
||||
/// <summary>
|
||||
/// 将当前数据绑定到某窗口类实例的字段,UI 加载后必须被执行
|
||||
/// </summary>
|
||||
/// <param name="ui">需要绑定数据的 UI</param>
|
||||
public void BindDataTo(IBindableUI ui)
|
||||
{
|
||||
if (ui == null)
|
||||
return;
|
||||
|
||||
#if DEBUG_LOG
|
||||
float time = Time.realtimeSinceStartup;
|
||||
Profiler.BeginSample("BindDataTo");
|
||||
#endif
|
||||
UIFieldsInfo fieldInfos = GetUIFieldsInfo(ui.GetType());
|
||||
|
||||
var controls = fieldInfos.controls;
|
||||
for (int i = 0, imax = controls.Count; i < imax; i++)
|
||||
{
|
||||
try
|
||||
{
|
||||
BindCtrl(ui, controls[i]);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Debug.LogError(e);
|
||||
}
|
||||
}
|
||||
|
||||
var subUIs = fieldInfos.subUIs;
|
||||
for (int i = 0, imax = subUIs.Count; i < imax; i++)
|
||||
BindSubUI(ui, subUIs[i]);
|
||||
|
||||
if (bindUIRefs == null)
|
||||
bindUIRefs = new List<WeakReference<IBindableUI>>();
|
||||
|
||||
bindUIRefs.Add(new WeakReference<IBindableUI>(ui));
|
||||
|
||||
#if DEBUG_LOG
|
||||
Profiler.EndSample();
|
||||
float span = Time.realtimeSinceStartup - time;
|
||||
if (span > 0.002f)
|
||||
Debug.LogWarningFormat("BindDataTo {0} 耗时{1}ms", ui.GetType().Name, span * 1000f);
|
||||
#endif
|
||||
}
|
||||
|
||||
private void BindCtrl(IBindableUI ui, FieldInfo fi)
|
||||
{
|
||||
int itemIdx = GetCtrlIndex(fi.Name);
|
||||
if (itemIdx == -1)
|
||||
{
|
||||
Debug.LogWarningFormat("can not find binding control of name [{0}] in prefab", fi.Name);
|
||||
return;
|
||||
}
|
||||
|
||||
var objs = ctrlItemDatas[itemIdx];
|
||||
|
||||
Type fieldType = fi.FieldType;
|
||||
if (fieldType.IsArray)
|
||||
{
|
||||
Array arrObj = Array.CreateInstance(fieldType.GetElementType(), objs.targets.Length);
|
||||
|
||||
// 给数组元素设置数据
|
||||
for (int j = 0, jmax = objs.targets.Length; j < jmax; j++)
|
||||
{
|
||||
if (objs.targets[j] != null)
|
||||
arrObj.SetValue(objs.targets[j], j);
|
||||
else
|
||||
Debug.LogErrorFormat("Component {0}[{1}] is null", objs.name, j);
|
||||
}
|
||||
fi.SetValue(ui, arrObj);
|
||||
}
|
||||
else
|
||||
{
|
||||
UnityEngine.Object component = GetComponent(itemIdx);
|
||||
if (component != null)
|
||||
fi.SetValue(ui, component);
|
||||
else
|
||||
Debug.LogErrorFormat("Component {0} is null", objs.name);
|
||||
}
|
||||
}
|
||||
|
||||
private void BindSubUI(IBindableUI ui, FieldInfo fi)
|
||||
{
|
||||
int subUIIdx = GetSubUIIndex(fi.Name);
|
||||
if(subUIIdx == -1)
|
||||
{
|
||||
Debug.LogErrorFormat("can not find binding subUI of name [{0}] in prefab", fi.Name);
|
||||
return;
|
||||
}
|
||||
|
||||
fi.SetValue(ui, subUIItemDatas[subUIIdx].subUIData);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取指定UI类的字段信息
|
||||
/// </summary>
|
||||
/// <param name="type"></param>
|
||||
/// <returns></returns>
|
||||
private static UIFieldsInfo GetUIFieldsInfo(Type type)
|
||||
{
|
||||
UIFieldsInfo uIFieldsInfo;
|
||||
if (s_uiFieldsCache.TryGetValue(type, out uIFieldsInfo))
|
||||
return uIFieldsInfo;
|
||||
|
||||
uIFieldsInfo = new UIFieldsInfo() { type = type };
|
||||
FieldInfo[] fis = type.GetFields(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance);
|
||||
for(int i = 0, imax = fis.Length; i < imax; i++)
|
||||
{
|
||||
FieldInfo fi = fis[i];
|
||||
|
||||
if (fi.IsDefined(typeof(ControlBindingAttribute), false))
|
||||
uIFieldsInfo.controls.Add(fi);
|
||||
else if (fi.IsDefined(typeof(SubUIBindingAttribute), false))
|
||||
uIFieldsInfo.subUIs.Add(fi);
|
||||
}
|
||||
|
||||
s_uiFieldsCache.Add(type, uIFieldsInfo);
|
||||
|
||||
return uIFieldsInfo;
|
||||
}
|
||||
#endregion
|
||||
|
||||
|
||||
|
||||
|
||||
#region UnBind
|
||||
private static List<UIControlData> s_tmpControlDataForUnbind = new List<UIControlData>();
|
||||
/// <summary>
|
||||
/// 解除指定UI及其子节点自动绑定字段的引用
|
||||
/// </summary>
|
||||
/// <param name="uiGo"></param>
|
||||
public static void UnBindUI(GameObject uiGo)
|
||||
{
|
||||
if (uiGo == null)
|
||||
return;
|
||||
|
||||
#if DEBUG_LOG
|
||||
float time = Time.realtimeSinceStartup;
|
||||
Profiler.BeginSample("UnBindUI");
|
||||
#endif
|
||||
|
||||
uiGo.GetComponentsInChildren(true, s_tmpControlDataForUnbind);
|
||||
for (int i = 0, imax = s_tmpControlDataForUnbind.Count; i < imax; i++)
|
||||
{
|
||||
UIControlData controlData = s_tmpControlDataForUnbind[i];
|
||||
if (controlData.bindUIRefs == null)
|
||||
continue;
|
||||
|
||||
List<WeakReference<IBindableUI>> bindUIRefs = controlData.bindUIRefs;
|
||||
for (int j = 0, jmax = bindUIRefs.Count; j < jmax; j++)
|
||||
{
|
||||
WeakReference<IBindableUI> bindUIRef = bindUIRefs[j];
|
||||
IBindableUI bindUI;
|
||||
if (!bindUIRef.TryGetTarget(out bindUI))
|
||||
continue;
|
||||
}
|
||||
|
||||
controlData.bindUIRefs = null;
|
||||
}
|
||||
s_tmpControlDataForUnbind.Clear();
|
||||
|
||||
#if DEBUG_LOG
|
||||
Profiler.EndSample();
|
||||
float span = Time.realtimeSinceStartup - time;
|
||||
if (span > 0.002f)
|
||||
Debug.LogWarningFormat("UnBindUI {0} 耗时{1}ms", uiGo.name, span * 1000f);
|
||||
#endif
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region Get,不建议使用
|
||||
|
||||
/// <summary>
|
||||
/// 找到指定名称的第一个组件, 不存在返回 null
|
||||
/// </summary>
|
||||
/// <typeparam name="T"></typeparam>
|
||||
/// <param name="name"></param>
|
||||
/// <returns></returns>
|
||||
public T GetComponent<T>(string name) where T : Component
|
||||
{
|
||||
int idx = GetCtrlIndex(name);
|
||||
if (idx == -1)
|
||||
return null;
|
||||
|
||||
var targets = ctrlItemDatas[idx].targets;
|
||||
if (targets.Length == 0)
|
||||
return null;
|
||||
|
||||
return targets[0] as T;
|
||||
}
|
||||
|
||||
public new UnityEngine.Object GetComponent(string name)
|
||||
{
|
||||
int idx = GetCtrlIndex(name);
|
||||
if (idx == -1)
|
||||
return null;
|
||||
|
||||
var targets = ctrlItemDatas[idx].targets;
|
||||
if (targets.Length == 0)
|
||||
return null;
|
||||
|
||||
return targets[0];
|
||||
}
|
||||
|
||||
public UnityEngine.Object GetComponent(int idx)
|
||||
{
|
||||
if (idx == -1 || idx >= ctrlItemDatas.Count)
|
||||
return null;
|
||||
|
||||
var targets = ctrlItemDatas[idx].targets;
|
||||
if (targets.Length == 0)
|
||||
return null;
|
||||
|
||||
return targets[0];
|
||||
}
|
||||
|
||||
public UnityEngine.Object[] GetComponents(string name)
|
||||
{
|
||||
int idx = GetCtrlIndex(name);
|
||||
if (idx == -1)
|
||||
return null;
|
||||
|
||||
return ctrlItemDatas[idx].targets;
|
||||
}
|
||||
|
||||
public UnityEngine.Object[] GetComponents(int idx)
|
||||
{
|
||||
if (idx == -1 || idx >= ctrlItemDatas.Count)
|
||||
return null;
|
||||
|
||||
return ctrlItemDatas[idx].targets;
|
||||
}
|
||||
|
||||
|
||||
|
||||
private int GetCtrlIndex(string name)
|
||||
{
|
||||
for (int i = 0, imax = ctrlItemDatas.Count; i < imax; i++)
|
||||
{
|
||||
CtrlItemData item = ctrlItemDatas[i];
|
||||
if (item.name == name)
|
||||
return i;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
private int GetSubUIIndex(string name)
|
||||
{
|
||||
for(int i = 0, imax = subUIItemDatas.Count; i < imax; i++)
|
||||
{
|
||||
SubUIItemData item = subUIItemDatas[i];
|
||||
if (item.name == name)
|
||||
return i;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region For Editor
|
||||
#if UNITY_EDITOR
|
||||
|
||||
public bool dataHasChanged = false;
|
||||
|
||||
public bool CorrectComponents()
|
||||
{
|
||||
if (ctrlItemDatas == null) return true;
|
||||
|
||||
bool isOK = true;
|
||||
for(int i = 0, imax = ctrlItemDatas.Count; i < imax; i++)
|
||||
{
|
||||
if (string.IsNullOrEmpty(ctrlItemDatas[i].name)) // TODO Check if is a valid varible name
|
||||
{
|
||||
Debug.LogErrorFormat("[{1}]第 {0} 个控件没有名字,请修正", i + 1, gameObject.name);
|
||||
return false;
|
||||
}
|
||||
|
||||
for (int j = ctrlItemDatas.Count - 1; j >= 0; j--)
|
||||
{
|
||||
if(ctrlItemDatas[i].name == ctrlItemDatas[j].name && i != j)
|
||||
{
|
||||
Debug.LogErrorFormat("[{3}]控件名字 [{0}] 第 {1} 项与第 {2} 项重复,请修正", ctrlItemDatas[i].name, i + 1, j + 1, gameObject.name);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
isOK = ReplaceTargetsToUIComponent();
|
||||
if(isOK)
|
||||
Debug.LogFormat("[{0}]控件绑定修正完毕", gameObject.name);
|
||||
|
||||
return isOK;
|
||||
}
|
||||
|
||||
public bool CheckSubUIs()
|
||||
{
|
||||
for (int i = 0, imax = subUIItemDatas.Count; i < imax; i++)
|
||||
{
|
||||
var subUI = subUIItemDatas[i];
|
||||
if(subUI != null)
|
||||
{
|
||||
if (string.IsNullOrEmpty(subUI.name))
|
||||
{
|
||||
Debug.LogErrorFormat("[{0}]第 {1} 个子UI没有设置名字, 请修正", gameObject.name, i + 1);
|
||||
return false;
|
||||
}
|
||||
|
||||
if(subUI.subUIData == null)
|
||||
{
|
||||
Debug.LogErrorFormat("[{0}]第 {1} 个子UI没有赋值, 请修正", gameObject.name, i + 1);
|
||||
return false;
|
||||
}
|
||||
|
||||
// 必须拖当前 Prefab 下的子UI
|
||||
if (!IsInCurrentPrefab(subUI.subUIData.transform))
|
||||
{
|
||||
Debug.LogErrorFormat("[{0}]第 {1} 个子UI [{2}]不是当前 Prefab 下的对象,请修正", gameObject.name, i + 1, subUI.name);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Debug.LogError("internal error at ControlBinding, pls contact author");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 由于自动拖上去的对象永远都是 GameObject,所以我们需要把它修正为正确的对象类型
|
||||
/// </summary>
|
||||
private bool ReplaceTargetsToUIComponent()
|
||||
{
|
||||
for (int i = 0, imax = ctrlItemDatas.Count; i < imax; i++)
|
||||
{
|
||||
var objs = ctrlItemDatas[i].targets;
|
||||
Type type = null;
|
||||
for(int j = 0, jmax = objs.Length; j < jmax; j++)
|
||||
{
|
||||
if(objs[j] == null)
|
||||
{
|
||||
Debug.LogErrorFormat("[{2}]控件名字 [{0}] 第 {1} 项为空,请修正", ctrlItemDatas[i].name, j + 1, gameObject.name);
|
||||
return false;
|
||||
}
|
||||
|
||||
GameObject go = objs[j] as GameObject;
|
||||
if (go == null)
|
||||
go = (objs[j] as Component).gameObject;
|
||||
|
||||
// 必须拖当前 Prefab 下的控件
|
||||
if (!IsInCurrentPrefab(go.transform))
|
||||
{
|
||||
Debug.LogErrorFormat("[{2}]控件名字 [{0}] 第 {1} 项不是当前 Prefab 下的控件,请修正", ctrlItemDatas[i].name, j + 1, gameObject.name);
|
||||
return false;
|
||||
}
|
||||
|
||||
UnityEngine.Object correctComponent = FindCorrectComponent(go, ctrlItemDatas[i].type);
|
||||
if(correctComponent == null)
|
||||
{
|
||||
Debug.LogErrorFormat("[{3}]控件 [{0}] 第 {1} 项不是 {2} 类型,请修正", ctrlItemDatas[i].name, j + 1, ctrlItemDatas[i].type, gameObject.name);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
if (type == null) // 当前变量的第一个控件时执行
|
||||
{
|
||||
if (string.IsNullOrEmpty(ctrlItemDatas[i].type))
|
||||
{
|
||||
type = correctComponent.GetType();
|
||||
}else
|
||||
{
|
||||
if(!_typeMap.TryGetValue(ctrlItemDatas[i].type, out type))
|
||||
{
|
||||
Debug.LogError("Internal Error, pls contact author");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if(correctComponent.GetType() != type && !correctComponent.GetType().IsSubclassOf(type))
|
||||
{
|
||||
Debug.LogErrorFormat("[{2}]控件名字 [{0}] 第 {1} 项与第 1 项的类型不同,请修正", ctrlItemDatas[i].name, j + 1, gameObject.name);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (objs[j] != correctComponent)
|
||||
dataHasChanged = true;
|
||||
|
||||
objs[j] = correctComponent;
|
||||
}
|
||||
|
||||
if(type.Name != ctrlItemDatas[i].type)
|
||||
{
|
||||
ctrlItemDatas[i].type = type.Name;
|
||||
//#if UNITY_2019_1_OR_NEWER
|
||||
// EditorUtility.ClearDirty(this);
|
||||
//#endif
|
||||
EditorUtility.SetDirty(this);
|
||||
PrefabUtility.RecordPrefabInstancePropertyModifications(this);
|
||||
}
|
||||
ctrlItemDatas[i].type = type.Name;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private bool IsInCurrentPrefab(Transform t)
|
||||
{
|
||||
do
|
||||
{
|
||||
if (t == transform)
|
||||
return true;
|
||||
t = t.parent;
|
||||
} while (t != null);
|
||||
return false;
|
||||
}
|
||||
|
||||
private UnityEngine.Object FindCorrectComponent(GameObject go, string typename)
|
||||
{
|
||||
if (typename == "GameObject")
|
||||
return go;
|
||||
|
||||
List<Component> components = new List<Component>();
|
||||
go.GetComponents(components);
|
||||
|
||||
Func<Type, Component> getSpecialTypeComp = (Type t) =>
|
||||
{
|
||||
foreach (var comp in components)
|
||||
{
|
||||
Type compType = comp.GetType();
|
||||
if (compType == t || compType.IsSubclassOf(t))
|
||||
{
|
||||
return comp;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
};
|
||||
|
||||
Component newComp = null;
|
||||
|
||||
if (string.IsNullOrEmpty(typename))
|
||||
{
|
||||
// 类型名为空则为自动类型,在 _typeMap 里从上往下找
|
||||
foreach (var kv in _typeMap)
|
||||
{
|
||||
newComp = getSpecialTypeComp(kv.Value);
|
||||
if (newComp != null)
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{// 指定了类型名则只找指定类型的控件
|
||||
Type type = null;
|
||||
if (_typeMap.TryGetValue(typename, out type))
|
||||
{
|
||||
newComp = getSpecialTypeComp(type);
|
||||
}
|
||||
}
|
||||
|
||||
return newComp;
|
||||
}
|
||||
|
||||
private bool IsNeedSave()
|
||||
{
|
||||
foreach(var ctrl in ctrlItemDatas)
|
||||
{
|
||||
if (string.IsNullOrEmpty(ctrl.type))
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
[ContextMenu("复制代码到剪贴板(Private)")]
|
||||
public void CopyCodeToClipBoardPrivate()
|
||||
{
|
||||
CopyCodeToClipBoardImpl("private");
|
||||
}
|
||||
|
||||
[ContextMenu("复制代码到剪贴板(Protected)")]
|
||||
public void CopyCodeToClipBoardProtected()
|
||||
{
|
||||
CopyCodeToClipBoardImpl("protected");
|
||||
}
|
||||
|
||||
[ContextMenu("复制代码到剪贴板(Public)")]
|
||||
public void CopyCodeToClipBoardPublic()
|
||||
{
|
||||
CopyCodeToClipBoardImpl("public");
|
||||
}
|
||||
|
||||
private void CopyCodeToClipBoardImpl(string accessLevel)
|
||||
{
|
||||
// 调用保存资源会导致 prefab 发生变化,因此只有有需要时才保存
|
||||
if (IsNeedSave())
|
||||
UIBindingPrefabSaveHelper.SavePrefab(gameObject);
|
||||
|
||||
StringBuilder sb = new StringBuilder(1024);
|
||||
sb.AppendLine("#region 控件绑定变量声明,自动生成请勿手改");
|
||||
sb.AppendLine("\t\t#pragma warning disable 0649"); // 变量未赋值
|
||||
|
||||
foreach (var ctrl in ctrlItemDatas)
|
||||
{
|
||||
if (ctrl.targets.Length == 0)
|
||||
continue;
|
||||
|
||||
if (ctrl.targets.Length == 1)
|
||||
sb.AppendFormat("\t\t[ControlBinding]\r\n\t\t{0} {1} {2};\r\n", accessLevel, ctrl.type, ctrl.name);
|
||||
else
|
||||
sb.AppendFormat("\t\t[ControlBinding]\r\n\t\t{0} {1}[] {2};\r\n", accessLevel, ctrl.type, ctrl.name);
|
||||
}
|
||||
|
||||
sb.AppendLine();
|
||||
foreach(var subUI in subUIItemDatas)
|
||||
{
|
||||
sb.AppendFormat("\t\t[SubUIBinding]\r\n\t\t{0} UIControlData {1};\r\n", accessLevel, subUI.name);
|
||||
}
|
||||
sb.AppendLine("\t\t#pragma warning restore 0649");
|
||||
sb.Append("#endregion\r\n\r\n");
|
||||
|
||||
UnityEngine.GUIUtility.systemCopyBuffer = sb.ToString();
|
||||
}
|
||||
|
||||
[ContextMenu("复制代码到剪贴板(Lua)")]
|
||||
public void CopyCodeToClipBoardLua()
|
||||
{
|
||||
// 调用保存资源会导致 prefab 发生变化,因此只有有需要时才保存
|
||||
if (IsNeedSave())
|
||||
UIBindingPrefabSaveHelper.SavePrefab(gameObject);
|
||||
|
||||
StringBuilder sb = new StringBuilder(1024);
|
||||
sb.Append("-- 控件绑定变量声明,自动生成请勿手改\r\n");
|
||||
|
||||
foreach (var ctrl in ctrlItemDatas)
|
||||
{
|
||||
if (ctrl.targets.Length == 0)
|
||||
continue;
|
||||
|
||||
sb.AppendFormat("local {0}\r\n", ctrl.name);
|
||||
}
|
||||
|
||||
sb.AppendFormat("\r\n");
|
||||
sb.AppendFormat("-- SubUI\r\n");
|
||||
foreach (var subUI in subUIItemDatas)
|
||||
{
|
||||
sb.AppendFormat("local {0}\r\n", subUI.name);
|
||||
}
|
||||
sb.Append("-- 控件绑定定义结束\r\n\r\n");
|
||||
|
||||
UnityEngine.GUIUtility.systemCopyBuffer = sb.ToString();
|
||||
}
|
||||
|
||||
|
||||
public void SetDirty()
|
||||
{
|
||||
#if UNITY_EDITOR
|
||||
UnityEditor.EditorUtility.SetDirty(gameObject);
|
||||
#if UNITY_2021_1_OR_NEWER
|
||||
var prefabStage = UnityEditor.SceneManagement.PrefabStageUtility.GetPrefabStage(gameObject);
|
||||
#else
|
||||
var prefabStage = UnityEditor.Experimental.SceneManagement.PrefabStageUtility.GetPrefabStage(gameObject);
|
||||
#endif
|
||||
if (prefabStage != null)
|
||||
{
|
||||
UnityEditor.SceneManagement.EditorSceneManager.MarkSceneDirty(prefabStage.scene);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
#endregion
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
fileFormatVersion: 2
|
||||
guid: bec254e92978598418e38c0641bcd88c
|
||||
timeCreated: 1521658864
|
||||
licenseType: Pro
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,412 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Cysharp.Threading.Tasks;
|
||||
using UnityEngine;
|
||||
using UnityEngine.EventSystems;
|
||||
using DG.Tweening;
|
||||
using YooAsset;
|
||||
|
||||
namespace Stary.Evo
|
||||
{
|
||||
public enum UIBlackType
|
||||
{
|
||||
None, // 无黑边,全适应
|
||||
Height, // 保持高度填满,两边黑边
|
||||
Width, // 保持宽度填满, 上下黑边
|
||||
AutoBlack, // 自动黑边(选中左右或上下黑边最少的一方)
|
||||
}
|
||||
|
||||
public class UIManager : SingletonMono<UIManager>
|
||||
{
|
||||
public int width = 1920;
|
||||
public int height = 1080;
|
||||
public UIBlackType uiBlackType = UIBlackType.None;
|
||||
|
||||
private Transform _root;
|
||||
private Camera _worldCamera;
|
||||
private Camera _uiCamera;
|
||||
|
||||
/// <summary>
|
||||
/// 屏幕渐变遮罩
|
||||
/// </summary>
|
||||
private CanvasGroup _blackMask;
|
||||
|
||||
private CanvasGroup _backgroundMask;
|
||||
private Tweener _fadeTweener;
|
||||
|
||||
/// <summary>
|
||||
/// 黑边
|
||||
/// </summary>
|
||||
private RectTransform[] _blacks = new RectTransform[2];
|
||||
|
||||
private Dictionary<string, UIViewController> _viewControllers;
|
||||
private Dictionary<UILayer, UILayerLogic> _layers;
|
||||
private HashSet<string> _openViews;
|
||||
private HashSet<string> _residentViews;
|
||||
|
||||
public EventSystem EventSystem { get; private set; }
|
||||
|
||||
private void Awake()
|
||||
{
|
||||
Initialize();
|
||||
}
|
||||
|
||||
private void Initialize()
|
||||
{
|
||||
_layers = new Dictionary<UILayer, UILayerLogic>();
|
||||
_viewControllers = new Dictionary<string, UIViewController>();
|
||||
_openViews = new HashSet<string>();
|
||||
_residentViews = new HashSet<string>();
|
||||
|
||||
_worldCamera = Camera.main;
|
||||
_worldCamera.cullingMask &= int.MaxValue ^ (1 << Layer.UI);
|
||||
|
||||
var root = GameObject.Find("UIRoot");
|
||||
if (root == null)
|
||||
{
|
||||
root = new GameObject("UIRoot");
|
||||
}
|
||||
|
||||
root.layer = Layer.UI;
|
||||
GameObject.DontDestroyOnLoad(root);
|
||||
_root = root.transform;
|
||||
|
||||
var camera = GameObject.Find("UICamera");
|
||||
if (camera == null)
|
||||
{
|
||||
camera = new GameObject("UICamera");
|
||||
}
|
||||
|
||||
_uiCamera = camera.GetOrAddComponent<Camera>();
|
||||
_uiCamera.cullingMask = 1 << Layer.UI;
|
||||
_uiCamera.transform.SetParent(_root);
|
||||
_uiCamera.orthographic = true;
|
||||
_uiCamera.clearFlags = CameraClearFlags.Depth;
|
||||
|
||||
EventSystem = EventSystem.current;
|
||||
|
||||
var layers = Enum.GetValues(typeof(UILayer));
|
||||
foreach (UILayer layer in layers)
|
||||
{
|
||||
bool is3d = layer == UILayer.SceneLayer;
|
||||
Canvas layerCanvas = UIExtension.CreateLayerCanvas(layer, is3d, _root, is3d ? _worldCamera : _uiCamera,
|
||||
width, height);
|
||||
UILayerLogic uILayerLogic = new UILayerLogic(layer, layerCanvas);
|
||||
_layers.Add(layer, uILayerLogic);
|
||||
}
|
||||
|
||||
_blackMask = UIExtension.CreateBlackMask(_layers[UILayer.BlackMaskLayer].canvas.transform);
|
||||
_backgroundMask = UIExtension.CreateBlackMask(_layers[UILayer.BackgroundLayer].canvas.transform);
|
||||
}
|
||||
|
||||
private void Update()
|
||||
{
|
||||
// TODO 不应该Update设置应该放在屏幕状态变动事件里
|
||||
ChangeOrCreateBlack();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 创建或者调整黑边,需间隔触发,由于有些设备屏幕是可以转动,是动态的
|
||||
/// </summary>
|
||||
private void ChangeOrCreateBlack()
|
||||
{
|
||||
if (_layers == null) return;
|
||||
var parent = _layers[UILayer.BackgroundLayer].canvas.transform as RectTransform;
|
||||
var uIBlackType = GetUIBlackType();
|
||||
switch (uIBlackType)
|
||||
{
|
||||
case UIBlackType.Height:
|
||||
// 高度适配时的左右黑边
|
||||
var rect = _blacks[0];
|
||||
if (rect == null)
|
||||
{
|
||||
_blacks[0] = rect = UIExtension.CreateBlackMask(parent, 1, "right").transform as RectTransform;
|
||||
}
|
||||
else if (Mathf.Abs(rect.anchoredPosition.x * 2 + parent.rect.width - width) < 1)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
rect.pivot = new Vector2(0, 0.5f);
|
||||
rect.anchorMin = new Vector2(1, 0);
|
||||
rect.anchorMax = new Vector2(1, 1);
|
||||
rect.sizeDelta = new Vector2(Mathf.Abs(width - parent.rect.width), 0);
|
||||
rect.anchoredPosition = new Vector2((width - parent.rect.width) / 2, 0);
|
||||
|
||||
rect = _blacks[1];
|
||||
if (rect == null)
|
||||
{
|
||||
_blacks[1] = rect = UIExtension.CreateBlackMask(parent, 1, "left").transform as RectTransform;
|
||||
}
|
||||
|
||||
rect.pivot = new Vector2(1, 0.5f);
|
||||
rect.anchorMin = new Vector2(0, 0);
|
||||
rect.anchorMax = new Vector2(0, 1);
|
||||
rect.sizeDelta = new Vector2(Mathf.Abs(width - parent.rect.width), 0);
|
||||
rect.anchoredPosition = new Vector2(-(width - parent.rect.width) / 2, 0);
|
||||
break;
|
||||
case UIBlackType.Width:
|
||||
// 宽度适配时的上下黑边
|
||||
rect = _blacks[0];
|
||||
if (rect == null)
|
||||
{
|
||||
_blacks[0] = rect = UIExtension.CreateBlackMask(parent, 1, "top").transform as RectTransform;
|
||||
}
|
||||
else if (Mathf.Abs(rect.anchoredPosition.y * 2 + parent.rect.height - height) < 1)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
rect.pivot = new Vector2(0.5f, 0);
|
||||
rect.anchorMin = new Vector2(0, 1);
|
||||
rect.anchorMax = new Vector2(1, 1);
|
||||
rect.sizeDelta = new Vector2(0, Mathf.Abs(height - parent.rect.height));
|
||||
rect.anchoredPosition = new Vector2(0, (height - parent.rect.height) / 2);
|
||||
|
||||
rect = _blacks[1];
|
||||
if (rect == null)
|
||||
{
|
||||
_blacks[1] = rect = UIExtension.CreateBlackMask(parent, 1, "bottom").transform as RectTransform;
|
||||
}
|
||||
|
||||
rect.pivot = new Vector2(0.5f, 1);
|
||||
rect.anchorMin = new Vector2(0, 0);
|
||||
rect.anchorMax = new Vector2(1, 0);
|
||||
rect.sizeDelta = new Vector2(0, Mathf.Abs(height - parent.rect.height));
|
||||
rect.anchoredPosition = new Vector2(0, -(height - parent.rect.height) / 2);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
public UIBlackType GetUIBlackType()
|
||||
{
|
||||
var uIBlackType = uiBlackType;
|
||||
if (uIBlackType == UIBlackType.AutoBlack)
|
||||
{
|
||||
var parent = _layers[UILayer.BackgroundLayer].canvas.transform as RectTransform;
|
||||
float widthDis = Mathf.Abs(width - parent.rect.width);
|
||||
float heightDis = Mathf.Abs(height - parent.rect.height);
|
||||
|
||||
if (widthDis < 1 && heightDis < 1)
|
||||
uIBlackType = UIBlackType.None;
|
||||
else if (widthDis > heightDis)
|
||||
uIBlackType = UIBlackType.Height;
|
||||
else
|
||||
uIBlackType = UIBlackType.Width;
|
||||
}
|
||||
|
||||
return uIBlackType;
|
||||
}
|
||||
|
||||
public Rect GetSafeArea()
|
||||
{
|
||||
Rect rect = Screen.safeArea;
|
||||
if (uiBlackType == UIBlackType.Width)
|
||||
{
|
||||
var parent = _layers[UILayer.BackgroundLayer].canvas.transform as RectTransform;
|
||||
float blackArea = Mathf.Abs(height - parent.rect.height) / 2;
|
||||
rect.yMin = Mathf.Max(0, rect.yMin - blackArea);
|
||||
rect.yMax = Mathf.Min(rect.yMax + blackArea, Screen.height);
|
||||
}
|
||||
else if (uiBlackType == UIBlackType.Height)
|
||||
{
|
||||
var parent = _layers[UILayer.BackgroundLayer].canvas.transform as RectTransform;
|
||||
float blackArea = Mathf.Abs(width - parent.rect.width) / 2;
|
||||
rect.xMin = Mathf.Max(0, rect.xMin - blackArea);
|
||||
rect.xMax = Mathf.Min(rect.xMax + blackArea, Screen.width);
|
||||
}
|
||||
|
||||
return rect;
|
||||
}
|
||||
|
||||
public void EnableBackgroundMask(bool enable)
|
||||
{
|
||||
_backgroundMask.alpha = enable ? 1 : 0;
|
||||
}
|
||||
|
||||
public async UniTask InitUIConfig()
|
||||
{
|
||||
// 初始化需要加载所有UI的配置
|
||||
|
||||
var handle = YooAssets.LoadAssetSync<UIConfig>("Config_UIConfig");
|
||||
await handle.Task;
|
||||
UIConfig uiConfig = handle.GetAssetObject<UIConfig>();
|
||||
if (uiConfig == null)
|
||||
{
|
||||
Debug.LogError($"UnityEvo:UIConfig初始化失败,请检查配置文件");
|
||||
return;
|
||||
}
|
||||
|
||||
var list = uiConfig.uiConfigJsons;
|
||||
|
||||
foreach (var cfg in list)
|
||||
{
|
||||
if (_viewControllers.ContainsKey(cfg.uiType))
|
||||
{
|
||||
Debug.LogErrorFormat("存在相同的uiType:{0}, 请检查UIConfig是否重复!", cfg.uiType.ToString());
|
||||
continue;
|
||||
}
|
||||
|
||||
_viewControllers.Add(cfg.uiType, new UIViewController
|
||||
{
|
||||
uiPath = cfg.pathId,
|
||||
uiType = cfg.uiType,
|
||||
uiLayer = _layers[cfg.uiLayer],
|
||||
isWindow = cfg.isWindow,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 注册常驻UI
|
||||
/// </summary>
|
||||
public void AddResidentUI<T>() where T : UIView
|
||||
{
|
||||
_residentViews.Add(typeof(T).Name);
|
||||
}
|
||||
|
||||
public void Open<T>(object userData = null, Action callback = null) where T : UIView
|
||||
{
|
||||
if (!_viewControllers.ContainsKey(typeof(T).Name))
|
||||
{
|
||||
Debug.LogErrorFormat("未配置uiType:{0}, 请检查UIConfig.cs!", typeof(T).Name);
|
||||
return;
|
||||
}
|
||||
|
||||
_openViews.Add(typeof(T).Name);
|
||||
_viewControllers[typeof(T).Name].Open<T>(userData, callback);
|
||||
}
|
||||
|
||||
public async UniTask Preload<T>() where T : UIView
|
||||
{
|
||||
if (!_viewControllers.TryGetValue(typeof(T).Name, out var controller))
|
||||
{
|
||||
Debug.LogErrorFormat("未配置uiType:{0}, 请检查UIConfig.cs!", typeof(T).Name);
|
||||
return;
|
||||
}
|
||||
|
||||
await controller.Load<T>();
|
||||
}
|
||||
|
||||
public async UniTask PreloadAll()
|
||||
{
|
||||
foreach (var controller in _viewControllers.Values)
|
||||
{
|
||||
var handle = YooAssets.LoadAssetSync<GameObject>(controller.uiPath);
|
||||
await handle.Task;
|
||||
GameObject gameObject = handle.GetAssetObject<GameObject>();
|
||||
}
|
||||
}
|
||||
|
||||
public bool IsOpen<T>() where T : UIView
|
||||
{
|
||||
return _openViews.Contains(typeof(T).Name);
|
||||
}
|
||||
|
||||
public void Close<T>(Action callback = null) where T : UIView
|
||||
{
|
||||
if (!_viewControllers.ContainsKey(typeof(T).Name))
|
||||
{
|
||||
Debug.LogErrorFormat("未配置uiType:{0}, 请检查UIConfig.cs!", typeof(T).Name);
|
||||
return;
|
||||
}
|
||||
|
||||
_openViews.Remove(typeof(T).Name);
|
||||
_viewControllers[typeof(T).Name].Close(callback);
|
||||
}
|
||||
|
||||
public void Close<T>(T view, Action callback = null) where T : UIView
|
||||
{
|
||||
Close<T>();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// UI建议都用事件进行交互,最好不使用该接口
|
||||
/// </summary>
|
||||
public T GetView<T>() where T : UIView
|
||||
{
|
||||
if (!_viewControllers.ContainsKey(typeof(T).Name))
|
||||
{
|
||||
Debug.LogErrorFormat("未配置uiType:{0}, 请检查UIConfig.cs!", typeof(T).Name);
|
||||
return null;
|
||||
}
|
||||
|
||||
return _viewControllers[typeof(T).Name].uiView as T;
|
||||
}
|
||||
|
||||
public void CloseAll(bool closeResidentView = false)
|
||||
{
|
||||
var list = ListPool<string>.Get();
|
||||
|
||||
foreach (var uiType in _openViews)
|
||||
{
|
||||
if (closeResidentView || !_residentViews.Contains(uiType))
|
||||
{
|
||||
_viewControllers[uiType].Close();
|
||||
list.Add(uiType);
|
||||
}
|
||||
}
|
||||
|
||||
foreach (var uiType in list)
|
||||
{
|
||||
_openViews.Remove(uiType);
|
||||
}
|
||||
|
||||
ListPool<string>.Release(list);
|
||||
}
|
||||
|
||||
public void ReleaseAll()
|
||||
{
|
||||
foreach (var controller in _viewControllers.Values)
|
||||
{
|
||||
if (!_residentViews.Contains(controller.uiType))
|
||||
{
|
||||
_openViews.Remove(controller.uiType);
|
||||
controller.Release();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void FadeIn(float duration = 0.5f, TweenCallback callback = null)
|
||||
{
|
||||
if (_fadeTweener != null && _fadeTweener.IsPlaying())
|
||||
_fadeTweener.Complete();
|
||||
_fadeTweener = _blackMask.DOFade(1.0f, duration);
|
||||
_fadeTweener.onComplete = callback;
|
||||
}
|
||||
|
||||
public void FadeOut(float duration = 0.5f, TweenCallback callback = null)
|
||||
{
|
||||
if (_fadeTweener != null && _fadeTweener.IsPlaying())
|
||||
_fadeTweener.Complete();
|
||||
_fadeTweener = _blackMask.DOFade(0.0f, duration);
|
||||
_fadeTweener.onComplete = callback;
|
||||
}
|
||||
|
||||
public void FadeInOut(float duration = 1.0f, TweenCallback callback = null)
|
||||
{
|
||||
if (_fadeTweener != null && _fadeTweener.IsPlaying())
|
||||
_fadeTweener.Complete();
|
||||
_fadeTweener = _blackMask.DOFade(1.0f, duration * 0.5f);
|
||||
_fadeTweener.onComplete += () =>
|
||||
{
|
||||
_fadeTweener = _blackMask.DOFade(0.0f, duration * 0.5f);
|
||||
_fadeTweener.onComplete = callback;
|
||||
};
|
||||
}
|
||||
|
||||
public void Cancel()
|
||||
{
|
||||
if (_layers.TryGetValue(UILayer.NormalLayer, out var layer) && layer.openedViews.Count > 0)
|
||||
{
|
||||
var viewController = layer.openedViews.Peek();
|
||||
if (viewController.uiView != null)
|
||||
{
|
||||
viewController.uiView.OnCancel();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 8cfcbc4a9d8ab3b4caf6a62eae0704e9
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: cbc37b0ef4d973c40ab221552e3c0b3a
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,191 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Resources;
|
||||
using Cysharp.Threading.Tasks;
|
||||
using UnityEngine;
|
||||
using UnityEngine.UI;
|
||||
using YooAsset;
|
||||
|
||||
namespace Stary.Evo
|
||||
{
|
||||
public class UIModelManager : Singleton<UIModelManager>
|
||||
{
|
||||
private Stack<Camera> m_CameraPool = new Stack<Camera>();
|
||||
private Stack<int> m_IndexPool = new Stack<int>();
|
||||
private int m_PoolCount = 0;
|
||||
private Camera m_UICamera;
|
||||
|
||||
private Transform m_UIModelRoot;
|
||||
private Light m_UIModelLight;
|
||||
|
||||
public Camera UICamera => m_UICamera;
|
||||
|
||||
public override void OnInitialize()
|
||||
{
|
||||
base.OnInitialize();
|
||||
|
||||
//m_UICamera = GameObject.Find("UICamera").GetOrAddComponent<Camera>();
|
||||
|
||||
m_UIModelRoot = new GameObject("UIModelRoot").transform;
|
||||
m_UIModelRoot.SetParentEx(null);
|
||||
GameObject.DontDestroyOnLoad(m_UIModelRoot);
|
||||
|
||||
m_UIModelLight = new GameObject("UIModelLight").GetOrAddComponent<Light>();
|
||||
m_UIModelLight.transform.SetParentEx(m_UIModelRoot);
|
||||
|
||||
m_UIModelLight.transform.localEulerAngles = new Vector3(36, 30, 0);
|
||||
m_UIModelLight.cookieSize = 10;
|
||||
m_UIModelLight.type = LightType.Directional;
|
||||
m_UIModelLight.cullingMask = 1 << Layer.UI | 1 << Layer.UIRenderToTarget;
|
||||
m_UIModelLight.shadows = LightShadows.None;
|
||||
|
||||
m_UIModelLight.gameObject.SetActive(false);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 加载一个模型到一张RawImage上
|
||||
/// </summary>
|
||||
public async UniTask LoadModelToRawImage(string path, RawImage rawImage, bool canDrag = true, Vector3 offset = default,
|
||||
Quaternion rot = default, Vector3 scale = default, bool isOrth = true, float orthSizeOrFOV = 1,
|
||||
Action<UIRenderToTexture, GameObject> callback = null)
|
||||
{
|
||||
if (rawImage == null)
|
||||
{
|
||||
Debug.LogError("RawImage Is Null!");
|
||||
return;
|
||||
}
|
||||
|
||||
rawImage.enabled = false;
|
||||
var handle = YooAssets.LoadAssetSync<GameObject>(path);
|
||||
await handle.Task;
|
||||
GameObject go = handle.GetAssetObject<GameObject>();
|
||||
|
||||
UnLoadModelByRawImage(rawImage);
|
||||
rawImage.enabled = true;
|
||||
LoadModelToRawImage(go, rawImage, canDrag, offset, rot, scale, isOrth, orthSizeOrFOV, callback);
|
||||
}
|
||||
|
||||
public void LoadModelToRawImage(GameObject go, RawImage rawImage, bool canDrag, Vector3 offset = default,
|
||||
Quaternion rot = default, Vector3 scale = default, bool isOrth = true, float orthSizeOrFOV = 1,
|
||||
Action<UIRenderToTexture, GameObject> callback = null)
|
||||
{
|
||||
if (go != null)
|
||||
{
|
||||
UIRenderToTexture renderToTexture = rawImage.GetOrAddComponent<UIRenderToTexture>();
|
||||
Vector3 pos;
|
||||
int index = 0;
|
||||
if (renderToTexture.Targets == null || renderToTexture.Targets.Count == 0)
|
||||
{
|
||||
index = m_IndexPool.Count > 0 ? m_IndexPool.Pop() : m_PoolCount++;
|
||||
}
|
||||
else
|
||||
{
|
||||
index = renderToTexture.Index;
|
||||
}
|
||||
|
||||
pos = new Vector3(100 * index, -10000, 0);
|
||||
renderToTexture.Init(pos, isOrth, orthSizeOrFOV, index);
|
||||
UpdateLight();
|
||||
|
||||
go.SetLayerRecursively(Layer.UIRenderToTarget);
|
||||
go.transform.SetParent(m_UIModelRoot);
|
||||
go.transform.localPosition = pos + offset;
|
||||
go.transform.localScale = scale == default ? Vector3.one : scale;
|
||||
go.transform.rotation = rot;
|
||||
renderToTexture.AddTarget(go, canDrag);
|
||||
callback?.Invoke(renderToTexture, go);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 卸载单个
|
||||
/// </summary>
|
||||
public void UnLoadModelByRawImage(RawImage rawImage, GameObject go)
|
||||
{
|
||||
if (rawImage != null && go != null)
|
||||
{
|
||||
UIRenderToTexture renderToTexture = rawImage.GetComponent<UIRenderToTexture>();
|
||||
int id = go.GetInstanceID();
|
||||
if (renderToTexture != null && renderToTexture.Targets != null &&
|
||||
renderToTexture.Targets.ContainsKey(id))
|
||||
{
|
||||
renderToTexture.Targets.Remove(id);
|
||||
//ResourceManager.Instance.GetResourceCore(UIConfig.UIPackageName).Recycle(go);
|
||||
if (renderToTexture.Targets.Count == 0)
|
||||
{
|
||||
m_IndexPool.Push(renderToTexture.Index);
|
||||
renderToTexture.ResetTarget();
|
||||
}
|
||||
|
||||
UpdateLight();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 卸载所有
|
||||
/// </summary>
|
||||
public void UnLoadModelByRawImage(RawImage rawImage, bool recycleGo = true)
|
||||
{
|
||||
if (rawImage != null)
|
||||
{
|
||||
UIRenderToTexture renderToTexture = rawImage.GetComponent<UIRenderToTexture>();
|
||||
if (renderToTexture != null && renderToTexture.Targets != null && renderToTexture.Targets.Count > 0)
|
||||
{
|
||||
if (recycleGo)
|
||||
{
|
||||
foreach (var target in renderToTexture.Targets.Values)
|
||||
{
|
||||
// ResourceManager.Instance.GetResourceCore(UIConfig.UIPackageName).Recycle(target.gameObject);
|
||||
}
|
||||
}
|
||||
|
||||
m_IndexPool.Push(renderToTexture.Index);
|
||||
renderToTexture.ResetTarget();
|
||||
UpdateLight();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void UpdateLight()
|
||||
{
|
||||
m_UIModelLight.gameObject.SetActive(m_CameraPool.Count < m_PoolCount);
|
||||
}
|
||||
|
||||
public Camera SpawnCamera()
|
||||
{
|
||||
if (m_CameraPool.Count > 0)
|
||||
{
|
||||
Camera camera = m_CameraPool.Pop();
|
||||
camera.gameObject.SetActive(true);
|
||||
return camera;
|
||||
}
|
||||
else
|
||||
{
|
||||
GameObject go = new GameObject("CameraRTT");
|
||||
go.transform.SetParentEx(m_UIModelRoot);
|
||||
Camera camera = go.GetOrAddComponent<Camera>();
|
||||
camera.fieldOfView = 30;
|
||||
camera.allowHDR = false;
|
||||
camera.backgroundColor = Color.clear;
|
||||
camera.useOcclusionCulling = false;
|
||||
camera.clearFlags = CameraClearFlags.SolidColor;
|
||||
camera.cullingMask = 1 << Layer.UIRenderToTarget;
|
||||
camera.farClipPlane = 30;
|
||||
camera.orthographicSize = 1;
|
||||
|
||||
return camera;
|
||||
}
|
||||
}
|
||||
|
||||
public void RecyleCamera(Camera camera)
|
||||
{
|
||||
if (camera != null)
|
||||
{
|
||||
camera.targetTexture = null;
|
||||
camera.gameObject.SetActive(false);
|
||||
m_CameraPool.Push(camera);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 1ef5008611a90c147a4a9d40cc4c0cc0
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,215 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
using UnityEngine.EventSystems;
|
||||
using UnityEngine.Experimental.Rendering;
|
||||
using UnityEngine.UI;
|
||||
|
||||
namespace Stary.Evo
|
||||
{
|
||||
|
||||
public class UIRenderToTexture : MonoBehaviour, IDragHandler, IBeginDragHandler, IEndDragHandler, IPointerClickHandler
|
||||
{
|
||||
public struct Target
|
||||
{
|
||||
public GameObject gameObject;
|
||||
public bool canDrag;
|
||||
}
|
||||
|
||||
private Camera m_Camera;
|
||||
private RawImage m_RawImage;
|
||||
private RenderTexture m_RenderTexture;
|
||||
private Dictionary<int, Target> m_Targets = new Dictionary<int, Target>();
|
||||
private int m_Index = -1;
|
||||
private Transform m_DragTarget;
|
||||
private float m_orthographicSize = 1;
|
||||
|
||||
public Camera Camera => m_Camera;
|
||||
public Dictionary<int, Target> Targets => m_Targets;
|
||||
public int Index => m_Index;
|
||||
/// <summary>
|
||||
/// 目标被点击
|
||||
/// </summary>
|
||||
public event Action<GameObject> OnTargetClick;
|
||||
|
||||
void OnDestroy()
|
||||
{
|
||||
if (m_Camera != null)
|
||||
UIModelManager.Instance.RecyleCamera(m_Camera);
|
||||
ReleaseRenderTexture();
|
||||
}
|
||||
|
||||
|
||||
public void Init(Vector3 vec, bool isOrth, float orth, int index)
|
||||
{
|
||||
InitCamera(isOrth, orth);
|
||||
m_Index = index;
|
||||
if (m_Camera)
|
||||
{
|
||||
m_Camera.transform.localPosition = vec + new Vector3(0, 0, 20);
|
||||
m_Camera.transform.localEulerAngles = new Vector3(0, 180, 0);
|
||||
}
|
||||
|
||||
if (m_RawImage == null)
|
||||
m_RawImage = GetComponent<RawImage>();
|
||||
|
||||
if (m_RenderTexture == null)
|
||||
{
|
||||
m_RenderTexture = RenderTexture.GetTemporary((int)m_RawImage.rectTransform.rect.width, (int)m_RawImage.rectTransform.rect.height, 1, RenderTextureFormat.ARGB32);
|
||||
m_RenderTexture.name = "UIRenderToTexture";
|
||||
}
|
||||
m_Camera.targetTexture = m_RenderTexture;
|
||||
m_RawImage.texture = m_RenderTexture;
|
||||
}
|
||||
|
||||
private void InitCamera(bool isOrth, float orth)
|
||||
{
|
||||
if (m_Camera == null)
|
||||
{
|
||||
m_Camera = UIModelManager.Instance.SpawnCamera();
|
||||
}
|
||||
else
|
||||
{
|
||||
m_Camera.gameObject.SetActive(true);
|
||||
}
|
||||
m_Camera.orthographic = isOrth;
|
||||
m_Camera.orthographicSize = orth;
|
||||
m_Camera.fieldOfView = orth;
|
||||
m_orthographicSize = orth;
|
||||
}
|
||||
|
||||
private void ReleaseRenderTexture()
|
||||
{
|
||||
if (m_RenderTexture != null)
|
||||
{
|
||||
RenderTexture.ReleaseTemporary(m_RenderTexture);
|
||||
m_RenderTexture = null;
|
||||
m_RawImage.texture = null;
|
||||
}
|
||||
}
|
||||
public bool AddTarget(GameObject target, bool canDrag)
|
||||
{
|
||||
if (target)
|
||||
{
|
||||
if (m_Targets == null)
|
||||
m_Targets = new Dictionary<int, Target>();
|
||||
|
||||
int id = target.GetInstanceID();
|
||||
if (!m_Targets.ContainsKey(id))
|
||||
{
|
||||
m_Targets.Add(id, new Target { gameObject = target, canDrag = canDrag });
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public void ResetTarget()
|
||||
{
|
||||
m_Targets.Clear();
|
||||
if (m_Camera != null)
|
||||
{
|
||||
UIModelManager.Instance.RecyleCamera(m_Camera);
|
||||
m_Camera = null;
|
||||
}
|
||||
m_Index = -1;
|
||||
ReleaseRenderTexture();
|
||||
}
|
||||
|
||||
private void Update()
|
||||
{
|
||||
if (m_Targets != null)
|
||||
{
|
||||
foreach (var target in m_Targets.Values)
|
||||
{
|
||||
if (m_DragTarget == null || m_DragTarget.gameObject != target.gameObject)
|
||||
target.gameObject.transform.rotation = Quaternion.Lerp(target.gameObject.transform.rotation, Quaternion.identity, Time.deltaTime * 5);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void SetClickTarget(Vector2 clickPos)
|
||||
{
|
||||
if (m_Targets.Count == 1)
|
||||
{
|
||||
foreach (var item in m_Targets.Values)
|
||||
{
|
||||
m_DragTarget = item.gameObject.transform;
|
||||
}
|
||||
return;
|
||||
}
|
||||
// 通过射线检测当前点击的模型
|
||||
// 拿到点击位置与UI位置的偏移百分比
|
||||
Camera uiCamera = UIModelManager.Instance.UICamera;
|
||||
float width = m_RawImage.rectTransform.rect.width;
|
||||
float height = m_RawImage.rectTransform.rect.height;
|
||||
Vector2 screenPos = RectTransformUtility.WorldToScreenPoint(uiCamera, transform.position);
|
||||
screenPos += new Vector2(width * (0.5f - m_RawImage.rectTransform.pivot.x), height * (0.5f - m_RawImage.rectTransform.pivot.y));
|
||||
Vector2 offset = clickPos - screenPos;
|
||||
offset = new Vector2(offset.x / width, offset.y / height);
|
||||
if (m_Camera.orthographic)
|
||||
{
|
||||
// 正交相机的渲染大小height=size*2, width = 宽高比*height
|
||||
float screenHeight = m_Camera.orthographicSize * 2;
|
||||
float screenWidth = m_Camera.pixelWidth * 1.0f / m_Camera.pixelHeight * screenHeight;
|
||||
Vector3 startPoint = m_Camera.transform.position + m_Camera.transform.right * offset.x * screenWidth + m_Camera.transform.up * offset.y * screenHeight;
|
||||
|
||||
Debug.DrawLine(startPoint, startPoint + m_Camera.transform.forward * 100, Color.red, 5f);
|
||||
if (Physics.Raycast(startPoint, m_Camera.transform.forward, out RaycastHit hit, 100, 1 << Layer.UIRenderToTarget))
|
||||
{
|
||||
m_DragTarget = hit.transform;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// 透视相机通过FOV和near可以求height, width同正交相机
|
||||
float screenHeight = Mathf.Tan(m_Camera.fieldOfView * 0.5f * Mathf.Deg2Rad) * m_Camera.nearClipPlane * 2;
|
||||
float screenWidth = m_Camera.pixelWidth * 1.0f / m_Camera.pixelHeight * screenHeight;
|
||||
Vector3 endPoint = m_Camera.transform.position + m_Camera.transform.forward * m_Camera.nearClipPlane
|
||||
+ m_Camera.transform.right * offset.x * screenWidth + m_Camera.transform.up * offset.y * screenHeight;
|
||||
Vector3 dir = (endPoint - m_Camera.transform.position).normalized;
|
||||
|
||||
Debug.DrawLine(m_Camera.transform.position, endPoint, Color.red, 5f);
|
||||
if (Physics.Raycast(m_Camera.transform.position, dir, out RaycastHit hit, m_Camera.farClipPlane, 1 << Layer.UIRenderToTarget))
|
||||
{
|
||||
m_DragTarget = hit.transform;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void OnBeginDrag(PointerEventData eventData)
|
||||
{
|
||||
m_DragTarget = null;
|
||||
SetClickTarget(eventData.position);
|
||||
|
||||
// 不能拖拽时置空
|
||||
if (m_DragTarget != null && m_Targets.TryGetValue(m_DragTarget.GetInstanceID(), out Target target) && !target.canDrag)
|
||||
{
|
||||
m_DragTarget = null;
|
||||
}
|
||||
}
|
||||
|
||||
public void OnDrag(PointerEventData eventData)
|
||||
{
|
||||
if (m_DragTarget != null)
|
||||
m_DragTarget.localEulerAngles -= new Vector3(0, eventData.delta.x, 0);
|
||||
}
|
||||
|
||||
public void OnEndDrag(PointerEventData eventData)
|
||||
{
|
||||
m_DragTarget = null;
|
||||
}
|
||||
|
||||
public void OnPointerClick(PointerEventData eventData)
|
||||
{
|
||||
m_DragTarget = null;
|
||||
SetClickTarget(eventData.position);
|
||||
|
||||
if (m_DragTarget != null)
|
||||
{
|
||||
// 点中模型,发送事件或者其他操作
|
||||
OnTargetClick?.Invoke(m_DragTarget.gameObject);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 0330a7f066ad9324ba9aef4e9041d15f
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 51fad6d16f65b2e49baa26490875f22d
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,58 @@
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Stary.Evo
|
||||
{
|
||||
public class UILoopItem : UISubView
|
||||
{
|
||||
protected int m_Index;
|
||||
protected RectTransform m_RectTransform;
|
||||
public int Index => m_Index;
|
||||
public UIScrollView UIScrollView { get; set; }
|
||||
|
||||
public override void OnInit()
|
||||
{
|
||||
base.OnInit();
|
||||
m_RectTransform = transform as RectTransform;
|
||||
}
|
||||
|
||||
public void UpdateData(IList dataList, int index, object userData)
|
||||
{
|
||||
if (!isInit)
|
||||
{
|
||||
OnInit();
|
||||
}
|
||||
m_Index = index;
|
||||
m_RectTransform.localPosition = Vector3.zero;
|
||||
m_RectTransform.anchoredPosition = UIScrollView.GetLocalPositionByIndex(index);
|
||||
CheckSelect(UIScrollView.SelectIndex);
|
||||
OnUpdateData(dataList, index, userData);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 选中切换时
|
||||
/// </summary>
|
||||
public virtual void CheckSelect(int index)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Item的宽高
|
||||
/// </summary>
|
||||
public virtual Vector2 GetRect()
|
||||
{
|
||||
return new Vector2(m_RectTransform.rect.width * m_RectTransform.localScale.x, m_RectTransform.rect.height * m_RectTransform.localScale.y);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 刷新数据时
|
||||
/// </summary>
|
||||
protected virtual void OnUpdateData(IList dataList, int index, object userData)
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: d78a289562ae2da4983a49b31b6fbb43
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,543 @@
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
using UnityEngine.UI;
|
||||
using UnityEngine.EventSystems;
|
||||
using static UnityEngine.RectTransform;
|
||||
using DG.Tweening;
|
||||
|
||||
namespace Stary.Evo
|
||||
{
|
||||
public enum AlignType
|
||||
{
|
||||
Left,
|
||||
Right,
|
||||
Top,
|
||||
Bottom,
|
||||
Center,
|
||||
}
|
||||
|
||||
public class UIScrollView : MonoBehaviour, IEndDragHandler
|
||||
{
|
||||
public ScrollRect m_ScrollRect;
|
||||
public RectTransform m_Content;
|
||||
/// <summary>
|
||||
/// 水平移动/垂直移动
|
||||
/// </summary>
|
||||
public Axis m_AxisType;
|
||||
/// <summary>
|
||||
/// 布局
|
||||
/// </summary>
|
||||
public AlignType m_AlignType;
|
||||
/// <summary>
|
||||
/// 子物体的中心点
|
||||
/// </summary>
|
||||
public PivotPresets m_ItemPivot;
|
||||
/// <summary>
|
||||
/// 开始间隔
|
||||
/// </summary>
|
||||
public int m_HorizontalStartSpace;
|
||||
/// <summary>
|
||||
/// 开始间隔
|
||||
/// </summary>
|
||||
public int m_VerticalStartSpace;
|
||||
/// <summary>
|
||||
/// 水平间隔
|
||||
/// </summary>
|
||||
public int m_HorizontalSpace;
|
||||
/// <summary>
|
||||
/// 垂直间隔
|
||||
/// </summary>
|
||||
public int m_VerticalSpace;
|
||||
/// <summary>
|
||||
/// 另一个方向上物品的个数,水平移动-表示列个数,垂直移动-表示行个数
|
||||
/// </summary>
|
||||
public int m_CountOfOtherAxis = 1;
|
||||
/// <summary>
|
||||
/// 是否分页
|
||||
/// </summary>
|
||||
public bool m_IsPaging;
|
||||
|
||||
private IList m_Datas;
|
||||
private PrefabPool m_PrefabPool;
|
||||
private List<UILoopItem> m_LoopItems;
|
||||
private int m_SelectIndex = -1;
|
||||
|
||||
private int m_HorizontalCount;
|
||||
private int m_VerticalCount;
|
||||
private float m_ChildWidth;
|
||||
private float m_ChildHeight;
|
||||
private int m_CurrentIndex;
|
||||
|
||||
private Type m_ItemType;
|
||||
private object m_UserData;
|
||||
|
||||
private Tweener m_Tweener;
|
||||
|
||||
public Action<int> OnSelectChanged;
|
||||
public int SelectIndex => m_SelectIndex;
|
||||
public List<UILoopItem> LoopItems => m_LoopItems;
|
||||
public int CurrentIndex => m_CurrentIndex;
|
||||
|
||||
private Rect parentRect;
|
||||
|
||||
private void Awake()
|
||||
{
|
||||
m_LoopItems = new List<UILoopItem>();
|
||||
m_ScrollRect.onValueChanged.AddListener(OnValueChanged);
|
||||
if (m_AxisType != Axis.Horizontal)
|
||||
m_ScrollRect.horizontal = false;
|
||||
if (m_AxisType != Axis.Vertical)
|
||||
m_ScrollRect.vertical = false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 刷新整个scrollview
|
||||
/// </summary>
|
||||
/// <param name="dataList">数据</param>
|
||||
/// <param name="prefab">预制体</param>
|
||||
/// <param name="type">类型</param>
|
||||
/// <param name="isPaging">是否分页</param>
|
||||
/// <param name="userData">用户数据</param>
|
||||
public void UpdateList(IList dataList, GameObject prefab, Type type, bool isKeepPos = false, object userData = null)
|
||||
{
|
||||
if (dataList == null || prefab == null)
|
||||
{
|
||||
Release();
|
||||
return;
|
||||
}
|
||||
|
||||
if (m_PrefabPool != null && m_PrefabPool.Prefab != prefab)
|
||||
{
|
||||
m_PrefabPool.Destroy();
|
||||
m_PrefabPool = null;
|
||||
}
|
||||
if (m_PrefabPool == null)
|
||||
{
|
||||
m_PrefabPool = PrefabPool.Create(prefab);
|
||||
}
|
||||
prefab.SetActive(false);
|
||||
m_PrefabPool.RecycleUseList();
|
||||
m_LoopItems.Clear();
|
||||
m_SelectIndex = -1;
|
||||
|
||||
RectTransform rect = prefab.GetComponent<RectTransform>();
|
||||
m_ChildWidth = rect.rect.width * rect.transform.localScale.x;
|
||||
m_ChildHeight = rect.rect.height * rect.transform.localScale.y;
|
||||
|
||||
var parent = m_ScrollRect.transform as RectTransform;
|
||||
parentRect = parent.rect;
|
||||
m_HorizontalCount = Mathf.CeilToInt((parentRect.width - m_HorizontalStartSpace) / (m_ChildWidth + m_HorizontalSpace));
|
||||
m_VerticalCount = Mathf.CeilToInt((parentRect.height - m_VerticalStartSpace) / (m_ChildHeight + m_VerticalSpace));
|
||||
|
||||
m_ItemType = type;
|
||||
m_Datas = dataList;
|
||||
m_UserData = userData;
|
||||
|
||||
m_Content.SetPivot(m_ItemPivot);
|
||||
Vector2 oldPos = m_Content.anchoredPosition;
|
||||
|
||||
if (m_Tweener != null)
|
||||
{
|
||||
m_Tweener.Kill();
|
||||
m_Tweener = null;
|
||||
}
|
||||
|
||||
if (m_CountOfOtherAxis == 0)
|
||||
{
|
||||
if (m_AxisType == Axis.Horizontal)
|
||||
m_CountOfOtherAxis = Mathf.FloorToInt((parentRect.height - m_VerticalStartSpace) / (m_ChildHeight + m_VerticalSpace));
|
||||
else
|
||||
m_CountOfOtherAxis = Mathf.FloorToInt((parentRect.width - m_HorizontalStartSpace) / (m_ChildWidth + m_HorizontalSpace));
|
||||
|
||||
m_CountOfOtherAxis = Math.Max(1, m_CountOfOtherAxis);
|
||||
}
|
||||
|
||||
if (m_AxisType == Axis.Horizontal)
|
||||
m_VerticalCount = m_CountOfOtherAxis;
|
||||
else
|
||||
m_HorizontalCount = m_CountOfOtherAxis;
|
||||
|
||||
int axisCount = Mathf.CeilToInt(dataList.Count * 1.0f / m_CountOfOtherAxis);
|
||||
switch (m_AxisType)
|
||||
{
|
||||
case Axis.Horizontal:
|
||||
if (m_AlignType == AlignType.Right)
|
||||
{
|
||||
m_Content.SetAnchor(AnchorPresets.VertStretchRight);
|
||||
}
|
||||
else
|
||||
{
|
||||
m_Content.SetAnchor(AnchorPresets.VertStretchLeft);
|
||||
}
|
||||
m_Content.sizeDelta = new Vector2(axisCount * m_ChildWidth + (axisCount - 1) * m_HorizontalSpace + m_HorizontalStartSpace * 2, 0);
|
||||
if (m_AlignType == AlignType.Center)
|
||||
{
|
||||
var viewPort = m_Content.parent as RectTransform;
|
||||
viewPort.anchorMin = new Vector2(0.5f, 0.5f);
|
||||
viewPort.anchorMax = new Vector2(0.5f, 0.5f);
|
||||
viewPort.pivot = new Vector2(0.5f, 0.5f);
|
||||
viewPort.anchoredPosition = Vector2.zero;
|
||||
viewPort.sizeDelta = new Vector2(m_Content.sizeDelta.x, parentRect.height);
|
||||
int verCount = Mathf.FloorToInt((parentRect.height - m_VerticalStartSpace) / (m_ChildHeight + m_VerticalSpace));
|
||||
if (verCount > m_Datas.Count)
|
||||
{
|
||||
viewPort.sizeDelta = new Vector2(m_Content.sizeDelta.x, (m_ChildHeight + m_VerticalSpace) * m_Datas.Count - m_VerticalSpace + m_VerticalStartSpace * 2);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case Axis.Vertical:
|
||||
if (m_AlignType == AlignType.Bottom)
|
||||
{
|
||||
m_Content.SetAnchor(AnchorPresets.BottomStretch);
|
||||
}
|
||||
else
|
||||
{
|
||||
m_Content.SetAnchor(AnchorPresets.HorStretchTop);
|
||||
}
|
||||
m_Content.sizeDelta = new Vector2(0, axisCount * m_ChildHeight + (axisCount - 1) * m_VerticalSpace + m_VerticalStartSpace * 2);
|
||||
if (m_AlignType == AlignType.Center)
|
||||
{
|
||||
var viewPort = m_Content.parent as RectTransform;
|
||||
viewPort.anchorMin = new Vector2(0.5f, 0.5f);
|
||||
viewPort.anchorMax = new Vector2(0.5f, 0.5f);
|
||||
viewPort.pivot = new Vector2(0.5f, 0.5f);
|
||||
viewPort.anchoredPosition = Vector2.zero;
|
||||
viewPort.sizeDelta = new Vector2(parentRect.width, m_Content.sizeDelta.y);
|
||||
int horCount = Mathf.CeilToInt((parentRect.width - m_HorizontalStartSpace) / (m_ChildWidth + m_HorizontalSpace));
|
||||
if (horCount > m_Datas.Count)
|
||||
{
|
||||
viewPort.sizeDelta = new Vector2((m_ChildWidth + m_HorizontalSpace) * m_Datas.Count - m_HorizontalSpace + m_HorizontalStartSpace * 2, m_Content.sizeDelta.y);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
if (isKeepPos)
|
||||
{
|
||||
m_Content.anchoredPosition = new Vector2(Mathf.Min(oldPos.x, m_Content.sizeDelta.x), Mathf.Min(oldPos.y, m_Content.sizeDelta.y));
|
||||
}
|
||||
else
|
||||
{
|
||||
m_Content.anchoredPosition = Vector2.zero;
|
||||
}
|
||||
m_CurrentIndex = GetCurrentItemIndex();
|
||||
UpdateContent(m_CurrentIndex);
|
||||
}
|
||||
|
||||
public void GetPos(int index, out int x, out int y)
|
||||
{
|
||||
if (m_AxisType == Axis.Horizontal)
|
||||
{
|
||||
x = index / m_CountOfOtherAxis;
|
||||
y = index % m_CountOfOtherAxis;
|
||||
}
|
||||
else
|
||||
{
|
||||
x = index % m_CountOfOtherAxis;
|
||||
y = index / m_CountOfOtherAxis;
|
||||
}
|
||||
}
|
||||
|
||||
public int GetIndex(int x, int y)
|
||||
{
|
||||
if (x < 0 || y < 0) return -1;
|
||||
|
||||
if (m_AxisType == Axis.Horizontal)
|
||||
{
|
||||
if (y >= m_CountOfOtherAxis) return -1;
|
||||
|
||||
return x * m_CountOfOtherAxis + y;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (x >= m_CountOfOtherAxis) return -1;
|
||||
|
||||
return y * m_CountOfOtherAxis + x;
|
||||
}
|
||||
}
|
||||
|
||||
public void UpdateContent(int index = 0)
|
||||
{
|
||||
if (m_Datas == null) return;
|
||||
|
||||
int maxCount = 0;
|
||||
switch (m_AxisType)
|
||||
{
|
||||
case Axis.Horizontal:
|
||||
maxCount = (m_HorizontalCount + 2) * m_CountOfOtherAxis;
|
||||
break;
|
||||
case Axis.Vertical:
|
||||
maxCount = (m_VerticalCount + 2) * m_CountOfOtherAxis;
|
||||
break;
|
||||
}
|
||||
|
||||
for (int i = 0; i < maxCount; i++)
|
||||
{
|
||||
int listIndex = index + i;
|
||||
if (m_Datas.Count > listIndex)
|
||||
{
|
||||
if (m_LoopItems.Count > i)
|
||||
{
|
||||
m_LoopItems[i].UpdateData(m_Datas, listIndex, m_UserData);
|
||||
}
|
||||
else
|
||||
{
|
||||
var go = m_PrefabPool.Get();
|
||||
RectTransform rectTransform = go.transform as RectTransform;
|
||||
rectTransform.SetPivot(m_ItemPivot);
|
||||
switch (m_ItemPivot)
|
||||
{
|
||||
case PivotPresets.TopLeft:
|
||||
case PivotPresets.TopCenter:
|
||||
rectTransform.SetAnchor(AnchorPresets.TopLeft);
|
||||
break;
|
||||
case PivotPresets.TopRight:
|
||||
rectTransform.SetAnchor(AnchorPresets.TopRight);
|
||||
break;
|
||||
case PivotPresets.MiddleLeft:
|
||||
case PivotPresets.MiddleCenter:
|
||||
rectTransform.SetAnchor(AnchorPresets.MiddleLeft);
|
||||
break;
|
||||
case PivotPresets.MiddleRight:
|
||||
rectTransform.SetAnchor(AnchorPresets.MiddleRight);
|
||||
break;
|
||||
case PivotPresets.BottomLeft:
|
||||
case PivotPresets.BottomCenter:
|
||||
rectTransform.SetAnchor(AnchorPresets.BottomLeft);
|
||||
break;
|
||||
case PivotPresets.BottomRight:
|
||||
rectTransform.SetAnchor(AnchorPresets.BottomRight);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
rectTransform.SetParent(m_Content);
|
||||
rectTransform.localScale = m_PrefabPool.Prefab.transform.localScale;
|
||||
UILoopItem loopItem = go.GetOrAddComponent(m_ItemType) as UILoopItem;
|
||||
loopItem.UIScrollView = this;
|
||||
m_LoopItems.Add(loopItem);
|
||||
loopItem.UpdateData(m_Datas, listIndex, m_UserData);
|
||||
}
|
||||
}
|
||||
else if (m_LoopItems.Count > i)
|
||||
{
|
||||
m_LoopItems[i].transform.localPosition = new Vector3(-10000, -10000);
|
||||
}
|
||||
}
|
||||
while (m_LoopItems.Count > maxCount)
|
||||
{
|
||||
UILoopItem loopItem = m_LoopItems[m_LoopItems.Count - 1];
|
||||
m_PrefabPool.Recycle(loopItem.gameObject);
|
||||
m_LoopItems.RemoveAt(m_LoopItems.Count - 1);
|
||||
}
|
||||
}
|
||||
|
||||
public Vector3 GetLocalPositionByIndex(int index)
|
||||
{
|
||||
float x, y, z;
|
||||
x = y = z = 0.0f;
|
||||
|
||||
int remain = index % m_CountOfOtherAxis;
|
||||
index /= m_CountOfOtherAxis;
|
||||
switch (m_AxisType)
|
||||
{
|
||||
case Axis.Horizontal:
|
||||
y = -m_VerticalStartSpace - remain * (m_ChildHeight + m_VerticalSpace);
|
||||
switch (m_AlignType)
|
||||
{
|
||||
case AlignType.Center:
|
||||
case AlignType.Left:
|
||||
case AlignType.Top:
|
||||
x = m_HorizontalStartSpace + index * (m_ChildWidth + m_HorizontalSpace);
|
||||
break;
|
||||
case AlignType.Right:
|
||||
case AlignType.Bottom:
|
||||
x = m_HorizontalStartSpace - index * (m_ChildWidth + m_HorizontalSpace);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case Axis.Vertical:
|
||||
x = m_HorizontalStartSpace + remain * (m_ChildWidth + m_HorizontalSpace);
|
||||
switch (m_AlignType)
|
||||
{
|
||||
case AlignType.Center:
|
||||
case AlignType.Left:
|
||||
case AlignType.Top:
|
||||
y = -m_VerticalStartSpace - index * (m_ChildHeight + m_VerticalSpace);
|
||||
break;
|
||||
case AlignType.Right:
|
||||
case AlignType.Bottom:
|
||||
y = m_VerticalStartSpace + index * (m_ChildHeight + m_VerticalSpace);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
return new Vector3(x, y, z);
|
||||
}
|
||||
|
||||
private void OnValueChanged(Vector2 vec)
|
||||
{
|
||||
int index = GetCurrentItemIndex();
|
||||
if (m_CurrentIndex != index)
|
||||
{
|
||||
m_CurrentIndex = index;
|
||||
UpdateContent(index);
|
||||
}
|
||||
}
|
||||
|
||||
private int GetCurrentItemIndex()
|
||||
{
|
||||
int index = 0;
|
||||
switch (m_AxisType)
|
||||
{
|
||||
case Axis.Horizontal:
|
||||
if (m_AlignType == AlignType.Left && m_Content.anchoredPosition.x >= 0) return 0;
|
||||
if (m_AlignType == AlignType.Right && m_Content.anchoredPosition.x <= 0) return 0;
|
||||
index = Mathf.FloorToInt((Mathf.Abs(m_Content.anchoredPosition.x) - m_HorizontalStartSpace) / (m_ChildWidth + m_HorizontalSpace)) * m_CountOfOtherAxis;
|
||||
break;
|
||||
case Axis.Vertical:
|
||||
if (m_AlignType == AlignType.Bottom && m_Content.anchoredPosition.y >= 0) return 0;
|
||||
if (m_AlignType == AlignType.Top && m_Content.anchoredPosition.y <= 0) return 0;
|
||||
index = Mathf.FloorToInt((Mathf.Abs(m_Content.anchoredPosition.y) - m_VerticalStartSpace) / (m_ChildHeight + m_VerticalSpace)) * m_CountOfOtherAxis;
|
||||
break;
|
||||
}
|
||||
return Mathf.Max(0, index);
|
||||
}
|
||||
|
||||
public void Select(int index)
|
||||
{
|
||||
if (m_Datas == null) return;
|
||||
|
||||
if (m_SelectIndex == index) return;
|
||||
|
||||
m_SelectIndex = index;
|
||||
|
||||
foreach (var item in m_LoopItems)
|
||||
{
|
||||
item.CheckSelect(index);
|
||||
}
|
||||
|
||||
if (index >= 0)
|
||||
{
|
||||
int maxCount = m_AxisType == Axis.Horizontal ? m_HorizontalCount : m_VerticalCount;
|
||||
int other = m_AxisType == Axis.Horizontal ? m_VerticalCount : m_HorizontalCount;
|
||||
MoveTo(index - (maxCount - 1) * other / 2);
|
||||
}
|
||||
|
||||
OnSelectChanged?.Invoke(index);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 移动
|
||||
/// </summary>
|
||||
public void MoveTo(int index, float duration = 0.3f)
|
||||
{
|
||||
index = Mathf.Clamp(index, 0, m_Datas.Count - 1);
|
||||
|
||||
int xIndex = 0, yIndex = 0;
|
||||
|
||||
if (m_AxisType == Axis.Horizontal)
|
||||
{
|
||||
yIndex = index % m_CountOfOtherAxis;
|
||||
xIndex = index / m_CountOfOtherAxis;
|
||||
}
|
||||
else
|
||||
{
|
||||
xIndex = index % m_CountOfOtherAxis;
|
||||
yIndex = index / m_CountOfOtherAxis;
|
||||
}
|
||||
|
||||
m_ScrollRect.StopMovement();
|
||||
|
||||
// x
|
||||
float pWidth = (m_Content.transform.parent as RectTransform).rect.width;
|
||||
float sWidth = m_Content.rect.width;
|
||||
float x = m_HorizontalStartSpace + (m_ChildWidth + m_HorizontalSpace) * xIndex;
|
||||
float limit = 0;
|
||||
if (sWidth > pWidth)
|
||||
{
|
||||
limit = sWidth - pWidth;
|
||||
}
|
||||
|
||||
if (m_AlignType == AlignType.Left)
|
||||
x = Mathf.Clamp(-x, -limit, limit);
|
||||
else
|
||||
x = Mathf.Clamp(x, -limit, limit);
|
||||
|
||||
// y
|
||||
float pHeight = (m_Content.transform.parent as RectTransform).rect.height;
|
||||
float sHeight = m_Content.rect.height;
|
||||
float y = m_VerticalStartSpace + (m_ChildHeight + m_VerticalSpace) * yIndex;
|
||||
limit = 0;
|
||||
if (sHeight > pHeight)
|
||||
{
|
||||
limit = sHeight - pHeight;
|
||||
}
|
||||
|
||||
if (m_AlignType == AlignType.Top)
|
||||
y = Mathf.Clamp(y, -limit, limit);
|
||||
else
|
||||
y = Mathf.Clamp(-y, -limit, limit);
|
||||
|
||||
if (m_Tweener != null)
|
||||
{
|
||||
UpdateContent(GetCurrentItemIndex());
|
||||
m_Tweener.Kill();
|
||||
m_Tweener = null;
|
||||
}
|
||||
|
||||
if (duration > 0 && Vector2.Distance(new Vector2(x, y), m_Content.anchoredPosition) > 1f)
|
||||
{
|
||||
m_Tweener = m_Content.DOAnchorPos(new Vector2(x, y), duration);
|
||||
}
|
||||
else
|
||||
{
|
||||
m_Content.anchoredPosition = new Vector2(x, y);
|
||||
}
|
||||
|
||||
if (m_Tweener != null)
|
||||
{
|
||||
m_Tweener.onComplete += () =>
|
||||
{
|
||||
UpdateContent(GetCurrentItemIndex());
|
||||
};
|
||||
}
|
||||
else
|
||||
{
|
||||
UpdateContent(GetCurrentItemIndex());
|
||||
}
|
||||
}
|
||||
|
||||
public void OnEndDrag(PointerEventData eventData)
|
||||
{
|
||||
if (!m_IsPaging) return;
|
||||
|
||||
// 计算最近的一页 并设置
|
||||
MoveTo(GetCurrentItemIndex());
|
||||
}
|
||||
|
||||
private void Update()
|
||||
{
|
||||
if (m_Datas == null || m_Datas.Count == 0 || m_PrefabPool == null || m_ItemType == null) return;
|
||||
|
||||
var parent = (m_ScrollRect.transform as RectTransform);
|
||||
if (parentRect != parent.rect)
|
||||
{
|
||||
UpdateList(m_Datas, m_PrefabPool.Prefab, m_ItemType, true, m_UserData);
|
||||
}
|
||||
}
|
||||
|
||||
public void Release()
|
||||
{
|
||||
m_LoopItems.Clear();
|
||||
if (m_PrefabPool != null)
|
||||
m_PrefabPool.RecycleUseList();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 8f9d6462b6841be41a1b950850260ffe
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: afb8f2807744de8459cd099b02d9e27c
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,64 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Cysharp.Threading.Tasks;
|
||||
using Unity.VisualScripting;
|
||||
using UnityEngine;
|
||||
using UnityEngine.Serialization;
|
||||
using YooAsset;
|
||||
|
||||
namespace Stary.Evo
|
||||
{
|
||||
[System.Serializable]
|
||||
public class UIConfigJson
|
||||
{
|
||||
public string uiType;
|
||||
public string pathId;
|
||||
public string path;
|
||||
public bool isWindow;
|
||||
public UILayer uiLayer;
|
||||
}
|
||||
[CreateAssetMenu(menuName = "Evo/UIConfig")]
|
||||
public class UIConfig : ScriptableObject
|
||||
{
|
||||
public string domain;
|
||||
public List<UIConfigJson> uiConfigJsons;
|
||||
|
||||
private const string UIConfigPath = "Assets/UI/UISystemPackage/UIConfig.json";
|
||||
public const string UIPackageName = "PanelPackage";
|
||||
|
||||
public List<UIConfigJson> GetAllConfigs()
|
||||
{
|
||||
if (uiConfigJsons.Count > 0)
|
||||
{
|
||||
return uiConfigJsons;
|
||||
}
|
||||
else
|
||||
{
|
||||
Debug.LogError("No UIConfigs found in domain: " + domain);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public static Type GetType(string typeName)
|
||||
{
|
||||
var type = Type.GetType(typeName);
|
||||
if (type != null)
|
||||
{
|
||||
return type;
|
||||
}
|
||||
|
||||
var assemblies = AppDomain.CurrentDomain.GetAssemblies();
|
||||
foreach (System.Reflection.Assembly assembly in assemblies)
|
||||
{
|
||||
type = Type.GetType(string.Format("{0}, {1}", typeName, assembly.FullName));
|
||||
if (type != null)
|
||||
{
|
||||
return type;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 16d24bc1f42c9344cbd4957ff9212b22
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,140 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Stary.Evo
|
||||
{
|
||||
public enum UILayer
|
||||
{
|
||||
SceneLayer = 1000,
|
||||
BackgroundLayer = 2000,
|
||||
NormalLayer = 3000,
|
||||
InfoLayer = 4000,
|
||||
TopLayer = 5000,
|
||||
TipLayer = 6000,
|
||||
BlackMaskLayer = 7000,
|
||||
}
|
||||
|
||||
public class UILayerLogic
|
||||
{
|
||||
public UILayer layer;
|
||||
public Canvas canvas;
|
||||
private int maxOrder;
|
||||
private HashSet<int> orders;
|
||||
public Stack<UIViewController> openedViews;
|
||||
|
||||
public UILayerLogic(UILayer layer, Canvas canvas)
|
||||
{
|
||||
this.layer = layer;
|
||||
this.canvas = canvas;
|
||||
maxOrder = (int)layer;
|
||||
orders = new HashSet<int>();
|
||||
openedViews = new Stack<UIViewController>();
|
||||
}
|
||||
|
||||
public void CloseUI(UIViewController closedUI)
|
||||
{
|
||||
int order = closedUI.order;
|
||||
PushOrder(closedUI);
|
||||
closedUI.order = 0;
|
||||
|
||||
if (openedViews.Count > 0)
|
||||
{
|
||||
var topViewController = openedViews.Peek();
|
||||
// 拿到最上层UI,如果被暂停的话,则恢复,
|
||||
// 暂停和恢复不影响其是否被覆盖隐藏,只要不是最上层UI都应该标记暂停状态
|
||||
if (topViewController != null && topViewController.isPause)
|
||||
{
|
||||
topViewController.isPause = false;
|
||||
if (topViewController.uiView != null)
|
||||
{
|
||||
topViewController.uiView.OnResume();
|
||||
}
|
||||
}
|
||||
|
||||
if (!closedUI.isWindow)
|
||||
{
|
||||
foreach (var viewController in openedViews)
|
||||
{
|
||||
if (viewController != closedUI
|
||||
&& viewController.isOpen
|
||||
&& viewController.order < order)
|
||||
{
|
||||
viewController.AddTopViewNum(-1);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void OpenUI(UIViewController openedUI)
|
||||
{
|
||||
if (openedUI.order == 0)
|
||||
{
|
||||
openedUI.order = PopOrder(openedUI);
|
||||
}
|
||||
|
||||
foreach (var viewController in openedViews)
|
||||
{
|
||||
if (viewController != openedUI
|
||||
&& viewController.isOpen
|
||||
&& viewController.order < openedUI.order
|
||||
&& viewController.uiView != null)
|
||||
{
|
||||
if (!viewController.isPause)
|
||||
{
|
||||
viewController.isPause = true;
|
||||
viewController.uiView.OnPause();
|
||||
}
|
||||
if (!openedUI.isWindow)
|
||||
{
|
||||
viewController.AddTopViewNum(1);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void PushOrder(UIViewController closedUI)
|
||||
{
|
||||
int order = closedUI.order;
|
||||
if (orders.Remove(order))
|
||||
{
|
||||
// 重新计算最大值
|
||||
maxOrder = (int)layer;
|
||||
foreach (var item in orders)
|
||||
{
|
||||
maxOrder = Mathf.Max(maxOrder, item);
|
||||
}
|
||||
|
||||
// 移除界面
|
||||
List<UIViewController> list = ListPool<UIViewController>.Get();
|
||||
while (openedViews.Count > 0)
|
||||
{
|
||||
var view = openedViews.Pop();
|
||||
if (view != closedUI)
|
||||
{
|
||||
list.Add(view);
|
||||
}
|
||||
else
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
for (int i = list.Count - 1; i >= 0; i--)
|
||||
{
|
||||
openedViews.Push(list[i]);
|
||||
}
|
||||
ListPool<UIViewController>.Release(list);
|
||||
}
|
||||
}
|
||||
|
||||
public int PopOrder(UIViewController uIViewController)
|
||||
{
|
||||
maxOrder += 10;
|
||||
orders.Add(maxOrder);
|
||||
openedViews.Push(uIViewController);
|
||||
return maxOrder;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 79754d061a9aabd43bed6e92b7a958f9
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,63 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Stary.Evo
|
||||
{
|
||||
public class UISubView : MonoBehaviour, IBindableUI
|
||||
{
|
||||
protected bool isInit = false;
|
||||
|
||||
private void Awake()
|
||||
{
|
||||
OnInit();
|
||||
OnAddListener();
|
||||
}
|
||||
|
||||
private void OnEnable()
|
||||
{
|
||||
OnOpen();
|
||||
}
|
||||
|
||||
private void OnDisable()
|
||||
{
|
||||
OnClose();
|
||||
}
|
||||
|
||||
private void OnDestroy()
|
||||
{
|
||||
OnRelease();
|
||||
OnRemoveListener();
|
||||
}
|
||||
|
||||
private void Bind()
|
||||
{
|
||||
if (isInit) return;
|
||||
var uIControlData = GetComponent<UIControlData>();
|
||||
if (uIControlData != null)
|
||||
uIControlData.BindDataTo(this);
|
||||
isInit = true;
|
||||
}
|
||||
|
||||
public virtual void OnInit() {
|
||||
if (isInit) return;
|
||||
Bind();
|
||||
}
|
||||
|
||||
public virtual void OnAddListener() { }
|
||||
|
||||
public virtual void OnRemoveListener() { }
|
||||
|
||||
public virtual void OnOpen()
|
||||
{
|
||||
if (!isInit)
|
||||
{
|
||||
OnInit();
|
||||
}
|
||||
}
|
||||
|
||||
public virtual void OnClose() { }
|
||||
|
||||
public virtual void OnRelease() { }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 5c72d350471207844abfed3c3f1f1f37
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,141 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
using UnityEngine.Rendering;
|
||||
using UnityEngine.UI;
|
||||
|
||||
namespace Stary.Evo
|
||||
{
|
||||
public class UIView : MonoBehaviour, IBindableUI
|
||||
{
|
||||
private UIViewController _controller;
|
||||
private GameObject _lastSelect;
|
||||
private Canvas _canvas;
|
||||
public GameObject DefaultSelect;
|
||||
|
||||
public UIViewController Controller => _controller;
|
||||
|
||||
public virtual void OnInit(UIControlData uIControlData, UIViewController controller)
|
||||
{
|
||||
if (uIControlData != null)
|
||||
{
|
||||
uIControlData.BindDataTo(this);
|
||||
}
|
||||
_controller = controller;
|
||||
_canvas = gameObject.GetOrAddComponent<Canvas>();
|
||||
gameObject.GetOrAddComponent<CanvasScaler>();
|
||||
gameObject.GetOrAddComponent<GraphicRaycaster>();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 事件监听
|
||||
/// </summary>
|
||||
public virtual void OnAddListener() { }
|
||||
|
||||
/// <summary>
|
||||
/// 事件移除
|
||||
/// </summary>
|
||||
public virtual void OnRemoveListener() { }
|
||||
|
||||
/// <summary>
|
||||
/// 打开
|
||||
/// </summary>
|
||||
public virtual void OnOpen(object userData)
|
||||
{
|
||||
SortOrder();
|
||||
|
||||
_canvas.overrideSorting = true;
|
||||
_canvas.sortingOrder = _controller.order;
|
||||
|
||||
OnAddListener();
|
||||
|
||||
_lastSelect = UnityEngine.EventSystems.EventSystem.current.currentSelectedGameObject;
|
||||
}
|
||||
|
||||
protected virtual void SortOrder()
|
||||
{
|
||||
SortOrder(transform, _controller.order + 1);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 递归的将所有孩子层级设置正确:一些默认摆在UI上的特效等正确分配层级
|
||||
/// </summary>
|
||||
protected int SortOrder(Transform target, int order)
|
||||
{
|
||||
var canvas = target.GetComponent<Canvas>();
|
||||
if (canvas != null && canvas != _canvas)
|
||||
{
|
||||
canvas.overrideSorting = true;
|
||||
canvas.sortingOrder = order++;
|
||||
canvas.gameObject.layer = Layer.UI;
|
||||
}
|
||||
var psr = target.GetComponent<ParticleSystemRenderer>();
|
||||
if (psr != null)
|
||||
{
|
||||
psr.sortingOrder = order++;
|
||||
psr.gameObject.layer = Layer.UI;
|
||||
}
|
||||
var sortGroup = target.GetComponent<SortingGroup>();
|
||||
if (sortGroup != null)
|
||||
{
|
||||
sortGroup.sortingOrder = order++;
|
||||
sortGroup.gameObject.SetLayerRecursively(Layer.UI);
|
||||
}
|
||||
var sr = target.GetComponent<SpriteRenderer>();
|
||||
if (sr != null)
|
||||
{
|
||||
sr.sortingOrder = order++;
|
||||
sr.gameObject.layer = Layer.UI;
|
||||
}
|
||||
for (int i = 0; i < target.childCount; i++)
|
||||
{
|
||||
order = SortOrder(target.GetChild(i), order);
|
||||
}
|
||||
return order;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 恢复
|
||||
/// </summary>
|
||||
public virtual void OnResume()
|
||||
{
|
||||
if (DefaultSelect != null)
|
||||
{
|
||||
UnityEngine.EventSystems.EventSystem.current.SetSelectedGameObject(DefaultSelect);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 被覆盖
|
||||
/// </summary>
|
||||
public virtual void OnPause()
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 被关闭
|
||||
/// </summary>
|
||||
public virtual void OnClose()
|
||||
{
|
||||
OnRemoveListener();
|
||||
|
||||
if (_lastSelect != null && _lastSelect.activeInHierarchy)
|
||||
{
|
||||
UnityEngine.EventSystems.EventSystem.current.SetSelectedGameObject(_lastSelect);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 取消按钮响应
|
||||
/// </summary>
|
||||
public virtual void OnCancel()
|
||||
{
|
||||
UIManager.Instance.Close(this);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 被卸载释放
|
||||
/// </summary>
|
||||
public virtual void OnRelease() { }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: f5c123e21fb60cb40bafea6c26519605
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,167 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Stary.Evo
|
||||
{
|
||||
public enum UIAppearType
|
||||
{
|
||||
None,
|
||||
Animation,
|
||||
Alpha,
|
||||
AlphaAndAnimation,
|
||||
Scale,
|
||||
ScaleAndAlpha,
|
||||
}
|
||||
|
||||
public class UIViewAnim : MonoBehaviour
|
||||
{
|
||||
public UIAppearType openType = UIAppearType.None;
|
||||
public UIAppearType closeType = UIAppearType.None;
|
||||
|
||||
public Animation animtion;
|
||||
public Transform target;
|
||||
public float animTime = 0.2f;
|
||||
|
||||
public float playRate;
|
||||
private float duration;
|
||||
private Action callback;
|
||||
private CanvasGroup canvasGroup;
|
||||
private Transform Target => target != null ? target : transform;
|
||||
private enum ViewType
|
||||
{
|
||||
None,
|
||||
Open,
|
||||
Close,
|
||||
}
|
||||
private ViewType viewType;
|
||||
|
||||
private void Start()
|
||||
{
|
||||
canvasGroup = gameObject.GetOrAddComponent<CanvasGroup>();
|
||||
playRate = 0;
|
||||
}
|
||||
|
||||
public void Open(Action callback = null)
|
||||
{
|
||||
playRate = 0;
|
||||
if (viewType == ViewType.Close)
|
||||
{
|
||||
this.callback?.Invoke();
|
||||
}
|
||||
if (!gameObject.activeSelf)
|
||||
{
|
||||
callback?.Invoke();
|
||||
return;
|
||||
}
|
||||
viewType = ViewType.Open;
|
||||
this.callback = callback;
|
||||
duration = (1 - playRate) * animTime;
|
||||
|
||||
if (openType == UIAppearType.Animation || openType == UIAppearType.AlphaAndAnimation)
|
||||
{
|
||||
if (animtion != null && animtion.clip != null)
|
||||
{
|
||||
var state = animtion[animtion.clip.name];
|
||||
|
||||
if (state != null)
|
||||
{
|
||||
state.normalizedTime = playRate;
|
||||
state.speed = state.length / animTime;
|
||||
}
|
||||
animtion.Play();
|
||||
}
|
||||
else if(openType == UIAppearType.Animation)
|
||||
{
|
||||
playRate = 1;
|
||||
Finish();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void Close(Action callback = null)
|
||||
{
|
||||
if (viewType == ViewType.Open)
|
||||
{
|
||||
this.callback?.Invoke();
|
||||
}
|
||||
if (!gameObject.activeSelf)
|
||||
{
|
||||
callback?.Invoke();
|
||||
return;
|
||||
}
|
||||
|
||||
viewType = ViewType.Close;
|
||||
this.callback = callback;
|
||||
duration = playRate * animTime;
|
||||
|
||||
if (closeType == UIAppearType.Animation || closeType == UIAppearType.AlphaAndAnimation)
|
||||
{
|
||||
if (animtion != null && animtion.clip != null)
|
||||
{
|
||||
var state = animtion[animtion.clip.name];
|
||||
|
||||
if (state != null)
|
||||
{
|
||||
state.normalizedTime = 1 - playRate;
|
||||
state.speed = -1 * state.length / animTime;
|
||||
}
|
||||
animtion.Play();
|
||||
}
|
||||
else if (openType == UIAppearType.Animation)
|
||||
{
|
||||
playRate = 0;
|
||||
Finish();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void LateUpdate()
|
||||
{
|
||||
switch (viewType)
|
||||
{
|
||||
case ViewType.Open:
|
||||
PlayAlphaAndScale(openType, false);
|
||||
break;
|
||||
case ViewType.Close:
|
||||
PlayAlphaAndScale(closeType, true);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 播放动画
|
||||
/// </summary>
|
||||
/// <param name="back">是否倒放</param>
|
||||
private void PlayAlphaAndScale(UIAppearType type,bool back)
|
||||
{
|
||||
duration -= Time.deltaTime;
|
||||
if (duration <= 0)
|
||||
{
|
||||
playRate = back ? 0 : 1;
|
||||
Finish();
|
||||
}
|
||||
else
|
||||
{
|
||||
playRate += Time.deltaTime / animTime * (back ? -1 : 1);
|
||||
}
|
||||
|
||||
if (type == UIAppearType.Alpha || type == UIAppearType.AlphaAndAnimation || type == UIAppearType.ScaleAndAlpha)
|
||||
{
|
||||
canvasGroup.alpha = Mathf.Lerp(0, 1, playRate);
|
||||
}
|
||||
if (type == UIAppearType.Scale || type == UIAppearType.ScaleAndAlpha)
|
||||
{
|
||||
Target.localScale = Vector3.Lerp(Vector3.zero, Vector3.one, playRate);
|
||||
}
|
||||
}
|
||||
private void Finish()
|
||||
{
|
||||
callback?.Invoke();
|
||||
callback = null;
|
||||
viewType = ViewType.None;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 5535a9c33d7602647adf310b63649cb5
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,201 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Cysharp.Threading.Tasks;
|
||||
using Unity.VisualScripting;
|
||||
using UnityEngine;
|
||||
using YooAsset;
|
||||
|
||||
namespace Stary.Evo
|
||||
{
|
||||
public class UIViewController
|
||||
{
|
||||
// 配置
|
||||
public string uiType;
|
||||
public string uiPath;
|
||||
public Type uiViewType;
|
||||
public UILayerLogic uiLayer;
|
||||
public bool isWindow;
|
||||
|
||||
public UIView uiView;
|
||||
public UIViewAnim uiViewAnim;
|
||||
public bool isLoading = false;
|
||||
public bool isOpen = false;
|
||||
public bool isPause = false;
|
||||
public int order;
|
||||
|
||||
/// <summary>
|
||||
/// 在我上面的界面(非窗口界面)的数量
|
||||
/// </summary>
|
||||
public int topViewNum;
|
||||
|
||||
public async UniTask Load(object userData = null, Action callback = null)
|
||||
{
|
||||
isLoading = true;
|
||||
|
||||
if (isOpen)
|
||||
{
|
||||
order = uiLayer.PopOrder(this);
|
||||
}
|
||||
|
||||
var handle = YooAssets.LoadAssetSync<GameObject>(uiPath);
|
||||
await handle.Task;
|
||||
GameObject go = handle.InstantiateSync();
|
||||
|
||||
if (!isLoading)
|
||||
{
|
||||
//ResourceManager.Instance.GetResourceCore(UIConfig.UIPackageName).Recycle(go);
|
||||
callback?.Invoke();
|
||||
Release();
|
||||
return;
|
||||
}
|
||||
|
||||
isLoading = false;
|
||||
uiView = (UIView)go.GetOrAddComponent(uiViewType);
|
||||
uiViewAnim = go.GetComponent<UIViewAnim>();
|
||||
uiView.transform.SetParentEx(uiLayer.canvas.transform);
|
||||
RectTransform rectTransform = uiView.transform as RectTransform;
|
||||
|
||||
switch (UIManager.Instance.GetUIBlackType())
|
||||
{
|
||||
case UIBlackType.None:
|
||||
// 全适配
|
||||
rectTransform.SetAnchor(AnchorPresets.StretchAll);
|
||||
rectTransform.anchoredPosition = Vector2.zero;
|
||||
rectTransform.sizeDelta = Vector2.zero;
|
||||
break;
|
||||
case UIBlackType.Height:
|
||||
// 保持高度填满,两边留黑边
|
||||
rectTransform.SetAnchor(AnchorPresets.VertStretchCenter);
|
||||
rectTransform.anchoredPosition = Vector2.zero;
|
||||
rectTransform.sizeDelta = new Vector2(UIManager.Instance.width, 0);
|
||||
rectTransform.SetSizeWithCurrentAnchors(RectTransform.Axis.Horizontal,
|
||||
UIManager.Instance.width);
|
||||
break;
|
||||
case UIBlackType.Width:
|
||||
// 保持宽度填满,上下留黑边
|
||||
rectTransform.SetAnchor(AnchorPresets.HorStretchMiddle);
|
||||
rectTransform.anchoredPosition = Vector2.zero;
|
||||
rectTransform.SetSizeWithCurrentAnchors(RectTransform.Axis.Vertical,
|
||||
UIManager.Instance.height);
|
||||
rectTransform.sizeDelta = new Vector2(0, UIManager.Instance.height);
|
||||
break;
|
||||
}
|
||||
|
||||
uiView.OnInit(go.GetComponent<UIControlData>(), this);
|
||||
uiView.transform.SetAsLastSibling();
|
||||
await UniTask.CompletedTask;
|
||||
|
||||
}
|
||||
|
||||
public async UniTask Load<T>(object userData = null, Action callback = null)
|
||||
{
|
||||
uiViewType = typeof(T);
|
||||
await Load(userData, callback);
|
||||
|
||||
if (isOpen)
|
||||
{
|
||||
Open<T>(userData, callback, true);
|
||||
}
|
||||
else
|
||||
{
|
||||
Close(callback);
|
||||
}
|
||||
}
|
||||
|
||||
public async void Open<T>(object userData = null, Action callback = null, bool isFirstOpen = false)
|
||||
{
|
||||
isOpen = true;
|
||||
if (isLoading) return;
|
||||
|
||||
if (uiView == null)
|
||||
{
|
||||
await Load<T>(userData, callback);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!isFirstOpen && isOpen && order > 0)
|
||||
{
|
||||
TrueClose();
|
||||
}
|
||||
|
||||
TrueOpen(userData, callback);
|
||||
if (uiViewAnim != null)
|
||||
{
|
||||
uiViewAnim.Open();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void Close(Action callback = null)
|
||||
{
|
||||
isOpen = false;
|
||||
if (isLoading) return;
|
||||
|
||||
if (uiView != null)
|
||||
{
|
||||
if (uiViewAnim != null)
|
||||
{
|
||||
uiViewAnim.Close(() => { TrueClose(callback); });
|
||||
}
|
||||
else
|
||||
{
|
||||
TrueClose(callback);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void Release()
|
||||
{
|
||||
if (uiView != null)
|
||||
{
|
||||
if (isOpen)
|
||||
TrueClose();
|
||||
uiView.OnRelease();
|
||||
GameObject.Destroy(uiView.gameObject);
|
||||
}
|
||||
|
||||
uiView = null;
|
||||
uiViewAnim = null;
|
||||
isLoading = false;
|
||||
isOpen = false;
|
||||
order = 0;
|
||||
}
|
||||
|
||||
private void TrueOpen(object userData = null, Action callback = null)
|
||||
{
|
||||
uiLayer.OpenUI(this);
|
||||
SetVisible(true);
|
||||
// 刷新一下显示
|
||||
AddTopViewNum(0);
|
||||
uiView.OnOpen(userData);
|
||||
uiView.OnResume();
|
||||
callback?.Invoke();
|
||||
}
|
||||
|
||||
private void TrueClose(Action callback = null)
|
||||
{
|
||||
uiLayer.CloseUI(this);
|
||||
// 刷新一下显示
|
||||
AddTopViewNum(-100000);
|
||||
SetVisible(false);
|
||||
uiView.OnPause();
|
||||
uiView.OnClose();
|
||||
callback?.Invoke();
|
||||
}
|
||||
|
||||
public void SetVisible(bool visible)
|
||||
{
|
||||
if (uiView != null)
|
||||
{
|
||||
uiView.gameObject.SetActive(visible);
|
||||
}
|
||||
}
|
||||
|
||||
public void AddTopViewNum(int num)
|
||||
{
|
||||
topViewNum += num;
|
||||
topViewNum = Mathf.Max(0, topViewNum);
|
||||
SetVisible(topViewNum <= 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: b3d89571e6c129d40ab1abae7299540b
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
Reference in New Issue
Block a user