超大量的更新 修复很多问题,gameplay特效初步

This commit is contained in:
2026-02-14 23:46:20 +08:00
parent ef8eb67259
commit 3a7a0b4669
360 changed files with 85670 additions and 4144 deletions
@@ -7,58 +7,51 @@ using UnityEngine.UI;
public class UI_SongsSelect_EnterAnim : MonoBehaviour
{
[Header("Scene")]
[SerializeField] private string requiredSceneName = "Songs_Select";
[SerializeField] private bool playOnEnable = true;
[SerializeField] private bool useUnscaledTime = true;
[Header("Roots")]
[SerializeField] string[] rootNames = { "artworks", "teamSelector", "Songs_Select" };
[SerializeField] bool play_OnEnable = true;
[SerializeField] string requiredSceneName = "Songs_Select";
[SerializeField] bool use_Unscaled = true;
[SerializeField] float start_Delay = 0.02f;
[Header("Excludes")]
[SerializeField] string[] exclude_Names = { "bg" };
[SerializeField] private string[] rootNames = { "artworks", "teamSelector", "Songs_Select" };
[SerializeField] private string[] excludeNames = { "bg" };
[Header("Timing")]
[SerializeField] float move_Time = 0.45f;
[SerializeField] float scale_Time = 0.45f;
[SerializeField] float scale_From = 0.92f;
[SerializeField] float move_Offset = 120f;
[SerializeField] Ease move_Ease = Ease.OutCubic;
[SerializeField] Ease scale_Ease = Ease.OutBack;
[Header("Safety")]
[SerializeField] bool reset_Hidden_CanvasGroups = true;
[SerializeField] float hidden_Alpha_Threshold = 0.01f;
[SerializeField] float force_Visible_Alpha = 1f;
[Header("Animation")]
[SerializeField] private float startDelay = 0.02f;
[SerializeField] private float itemDuration = 0.26f;
[SerializeField] private float itemStagger = 0.03f;
[SerializeField] private float fromOffsetY = 42f;
[SerializeField] private Ease moveEase = Ease.OutCubic;
[SerializeField] private Ease fadeEase = Ease.OutCubic;
Sequence enter_Sequence;
readonly List<NodeState> cached_Nodes = new List<NodeState>();
readonly List<SelectableState> cached_Selectables = new List<SelectableState>();
bool restorePending;
bool playRequested;
private Sequence enterSequence;
private readonly List<NodeState> nodeStates = new List<NodeState>();
private readonly List<SelectableState> selectables = new List<SelectableState>();
private bool restorePending;
private bool playRequested;
class NodeState
private class NodeState
{
public Transform tr;
public bool isRect;
public Vector2 anchoredPos;
public Vector3 localPos;
public Vector3 localScale;
public Quaternion localRot;
public RectTransform rect;
public Vector2 basePos;
public CanvasGroup canvasGroup;
public float baseAlpha;
public bool createdCanvasGroup;
}
class SelectableState
private class SelectableState
{
public Selectable s;
public Selectable selectable;
public bool interactable;
}
void OnEnable()
private void OnEnable()
{
if (play_OnEnable && IsAllowedScene())
{
if (playOnEnable && IsAllowedScene())
Play();
}
}
void OnDisable()
private void OnDisable()
{
KillTweens();
RestoreAll();
@@ -72,17 +65,16 @@ public class UI_SongsSelect_EnterAnim : MonoBehaviour
return;
}
if (playRequested)
{
return;
}
playRequested = true;
KillTweens();
StartCoroutine(PlayRoutine());
}
IEnumerator PlayRoutine()
private IEnumerator PlayRoutine()
{
yield return null; // allow layout settle
yield return null;
List<Transform> roots = FindRoots();
if (roots.Count == 0)
@@ -90,28 +82,73 @@ public class UI_SongsSelect_EnterAnim : MonoBehaviour
playRequested = false;
yield break;
}
if (reset_Hidden_CanvasGroups)
List<RectTransform> targets = CollectTargets(roots);
if (targets.Count == 0)
{
ResetHiddenCanvasGroups(roots);
playRequested = false;
yield break;
}
cached_Nodes.Clear();
cached_Selectables.Clear();
nodeStates.Clear();
selectables.Clear();
restorePending = true;
enter_Sequence = DOTween.Sequence().SetUpdate(use_Unscaled).SetDelay(start_Delay);
LockSelectables(roots);
CollectSelectables(roots);
AnimateTransforms(roots);
enterSequence = DOTween.Sequence().SetUpdate(useUnscaledTime).SetDelay(startDelay);
float duration = Mathf.Max(move_Time, scale_Time);
StartCoroutine(FailSafeRestore(duration + 0.1f));
if (enter_Sequence.Duration(false) > 0.001f)
for (int i = 0; i < targets.Count; i++)
{
enter_Sequence.OnComplete(RestoreAll);
enter_Sequence.OnKill(RestoreAll);
enter_Sequence.Play();
RectTransform rt = targets[i];
if (rt == null)
continue;
CanvasGroup group = rt.GetComponent<CanvasGroup>();
bool created = false;
if (group == null)
{
group = rt.gameObject.AddComponent<CanvasGroup>();
created = true;
}
Vector2 basePos = rt.anchoredPosition;
float baseAlpha = group.alpha <= 0f ? 1f : group.alpha;
nodeStates.Add(new NodeState
{
rect = rt,
basePos = basePos,
canvasGroup = group,
baseAlpha = baseAlpha,
createdCanvasGroup = created
});
rt.DOKill();
group.DOKill();
rt.anchoredPosition = basePos - new Vector2(0f, Mathf.Abs(fromOffsetY));
group.alpha = 0f;
float start = i * Mathf.Max(0f, itemStagger);
enterSequence.Insert(start,
rt.DOAnchorPos(basePos, Mathf.Max(0.01f, itemDuration))
.SetEase(moveEase)
.SetUpdate(useUnscaledTime));
enterSequence.Insert(start,
group.DOFade(baseAlpha, Mathf.Max(0.01f, itemDuration))
.SetEase(fadeEase)
.SetUpdate(useUnscaledTime));
}
float total = enterSequence.Duration(false);
StartCoroutine(FailSafeRestore(total + 0.1f));
if (enterSequence.Duration(false) > 0.001f)
{
enterSequence.OnComplete(RestoreAll);
enterSequence.OnKill(RestoreAll);
enterSequence.Play();
}
else
{
@@ -119,311 +156,244 @@ public class UI_SongsSelect_EnterAnim : MonoBehaviour
}
}
IEnumerator FailSafeRestore(float delay)
private IEnumerator FailSafeRestore(float delay)
{
float t = 0f;
while (t < delay)
float elapsed = 0f;
while (elapsed < delay)
{
t += use_Unscaled ? Time.unscaledDeltaTime : Time.deltaTime;
elapsed += useUnscaledTime ? Time.unscaledDeltaTime : Time.deltaTime;
yield return null;
}
if (restorePending)
{
RestoreAll();
}
}
void AnimateTransforms(List<Transform> roots)
{
HashSet<Transform> animated = new HashSet<Transform>();
for (int r = 0; r < roots.Count; r++)
{
Transform root = roots[r];
if (root == null) continue;
AnimateChildrenRespectingExcludes(root, animated);
}
}
void AnimateChildrenRespectingExcludes(Transform parent, HashSet<Transform> animated)
{
if (parent == null) return;
for (int i = 0; i < parent.childCount; i++)
{
Transform child = parent.GetChild(i);
if (child == null) continue;
if (!child.gameObject.activeInHierarchy) continue;
if (ShouldSkip(child)) continue;
if (child.GetComponent<Canvas>() != null)
{
AnimateChildrenRespectingExcludes(child, animated);
continue;
}
if (ContainsExcludedDescendant(child))
{
AnimateChildrenRespectingExcludes(child, animated);
continue;
}
RectTransform rect = child as RectTransform;
if (rect == null) continue;
if (animated.Contains(child)) continue;
animated.Add(child);
AnimateNode(rect);
}
}
bool ShouldSkip(Transform tr)
{
if (tr == null) return false;
for (int i = 0; i < exclude_Names.Length; i++)
{
if (string.IsNullOrEmpty(exclude_Names[i])) continue;
if (tr.name == exclude_Names[i]) return true;
}
return false;
}
bool ContainsExcludedDescendant(Transform tr)
{
if (tr == null || exclude_Names == null || exclude_Names.Length == 0) return false;
for (int i = 0; i < exclude_Names.Length; i++)
{
string name = exclude_Names[i];
if (string.IsNullOrEmpty(name)) continue;
Transform found = tr.Find(name);
if (found != null) return true;
}
return false;
}
void AnimateNode(Transform node)
{
bool isRect = node is RectTransform;
Vector2 basePos = isRect ? ((RectTransform)node).anchoredPosition : (Vector2)node.localPosition;
Vector3 baseScale = node.localScale;
Quaternion baseRot = node.localRotation;
node.DOKill();
Vector2 offset = ComputeOffset(basePos, move_Offset);
if (HasLayoutInParents(node))
{
offset = Vector2.zero;
}
CacheBase(node, isRect, basePos, baseScale, baseRot);
if (isRect)
{
((RectTransform)node).anchoredPosition = basePos + offset;
}
else
{
node.localPosition = (Vector3)(basePos + offset);
}
node.localScale = baseScale * scale_From;
node.localRotation = baseRot;
if (offset.sqrMagnitude > 0.01f)
{
if (isRect)
{
enter_Sequence.Join(((RectTransform)node).DOAnchorPos(basePos, move_Time).SetEase(move_Ease));
}
else
{
enter_Sequence.Join(node.DOLocalMove(basePos, move_Time).SetEase(move_Ease));
}
}
enter_Sequence.Join(node.DOScale(baseScale, scale_Time).SetEase(scale_Ease));
}
Vector2 ComputeOffset(Vector2 basePos, float amount)
{
float xDir = basePos.x >= 0f ? 1f : -1f;
float yDir = basePos.y >= 0f ? 1f : -1f;
float yAmount = amount * 0.65f;
return new Vector2(xDir * amount, yDir * yAmount);
}
bool HasLayoutInParents(Transform tr)
{
if (tr == null) return false;
Transform current = tr;
while (current != null)
{
if (current.GetComponent<LayoutGroup>() != null || current.GetComponent<ContentSizeFitter>() != null)
{
return true;
}
current = current.parent;
}
return false;
}
void CollectSelectables(List<Transform> roots)
private void LockSelectables(List<Transform> roots)
{
HashSet<Selectable> seen = new HashSet<Selectable>();
for (int r = 0; r < roots.Count; r++)
{
Transform root = roots[r];
if (root == null) continue;
Selectable[] selects = root.GetComponentsInChildren<Selectable>(true);
for (int i = 0; i < selects.Length; i++)
if (root == null)
continue;
Selectable[] all = root.GetComponentsInChildren<Selectable>(true);
for (int i = 0; i < all.Length; i++)
{
Selectable s = selects[i];
if (s == null || seen.Contains(s)) continue;
Selectable s = all[i];
if (s == null || seen.Contains(s))
continue;
seen.Add(s);
cached_Selectables.Add(new SelectableState { s = s, interactable = s.interactable });
selectables.Add(new SelectableState { selectable = s, interactable = s.interactable });
s.interactable = false;
}
}
}
void ResetHiddenCanvasGroups(List<Transform> roots)
private List<RectTransform> CollectTargets(List<Transform> roots)
{
HashSet<CanvasGroup> seen = new HashSet<CanvasGroup>();
List<RectTransform> list = new List<RectTransform>();
HashSet<RectTransform> seen = new HashSet<RectTransform>();
for (int r = 0; r < roots.Count; r++)
{
Transform root = roots[r];
if (root == null) continue;
CanvasGroup[] groups = root.GetComponentsInChildren<CanvasGroup>(true);
for (int i = 0; i < groups.Length; i++)
if (root == null)
continue;
CollectUnder(root, list, seen);
}
list.Sort((a, b) =>
{
if (a == null && b == null) return 0;
if (a == null) return 1;
if (b == null) return -1;
Vector3 pa = a.position;
Vector3 pb = b.position;
int yOrder = -pa.y.CompareTo(pb.y); // top -> bottom
if (yOrder != 0) return yOrder;
return pa.x.CompareTo(pb.x); // left -> right
});
return list;
}
private void CollectUnder(Transform parent, List<RectTransform> list, HashSet<RectTransform> seen)
{
if (parent == null)
return;
for (int i = 0; i < parent.childCount; i++)
{
Transform child = parent.GetChild(i);
if (child == null || !child.gameObject.activeInHierarchy)
continue;
if (ShouldSkip(child))
continue;
RectTransform rt = child as RectTransform;
if (rt != null && IsPanelLike(child) && !seen.Contains(rt))
{
CanvasGroup cg = groups[i];
if (cg == null || seen.Contains(cg)) continue;
seen.Add(cg);
if (cg.alpha <= hidden_Alpha_Threshold)
{
cg.alpha = force_Visible_Alpha;
}
seen.Add(rt);
list.Add(rt);
}
CollectUnder(child, list, seen);
}
}
void CacheBase(Transform tr, bool isRect, Vector2 basePos, Vector3 baseScale, Quaternion baseRot)
private bool IsPanelLike(Transform tr)
{
if (tr == null) return;
cached_Nodes.Add(new NodeState
{
tr = tr,
isRect = isRect,
anchoredPos = basePos,
localPos = tr.localPosition,
localScale = baseScale,
localRot = baseRot
});
if (tr == null)
return false;
if (tr.GetComponent<LayoutGroup>() != null)
return true;
if (tr.GetComponent<Button>() != null || tr.GetComponent<Toggle>() != null || tr.GetComponent<ScrollRect>() != null)
return true;
if (tr.GetComponent<CanvasGroup>() != null)
return true;
if (tr.childCount >= 2)
return true;
return false;
}
void RestoreAll()
private bool ShouldSkip(Transform tr)
{
if (tr == null || excludeNames == null)
return false;
for (int i = 0; i < excludeNames.Length; i++)
{
string name = excludeNames[i];
if (string.IsNullOrEmpty(name))
continue;
if (string.Equals(tr.name, name, System.StringComparison.OrdinalIgnoreCase))
return true;
}
return false;
}
private void RestoreAll()
{
restorePending = false;
playRequested = false;
for (int i = 0; i < cached_Nodes.Count; i++)
for (int i = 0; i < nodeStates.Count; i++)
{
NodeState state = cached_Nodes[i];
if (state == null || state.tr == null) continue;
state.tr.DOKill();
if (state.isRect)
{
RectTransform rt = state.tr as RectTransform;
if (rt != null) rt.anchoredPosition = state.anchoredPos;
}
state.tr.localPosition = state.localPos;
state.tr.localScale = state.localScale;
state.tr.localRotation = state.localRot;
NodeState st = nodeStates[i];
if (st == null || st.rect == null)
continue;
st.rect.DOKill();
if (st.canvasGroup != null)
st.canvasGroup.DOKill();
st.rect.anchoredPosition = st.basePos;
if (st.canvasGroup != null)
st.canvasGroup.alpha = st.baseAlpha;
}
for (int i = 0; i < cached_Selectables.Count; i++)
for (int i = 0; i < selectables.Count; i++)
{
SelectableState ss = cached_Selectables[i];
if (ss == null || ss.s == null) continue;
ss.s.interactable = ss.interactable;
SelectableState ss = selectables[i];
if (ss == null || ss.selectable == null)
continue;
ss.selectable.interactable = ss.interactable;
}
cached_Nodes.Clear();
cached_Selectables.Clear();
nodeStates.Clear();
selectables.Clear();
}
void KillTweens()
private void KillTweens()
{
if (enter_Sequence != null)
if (enterSequence != null)
{
enter_Sequence.Kill();
enter_Sequence = null;
enterSequence.Kill();
enterSequence = null;
}
}
bool IsAllowedScene()
private bool IsAllowedScene()
{
if (string.IsNullOrEmpty(requiredSceneName))
return true;
Scene active = SceneManager.GetActiveScene();
if (active.IsValid() && active.name == requiredSceneName)
return true;
Scene own = gameObject.scene;
return own.IsValid() && own.name == requiredSceneName;
if (own.IsValid() && own.name == requiredSceneName)
return true;
Scene active = SceneManager.GetActiveScene();
return active.IsValid() && active.name == requiredSceneName;
}
List<Transform> FindRoots()
private List<Transform> FindRoots()
{
List<Transform> roots = new List<Transform>();
Scene activeScene = SceneManager.GetActiveScene();
Scene scene = gameObject.scene.IsValid() && gameObject.scene.isLoaded
? gameObject.scene
: SceneManager.GetActiveScene();
for (int i = 0; i < rootNames.Length; i++)
{
string name = rootNames[i];
if (string.IsNullOrEmpty(name)) continue;
GameObject go = FindInScene(activeScene, name);
if (go == null) continue;
roots.Add(go.transform);
}
if (roots.Count > 1)
{
roots = FilterNestedRoots(roots);
if (string.IsNullOrEmpty(name))
continue;
Transform found = FindInSceneByName(scene, name);
if (found != null)
roots.Add(found);
}
if (roots.Count == 0)
{
var canvases = Object.FindObjectsByType<Canvas>(FindObjectsInactive.Include, FindObjectsSortMode.None);
Canvas[] canvases = UnityEngine.Object.FindObjectsByType<Canvas>(FindObjectsInactive.Include, FindObjectsSortMode.None);
for (int i = 0; i < canvases.Length; i++)
{
if (canvases[i] == null) continue;
if (canvases[i].gameObject.scene != activeScene) continue;
roots.Add(canvases[i].transform);
}
if (roots.Count > 1)
{
roots = FilterNestedRoots(roots);
Canvas c = canvases[i];
if (c == null || c.gameObject.scene != scene)
continue;
roots.Add(c.transform);
}
}
if (roots.Count == 0)
{
roots.Add(transform);
}
return roots;
return FilterNestedRoots(roots);
}
GameObject FindInScene(Scene scene, string name)
private Transform FindInSceneByName(Scene scene, string objectName)
{
if (!scene.IsValid() || !scene.isLoaded) return null;
var all = Resources.FindObjectsOfTypeAll<Transform>();
if (!scene.IsValid() || !scene.isLoaded || string.IsNullOrEmpty(objectName))
return null;
Transform[] all = UnityEngine.Object.FindObjectsByType<Transform>(FindObjectsInactive.Include, FindObjectsSortMode.None);
for (int i = 0; i < all.Length; i++)
{
var t = all[i];
if (t == null) continue;
if (t.gameObject.scene != scene) continue;
if (t.name == name) return t.gameObject;
Transform t = all[i];
if (t == null || t.gameObject.scene != scene)
continue;
if (string.Equals(t.name, objectName, System.StringComparison.OrdinalIgnoreCase))
return t;
}
return null;
}
List<Transform> FilterNestedRoots(List<Transform> roots)
private List<Transform> FilterNestedRoots(List<Transform> roots)
{
List<Transform> filtered = new List<Transform>();
for (int i = 0; i < roots.Count; i++)
{
Transform candidate = roots[i];
if (candidate == null) continue;
bool isChild = false;
if (candidate == null)
continue;
bool childOfOther = false;
for (int j = 0; j < roots.Count; j++)
{
if (i == j) continue;
@@ -431,14 +401,12 @@ public class UI_SongsSelect_EnterAnim : MonoBehaviour
if (other == null) continue;
if (candidate.IsChildOf(other))
{
isChild = true;
childOfOther = true;
break;
}
}
if (!isChild)
{
if (!childOfOther)
filtered.Add(candidate);
}
}
return filtered;
}
@@ -446,71 +414,69 @@ public class UI_SongsSelect_EnterAnim : MonoBehaviour
static class UI_SongsSelect_EnterAnimBootstrap
{
static bool installed;
private static bool installed;
[RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.SubsystemRegistration)]
static void Reset()
private static void Reset()
{
installed = false;
}
[RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.BeforeSceneLoad)]
static void Install()
private static void Install()
{
if (installed) return;
installed = true;
GameObject runner = GameObject.Find("__SongsSelectEnterAnimRunner");
if (runner == null)
{
runner = new GameObject("__SongsSelectEnterAnimRunner");
Object.DontDestroyOnLoad(runner);
UnityEngine.Object.DontDestroyOnLoad(runner);
}
if (runner.GetComponent<SongsSelectEnterAnimRunner>() == null)
{
runner.AddComponent<SongsSelectEnterAnimRunner>();
}
}
}
class SongsSelectEnterAnimRunner : MonoBehaviour
{
Coroutine playRoutine;
private Coroutine playRoutine;
void OnEnable()
private void OnEnable()
{
SceneManager.sceneLoaded += OnSceneLoaded;
SceneManager.activeSceneChanged += OnActiveSceneChanged;
TryPlay(SceneManager.GetActiveScene());
}
void OnDisable()
private void OnDisable()
{
SceneManager.sceneLoaded -= OnSceneLoaded;
SceneManager.activeSceneChanged -= OnActiveSceneChanged;
}
void OnSceneLoaded(Scene scene, LoadSceneMode mode)
private void OnSceneLoaded(Scene scene, LoadSceneMode mode)
{
TryPlay(scene);
}
void OnActiveSceneChanged(Scene from, Scene to)
private void OnActiveSceneChanged(Scene from, Scene to)
{
TryPlay(to);
}
void TryPlay(Scene scene)
private void TryPlay(Scene scene)
{
if (scene.name != "Songs_Select") return;
if (scene.name != "Songs_Select")
return;
if (playRoutine != null)
{
StopCoroutine(playRoutine);
playRoutine = null;
}
playRoutine = StartCoroutine(PlayWhenReady(scene));
}
IEnumerator PlayWhenReady(Scene scene)
private IEnumerator PlayWhenReady(Scene scene)
{
for (int i = 0; i < 6; i++)
{
@@ -521,79 +487,61 @@ class SongsSelectEnterAnimRunner : MonoBehaviour
}
yield return null;
}
yield return new WaitForSeconds(0.1f);
yield return new WaitForSecondsRealtime(0.08f);
TryAttachAndPlay(scene);
playRoutine = null;
}
bool TryAttachAndPlay(Scene scene)
private bool TryAttachAndPlay(Scene scene)
{
UI_SongsSelect_EnterAnim anim = FindAnimInScene(scene);
if (anim == null)
{
GameObject host = FindInScene(scene, "Songs_Select");
GameObject host = FindInScene(scene, "__SongsSelectEnterAnimHost");
if (host == null)
{
host = FindInScene(scene, "teamSelector");
}
if (host == null)
{
Canvas anyCanvas = FindCanvasInScene(scene);
host = anyCanvas != null ? anyCanvas.gameObject : null;
}
if (host == null)
{
return false;
host = new GameObject("__SongsSelectEnterAnimHost");
try { SceneManager.MoveGameObjectToScene(host, scene); } catch { }
}
anim = host.GetComponent<UI_SongsSelect_EnterAnim>();
if (anim == null)
{
anim = host.AddComponent<UI_SongsSelect_EnterAnim>();
}
}
if (!anim.isActiveAndEnabled)
{
anim.enabled = true;
}
anim.Play();
return true;
}
UI_SongsSelect_EnterAnim FindAnimInScene(Scene scene)
private UI_SongsSelect_EnterAnim FindAnimInScene(Scene scene)
{
var all = Resources.FindObjectsOfTypeAll<UI_SongsSelect_EnterAnim>();
UI_SongsSelect_EnterAnim[] all = UnityEngine.Object.FindObjectsByType<UI_SongsSelect_EnterAnim>(FindObjectsInactive.Include, FindObjectsSortMode.None);
for (int i = 0; i < all.Length; i++)
{
var anim = all[i];
UI_SongsSelect_EnterAnim anim = all[i];
if (anim == null) continue;
if (anim.gameObject.scene == scene) return anim;
}
return null;
}
GameObject FindInScene(Scene scene, string name)
private GameObject FindInScene(Scene scene, string objectName)
{
if (!scene.IsValid() || !scene.isLoaded) return null;
var all = Resources.FindObjectsOfTypeAll<Transform>();
for (int i = 0; i < all.Length; i++)
{
var t = all[i];
if (t == null) continue;
if (t.gameObject.scene != scene) continue;
if (t.name == name) return t.gameObject;
}
return null;
}
if (!scene.IsValid() || !scene.isLoaded)
return null;
Canvas FindCanvasInScene(Scene scene)
{
var all = Resources.FindObjectsOfTypeAll<Canvas>();
Transform[] all = UnityEngine.Object.FindObjectsByType<Transform>(FindObjectsInactive.Include, FindObjectsSortMode.None);
for (int i = 0; i < all.Length; i++)
{
var c = all[i];
if (c == null) continue;
if (c.gameObject.scene != scene) continue;
return c;
Transform t = all[i];
if (t == null || t.gameObject.scene != scene)
continue;
if (t.name == objectName)
return t.gameObject;
}
return null;
}