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

This commit is contained in:
FloatGaming
2026-02-14 23:46:20 +08:00
parent ef8eb67259
commit 3a7a0b4669
360 changed files with 85670 additions and 4144 deletions
@@ -0,0 +1,441 @@
using System.Collections;
using DG.Tweening;
using UnityEngine;
using UnityEngine.EventSystems;
using UnityEngine.SceneManagement;
using UnityEngine.UI;
public class UI_CharacterDialogController : MonoBehaviour
{
[SerializeField] private string requiredSceneName = "UI_UI";
[SerializeField] private string characterObjectName = "Image_Character";
[SerializeField] private string dialogObjectName = "UI_DIALOG";
[Header("Enter")]
[SerializeField] private float enterDuration = 0.3f;
[SerializeField] private float enterFromOffsetY = 60f;
[SerializeField] private Ease enterEase = Ease.OutCubic;
[Header("Blink Out")]
[SerializeField] private int blinkCount = 2;
[SerializeField] private float blinkHalfTime = 0.05f;
[Header("Auto Hide")]
[SerializeField] private float idleHideDelay = 5f;
[SerializeField] private bool useUnscaledTime = true;
private RectTransform dialogRect;
private CanvasGroup dialogGroup;
private Vector2 dialogBasePos;
private bool basePosCached;
private RectTransform boundCharacterRect;
private int bindAttemptToken;
private bool isVisible;
private Coroutine idleRoutine;
private Coroutine bindRoutine;
private Coroutine keepAliveRoutine;
private Sequence dialogSequence;
private UI_CharacterDialogClickProxy clickProxy;
private Button characterButton;
private bool initialHideDone;
private void OnEnable()
{
SceneManager.sceneLoaded -= OnSceneLoaded;
SceneManager.sceneLoaded += OnSceneLoaded;
SceneManager.activeSceneChanged -= OnActiveSceneChanged;
SceneManager.activeSceneChanged += OnActiveSceneChanged;
RebindSoon();
if (keepAliveRoutine == null)
keepAliveRoutine = StartCoroutine(KeepBindingAliveRoutine());
}
private void OnDisable()
{
SceneManager.sceneLoaded -= OnSceneLoaded;
SceneManager.activeSceneChanged -= OnActiveSceneChanged;
KillTweens();
if (characterButton != null)
{
characterButton.onClick.RemoveListener(OnCharacterClicked);
characterButton = null;
}
if (idleRoutine != null)
{
StopCoroutine(idleRoutine);
idleRoutine = null;
}
if (bindRoutine != null)
{
StopCoroutine(bindRoutine);
bindRoutine = null;
}
if (keepAliveRoutine != null)
{
StopCoroutine(keepAliveRoutine);
keepAliveRoutine = null;
}
clickProxy = null;
dialogRect = null;
dialogGroup = null;
boundCharacterRect = null;
basePosCached = false;
initialHideDone = false;
}
public void RebindSoon()
{
bindAttemptToken++;
if (bindRoutine != null)
StopCoroutine(bindRoutine);
bindRoutine = StartCoroutine(BindRoutine(bindAttemptToken));
}
private IEnumerator BindRoutine(int token)
{
yield return null;
TryBind();
yield return null;
if (token != bindAttemptToken)
yield break;
yield return null;
TryBind();
if (token != bindAttemptToken)
yield break;
yield return null;
TryBind();
if (token != bindAttemptToken)
yield break;
yield return new WaitForSecondsRealtime(0.2f);
TryBind();
if (token != bindAttemptToken)
yield break;
yield return new WaitForSecondsRealtime(0.6f);
TryBind();
bindRoutine = null;
}
private void TryBind()
{
if (!IsAllowedScene())
return;
Scene scene = gameObject.scene;
if (!scene.IsValid() || !scene.isLoaded)
scene = SceneManager.GetActiveScene();
Transform dialogTr = FindInSceneByName(scene, dialogObjectName);
if (dialogTr == null)
dialogTr = FindInSceneByName(SceneManager.GetActiveScene(), dialogObjectName);
if (dialogTr != null)
{
RectTransform nextDialogRect = dialogTr as RectTransform;
bool dialogChanged = dialogRect != nextDialogRect;
dialogRect = nextDialogRect;
if (dialogRect != null)
{
dialogGroup = dialogRect.GetComponent<CanvasGroup>();
if (dialogGroup == null)
dialogGroup = dialogRect.gameObject.AddComponent<CanvasGroup>();
if (dialogChanged || !basePosCached)
{
dialogBasePos = dialogRect.anchoredPosition;
basePosCached = true;
}
}
if (!initialHideDone)
{
HideImmediate();
initialHideDone = true;
}
}
Transform characterTr = FindInSceneByName(scene, characterObjectName);
if (characterTr == null)
characterTr = FindInSceneByName(SceneManager.GetActiveScene(), characterObjectName);
if (characterTr != null)
{
boundCharacterRect = characterTr as RectTransform;
clickProxy = characterTr.GetComponent<UI_CharacterDialogClickProxy>();
if (clickProxy == null)
clickProxy = characterTr.gameObject.AddComponent<UI_CharacterDialogClickProxy>();
clickProxy.Bind(this);
// Ensure the image can receive click events.
Graphic graphic = characterTr.GetComponent<Graphic>();
if (graphic != null)
graphic.raycastTarget = true;
// Also bind through Button click to avoid missing pointer callbacks.
Button btn = characterTr.GetComponent<Button>();
if (btn == null)
{
btn = characterTr.gameObject.AddComponent<Button>();
btn.transition = Selectable.Transition.None;
if (graphic != null)
btn.targetGraphic = graphic;
}
if (characterButton != null && characterButton != btn)
characterButton.onClick.RemoveListener(OnCharacterClicked);
characterButton = btn;
characterButton.onClick.RemoveListener(OnCharacterClicked);
characterButton.onClick.AddListener(OnCharacterClicked);
}
else
{
boundCharacterRect = null;
}
}
public void OnCharacterClicked()
{
if (!IsBindingValid())
TryBind();
if (dialogRect == null || dialogGroup == null || !basePosCached)
return;
if (isVisible)
{
BlinkOut(() => PlayEnter(), deactivateAtEnd: true);
}
else
{
PlayEnter();
}
}
private void PlayEnter()
{
if (dialogRect == null || dialogGroup == null)
return;
KillTweens();
dialogRect.gameObject.SetActive(true);
dialogRect.anchoredPosition = dialogBasePos - new Vector2(0f, Mathf.Abs(enterFromOffsetY));
dialogGroup.alpha = 0f;
dialogSequence = DOTween.Sequence().SetUpdate(useUnscaledTime);
dialogSequence.Join(dialogRect.DOAnchorPos(dialogBasePos, Mathf.Max(0.01f, enterDuration)).SetEase(enterEase));
dialogSequence.Join(dialogGroup.DOFade(1f, Mathf.Max(0.01f, enterDuration)).SetEase(Ease.OutCubic));
dialogSequence.OnComplete(() => dialogSequence = null);
isVisible = true;
RestartIdleTimer();
}
private void BlinkOut(System.Action onComplete, bool deactivateAtEnd)
{
if (dialogRect == null || dialogGroup == null)
{
onComplete?.Invoke();
return;
}
KillTweens();
dialogRect.gameObject.SetActive(true);
dialogSequence = DOTween.Sequence().SetUpdate(useUnscaledTime);
int blinks = Mathf.Max(1, blinkCount);
float half = Mathf.Max(0.01f, blinkHalfTime);
for (int i = 0; i < blinks; i++)
{
dialogSequence.Append(dialogGroup.DOFade(0f, half).SetEase(Ease.OutQuad));
dialogSequence.Append(dialogGroup.DOFade(1f, half).SetEase(Ease.OutQuad));
}
dialogSequence.Append(dialogGroup.DOFade(0f, half).SetEase(Ease.OutQuad));
dialogSequence.OnComplete(() =>
{
dialogSequence = null;
isVisible = false;
if (deactivateAtEnd && dialogRect != null)
dialogRect.gameObject.SetActive(false);
onComplete?.Invoke();
});
}
private void RestartIdleTimer()
{
if (idleRoutine != null)
StopCoroutine(idleRoutine);
idleRoutine = StartCoroutine(IdleHideRoutine());
}
private IEnumerator IdleHideRoutine()
{
float delay = Mathf.Max(0.2f, idleHideDelay);
float t = 0f;
while (t < delay)
{
t += useUnscaledTime ? Time.unscaledDeltaTime : Time.deltaTime;
yield return null;
}
if (isVisible)
{
BlinkOut(onComplete: null, deactivateAtEnd: true);
}
idleRoutine = null;
}
private void HideImmediate()
{
if (dialogRect == null || dialogGroup == null)
return;
KillTweens();
dialogGroup.alpha = 0f;
dialogRect.anchoredPosition = dialogBasePos;
dialogRect.gameObject.SetActive(false);
isVisible = false;
}
private void KillTweens()
{
if (dialogSequence != null)
{
dialogSequence.Kill();
dialogSequence = null;
}
if (dialogRect != null)
dialogRect.DOKill();
if (dialogGroup != null)
dialogGroup.DOKill();
}
private void OnSceneLoaded(Scene scene, LoadSceneMode mode)
{
if (string.Equals(scene.name, requiredSceneName, System.StringComparison.OrdinalIgnoreCase))
RebindSoon();
}
private void OnActiveSceneChanged(Scene from, Scene to)
{
if (string.Equals(to.name, requiredSceneName, System.StringComparison.OrdinalIgnoreCase))
RebindSoon();
}
private IEnumerator KeepBindingAliveRoutine()
{
while (enabled)
{
if (IsAllowedScene() && !IsBindingValid())
RebindSoon();
yield return new WaitForSecondsRealtime(0.5f);
}
}
private bool IsBindingValid()
{
if (!IsAllowedScene())
return false;
if (dialogRect == null || dialogGroup == null || !basePosCached)
return false;
if (boundCharacterRect == null)
return false;
if (characterButton == null)
return false;
return true;
}
private bool IsAllowedScene()
{
if (string.IsNullOrEmpty(requiredSceneName))
return true;
Scene own = gameObject.scene;
if (own.IsValid() && string.Equals(own.name, requiredSceneName, System.StringComparison.OrdinalIgnoreCase))
return true;
Scene active = SceneManager.GetActiveScene();
return active.IsValid() && string.Equals(active.name, requiredSceneName, System.StringComparison.OrdinalIgnoreCase);
}
private Transform FindInSceneByName(Scene scene, string objectName)
{
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++)
{
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;
}
}
public class UI_CharacterDialogClickProxy : MonoBehaviour, IPointerClickHandler
{
private UI_CharacterDialogController controller;
public void Bind(UI_CharacterDialogController owner)
{
controller = owner;
}
public void OnPointerClick(PointerEventData eventData)
{
controller?.OnCharacterClicked();
}
}
static class UI_CharacterDialogControllerBootstrap
{
private const string SceneName = "UI_UI";
private const string HostName = "__UICharacterDialogControllerHost";
[RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.BeforeSceneLoad)]
private static void Init()
{
SceneManager.sceneLoaded -= OnSceneLoaded;
SceneManager.sceneLoaded += OnSceneLoaded;
}
private static void OnSceneLoaded(Scene scene, LoadSceneMode mode)
{
if (!string.Equals(scene.name, SceneName, System.StringComparison.OrdinalIgnoreCase))
return;
GameObject host = FindHostInScene(scene, HostName);
if (host == null)
{
host = new GameObject(HostName);
SceneManager.MoveGameObjectToScene(host, scene);
}
UI_CharacterDialogController controller = host.GetComponent<UI_CharacterDialogController>();
if (controller == null)
controller = host.AddComponent<UI_CharacterDialogController>();
controller.RebindSoon();
}
private static GameObject FindHostInScene(Scene scene, string hostName)
{
if (!scene.IsValid() || !scene.isLoaded)
return null;
Transform[] all = UnityEngine.Object.FindObjectsByType<Transform>(FindObjectsInactive.Include, FindObjectsSortMode.None);
for (int i = 0; i < all.Length; i++)
{
Transform t = all[i];
if (t == null || t.gameObject.scene != scene)
continue;
if (t.name == hostName)
return t.gameObject;
}
return null;
}
}
@@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: 51eb8dcab528ffb46855652bbb8c71e9
@@ -37,7 +37,7 @@ class UI_Panel_Character : MonoBehaviour
}
else if(canvasGroup == null)
{
//Debug.LogError("Error for getting canvas group");
// Documentation text normalized.
return;
}
@@ -118,4 +118,4 @@ class UI_Panel_Character : MonoBehaviour
yield return null;
}
}
}
}
+107 -65
View File
@@ -1,4 +1,4 @@
using System;
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
@@ -274,8 +274,7 @@ public class UI_Panel_Main : Singleton_Mono<UI_Panel_Main>
var so = Instantiate(item);
data_List.Add(so);
// 每处理 5 个数据等待一帧,防止主线程卡死
if (i > 0 && i % 5 == 0)
// Documentation text normalized.
{
yield return null;
}
@@ -324,6 +323,13 @@ public class UI_Panel_Main : Singleton_Mono<UI_Panel_Main>
{
return false;
}
if (panel == ui_Panel_Setting)
{
UI_SettingsPanelEnterAnim enterAnim = panel.GetComponent<UI_SettingsPanelEnterAnim>();
if (enterAnim == null)
enterAnim = panel.AddComponent<UI_SettingsPanelEnterAnim>();
enterAnim.enabled = true;
}
panel.SetActive(true);
return true;
}
@@ -334,7 +340,7 @@ public class UI_Panel_Main : Singleton_Mono<UI_Panel_Main>
return;
}
selectScene_Loading = true;
// 使用异步加载场景,防止 GUI 冻结
// Documentation text normalized.
StartCoroutine(LoadSelectSceneAsync());
}
@@ -342,7 +348,7 @@ public class UI_Panel_Main : Singleton_Mono<UI_Panel_Main>
{
AsyncOperation asyncLoad = SceneManager.LoadSceneAsync(ui_Select_Music_Scene_Name, LoadSceneMode.Single);
// 等待加载完成
// Documentation text normalized.
while (!asyncLoad.isDone)
{
yield return null;
@@ -362,6 +368,8 @@ public class UI_Panel_Main : Singleton_Mono<UI_Panel_Main>
Setup_RightButtons_Hover();
Setup_Jiantou_Hover();
Fix_Button_Raycast();
Ensure_Character_Dialog_Controller();
StartCoroutine(Ensure_Character_Dialog_Controller_Delayed());
if (play_Enter_OnEnable)
{
Start_Enter_Routine();
@@ -371,6 +379,55 @@ public class UI_Panel_Main : Singleton_Mono<UI_Panel_Main>
Start_Jiantou_Loop();
}
}
IEnumerator Ensure_Character_Dialog_Controller_Delayed()
{
yield return null;
Ensure_Character_Dialog_Controller();
yield return null;
Ensure_Character_Dialog_Controller();
}
void Ensure_Character_Dialog_Controller()
{
Scene scene = SceneManager.GetActiveScene();
if (!scene.IsValid() || !string.Equals(scene.name, "UI_UI", StringComparison.OrdinalIgnoreCase))
{
return;
}
GameObject host = null;
Transform[] all = UnityEngine.Object.FindObjectsByType<Transform>(FindObjectsInactive.Include, FindObjectsSortMode.None);
for (int i = 0; i < all.Length; i++)
{
Transform t = all[i];
if (t == null || t.gameObject.scene != scene)
{
continue;
}
if (string.Equals(t.name, "__UICharacterDialogControllerHost", StringComparison.Ordinal))
{
host = t.gameObject;
break;
}
}
if (host == null)
{
host = new GameObject("__UICharacterDialogControllerHost");
try { SceneManager.MoveGameObjectToScene(host, scene); } catch { }
}
UI_CharacterDialogController controller = host.GetComponent<UI_CharacterDialogController>();
if (controller == null)
{
controller = host.AddComponent<UI_CharacterDialogController>();
}
if (!controller.enabled)
{
controller.enabled = true;
}
controller.RebindSoon();
}
void Fix_Button_Raycast()
{
if (!fix_Button_Raycast)
@@ -3234,15 +3291,17 @@ public class UI_RightButtonHover : MonoBehaviour, IPointerEnterHandler, IPointer
float textFlashInterval = 0.02f;
RectTransform imageRect;
Vector2 imageBasePos;
CanvasGroup imageGroup;
readonly List<CanvasGroup> textGroups = new();
Tween imageTween;
readonly List<Tween> textTweens = new();
public void ApplyConfig(float idleOffsetValue, float finalOffsetValue, float moveTimeValue, Ease moveEaseValue,
float textFlashTimeValue, int textFlashCountValue, float textFlashIntervalValue)
{
idleOffset = Mathf.Max(0f, idleOffsetValue);
finalOffset = finalOffsetValue;
// Keep icon inside the button frame: positive config means "shift left by this amount".
// Use a softened offset so icon sits slightly more to the right.
finalOffset = -Mathf.Abs(finalOffsetValue) * 0.75f;
moveTime = Mathf.Max(0.01f, moveTimeValue);
moveEase = moveEaseValue;
textFlashTime = Mathf.Max(0.01f, textFlashTimeValue);
@@ -3276,6 +3335,12 @@ public class UI_RightButtonHover : MonoBehaviour, IPointerEnterHandler, IPointer
if (imageRect != null)
{
imageBasePos = imageRect.anchoredPosition;
if (imageGroup == null)
{
imageGroup = imageRect.GetComponent<CanvasGroup>();
if (imageGroup == null)
imageGroup = imageRect.gameObject.AddComponent<CanvasGroup>();
}
}
textGroups.Clear();
for (int i = 0; i < transform.childCount; i++)
@@ -3318,32 +3383,36 @@ public class UI_RightButtonHover : MonoBehaviour, IPointerEnterHandler, IPointer
{
if (imageRect != null)
{
imageRect.anchoredPosition = imageBasePos + Vector2.left * idleOffset;
// Keep icon at its final position; only toggle visibility on hover.
imageRect.anchoredPosition = imageBasePos + Vector2.right * finalOffset;
}
if (imageGroup != null)
{
imageGroup.alpha = 0f; // hidden until hover
}
for (int i = 0; i < textGroups.Count; i++)
{
if (textGroups[i] != null)
{
textGroups[i].alpha = 0f;
// Text should always be visible (no flash-in).
textGroups[i].alpha = 1f;
}
}
}
public void OnPointerEnter(PointerEventData eventData)
{
MoveImage(true);
FlashTexts();
FlashImage();
}
public void OnPointerExit(PointerEventData eventData)
{
MoveImage(false);
HideTexts();
HideImage();
}
void MoveImage(bool toFinal)
void FlashImage()
{
if (imageRect == null)
if (imageRect == null || imageGroup == null)
{
return;
}
@@ -3352,69 +3421,42 @@ public class UI_RightButtonHover : MonoBehaviour, IPointerEnterHandler, IPointer
imageTween.Kill();
imageTween = null;
}
Vector2 target = toFinal
? imageBasePos + Vector2.right * finalOffset
: imageBasePos + Vector2.left * idleOffset;
imageTween = imageRect.DOAnchorPos(target, moveTime)
.SetEase(moveEase)
.SetUpdate(true);
}
void FlashTexts()
{
HideTexts();
for (int i = 0; i < textGroups.Count; i++)
{
CanvasGroup group = textGroups[i];
if (group == null)
{
continue;
}
group.alpha = 0f;
Sequence seq = DOTween.Sequence().SetUpdate(true);
for (int c = 0; c < textFlashCount; c++)
{
seq.Append(group.DOFade(1f, textFlashTime).SetEase(Ease.OutQuad));
seq.Append(group.DOFade(0f, textFlashTime).SetEase(Ease.InQuad));
if (textFlashInterval > 0f)
{
seq.AppendInterval(textFlashInterval);
}
}
seq.Append(group.DOFade(1f, textFlashTime).SetEase(Ease.OutQuad));
textTweens.Add(seq);
}
}
// Ensure icon is at its final position (no translation anim).
imageRect.anchoredPosition = imageBasePos + Vector2.right * finalOffset;
void HideTexts()
{
for (int i = 0; i < textTweens.Count; i++)
// Flash-in (blink) on hover, then stay visible.
imageGroup.alpha = 0f;
Sequence seq = DOTween.Sequence().SetUpdate(true);
for (int c = 0; c < textFlashCount; c++)
{
Tween tween = textTweens[i];
if (tween != null)
seq.Append(imageGroup.DOFade(1f, textFlashTime).SetEase(Ease.OutQuad));
seq.Append(imageGroup.DOFade(0f, textFlashTime).SetEase(Ease.InQuad));
if (textFlashInterval > 0f)
{
tween.Kill();
}
}
textTweens.Clear();
for (int i = 0; i < textGroups.Count; i++)
{
CanvasGroup group = textGroups[i];
if (group != null)
{
group.alpha = 0f;
seq.AppendInterval(textFlashInterval);
}
}
seq.Append(imageGroup.DOFade(1f, textFlashTime).SetEase(Ease.OutQuad));
imageTween = seq;
}
void KillTweens()
void HideImage()
{
if (imageTween != null)
{
imageTween.Kill();
imageTween = null;
}
HideTexts();
if (imageGroup != null)
{
imageGroup.alpha = 0f;
}
}
void KillTweens()
{
HideImage();
}
}
@@ -3603,7 +3645,7 @@ public class UI_StartButtonHover : MonoBehaviour, IPointerEnterHandler, IPointer
char[] filler = new char[remain];
for (int r = 0; r < remain; r++)
{
filler[r] = useDot ? '·' : randomChars[(i + r) % randomChars.Length];
filler[r] = useDot ? '' : randomChars[(i + r) % randomChars.Length];
}
suffix = new string(filler);
}
+101 -1
View File
@@ -1,5 +1,7 @@
using UnityEngine;
using UnityEngine.UI;
using DG.Tweening;
using System.Collections.Generic;
public class ui_Panel_Setting : MonoBehaviour
{
@@ -10,6 +12,19 @@ public class ui_Panel_Setting : MonoBehaviour
[SerializeField] Toggle toggle_View;
[SerializeField] Toggle toggle_View_Pie;
[SerializeField] GameObject view_Content;
[Header("Enter Animation")]
[SerializeField] bool playEnterAnimation = true;
[SerializeField] float enterItemDuration = 0.24f;
[SerializeField] float enterItemStagger = 0.03f;
[SerializeField] float enterOffsetY = 28f;
[SerializeField] Ease enterEase = Ease.OutCubic;
private readonly List<RectTransform> enterItems = new List<RectTransform>();
private readonly List<CanvasGroup> enterGroups = new List<CanvasGroup>();
private readonly List<Vector2> enterBasePos = new List<Vector2>();
private Sequence enterSequence;
private void Awake()
{
button_Close?.onClick.AddListener(Close);
@@ -36,6 +51,20 @@ public class ui_Panel_Setting : MonoBehaviour
toggle_Game.isOn = true;
}
private void OnEnable()
{
if (playEnterAnimation)
{
PlayEnterAnimation();
}
}
private void OnDisable()
{
KillEnterAnimation();
}
private void Update()
{
if (Input.GetKeyDown(KeyCode.Escape))
@@ -43,8 +72,79 @@ public class ui_Panel_Setting : MonoBehaviour
Close();
}
}
private void PlayEnterAnimation()
{
KillEnterAnimation();
CacheEnterItems();
if (enterItems.Count == 0)
return;
enterSequence = DOTween.Sequence().SetUpdate(true);
for (int i = 0; i < enterItems.Count; i++)
{
RectTransform rt = enterItems[i];
CanvasGroup cg = enterGroups[i];
Vector2 basePos = enterBasePos[i];
if (rt == null || cg == null)
continue;
rt.DOKill();
cg.DOKill();
rt.anchoredPosition = basePos - new Vector2(0f, Mathf.Abs(enterOffsetY));
cg.alpha = 0f;
float start = i * Mathf.Max(0f, enterItemStagger);
enterSequence.Insert(start,
rt.DOAnchorPos(basePos, Mathf.Max(0.01f, enterItemDuration))
.SetEase(enterEase)
.SetUpdate(true));
enterSequence.Insert(start,
cg.DOFade(1f, Mathf.Max(0.01f, enterItemDuration))
.SetEase(Ease.OutCubic)
.SetUpdate(true));
}
}
private void CacheEnterItems()
{
enterItems.Clear();
enterGroups.Clear();
enterBasePos.Clear();
for (int i = 0; i < transform.childCount; i++)
{
Transform child = transform.GetChild(i);
if (child == null || !child.gameObject.activeInHierarchy)
continue;
RectTransform rt = child as RectTransform;
if (rt == null)
continue;
CanvasGroup cg = rt.GetComponent<CanvasGroup>();
if (cg == null)
cg = rt.gameObject.AddComponent<CanvasGroup>();
enterItems.Add(rt);
enterGroups.Add(cg);
enterBasePos.Add(rt.anchoredPosition);
}
}
private void KillEnterAnimation()
{
if (enterSequence != null)
{
enterSequence.Kill();
enterSequence = null;
}
}
void Close()
{
gameObject.SetActive(false);
}
}
}
@@ -0,0 +1,116 @@
using DG.Tweening;
using UnityEngine;
[DisallowMultipleComponent]
public class UI_SettingsPanelEnterAnim : MonoBehaviour
{
[SerializeField] private RectTransform moveTarget;
[SerializeField] private CanvasGroup fadeTarget;
[SerializeField] private bool playOnEnable = true;
[SerializeField] private float enterDuration = 0.3f;
[SerializeField] private float fromOffsetY = 32f;
[SerializeField] private Ease enterEase = Ease.OutCubic;
[SerializeField] private bool useUnscaledTime = true;
private Sequence enterSequence;
private bool basePosCached;
private Vector2 basePos;
private void Awake()
{
AutoWire();
CacheBasePos();
}
private void OnEnable()
{
if (playOnEnable)
Play();
}
private void OnDisable()
{
KillTween();
ResetToBase();
}
public void Play()
{
AutoWire();
CacheBasePos();
if (moveTarget == null || fadeTarget == null)
return;
KillTween();
moveTarget.anchoredPosition = basePos - new Vector2(0f, Mathf.Abs(fromOffsetY));
fadeTarget.alpha = 0f;
fadeTarget.interactable = false;
fadeTarget.blocksRaycasts = false;
enterSequence = DOTween.Sequence().SetUpdate(useUnscaledTime);
enterSequence.Join(moveTarget.DOAnchorPos(basePos, Mathf.Max(0.01f, enterDuration)).SetEase(enterEase));
enterSequence.Join(fadeTarget.DOFade(1f, Mathf.Max(0.01f, enterDuration)).SetEase(Ease.OutCubic));
enterSequence.OnComplete(() =>
{
fadeTarget.interactable = true;
fadeTarget.blocksRaycasts = true;
enterSequence = null;
});
}
private void AutoWire()
{
if (moveTarget == null)
{
moveTarget = transform as RectTransform;
if (moveTarget == null)
moveTarget = GetComponentInChildren<RectTransform>(true);
}
if (fadeTarget == null)
fadeTarget = GetComponent<CanvasGroup>();
if (fadeTarget == null)
fadeTarget = gameObject.AddComponent<CanvasGroup>();
}
private void CacheBasePos()
{
if (moveTarget == null)
return;
if (!basePosCached)
{
basePos = moveTarget.anchoredPosition;
basePosCached = true;
}
}
private void ResetToBase()
{
if (moveTarget != null && basePosCached)
moveTarget.anchoredPosition = basePos;
if (fadeTarget != null)
{
fadeTarget.alpha = 1f;
fadeTarget.interactable = true;
fadeTarget.blocksRaycasts = true;
}
}
private void KillTween()
{
if (enterSequence != null)
{
enterSequence.Kill();
enterSequence = null;
}
if (moveTarget != null)
moveTarget.DOKill();
if (fadeTarget != null)
fadeTarget.DOKill();
}
}
@@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: 128b12802ff1c684abfc7da39a0deb5c
@@ -313,6 +313,127 @@ MonoBehaviour:
m_FillOrigin: 0
m_UseSpriteMesh: 0
m_PixelsPerUnitMultiplier: 1
--- !u!1 &698142945755259558
GameObject:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
serializedVersion: 6
m_Component:
- component: {fileID: 664855366139876558}
- component: {fileID: 6815741791543722666}
- component: {fileID: 1445541171937349538}
- component: {fileID: 1221776354986423673}
m_Layer: 0
m_Name: back
m_TagString: Untagged
m_Icon: {fileID: 0}
m_NavMeshLayer: 0
m_StaticEditorFlags: 0
m_IsActive: 1
--- !u!224 &664855366139876558
RectTransform:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 698142945755259558}
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
m_LocalPosition: {x: 0, y: 0, z: 0}
m_LocalScale: {x: 1, y: 1, z: 1}
m_ConstrainProportionsScale: 0
m_Children:
- {fileID: 8436329948899178167}
m_Father: {fileID: 4201371652593379150}
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
m_AnchorMin: {x: 0, y: 0}
m_AnchorMax: {x: 0, y: 0}
m_AnchoredPosition: {x: 0, y: 0}
m_SizeDelta: {x: 97, y: 97}
m_Pivot: {x: 0.5, y: 0.5}
--- !u!222 &6815741791543722666
CanvasRenderer:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 698142945755259558}
m_CullTransparentMesh: 1
--- !u!114 &1445541171937349538
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 698142945755259558}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3}
m_Name:
m_EditorClassIdentifier:
m_Material: {fileID: 0}
m_Color: {r: 1, g: 1, b: 1, a: 1}
m_RaycastTarget: 1
m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0}
m_Maskable: 1
m_OnCullStateChanged:
m_PersistentCalls:
m_Calls: []
m_Sprite: {fileID: 6349329690924382296, guid: ff06dc687af02f74c8fbd98368463fc2, type: 3}
m_Type: 0
m_PreserveAspect: 0
m_FillCenter: 1
m_FillMethod: 4
m_FillAmount: 1
m_FillClockwise: 1
m_FillOrigin: 0
m_UseSpriteMesh: 0
m_PixelsPerUnitMultiplier: 1
--- !u!114 &1221776354986423673
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 698142945755259558}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: 4e29b1a8efbd4b44bb3f3716e73f07ff, type: 3}
m_Name:
m_EditorClassIdentifier:
m_Navigation:
m_Mode: 3
m_WrapAround: 0
m_SelectOnUp: {fileID: 0}
m_SelectOnDown: {fileID: 0}
m_SelectOnLeft: {fileID: 0}
m_SelectOnRight: {fileID: 0}
m_Transition: 1
m_Colors:
m_NormalColor: {r: 1, g: 1, b: 1, a: 1}
m_HighlightedColor: {r: 0.9607843, g: 0.9607843, b: 0.9607843, a: 1}
m_PressedColor: {r: 0.78431374, g: 0.78431374, b: 0.78431374, a: 1}
m_SelectedColor: {r: 0.9607843, g: 0.9607843, b: 0.9607843, a: 1}
m_DisabledColor: {r: 0.78431374, g: 0.78431374, b: 0.78431374, a: 0.5019608}
m_ColorMultiplier: 1
m_FadeDuration: 0.1
m_SpriteState:
m_HighlightedSprite: {fileID: 0}
m_PressedSprite: {fileID: 0}
m_SelectedSprite: {fileID: 0}
m_DisabledSprite: {fileID: 0}
m_AnimationTriggers:
m_NormalTrigger: Normal
m_HighlightedTrigger: Highlighted
m_PressedTrigger: Pressed
m_SelectedTrigger: Selected
m_DisabledTrigger: Disabled
m_Interactable: 1
m_TargetGraphic: {fileID: 1445541171937349538}
m_OnClick:
m_PersistentCalls:
m_Calls: []
--- !u!1 &794346939895717571
GameObject:
m_ObjectHideFlags: 0
@@ -829,6 +950,7 @@ RectTransform:
- {fileID: 1216734273723155318}
- {fileID: 4507029859229390628}
- {fileID: 3166511394318740470}
- {fileID: 4201371652593379150}
m_Father: {fileID: 4008714089197239054}
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
m_AnchorMin: {x: 0, y: 1}
@@ -1702,6 +1824,81 @@ MonoBehaviour:
m_FillOrigin: 0
m_UseSpriteMesh: 0
m_PixelsPerUnitMultiplier: 1
--- !u!1 &1883765842619825806
GameObject:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
serializedVersion: 6
m_Component:
- component: {fileID: 8344488991073226701}
- component: {fileID: 8707209540160881515}
- component: {fileID: 3843922392991303629}
m_Layer: 0
m_Name: Image
m_TagString: Untagged
m_Icon: {fileID: 0}
m_NavMeshLayer: 0
m_StaticEditorFlags: 0
m_IsActive: 1
--- !u!224 &8344488991073226701
RectTransform:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 1883765842619825806}
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
m_LocalPosition: {x: 0, y: 0, z: 0}
m_LocalScale: {x: 1, y: 1, z: 1}
m_ConstrainProportionsScale: 0
m_Children: []
m_Father: {fileID: 5977557715898357349}
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
m_AnchorMin: {x: 0.6977236, y: 0.32699218}
m_AnchorMax: {x: 0.6977236, y: 0.32699218}
m_AnchoredPosition: {x: -19.179, y: 16.782}
m_SizeDelta: {x: 53.555, y: 53.5554}
m_Pivot: {x: 0.5, y: 0.5}
--- !u!222 &8707209540160881515
CanvasRenderer:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 1883765842619825806}
m_CullTransparentMesh: 1
--- !u!114 &3843922392991303629
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 1883765842619825806}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3}
m_Name:
m_EditorClassIdentifier:
m_Material: {fileID: 0}
m_Color: {r: 1, g: 1, b: 1, a: 1}
m_RaycastTarget: 1
m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0}
m_Maskable: 1
m_OnCullStateChanged:
m_PersistentCalls:
m_Calls: []
m_Sprite: {fileID: 21300000, guid: d0ef0c9be447e1f4296eb8a4b9195c8c, type: 3}
m_Type: 0
m_PreserveAspect: 0
m_FillCenter: 1
m_FillMethod: 4
m_FillAmount: 1
m_FillClockwise: 1
m_FillOrigin: 0
m_UseSpriteMesh: 0
m_PixelsPerUnitMultiplier: 1
--- !u!1 &1934290382038477745
GameObject:
m_ObjectHideFlags: 0
@@ -1777,6 +1974,71 @@ MonoBehaviour:
m_FillOrigin: 0
m_UseSpriteMesh: 0
m_PixelsPerUnitMultiplier: 1
--- !u!1 &2123526779575187879
GameObject:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
serializedVersion: 6
m_Component:
- component: {fileID: 4201371652593379150}
- component: {fileID: 4595481187193100221}
m_Layer: 0
m_Name: New back
m_TagString: Untagged
m_Icon: {fileID: 0}
m_NavMeshLayer: 0
m_StaticEditorFlags: 0
m_IsActive: 1
--- !u!224 &4201371652593379150
RectTransform:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 2123526779575187879}
m_LocalRotation: {x: -0, y: -0, z: -0, w: 1}
m_LocalPosition: {x: 0, y: 0, z: 5.504588}
m_LocalScale: {x: 0.51, y: 0.51, z: 0.51}
m_ConstrainProportionsScale: 1
m_Children:
- {fileID: 6419923115795927302}
- {fileID: 664855366139876558}
- {fileID: 5977557715898357349}
m_Father: {fileID: 5634981615641515618}
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
m_AnchorMin: {x: 0.5, y: 0.5}
m_AnchorMax: {x: 0.5, y: 0.5}
m_AnchoredPosition: {x: -329.2, y: 0.00002670288}
m_SizeDelta: {x: 2410.4807, y: 100}
m_Pivot: {x: 0.5, y: 0.5}
--- !u!114 &4595481187193100221
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 2123526779575187879}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: 30649d3a9faa99c48a7b1166b86bf2a0, type: 3}
m_Name:
m_EditorClassIdentifier:
m_Padding:
m_Left: 0
m_Right: 0
m_Top: 0
m_Bottom: 0
m_ChildAlignment: 0
m_Spacing: -2040.77
m_ChildForceExpandWidth: 1
m_ChildForceExpandHeight: 1
m_ChildControlWidth: 0
m_ChildControlHeight: 0
m_ChildScaleWidth: 0
m_ChildScaleHeight: 0
m_ReverseArrangement: 0
--- !u!1 &2157369845151287564
GameObject:
m_ObjectHideFlags: 0
@@ -2238,6 +2500,127 @@ RectTransform:
m_AnchoredPosition: {x: -675.6, y: -0.00005340576}
m_SizeDelta: {x: 128, y: 30}
m_Pivot: {x: 0.5, y: 0.5}
--- !u!1 &2496832619426805493
GameObject:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
serializedVersion: 6
m_Component:
- component: {fileID: 5977557715898357349}
- component: {fileID: 7995155685421482441}
- component: {fileID: 3428519051158734592}
- component: {fileID: 4088529162781090059}
m_Layer: 0
m_Name: home
m_TagString: Untagged
m_Icon: {fileID: 0}
m_NavMeshLayer: 0
m_StaticEditorFlags: 0
m_IsActive: 1
--- !u!224 &5977557715898357349
RectTransform:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 2496832619426805493}
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
m_LocalPosition: {x: 0, y: 0, z: 0}
m_LocalScale: {x: 1, y: 1, z: 1}
m_ConstrainProportionsScale: 0
m_Children:
- {fileID: 8344488991073226701}
m_Father: {fileID: 4201371652593379150}
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
m_AnchorMin: {x: 0, y: 0}
m_AnchorMax: {x: 0, y: 0}
m_AnchoredPosition: {x: 0, y: 0}
m_SizeDelta: {x: 97, y: 97}
m_Pivot: {x: 0.5, y: 0.5}
--- !u!222 &7995155685421482441
CanvasRenderer:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 2496832619426805493}
m_CullTransparentMesh: 1
--- !u!114 &3428519051158734592
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 2496832619426805493}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3}
m_Name:
m_EditorClassIdentifier:
m_Material: {fileID: 0}
m_Color: {r: 1, g: 1, b: 1, a: 1}
m_RaycastTarget: 1
m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0}
m_Maskable: 1
m_OnCullStateChanged:
m_PersistentCalls:
m_Calls: []
m_Sprite: {fileID: 6349329690924382296, guid: ff06dc687af02f74c8fbd98368463fc2, type: 3}
m_Type: 0
m_PreserveAspect: 0
m_FillCenter: 1
m_FillMethod: 4
m_FillAmount: 1
m_FillClockwise: 1
m_FillOrigin: 0
m_UseSpriteMesh: 0
m_PixelsPerUnitMultiplier: 1
--- !u!114 &4088529162781090059
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 2496832619426805493}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: 4e29b1a8efbd4b44bb3f3716e73f07ff, type: 3}
m_Name:
m_EditorClassIdentifier:
m_Navigation:
m_Mode: 3
m_WrapAround: 0
m_SelectOnUp: {fileID: 0}
m_SelectOnDown: {fileID: 0}
m_SelectOnLeft: {fileID: 0}
m_SelectOnRight: {fileID: 0}
m_Transition: 1
m_Colors:
m_NormalColor: {r: 1, g: 1, b: 1, a: 1}
m_HighlightedColor: {r: 0.9607843, g: 0.9607843, b: 0.9607843, a: 1}
m_PressedColor: {r: 0.78431374, g: 0.78431374, b: 0.78431374, a: 1}
m_SelectedColor: {r: 0.9607843, g: 0.9607843, b: 0.9607843, a: 1}
m_DisabledColor: {r: 0.78431374, g: 0.78431374, b: 0.78431374, a: 0.5019608}
m_ColorMultiplier: 1
m_FadeDuration: 0.1
m_SpriteState:
m_HighlightedSprite: {fileID: 0}
m_PressedSprite: {fileID: 0}
m_SelectedSprite: {fileID: 0}
m_DisabledSprite: {fileID: 0}
m_AnimationTriggers:
m_NormalTrigger: Normal
m_HighlightedTrigger: Highlighted
m_PressedTrigger: Pressed
m_SelectedTrigger: Selected
m_DisabledTrigger: Disabled
m_Interactable: 1
m_TargetGraphic: {fileID: 3428519051158734592}
m_OnClick:
m_PersistentCalls:
m_Calls: []
--- !u!1 &2529537244873479850
GameObject:
m_ObjectHideFlags: 0
@@ -4040,6 +4423,11 @@ MonoBehaviour:
userInfo_prefab: {fileID: 0}
email_prefab: {fileID: 3756075665884320709, guid: 41f4ea31b64f18d48aeef21b79930a6c, type: 3}
notice_prefab: {fileID: 8527835049849151044, guid: 06bb6d3a45697374ab4f5ff36356d138, type: 3}
back_navButton: {fileID: 0}
home_navButton: {fileID: 0}
settings_navButton: {fileID: 0}
homeSceneName: UI_UI
backFallbackSceneName: Main_main
--- !u!114 &2510911207525280717
MonoBehaviour:
m_ObjectHideFlags: 0
@@ -4436,6 +4824,85 @@ MonoBehaviour:
m_FillOrigin: 0
m_UseSpriteMesh: 0
m_PixelsPerUnitMultiplier: 1
--- !u!1 &5455887339197002951
GameObject:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
serializedVersion: 6
m_Component:
- component: {fileID: 94861546549908736}
- component: {fileID: 185682819927651411}
- component: {fileID: 8311074806369947263}
m_Layer: 0
m_Name: Text (Legacy)
m_TagString: Untagged
m_Icon: {fileID: 0}
m_NavMeshLayer: 0
m_StaticEditorFlags: 0
m_IsActive: 1
--- !u!224 &94861546549908736
RectTransform:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 5455887339197002951}
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
m_LocalPosition: {x: 0, y: 0, z: 0}
m_LocalScale: {x: 1, y: 1, z: 1}
m_ConstrainProportionsScale: 0
m_Children: []
m_Father: {fileID: 6419923115795927302}
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
m_AnchorMin: {x: 0.5, y: 0.5}
m_AnchorMax: {x: 0.5, y: 0.5}
m_AnchoredPosition: {x: 7.1215, y: -0.0335}
m_SizeDelta: {x: 56.838, y: 58.3341}
m_Pivot: {x: 0.5, y: 0.5}
--- !u!222 &185682819927651411
CanvasRenderer:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 5455887339197002951}
m_CullTransparentMesh: 1
--- !u!114 &8311074806369947263
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 5455887339197002951}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: 5f7201a12d95ffc409449d95f23cf332, type: 3}
m_Name:
m_EditorClassIdentifier:
m_Material: {fileID: 0}
m_Color: {r: 0, g: 0, b: 0, a: 1}
m_RaycastTarget: 1
m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0}
m_Maskable: 1
m_OnCullStateChanged:
m_PersistentCalls:
m_Calls: []
m_FontData:
m_Font: {fileID: 12800000, guid: cc180dff846d13a4d88ddaed6f77e5cd, type: 3}
m_FontSize: 44
m_FontStyle: 0
m_BestFit: 0
m_MinSize: 10
m_MaxSize: 44
m_Alignment: 4
m_AlignByGeometry: 0
m_RichText: 1
m_HorizontalOverflow: 0
m_VerticalOverflow: 0
m_LineSpacing: 1
m_Text: "\uFF1F"
--- !u!1 &5745207992015071035
GameObject:
m_ObjectHideFlags: 0
@@ -5469,6 +5936,128 @@ MonoBehaviour:
m_Spacing: {x: 20, y: 20}
m_Constraint: 1
m_ConstraintCount: 4
--- !u!1 &7302066207285333480
GameObject:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
serializedVersion: 6
m_Component:
- component: {fileID: 6419923115795927302}
- component: {fileID: 1613315426306319868}
- component: {fileID: 510332109012089948}
- component: {fileID: 6945238783669072533}
m_Layer: 0
m_Name: question
m_TagString: Untagged
m_Icon: {fileID: 0}
m_NavMeshLayer: 0
m_StaticEditorFlags: 0
m_IsActive: 1
--- !u!224 &6419923115795927302
RectTransform:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 7302066207285333480}
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
m_LocalPosition: {x: 0, y: 0, z: 0}
m_LocalScale: {x: 1, y: 1, z: 1}
m_ConstrainProportionsScale: 0
m_Children:
- {fileID: 4789218457072247502}
- {fileID: 94861546549908736}
m_Father: {fileID: 4201371652593379150}
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
m_AnchorMin: {x: 0, y: 0}
m_AnchorMax: {x: 0, y: 0}
m_AnchoredPosition: {x: 0, y: 0}
m_SizeDelta: {x: 97, y: 97}
m_Pivot: {x: 0.5, y: 0.5}
--- !u!222 &1613315426306319868
CanvasRenderer:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 7302066207285333480}
m_CullTransparentMesh: 1
--- !u!114 &510332109012089948
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 7302066207285333480}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3}
m_Name:
m_EditorClassIdentifier:
m_Material: {fileID: 0}
m_Color: {r: 1, g: 1, b: 1, a: 1}
m_RaycastTarget: 1
m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0}
m_Maskable: 1
m_OnCullStateChanged:
m_PersistentCalls:
m_Calls: []
m_Sprite: {fileID: 6349329690924382296, guid: ff06dc687af02f74c8fbd98368463fc2, type: 3}
m_Type: 0
m_PreserveAspect: 0
m_FillCenter: 1
m_FillMethod: 4
m_FillAmount: 1
m_FillClockwise: 1
m_FillOrigin: 0
m_UseSpriteMesh: 0
m_PixelsPerUnitMultiplier: 1
--- !u!114 &6945238783669072533
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 7302066207285333480}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: 4e29b1a8efbd4b44bb3f3716e73f07ff, type: 3}
m_Name:
m_EditorClassIdentifier:
m_Navigation:
m_Mode: 3
m_WrapAround: 0
m_SelectOnUp: {fileID: 0}
m_SelectOnDown: {fileID: 0}
m_SelectOnLeft: {fileID: 0}
m_SelectOnRight: {fileID: 0}
m_Transition: 1
m_Colors:
m_NormalColor: {r: 1, g: 1, b: 1, a: 1}
m_HighlightedColor: {r: 0.9607843, g: 0.9607843, b: 0.9607843, a: 1}
m_PressedColor: {r: 0.78431374, g: 0.78431374, b: 0.78431374, a: 1}
m_SelectedColor: {r: 0.9607843, g: 0.9607843, b: 0.9607843, a: 1}
m_DisabledColor: {r: 0.78431374, g: 0.78431374, b: 0.78431374, a: 0.5019608}
m_ColorMultiplier: 1
m_FadeDuration: 0.1
m_SpriteState:
m_HighlightedSprite: {fileID: 0}
m_PressedSprite: {fileID: 0}
m_SelectedSprite: {fileID: 0}
m_DisabledSprite: {fileID: 0}
m_AnimationTriggers:
m_NormalTrigger: Normal
m_HighlightedTrigger: Highlighted
m_PressedTrigger: Pressed
m_SelectedTrigger: Selected
m_DisabledTrigger: Disabled
m_Interactable: 1
m_TargetGraphic: {fileID: 510332109012089948}
m_OnClick:
m_PersistentCalls:
m_Calls: []
--- !u!1 &7324940213527366140
GameObject:
m_ObjectHideFlags: 0
@@ -6128,7 +6717,7 @@ GameObject:
m_Icon: {fileID: 0}
m_NavMeshLayer: 0
m_StaticEditorFlags: 0
m_IsActive: 1
m_IsActive: 0
--- !u!224 &2726789671155220641
RectTransform:
m_ObjectHideFlags: 0
@@ -6345,6 +6934,81 @@ MonoBehaviour:
m_FillOrigin: 0
m_UseSpriteMesh: 0
m_PixelsPerUnitMultiplier: 1
--- !u!1 &8339357190892337068
GameObject:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
serializedVersion: 6
m_Component:
- component: {fileID: 8436329948899178167}
- component: {fileID: 4450874966179245808}
- component: {fileID: 6474466730584838898}
m_Layer: 0
m_Name: Image
m_TagString: Untagged
m_Icon: {fileID: 0}
m_NavMeshLayer: 0
m_StaticEditorFlags: 0
m_IsActive: 1
--- !u!224 &8436329948899178167
RectTransform:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 8339357190892337068}
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
m_LocalPosition: {x: 0, y: 0, z: 0}
m_LocalScale: {x: 1, y: 1, z: 1}
m_ConstrainProportionsScale: 0
m_Children: []
m_Father: {fileID: 664855366139876558}
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
m_AnchorMin: {x: 0.5, y: 0.5}
m_AnchorMax: {x: 0.5, y: 0.5}
m_AnchoredPosition: {x: -0.0000038147, y: 0.000049591}
m_SizeDelta: {x: 36.928, y: 36.928}
m_Pivot: {x: 0.5, y: 0.5}
--- !u!222 &4450874966179245808
CanvasRenderer:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 8339357190892337068}
m_CullTransparentMesh: 1
--- !u!114 &6474466730584838898
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 8339357190892337068}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3}
m_Name:
m_EditorClassIdentifier:
m_Material: {fileID: 0}
m_Color: {r: 1, g: 1, b: 1, a: 1}
m_RaycastTarget: 1
m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0}
m_Maskable: 1
m_OnCullStateChanged:
m_PersistentCalls:
m_Calls: []
m_Sprite: {fileID: 1172102457425465809, guid: b48603b1f2d0d6f428723f0d89e4dafc, type: 3}
m_Type: 0
m_PreserveAspect: 0
m_FillCenter: 1
m_FillMethod: 4
m_FillAmount: 1
m_FillClockwise: 1
m_FillOrigin: 0
m_UseSpriteMesh: 0
m_PixelsPerUnitMultiplier: 1
--- !u!1 &8442525676262455151
GameObject:
m_ObjectHideFlags: 0
@@ -6935,6 +7599,81 @@ MonoBehaviour:
m_FillOrigin: 0
m_UseSpriteMesh: 0
m_PixelsPerUnitMultiplier: 1
--- !u!1 &8891292652493349475
GameObject:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
serializedVersion: 6
m_Component:
- component: {fileID: 4789218457072247502}
- component: {fileID: 3389991985103273735}
- component: {fileID: 2938340339765009532}
m_Layer: 0
m_Name: Image
m_TagString: Untagged
m_Icon: {fileID: 0}
m_NavMeshLayer: 0
m_StaticEditorFlags: 0
m_IsActive: 0
--- !u!224 &4789218457072247502
RectTransform:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 8891292652493349475}
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
m_LocalPosition: {x: 0, y: 0, z: 0}
m_LocalScale: {x: 1, y: 1, z: 1}
m_ConstrainProportionsScale: 0
m_Children: []
m_Father: {fileID: 6419923115795927302}
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
m_AnchorMin: {x: 0.6977236, y: 0.32699218}
m_AnchorMax: {x: 0.6977236, y: 0.32699218}
m_AnchoredPosition: {x: -19.179, y: 16.782}
m_SizeDelta: {x: 42.5956, y: 40.1846}
m_Pivot: {x: 0.5, y: 0.5}
--- !u!222 &3389991985103273735
CanvasRenderer:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 8891292652493349475}
m_CullTransparentMesh: 1
--- !u!114 &2938340339765009532
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 8891292652493349475}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3}
m_Name:
m_EditorClassIdentifier:
m_Material: {fileID: 0}
m_Color: {r: 1, g: 1, b: 1, a: 1}
m_RaycastTarget: 1
m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0}
m_Maskable: 1
m_OnCullStateChanged:
m_PersistentCalls:
m_Calls: []
m_Sprite: {fileID: -7462228084874713130, guid: cad5616c19ca266448fcf54f97fe766d, type: 3}
m_Type: 0
m_PreserveAspect: 0
m_FillCenter: 1
m_FillMethod: 4
m_FillAmount: 1
m_FillClockwise: 1
m_FillOrigin: 0
m_UseSpriteMesh: 0
m_PixelsPerUnitMultiplier: 1
--- !u!1 &8926842291454856642
GameObject:
m_ObjectHideFlags: 0
@@ -6969,7 +7708,7 @@ RectTransform:
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
m_AnchorMin: {x: 0.5, y: 0.5}
m_AnchorMax: {x: 0.5, y: 0.5}
m_AnchoredPosition: {x: 163.2, y: 0}
m_AnchoredPosition: {x: 232.8, y: 0}
m_SizeDelta: {x: 200, y: 50}
m_Pivot: {x: 0.5, y: 0.5}
--- !u!222 &3583705284184792287
@@ -7007,13 +7746,13 @@ MonoBehaviour:
m_BestFit: 0
m_MinSize: 10
m_MaxSize: 61
m_Alignment: 4
m_Alignment: 3
m_AlignByGeometry: 0
m_RichText: 1
m_HorizontalOverflow: 0
m_VerticalOverflow: 0
m_LineSpacing: 1
m_Text: 114
m_Text: player_rks
--- !u!1 &9065634752865683599
GameObject:
m_ObjectHideFlags: 0
@@ -1,6 +1,8 @@
using UnityEngine;
using UnityEngine.UI;
using UnityEngine.Events;
using UnityEngine.SceneManagement;
using System.Collections.Generic;
public class btmandtopController : MonoBehaviour
{
@@ -31,12 +33,22 @@ public class btmandtopController : MonoBehaviour
public GameObject email_prefab;
public GameObject notice_prefab;
[Header("New Back Buttons")]
[SerializeField] private Button back_navButton;
[SerializeField] private Button home_navButton;
[SerializeField] private Button settings_navButton;
[SerializeField] private string homeSceneName = "UI_UI";
[SerializeField] private string backFallbackSceneName = "Main_main";
private UnityAction instantiateSettings;
private UnityAction instantiateUserInfo;
private UnityAction instantiateStore;
private UnityAction instantiateShowLevel;
private UnityAction instantiateEmail;
private UnityAction instantiateNotice;
private UnityAction navBackAction;
private UnityAction navHomeAction;
private UnityAction navSettingsAction;
// cached reference to the settings instance to ensure only one exists
private GameObject settingsInstance;
@@ -46,10 +58,16 @@ public class btmandtopController : MonoBehaviour
private CanvasGroup musicPicGroup;
private Coroutine musicPicFade;
private bool musicPicVisible = true;
private bool navSceneLoading = false;
private static readonly List<string> sceneHistory = new List<string>();
private static bool sceneHistoryHooked = false;
private static string trackedCurrentScene = string.Empty;
void Awake()
{
EnsureMusicPicRoot();
InitializeSceneHistoryIfNeeded();
}
void Start()
@@ -85,6 +103,8 @@ public class btmandtopController : MonoBehaviour
if (notice_display != null)
notice_display.onClick.AddListener(instantiateNotice);
BindNewBackButtons();
EnsureMusicPicRoot();
SetupMusicPicDefault();
if (button_Music != null)
@@ -112,6 +132,7 @@ public class btmandtopController : MonoBehaviour
if (settingsInstance == null)
{
settingsInstance = Instantiate(settings_prefab, putPrefabsHere.transform);
EnsureSettingsEnterAnimator(settingsInstance);
settingsInstance.SetActive(false);
// try to set canvas camera now as in previous behavior
@@ -135,6 +156,7 @@ public class btmandtopController : MonoBehaviour
{
// ensure it's parented correctly under putPrefabsHere
settingsInstance.transform.SetParent(putPrefabsHere.transform, false);
EnsureSettingsEnterAnimator(settingsInstance);
settingsInstance.SetActive(false);
}
}
@@ -309,6 +331,13 @@ public class btmandtopController : MonoBehaviour
if (button_Music != null)
button_Music.onClick.RemoveListener(ToggleMusicPicLocal);
if (back_navButton != null && navBackAction != null)
back_navButton.onClick.RemoveListener(navBackAction);
if (home_navButton != null && navHomeAction != null)
home_navButton.onClick.RemoveListener(navHomeAction);
if (settings_navButton != null && navSettingsAction != null)
settings_navButton.onClick.RemoveListener(navSettingsAction);
}
private void ToggleSettingsPrefab()
@@ -319,6 +348,7 @@ public class btmandtopController : MonoBehaviour
if (settingsInstance == null)
{
settingsInstance = Instantiate(settings_prefab, putPrefabsHere.transform);
EnsureSettingsEnterAnimator(settingsInstance);
// attempt to set canvas camera
try
@@ -341,6 +371,8 @@ public class btmandtopController : MonoBehaviour
return;
}
EnsureSettingsEnterAnimator(settingsInstance);
// Toggle active state
bool active = settingsInstance.activeSelf;
settingsInstance.SetActive(!active);
@@ -445,4 +477,174 @@ public class btmandtopController : MonoBehaviour
instance = null;
}
}
private void EnsureSettingsEnterAnimator(GameObject instance)
{
if (instance == null) return;
UI_SettingsPanelEnterAnim anim = instance.GetComponent<UI_SettingsPanelEnterAnim>();
if (anim == null)
anim = instance.AddComponent<UI_SettingsPanelEnterAnim>();
anim.enabled = true;
}
private void BindNewBackButtons()
{
ResolveNewBackButtons();
navBackAction = OnBackNavClicked;
navHomeAction = OnHomeNavClicked;
navSettingsAction = OnSettingsNavClicked;
if (back_navButton != null)
{
back_navButton.onClick.RemoveListener(navBackAction);
back_navButton.onClick.AddListener(navBackAction);
}
if (home_navButton != null)
{
home_navButton.onClick.RemoveListener(navHomeAction);
home_navButton.onClick.AddListener(navHomeAction);
}
if (settings_navButton != null)
{
settings_navButton.onClick.RemoveListener(navSettingsAction);
settings_navButton.onClick.AddListener(navSettingsAction);
}
}
private void ResolveNewBackButtons()
{
Transform navRoot = FindChildRecursive(transform, "New back");
if (navRoot == null)
{
GameObject sceneRoot = FindByName("New back");
if (sceneRoot != null)
navRoot = sceneRoot.transform;
}
if (back_navButton == null)
back_navButton = FindButtonByName(navRoot, "back");
if (home_navButton == null)
home_navButton = FindButtonByName(navRoot, "home");
if (settings_navButton == null)
settings_navButton = FindButtonByName(navRoot, "settings");
}
private static Transform FindChildRecursive(Transform root, string childName)
{
if (root == null || string.IsNullOrEmpty(childName)) return null;
if (root.name == childName) return root;
for (int i = 0; i < root.childCount; i++)
{
Transform child = root.GetChild(i);
Transform found = FindChildRecursive(child, childName);
if (found != null) return found;
}
return null;
}
private static Button FindButtonByName(Transform root, string name)
{
if (string.IsNullOrEmpty(name)) return null;
if (root != null)
{
Button[] buttons = root.GetComponentsInChildren<Button>(true);
for (int i = 0; i < buttons.Length; i++)
{
Button btn = buttons[i];
if (btn != null && string.Equals(btn.gameObject.name, name, System.StringComparison.OrdinalIgnoreCase))
return btn;
}
}
return null;
}
private static void InitializeSceneHistoryIfNeeded()
{
if (sceneHistoryHooked) return;
sceneHistoryHooked = true;
trackedCurrentScene = SceneManager.GetActiveScene().name ?? string.Empty;
SceneManager.sceneLoaded += OnSceneLoadedTrackHistory;
}
private static void OnSceneLoadedTrackHistory(Scene scene, LoadSceneMode mode)
{
string incoming = scene.name ?? string.Empty;
if (!string.IsNullOrEmpty(trackedCurrentScene) &&
!string.Equals(trackedCurrentScene, incoming, System.StringComparison.OrdinalIgnoreCase))
{
if (sceneHistory.Count == 0 ||
!string.Equals(sceneHistory[sceneHistory.Count - 1], trackedCurrentScene, System.StringComparison.OrdinalIgnoreCase))
{
sceneHistory.Add(trackedCurrentScene);
if (sceneHistory.Count > 24) sceneHistory.RemoveAt(0);
}
}
trackedCurrentScene = incoming;
}
private static string PopPreviousSceneName(string currentScene)
{
for (int i = sceneHistory.Count - 1; i >= 0; i--)
{
string candidate = sceneHistory[i];
sceneHistory.RemoveAt(i);
if (string.IsNullOrEmpty(candidate)) continue;
if (string.Equals(candidate, currentScene, System.StringComparison.OrdinalIgnoreCase)) continue;
return candidate;
}
return null;
}
private void OnBackNavClicked()
{
if (navSceneLoading) return;
InitializeSceneHistoryIfNeeded();
string current = SceneManager.GetActiveScene().name ?? string.Empty;
string target = PopPreviousSceneName(current);
if (string.IsNullOrEmpty(target))
{
target = string.IsNullOrEmpty(backFallbackSceneName) ? "Main_main" : backFallbackSceneName;
}
if (!string.IsNullOrEmpty(target) &&
!string.Equals(target, current, System.StringComparison.OrdinalIgnoreCase))
{
StartCoroutine(LoadNavSceneAsync(target));
}
}
private void OnHomeNavClicked()
{
if (navSceneLoading) return;
string target = string.IsNullOrEmpty(homeSceneName) ? "UI_UI" : homeSceneName;
StartCoroutine(LoadNavSceneAsync(target));
}
private void OnSettingsNavClicked()
{
ToggleSettingsPrefab();
}
private System.Collections.IEnumerator LoadNavSceneAsync(string sceneName)
{
if (string.IsNullOrEmpty(sceneName)) yield break;
if (navSceneLoading) yield break;
navSceneLoading = true;
Time.timeScale = 1f;
AsyncOperation op = SceneManager.LoadSceneAsync(sceneName, LoadSceneMode.Single);
while (op != null && !op.isDone)
{
yield return null;
}
navSceneLoading = false;
}
}
+6 -4
View File
@@ -1,4 +1,4 @@
using System.Collections.Generic;
using System.Collections.Generic;
using System.Linq;
using UnityEngine;
@@ -55,14 +55,16 @@ public class Music_Mgr : Singleton_Mono<Music_Mgr>
for (int i = 0; i < rawData.Length; i++)
{
Music_Data_List.Add(rawData[i]);
// 每 10 个数据等待一帧
if (i > 0 && i % 10 == 0) yield return null;
// Avoid a frame hitch if there are many clips in Resources.
if ((i & 7) == 7) yield return null;
}
if (Music_Data_List.Count > 0)
{
Play(Music_Data_List[0]);
}
yield break;
}
public void Play(Music_Data data)
{
@@ -74,4 +76,4 @@ public class Music_Mgr : Singleton_Mono<Music_Mgr>
{
return true;
}
}
}
@@ -1,17 +1,16 @@
using System.Collections;
using System.Collections;
using UnityEngine;
// 通过 PlayTween() 触发动画
// Documentation text normalized.
public class SimpleAxisTween : MonoBehaviour
{
public enum Axis { X, Y } // 轴向选项
public enum Axis { X, Y } // Documentation text normalized.
[Header("Tween Settings")]
public Axis axis = Axis.X; // 要缓动的轴
public float from = 0f; // 起始值
public float to = 100f; // 终点值
public float duration = 1f; // 总时长(秒)——外部可调
public Axis axis = Axis.X; // Documentation text normalized.
public float from = 0f;
public float to = 0f;
[Min(0.01f)] public float duration = 0.35f;
public AnimationCurve ease = AnimationCurve.EaseInOut(0, 0, 1, 1);
@@ -41,15 +40,15 @@ public class SimpleAxisTween : MonoBehaviour
elapsed += Time.unscaledDeltaTime;
float t = Mathf.Clamp01(elapsed / duration);
float easedT = ease.Evaluate(t);
float current = Mathf.Lerp(from, to, easedT);
// 缓动插值
float current = Mathf.LerpUnclamped(from, to, easedT);
// Documentation text normalized.
SetPosition(current);
yield return null;
}
// 强制落在终点
// Documentation text normalized.
SetPosition(to);
tweenCo = null;
}
@@ -71,4 +70,4 @@ public class SimpleAxisTween : MonoBehaviour
transform.localPosition = pos;
}
}
}
}
+615 -25
View File
@@ -1,43 +1,88 @@
using UnityEngine;
using UnityEngine;
using System;
using System.Collections;
using UnityEngine.SceneManagement;
using UnityEngine.UI;
#if UNITY_EDITOR
using UnityEditor;
#endif
/// <summary>
/// Simple pause manager. Call Pause(true) to pause or Pause(false) to resume.
/// - overlayRoot: GameObject that will be enabled when paused and disabled when resumed.
/// - Pressing Escape toggles pause while the manager exists.
/// Central gameplay pause manager.
/// - ESC / top-right Pause button can pause only in gameplay scene.
/// - Continue: hide pause panel, replay 3-2-1-Go, then resume chart + music.
/// - Replay: reload current gameplay scene (with current selected song/difficulty if available).
/// - Exit: return to selectYourSongFirst.
/// </summary>
public class PauseManager : MonoBehaviour
{
public static PauseManager Instance { get; private set; }
[Header("Overlay")]
public GameObject overlayRoot; // object to enable/disable on pause
public GameObject overlayRoot;
[SerializeField] private float overlayFadeDuration = 0.2f;
[SerializeField] private bool preferPausePrefabOverWhiteScreen = true;
[SerializeField] private string legacyWhiteScreenRootName = "pauseWhiteScreen";
[Header("Gameplay Scope")]
[SerializeField] private bool onlyInGameplayScene = true;
[SerializeField] private string gameplaySceneName = "gamePlay_gamePlay";
[SerializeField] private bool requirePlaybackStarted = true;
[Header("Buttons")]
[SerializeField] private string pauseButtonScenePath = "artworks/NEW UI/zhuangshi (3)/Pause";
[SerializeField] private Button pauseTriggerButton;
[SerializeField] private Button continueButton;
[SerializeField] private Button replayButton;
[SerializeField] private Button exitButton;
[SerializeField] private Button settingsButton;
[Header("Pause Entry Animation")]
[SerializeField] private bool playPauseEntryAnimation = true;
[SerializeField] private float pauseItemEnterDuration = 0.18f;
[SerializeField] private float pauseItemEnterStagger = 0.016f;
public bool IsPaused { get; private set; } = false;
// ͣ״̬ı¼
public event Action<bool> OnPauseStateChanged;
private CanvasGroup overlayCanvasGroup;
private RectTransform overlayPanelRoot;
private CanvasGroup overlayPanelCanvasGroup;
private Vector3 panelShownScale = Vector3.zero;
private static readonly Vector3 PanelHiddenScale = Vector3.zero;
private Coroutine overlayFadeCoroutine;
private Coroutine continueCoroutine;
private bool buttonsBound = false;
private float nextBindRetryTime = 0f;
private const string ExitSceneName = "selectYourSongFirst";
void Awake()
{
if (Instance == null) Instance = this;
else Destroy(gameObject);
else
{
Destroy(gameObject);
return;
}
}
void Start()
{
if (overlayRoot != null)
overlayRoot.SetActive(false);
ResolveOverlayRootForPausePrefab();
EnsureOverlayCanvasGroup();
EnsureOverlayPanelRoot();
SetOverlayVisibleImmediate(false);
TryBindButtons(force: true);
}
void Update()
{
// Delete = immediate quit (stop play in editor or quit app)
if (!buttonsBound && Time.unscaledTime >= nextBindRetryTime)
{
TryBindButtons(force: false);
}
if (Input.GetKeyDown(KeyCode.Delete))
{
#if UNITY_EDITOR
@@ -50,54 +95,599 @@ public class PauseManager : MonoBehaviour
if (Input.GetKeyDown(KeyCode.Escape))
{
TogglePause();
// User requested ESC as pause trigger in gameplay only.
if (CanPauseFromInput() && !IsPaused)
{
Pause(true);
}
}
// ͣ״̬Ұ Backspace ʱ
// Keep existing Backspace quick-exit while paused.
if (IsPaused && Input.GetKeyDown(KeyCode.Backspace))
{
// ָʱ¼Ȼ
Pause(false);
// ȷĿеƥ
StartCoroutine(LoadSceneAsync("Main_main"));
}
}
/// <summary>
/// Pause or resume the game. Call Pause(true) to pause.
/// This implementation enables/disables overlayRoot and sets Time.timeScale.
/// </summary>
public void Pause(bool pause)
{
if (pause)
{
if (IsPaused) return;
if (overlayRoot != null) overlayRoot.SetActive(true);
Time.timeScale = 0f;
IsPaused = true;
Time.timeScale = 0f;
OnPauseStateChanged?.Invoke(true);
// Startup flows call Pause(true) before real gameplay starts.
// In that phase we keep time paused but do not show pause UI.
bool allowOverlay = CanPauseFromInput();
if (allowOverlay)
ShowOverlayAnimated(true);
else
SetOverlayVisibleImmediate(false);
}
else
{
if (!IsPaused) return;
if (overlayRoot != null) overlayRoot.SetActive(false);
Time.timeScale = 1f;
IsPaused = false;
Time.timeScale = 1f;
OnPauseStateChanged?.Invoke(false);
ShowOverlayAnimated(false);
}
}
public void TogglePause()
{
Pause(!IsPaused);
if (!CanPauseFromInput()) return;
if (!IsPaused) Pause(true);
}
public void ContinueFromPause()
{
if (!IsPaused) return;
if (continueCoroutine != null) return;
continueCoroutine = StartCoroutine(ContinueFromPauseCoroutine());
}
public void ReplayFromPause()
{
if (!IsPaused) return;
if (continueCoroutine != null)
{
StopCoroutine(continueCoroutine);
continueCoroutine = null;
}
StartCoroutine(ReplayFromPauseCoroutine());
}
public void ExitFromPause()
{
if (!IsPaused) return;
if (continueCoroutine != null)
{
StopCoroutine(continueCoroutine);
continueCoroutine = null;
}
StartCoroutine(ExitFromPauseCoroutine());
}
private bool IsGameplaySceneActive()
{
string sceneName = SceneManager.GetActiveScene().name ?? string.Empty;
if (string.Equals(sceneName, gameplaySceneName, StringComparison.OrdinalIgnoreCase)) return true;
if (sceneName.IndexOf("gameplay", StringComparison.OrdinalIgnoreCase) >= 0) return true;
return false;
}
private bool CanPauseFromInput()
{
if (onlyInGameplayScene && !IsGameplaySceneActive()) return false;
if (!requirePlaybackStarted) return true;
var gm = FindAnyObjectByType<GameManager>();
if (gm == null) return false;
return gm.PlaybackStarted;
}
private void EnsureOverlayCanvasGroup()
{
if (overlayRoot == null) return;
overlayCanvasGroup = overlayRoot.GetComponent<CanvasGroup>();
if (overlayCanvasGroup == null)
overlayCanvasGroup = overlayRoot.AddComponent<CanvasGroup>();
}
private void ResolveOverlayRootForPausePrefab()
{
if (!preferPausePrefabOverWhiteScreen) return;
// Prefer the real pause prefab root (contains Continue/Replay/Exit).
GameObject pauseRoot = FindPauseMenuRootInScene();
if (pauseRoot != null)
{
overlayRoot = pauseRoot;
return;
}
if (overlayRoot == null) return;
// Legacy setup fallback: PauseManager points to pauseWhiteScreen.
if (!string.Equals(overlayRoot.name, legacyWhiteScreenRootName, StringComparison.OrdinalIgnoreCase))
return;
GameObject candidate = FindPauseOverlayCandidate(overlayRoot.transform);
if (candidate == null)
candidate = FindPauseOverlayCandidate(null);
if (candidate != null && candidate != overlayRoot)
overlayRoot = candidate;
}
private GameObject FindPauseOverlayCandidate(Transform searchRoot)
{
Canvas[] canvases = searchRoot != null
? searchRoot.GetComponentsInChildren<Canvas>(true)
: FindObjectsByType<Canvas>(FindObjectsInactive.Include, FindObjectsSortMode.None);
for (int i = 0; i < canvases.Length; i++)
{
Canvas canvas = canvases[i];
if (canvas == null) continue;
GameObject go = canvas.gameObject;
if (go == null || go == overlayRoot) continue;
if (!HasPauseButtons(go)) continue;
return go;
}
return null;
}
private GameObject FindPauseMenuRootInScene()
{
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.IsValid()) continue;
if (!string.Equals(t.name, "pause", StringComparison.OrdinalIgnoreCase)) continue;
GameObject go = t.gameObject;
if (HasPauseButtons(go))
return go;
}
// Fallback: any object that contains all three pause action buttons.
for (int i = 0; i < all.Length; i++)
{
var t = all[i];
if (t == null) continue;
if (!t.gameObject.scene.IsValid()) continue;
GameObject go = t.gameObject;
if (HasPauseButtons(go))
return go;
}
return null;
}
private static bool HasPauseButtons(GameObject root)
{
if (root == null) return false;
Button[] buttons = root.GetComponentsInChildren<Button>(true);
bool hasContinue = false;
bool hasReplay = false;
bool hasExit = false;
for (int i = 0; i < buttons.Length; i++)
{
Button b = buttons[i];
if (b == null) continue;
string n = b.gameObject.name;
if (string.Equals(n, "Continue", StringComparison.OrdinalIgnoreCase)) hasContinue = true;
else if (string.Equals(n, "Replay", StringComparison.OrdinalIgnoreCase)) hasReplay = true;
else if (string.Equals(n, "Exit", StringComparison.OrdinalIgnoreCase)) hasExit = true;
}
return hasContinue && hasReplay && hasExit;
}
private void EnsureOverlayPanelRoot()
{
if (overlayRoot == null) return;
if (overlayPanelRoot == null)
{
var canvases = overlayRoot.GetComponentsInChildren<Canvas>(true);
for (int i = 0; i < canvases.Length; i++)
{
var canvas = canvases[i];
if (canvas == null) continue;
if (canvas.gameObject == overlayRoot) continue;
overlayPanelRoot = canvas.GetComponent<RectTransform>();
if (overlayPanelRoot != null)
break;
}
if (overlayPanelRoot == null)
{
var rts = overlayRoot.GetComponentsInChildren<RectTransform>(true);
for (int i = 0; i < rts.Length; i++)
{
var rt = rts[i];
if (rt == null) continue;
if (rt.gameObject == overlayRoot) continue;
overlayPanelRoot = rt;
break;
}
}
}
if (overlayPanelRoot == null) return;
if (overlayPanelCanvasGroup == null)
{
overlayPanelCanvasGroup = overlayPanelRoot.GetComponent<CanvasGroup>();
if (overlayPanelCanvasGroup == null)
overlayPanelCanvasGroup = overlayPanelRoot.gameObject.AddComponent<CanvasGroup>();
}
if (IsScaleNearlyZero(panelShownScale))
{
Vector3 current = overlayPanelRoot.localScale;
panelShownScale = IsScaleNearlyZero(current) ? Vector3.one : current;
}
}
private static bool IsScaleNearlyZero(Vector3 scale)
{
return Mathf.Abs(scale.x) <= 0.0001f
&& Mathf.Abs(scale.y) <= 0.0001f
&& Mathf.Abs(scale.z) <= 0.0001f;
}
private void SetOverlayVisibleImmediate(bool visible)
{
if (overlayRoot == null) return;
EnsureOverlayCanvasGroup();
EnsureOverlayPanelRoot();
overlayRoot.SetActive(visible);
if (overlayCanvasGroup != null)
{
overlayCanvasGroup.alpha = visible ? 1f : 0f;
overlayCanvasGroup.interactable = visible;
overlayCanvasGroup.blocksRaycasts = visible;
}
if (overlayPanelCanvasGroup != null)
{
overlayPanelCanvasGroup.alpha = visible ? 1f : 0f;
overlayPanelCanvasGroup.interactable = visible;
overlayPanelCanvasGroup.blocksRaycasts = visible;
}
if (overlayPanelRoot != null)
{
overlayPanelRoot.localScale = visible ? panelShownScale : PanelHiddenScale;
}
}
private void ShowOverlayAnimated(bool show)
{
if (overlayRoot == null)
return;
EnsureOverlayCanvasGroup();
if (overlayFadeCoroutine != null)
{
StopCoroutine(overlayFadeCoroutine);
overlayFadeCoroutine = null;
}
overlayFadeCoroutine = StartCoroutine(FadeOverlayCoroutine(show));
}
private IEnumerator FadeOverlayCoroutine(bool show)
{
if (overlayRoot == null)
yield break;
EnsureOverlayCanvasGroup();
EnsureOverlayPanelRoot();
if (show && !overlayRoot.activeSelf)
overlayRoot.SetActive(true);
// Pause entry animation helper may be unavailable in some compile targets.
// Keep pause functionality independent from that optional visual effect.
float startA = overlayCanvasGroup != null ? overlayCanvasGroup.alpha : (show ? 0f : 1f);
float startPanelA = overlayPanelCanvasGroup != null ? overlayPanelCanvasGroup.alpha : startA;
float targetA = show ? 1f : 0f;
Vector3 startScale = overlayPanelRoot != null ? overlayPanelRoot.localScale : panelShownScale;
if (show && IsScaleNearlyZero(startScale))
startScale = PanelHiddenScale;
Vector3 targetScale = show ? panelShownScale : PanelHiddenScale;
float duration = Mathf.Max(0.01f, overlayFadeDuration);
float t = 0f;
if (show)
{
if (overlayCanvasGroup != null)
{
overlayCanvasGroup.interactable = true;
overlayCanvasGroup.blocksRaycasts = true;
}
if (overlayPanelCanvasGroup != null)
{
overlayPanelCanvasGroup.interactable = true;
overlayPanelCanvasGroup.blocksRaycasts = true;
}
}
else
{
if (overlayCanvasGroup != null)
{
overlayCanvasGroup.interactable = false;
overlayCanvasGroup.blocksRaycasts = false;
}
if (overlayPanelCanvasGroup != null)
{
overlayPanelCanvasGroup.interactable = false;
overlayPanelCanvasGroup.blocksRaycasts = false;
}
}
while (t < duration)
{
t += Time.unscaledDeltaTime;
float k = Mathf.Clamp01(t / duration);
if (overlayCanvasGroup != null)
overlayCanvasGroup.alpha = Mathf.Lerp(startA, targetA, k);
if (overlayPanelCanvasGroup != null)
overlayPanelCanvasGroup.alpha = Mathf.Lerp(startPanelA, targetA, k);
if (overlayPanelRoot != null)
overlayPanelRoot.localScale = Vector3.Lerp(startScale, targetScale, k);
yield return null;
}
if (overlayCanvasGroup != null)
overlayCanvasGroup.alpha = targetA;
if (overlayPanelCanvasGroup != null)
overlayPanelCanvasGroup.alpha = targetA;
if (overlayPanelRoot != null)
overlayPanelRoot.localScale = targetScale;
if (!show)
overlayRoot.SetActive(false);
overlayFadeCoroutine = null;
}
private IEnumerator ContinueFromPauseCoroutine()
{
// Start hiding panel, but do not wait before countdown starts.
ShowOverlayAnimated(false);
// Replay 3-2-1-Go immediately on continue click.
var gm = FindAnyObjectByType<GameManager>();
var ready = gm != null ? gm.readyLetsGo : FindAnyObjectByType<readyLetsGo>();
float originalWaitingDuration = 0f;
bool waitingDurationOverridden = false;
if (ready != null)
{
// Remove extra idle delay before countdown visuals in continue flow.
originalWaitingDuration = ready.waitingDuration;
ready.waitingDuration = 0f;
waitingDurationOverridden = true;
try { ready.ResetPlayState(); } catch { }
try { ready.PlaySequence(); } catch { }
int imageCount = ready._321goImages != null ? ready._321goImages.Count : 0;
float sequenceDuration = 0.25f
+ 0f
+ Mathf.Max(0f, imageCount * ready.oneImageDuration)
+ 0.15f;
if (sequenceDuration > 0f)
yield return new WaitForSecondsRealtime(sequenceDuration);
}
if (waitingDurationOverridden && ready != null)
{
ready.waitingDuration = originalWaitingDuration;
}
// Resume chart + music.
Pause(false);
continueCoroutine = null;
}
private IEnumerator ReplayFromPauseCoroutine()
{
SetOverlayVisibleImmediate(false);
IsPaused = false;
Time.timeScale = 1f;
try { OnPauseStateChanged?.Invoke(false); } catch { }
var bmm = FindAnyObjectByType<BeatmapManager>();
if (bmm != null && bmm.assignedSongData != null)
{
int diff = bmm.assignedDifficulty;
if (diff < 0) diff = 0;
BeatmapManager.SetPendingSong(bmm.assignedSongData, diff);
}
string current = SceneManager.GetActiveScene().name;
yield return LoadSceneAsync(current);
}
private IEnumerator ExitFromPauseCoroutine()
{
SetOverlayVisibleImmediate(false);
IsPaused = false;
Time.timeScale = 1f;
try { OnPauseStateChanged?.Invoke(false); } catch { }
yield return LoadSceneAsync(ExitSceneName);
}
private IEnumerator LoadSceneAsync(string sceneName)
{
AsyncOperation asyncLoad = SceneManager.LoadSceneAsync(sceneName);
while (!asyncLoad.isDone)
{
yield return null;
}
private void TryBindButtons(bool force)
{
if (buttonsBound && !force) return;
if (onlyInGameplayScene && !IsGameplaySceneActive() && !force)
{
nextBindRetryTime = Time.unscaledTime + 1f;
return;
}
if (pauseTriggerButton == null)
{
var pauseGO = GameObject.Find(pauseButtonScenePath);
if (pauseGO == null)
pauseGO = FindByNameInScene("Pause");
if (pauseGO != null)
pauseTriggerButton = pauseGO.GetComponent<Button>();
}
if (overlayRoot != null)
{
if (continueButton == null) continueButton = FindButtonInOverlay("Continue");
if (replayButton == null) replayButton = FindButtonInOverlay("Replay");
if (exitButton == null) exitButton = FindButtonInOverlay("Exit");
if (settingsButton == null) settingsButton = FindButtonInOverlay("settings");
}
if (pauseTriggerButton != null)
{
pauseTriggerButton.onClick.RemoveListener(OnPauseButtonClicked);
pauseTriggerButton.onClick.AddListener(OnPauseButtonClicked);
}
if (continueButton != null)
{
continueButton.onClick.RemoveListener(ContinueFromPause);
continueButton.onClick.AddListener(ContinueFromPause);
}
if (replayButton != null)
{
replayButton.onClick.RemoveListener(ReplayFromPause);
replayButton.onClick.AddListener(ReplayFromPause);
}
if (exitButton != null)
{
exitButton.onClick.RemoveListener(ExitFromPause);
exitButton.onClick.AddListener(ExitFromPause);
}
if (settingsButton != null)
{
settingsButton.onClick.RemoveListener(OnSettingsButtonClicked);
settingsButton.onClick.AddListener(OnSettingsButtonClicked);
}
buttonsBound = pauseTriggerButton != null && continueButton != null && replayButton != null && exitButton != null;
nextBindRetryTime = Time.unscaledTime + (buttonsBound ? 9999f : 1f);
}
private void OnPauseButtonClicked()
{
if (!CanPauseFromInput()) return;
if (!IsPaused) Pause(true);
}
private void OnSettingsButtonClicked()
{
if (!IsPaused) return;
if (TryOpenExistingSettingsPanel()) return;
var topController = FindAnyObjectByType<btmandtopController>();
if (topController != null)
{
topController.SendMessage("OnSettingsNavClicked", SendMessageOptions.DontRequireReceiver);
return;
}
Debug.LogWarning("[PauseManager] Settings button clicked, but no settings panel source was found.");
}
private bool TryOpenExistingSettingsPanel()
{
var settingsPanels = Resources.FindObjectsOfTypeAll<ui_Panel_Setting>();
for (int i = 0; i < settingsPanels.Length; i++)
{
ui_Panel_Setting panel = settingsPanels[i];
if (panel == null) continue;
GameObject go = panel.gameObject;
if (go == null || !go.scene.IsValid()) continue;
go.SetActive(true);
go.transform.SetAsLastSibling();
CanvasGroup cg = go.GetComponent<CanvasGroup>();
if (cg != null)
{
cg.interactable = true;
cg.blocksRaycasts = true;
}
UI_SettingsPanelEnterAnim enterAnim = go.GetComponent<UI_SettingsPanelEnterAnim>();
if (enterAnim != null) enterAnim.Play();
return true;
}
GameObject byName = FindByNameInScene("ui_Panel_Setting");
if (byName != null)
{
byName.SetActive(true);
byName.transform.SetAsLastSibling();
UI_SettingsPanelEnterAnim enterAnim = byName.GetComponent<UI_SettingsPanelEnterAnim>();
if (enterAnim != null) enterAnim.Play();
return true;
}
return false;
}
private Button FindButtonInOverlay(string buttonName)
{
if (overlayRoot == null || string.IsNullOrEmpty(buttonName)) return null;
var buttons = overlayRoot.GetComponentsInChildren<Button>(true);
for (int i = 0; i < buttons.Length; i++)
{
var b = buttons[i];
if (b == null) continue;
if (string.Equals(b.gameObject.name, buttonName, StringComparison.OrdinalIgnoreCase))
return b;
}
return null;
}
private GameObject FindByNameInScene(string name)
{
if (string.IsNullOrEmpty(name)) return null;
var all = Resources.FindObjectsOfTypeAll<Transform>();
for (int i = 0; i < all.Length; i++)
{
var t = all[i];
if (t == null) continue;
if (!string.Equals(t.name, name, StringComparison.OrdinalIgnoreCase)) continue;
if (t.gameObject.scene.IsValid())
return t.gameObject;
}
return null;
}
}
@@ -0,0 +1,180 @@
using System;
using System.Collections.Generic;
using DG.Tweening;
using UnityEngine;
using UnityEngine.UI;
public static class UI_OrderedEntryAnimator
{
public static Sequence Play(
Transform root,
float itemDuration,
float itemStagger,
Vector2 fromOffset,
bool useUnscaledTime,
Predicate<RectTransform> includePredicate = null)
{
if (root == null) return null;
List<RectTransform> targets = CollectTargets(root, includePredicate);
if (targets.Count == 0) return null;
targets.Sort(CompareByTopThenLeft);
float duration = Mathf.Max(0.01f, itemDuration);
float stagger = Mathf.Max(0f, itemStagger);
Sequence sequence = DOTween.Sequence().SetUpdate(useUnscaledTime);
for (int i = 0; i < targets.Count; i++)
{
RectTransform rt = targets[i];
if (rt == null || !rt.gameObject.activeInHierarchy) continue;
CanvasGroup group = rt.GetComponent<CanvasGroup>();
if (group == null) group = rt.gameObject.AddComponent<CanvasGroup>();
rt.DOKill();
group.DOKill();
Vector2 basePos = rt.anchoredPosition;
float baseAlpha = group.alpha <= 0f ? 1f : group.alpha;
rt.anchoredPosition = basePos + fromOffset;
group.alpha = 0f;
float startAt = i * stagger;
sequence.Insert(startAt, rt.DOAnchorPos(basePos, duration).SetEase(Ease.OutCubic).SetUpdate(useUnscaledTime));
sequence.Insert(startAt, group.DOFade(baseAlpha, duration).SetEase(Ease.OutCubic).SetUpdate(useUnscaledTime));
}
return sequence;
}
public static Sequence PlayKeyDownFlash(
Transform keyDownRoot,
bool useUnscaledTime,
float fromYOffset = 36f,
float itemStagger = 0.03f)
{
if (keyDownRoot == null) return null;
List<RectTransform> targets = CollectKeyDownRects(keyDownRoot);
if (targets.Count == 0) return null;
targets.Sort(CompareByTopThenLeft);
Sequence sequence = DOTween.Sequence().SetUpdate(useUnscaledTime);
float moveDuration = 0.1f;
float stagger = Mathf.Max(0f, itemStagger);
float offsetY = Mathf.Abs(fromYOffset);
for (int i = 0; i < targets.Count; i++)
{
RectTransform rt = targets[i];
if (rt == null || !rt.gameObject.activeInHierarchy) continue;
CanvasGroup group = rt.GetComponent<CanvasGroup>();
if (group == null) group = rt.gameObject.AddComponent<CanvasGroup>();
rt.DOKill();
group.DOKill();
Vector2 basePos = rt.anchoredPosition;
rt.anchoredPosition = basePos - new Vector2(0f, offsetY);
group.alpha = 0f;
float startAt = i * stagger;
sequence.Insert(startAt, rt.DOAnchorPos(basePos, moveDuration).SetEase(Ease.OutCubic).SetUpdate(useUnscaledTime));
sequence.Insert(startAt, group.DOFade(1f, 0.028f).SetEase(Ease.Linear).SetUpdate(useUnscaledTime));
sequence.Insert(startAt + 0.028f, group.DOFade(0.2f, 0.026f).SetEase(Ease.Linear).SetUpdate(useUnscaledTime));
sequence.Insert(startAt + 0.054f, group.DOFade(1f, 0.04f).SetEase(Ease.OutCubic).SetUpdate(useUnscaledTime));
}
return sequence;
}
public static bool IsNamedOrChildOf(Transform target, string name)
{
if (target == null || string.IsNullOrEmpty(name)) return false;
Transform it = target;
while (it != null)
{
if (string.Equals(it.name, name, StringComparison.OrdinalIgnoreCase))
return true;
it = it.parent;
}
return false;
}
private static List<RectTransform> CollectTargets(Transform root, Predicate<RectTransform> includePredicate)
{
List<RectTransform> list = new List<RectTransform>(128);
HashSet<RectTransform> seen = new HashSet<RectTransform>();
Stack<Transform> stack = new Stack<Transform>();
stack.Push(root);
while (stack.Count > 0)
{
Transform parent = stack.Pop();
if (parent == null) continue;
for (int i = 0; i < parent.childCount; i++)
{
Transform child = parent.GetChild(i);
if (child == null) continue;
stack.Push(child);
RectTransform rt = child as RectTransform;
if (rt == null || !child.gameObject.activeInHierarchy) continue;
if (includePredicate != null && !includePredicate(rt)) continue;
if (!IsPanelLike(child)) continue;
if (!seen.Add(rt)) continue;
list.Add(rt);
}
}
return list;
}
private static List<RectTransform> CollectKeyDownRects(Transform root)
{
List<RectTransform> list = new List<RectTransform>(16);
RectTransform[] all = root.GetComponentsInChildren<RectTransform>(true);
for (int i = 0; i < all.Length; i++)
{
RectTransform rt = all[i];
if (rt == null || !rt.gameObject.activeInHierarchy) continue;
if (rt == root) continue;
string n = rt.name ?? string.Empty;
if (n.IndexOf("sdw 3", StringComparison.OrdinalIgnoreCase) < 0) continue;
list.Add(rt);
}
return list;
}
private static bool IsPanelLike(Transform tr)
{
if (tr == null) return false;
if (tr.GetComponent<Selectable>() != null) return true;
if (tr.GetComponent<Graphic>() != null) return true;
if (tr.GetComponent<LayoutGroup>() != null) return true;
if (tr.GetComponent<CanvasGroup>() != null) return true;
return tr.childCount > 0;
}
private static int CompareByTopThenLeft(RectTransform a, RectTransform 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 xOrder = pa.x.CompareTo(pb.x); // left -> right
if (xOrder != 0) return xOrder;
return -pa.y.CompareTo(pb.y); // top -> bottom
}
}
@@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: 893b9011544d6c14ab8eee7fc3b45b3b
+14 -3
View File
@@ -15,7 +15,9 @@ public class UI_Show_Anim : MonoBehaviour
{
canvasGroup.alpha = 0;
float a = 0;
DOTween.To(() => a, (f) => { a = f; canvasGroup.alpha = f; }, 1, animTime_Alpha).SetUpdate(true);
DOTween.To(() => a, (f) => { a = f; canvasGroup.alpha = f; }, 1, animTime_Alpha)
.SetUpdate(true)
.SetTarget(canvasGroup);
}
}
public void Close()
@@ -25,11 +27,20 @@ public class UI_Show_Anim : MonoBehaviour
if (gameObject.Try_Get_Component(out CanvasGroup canvasGroup))
{
float a = 1;
DOTween.To(() => a, (f) => { a = f; canvasGroup.alpha = f; }, 0, animTime_Alpha).SetUpdate(true);
DOTween.To(() => a, (f) => { a = f; canvasGroup.alpha = f; }, 0, animTime_Alpha)
.SetUpdate(true)
.SetTarget(canvasGroup);
}
}
void Clear()
{
DOTween.KillAll(transform);
// Only kill tweens that belong to this UI element.
// Passing a Transform into DOTween.KillAll(...) is dangerous in Unity because Transform has an implicit bool
// conversion, which ends up calling KillAll(true) and wipes tweens globally.
transform.DOKill();
if (gameObject.Try_Get_Component(out CanvasGroup canvasGroup))
{
canvasGroup.DOKill();
}
}
}
@@ -0,0 +1,279 @@
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.SceneManagement;
using UnityEngine.UI;
public class UI_UnimplementedFeatureBlocker : MonoBehaviour
{
public static bool RuntimeEnabled = false;
[SerializeField] private string[] blockedButtonNames =
{
"Button_STORY",
"Button_IDOL",
"Button_NOTEBOOK",
"launchEzGame",
"Button_CHARACTER_SET",
"Button_Market",
"Button_Personal_information",
"Button_view_level",
"Button_Mail",
"Button_notice"
};
private Coroutine bindRoutine;
private Coroutine continuousBindRoutine;
private void OnEnable()
{
if (!RuntimeEnabled)
{
CleanupOverlaysInLoadedScenes();
enabled = false;
return;
}
SceneManager.sceneLoaded -= OnSceneLoaded;
SceneManager.sceneLoaded += OnSceneLoaded;
StartBind(SceneManager.GetActiveScene());
if (continuousBindRoutine == null)
continuousBindRoutine = StartCoroutine(ContinuousBindLoop());
}
private void OnDisable()
{
SceneManager.sceneLoaded -= OnSceneLoaded;
if (bindRoutine != null)
{
StopCoroutine(bindRoutine);
bindRoutine = null;
}
if (continuousBindRoutine != null)
{
StopCoroutine(continuousBindRoutine);
continuousBindRoutine = null;
}
}
private void OnSceneLoaded(Scene scene, LoadSceneMode mode)
{
StartBind(scene);
}
private void StartBind(Scene scene)
{
if (!scene.IsValid() || !scene.isLoaded)
return;
if (bindRoutine != null)
{
StopCoroutine(bindRoutine);
bindRoutine = null;
}
bindRoutine = StartCoroutine(BindRoutine(scene));
}
private IEnumerator BindRoutine(Scene scene)
{
// Repeat binding multiple times so we override listeners added in Start/OnEnable by scene scripts.
for (int i = 0; i < 4; i++)
{
ApplyBlockers();
yield return new WaitForSecondsRealtime(0.12f);
}
bindRoutine = null;
}
private IEnumerator ContinuousBindLoop()
{
while (enabled)
{
ApplyBlockers();
yield return new WaitForSecondsRealtime(0.5f);
}
}
private void ApplyBlockers()
{
if (blockedButtonNames == null || blockedButtonNames.Length == 0)
return;
HashSet<Button> candidates = new HashSet<Button>();
Transform[] all = UnityEngine.Object.FindObjectsByType<Transform>(FindObjectsInactive.Include, FindObjectsSortMode.None);
for (int j = 0; j < all.Length; j++)
{
Transform t = all[j];
if (t == null)
continue;
if (!t.gameObject.scene.IsValid() || !t.gameObject.scene.isLoaded)
continue;
if (!IsBlockedName(t.name))
continue;
CollectNearbyButtons(t, candidates);
}
foreach (Button btn in candidates)
{
if (btn == null)
continue;
btn.onClick.RemoveAllListeners();
btn.onClick.AddListener(OnBlockedButtonClick);
EnsureOverlayClickBlocker(btn);
}
}
private void CollectNearbyButtons(Transform target, HashSet<Button> set)
{
if (target == null || set == null)
return;
Button self = target.GetComponent<Button>();
if (self != null)
set.Add(self);
Button parent = target.GetComponentInParent<Button>(true);
if (parent != null)
set.Add(parent);
Button[] children = target.GetComponentsInChildren<Button>(true);
for (int i = 0; i < children.Length; i++)
{
if (children[i] != null)
set.Add(children[i]);
}
}
private bool IsBlockedName(string objectName)
{
if (string.IsNullOrEmpty(objectName) || blockedButtonNames == null)
return false;
string current = NormalizeName(objectName);
for (int i = 0; i < blockedButtonNames.Length; i++)
{
string target = blockedButtonNames[i];
if (string.IsNullOrEmpty(target))
continue;
string normalizedTarget = NormalizeName(target);
if (current == normalizedTarget)
return true;
if (current.Contains(normalizedTarget) || normalizedTarget.Contains(current))
return true;
}
return false;
}
private string NormalizeName(string value)
{
if (string.IsNullOrEmpty(value))
return string.Empty;
return value
.Replace(" ", "")
.Replace("_", "")
.Replace("-", "")
.ToLowerInvariant();
}
private void EnsureOverlayClickBlocker(Button sourceButton)
{
if (sourceButton == null) return;
const string overlayName = "__BlockedFeatureOverlay";
Transform host = sourceButton.targetGraphic != null
? sourceButton.targetGraphic.transform
: sourceButton.transform;
if (host == null)
host = sourceButton.transform;
Transform existing = host.Find(overlayName);
GameObject overlayGo;
if (existing == null)
{
overlayGo = new GameObject(overlayName, typeof(RectTransform), typeof(Image), typeof(Button));
overlayGo.transform.SetParent(host, false);
RectTransform rt = overlayGo.GetComponent<RectTransform>();
rt.anchorMin = Vector2.zero;
rt.anchorMax = Vector2.one;
rt.offsetMin = Vector2.zero;
rt.offsetMax = Vector2.zero;
rt.localScale = Vector3.one;
Image img = overlayGo.GetComponent<Image>();
img.color = new Color(1f, 1f, 1f, 0f);
img.raycastTarget = true;
}
else
{
overlayGo = existing.gameObject;
}
overlayGo.SetActive(true);
overlayGo.transform.SetAsLastSibling();
Button overlayBtn = overlayGo.GetComponent<Button>();
if (overlayBtn != null)
{
overlayBtn.transition = Selectable.Transition.None;
overlayBtn.onClick.RemoveAllListeners();
overlayBtn.onClick.AddListener(OnBlockedButtonClick);
}
}
private void OnBlockedButtonClick()
{
if (!RuntimeEnabled)
return;
UnimplementedFeaturePrompt.ShowPrompt();
}
private static void CleanupOverlaysInLoadedScenes()
{
Transform[] all = UnityEngine.Object.FindObjectsByType<Transform>(FindObjectsInactive.Include, FindObjectsSortMode.None);
for (int i = 0; i < all.Length; i++)
{
Transform t = all[i];
if (t == null)
continue;
if (!t.gameObject.scene.IsValid() || !t.gameObject.scene.isLoaded)
continue;
if (!string.Equals(t.name, "__BlockedFeatureOverlay", System.StringComparison.Ordinal))
continue;
if (Application.isPlaying)
UnityEngine.Object.Destroy(t.gameObject);
else
UnityEngine.Object.DestroyImmediate(t.gameObject);
}
}
}
static class UI_UnimplementedFeatureBlockerBootstrap
{
[RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.BeforeSceneLoad)]
private static void Init()
{
if (!UI_UnimplementedFeatureBlocker.RuntimeEnabled)
{
GameObject old = GameObject.Find("__UnimplementedFeatureBlockerHost");
if (old != null)
UnityEngine.Object.Destroy(old);
return;
}
GameObject host = GameObject.Find("__UnimplementedFeatureBlockerHost");
if (host == null)
host = new GameObject("__UnimplementedFeatureBlockerHost");
UnityEngine.Object.DontDestroyOnLoad(host);
if (host.GetComponent<UI_UnimplementedFeatureBlocker>() == null)
host.AddComponent<UI_UnimplementedFeatureBlocker>();
}
}
@@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: d6590632f0e73e14fa145e8027875df2
@@ -0,0 +1,485 @@
using System.Collections;
using UnityEngine;
using UnityEngine.SceneManagement;
using UnityEngine.UI;
public class UnimplementedFeaturePrompt : MonoBehaviour
{
public static bool RuntimeEnabled = false;
private static UnimplementedFeaturePrompt instance;
[Header("Flash")]
[SerializeField] private int flashCount = 2;
[SerializeField] private float flashOnTime = 0.04f;
[SerializeField] private float flashOffTime = 0.03f;
private GameObject root;
private GameObject pressText;
private GameObject noChoice;
private GameObject choiceLessThanFive;
private GameObject image3;
private Button continueButton;
private Button considerButton;
private Button doNotShowAgainButton;
private Button okayButton;
private Coroutine flashRoutine;
public static void ShowPrompt()
{
if (!RuntimeEnabled)
return;
EnsureInstance();
if (instance != null)
instance.ShowInternal();
}
private static void EnsureInstance()
{
if (instance != null)
return;
GameObject host = GameObject.Find("__UnimplementedFeaturePromptHost");
if (host == null)
{
host = new GameObject("__UnimplementedFeaturePromptHost");
DontDestroyOnLoad(host);
}
instance = host.GetComponent<UnimplementedFeaturePrompt>();
if (instance == null)
instance = host.AddComponent<UnimplementedFeaturePrompt>();
}
private void OnEnable()
{
SceneManager.sceneLoaded -= OnSceneLoaded;
SceneManager.sceneLoaded += OnSceneLoaded;
}
private void OnDisable()
{
SceneManager.sceneLoaded -= OnSceneLoaded;
}
private void OnSceneLoaded(Scene scene, LoadSceneMode mode)
{
// Re-resolve references every scene so we can reuse existing UI if present.
root = null;
pressText = null;
noChoice = null;
choiceLessThanFive = null;
image3 = null;
continueButton = null;
considerButton = null;
doNotShowAgainButton = null;
okayButton = null;
}
private void ShowInternal()
{
EnsurePromptRoot();
if (root == null)
{
Debug.LogWarning("[UnimplementedFeaturePrompt] Prompt root was not found and fallback creation failed.");
return;
}
EnsureMinimumPromptElements();
BringRootToFront();
BindOkayButton();
root.SetActive(true);
CanvasGroup rootGroup = root.GetComponent<CanvasGroup>();
if (rootGroup != null)
rootGroup.alpha = 1f;
SetActiveSafe(noChoice, false);
SetActiveSafe(choiceLessThanFive, false);
SetActiveSafe(image3, false);
SetButtonVisible(continueButton, false);
SetButtonVisible(considerButton, false);
SetButtonVisible(doNotShowAgainButton, false);
SetButtonVisible(okayButton, true);
SetActiveSafe(pressText, true);
if (flashRoutine != null)
StopCoroutine(flashRoutine);
flashRoutine = StartCoroutine(FlashMessage());
}
private IEnumerator FlashMessage()
{
GameObject target = pressText != null ? pressText : root;
if (target == null)
yield break;
CanvasGroup cg = target.GetComponent<CanvasGroup>();
if (cg == null)
cg = target.AddComponent<CanvasGroup>();
int count = Mathf.Max(1, flashCount);
float onTime = Mathf.Clamp(flashOnTime, 0.01f, 0.05f);
float offTime = Mathf.Clamp(flashOffTime, 0.01f, 0.05f);
cg.alpha = 0f;
for (int i = 0; i < count; i++)
{
cg.alpha = 1f;
yield return new WaitForSecondsRealtime(onTime);
if (i < count - 1)
{
cg.alpha = 0f;
yield return new WaitForSecondsRealtime(offTime);
}
}
cg.alpha = 1f;
flashRoutine = null;
}
private void OnOkayClicked()
{
if (flashRoutine != null)
{
StopCoroutine(flashRoutine);
flashRoutine = null;
}
if (root != null)
root.SetActive(false);
}
private void BindOkayButton()
{
if (okayButton == null)
return;
okayButton.onClick.RemoveListener(OnOkayClicked);
okayButton.onClick.AddListener(OnOkayClicked);
}
private void EnsurePromptRoot()
{
Scene activeScene = SceneManager.GetActiveScene();
if (root != null && root.scene.IsValid() && root.scene == activeScene)
return;
root = FindSceneObjectByExactName("\uFF01mustselectyouridol");
if (root == null)
root = FindSceneObjectByContainsName("mustselectyouridol");
if (root == null)
root = CreateFallbackPrompt();
if (root == null)
return;
pressText = FindChildByName(root.transform, "Press an unimplemented feature");
if (pressText == null)
pressText = FindChildByName(root.transform, "pressanunimplementedfeature");
noChoice = FindChildByName(root.transform, "No choice");
choiceLessThanFive = FindChildByName(root.transform, "choice < 5");
image3 = FindChildByName(root.transform, "Image (3)");
continueButton = FindButtonByName(root.transform, "Continue");
considerButton = FindButtonByName(root.transform, "Consider");
doNotShowAgainButton = FindButtonByName(root.transform, "Do not show again");
okayButton = FindButtonByName(root.transform, "okay");
if (okayButton == null)
okayButton = FindButtonByContainsName(root.transform, "ok");
}
private GameObject CreateFallbackPrompt()
{
Canvas canvas = FindTopCanvasInActiveScene();
if (canvas == null)
canvas = CreateFallbackCanvas();
if (canvas == null)
return null;
GameObject rootGo = new GameObject("\uFF01mustselectyouridol", typeof(RectTransform), typeof(CanvasGroup), typeof(Image));
rootGo.transform.SetParent(canvas.transform, false);
RectTransform rootRt = rootGo.GetComponent<RectTransform>();
rootRt.anchorMin = Vector2.zero;
rootRt.anchorMax = Vector2.one;
rootRt.offsetMin = Vector2.zero;
rootRt.offsetMax = Vector2.zero;
Image bg = rootGo.GetComponent<Image>();
bg.color = new Color(0f, 0f, 0f, 0.35f);
GameObject textGo = new GameObject("Press an unimplemented feature", typeof(RectTransform), typeof(Text));
textGo.transform.SetParent(rootGo.transform, false);
RectTransform textRt = textGo.GetComponent<RectTransform>();
textRt.anchorMin = new Vector2(0.5f, 0.5f);
textRt.anchorMax = new Vector2(0.5f, 0.5f);
textRt.sizeDelta = new Vector2(820f, 80f);
textRt.anchoredPosition = new Vector2(0f, 40f);
Text t = textGo.GetComponent<Text>();
t.font = Resources.GetBuiltinResource<Font>("LegacyRuntime.ttf");
t.fontSize = 40;
t.alignment = TextAnchor.MiddleCenter;
t.color = Color.white;
t.text = "Press an unimplemented feature";
GameObject okayGo = new GameObject("okay", typeof(RectTransform), typeof(Image), typeof(Button));
okayGo.transform.SetParent(rootGo.transform, false);
RectTransform okayRt = okayGo.GetComponent<RectTransform>();
okayRt.anchorMin = new Vector2(0.5f, 0.5f);
okayRt.anchorMax = new Vector2(0.5f, 0.5f);
okayRt.sizeDelta = new Vector2(200f, 60f);
okayRt.anchoredPosition = new Vector2(0f, -40f);
Image okBg = okayGo.GetComponent<Image>();
okBg.color = Color.white;
GameObject okayTextGo = new GameObject("Text (Legacy)", typeof(RectTransform), typeof(Text));
okayTextGo.transform.SetParent(okayGo.transform, false);
RectTransform okayTextRt = okayTextGo.GetComponent<RectTransform>();
okayTextRt.anchorMin = Vector2.zero;
okayTextRt.anchorMax = Vector2.one;
okayTextRt.offsetMin = Vector2.zero;
okayTextRt.offsetMax = Vector2.zero;
Text okText = okayTextGo.GetComponent<Text>();
okText.font = Resources.GetBuiltinResource<Font>("LegacyRuntime.ttf");
okText.fontSize = 30;
okText.alignment = TextAnchor.MiddleCenter;
okText.color = new Color(0.23f, 0.23f, 0.23f, 1f);
okText.text = "okay";
return rootGo;
}
private static void SetButtonVisible(Button button, bool visible)
{
if (button != null)
button.gameObject.SetActive(visible);
}
private static void SetActiveSafe(GameObject go, bool active)
{
if (go != null)
go.SetActive(active);
}
private static GameObject FindSceneObjectByExactName(string objectName)
{
if (string.IsNullOrEmpty(objectName))
return null;
Scene scene = SceneManager.GetActiveScene();
Transform[] all = UnityEngine.Object.FindObjectsByType<Transform>(FindObjectsInactive.Include, FindObjectsSortMode.None);
for (int i = 0; i < all.Length; i++)
{
Transform t = all[i];
if (t == null || t.gameObject.scene != scene)
continue;
if (string.Equals(t.name, objectName, System.StringComparison.OrdinalIgnoreCase))
return t.gameObject;
}
return null;
}
private static GameObject FindSceneObjectByContainsName(string token)
{
if (string.IsNullOrEmpty(token))
return null;
Scene scene = SceneManager.GetActiveScene();
Transform[] all = UnityEngine.Object.FindObjectsByType<Transform>(FindObjectsInactive.Include, FindObjectsSortMode.None);
for (int i = 0; i < all.Length; i++)
{
Transform t = all[i];
if (t == null || t.gameObject.scene != scene)
continue;
if (t.name.IndexOf(token, System.StringComparison.OrdinalIgnoreCase) >= 0)
return t.gameObject;
}
return null;
}
private static GameObject FindChildByName(Transform root, string childName)
{
if (root == null || string.IsNullOrEmpty(childName))
return null;
Transform[] children = root.GetComponentsInChildren<Transform>(true);
for (int i = 0; i < children.Length; i++)
{
Transform c = children[i];
if (c != null && string.Equals(c.name, childName, System.StringComparison.OrdinalIgnoreCase))
return c.gameObject;
}
return null;
}
private static Button FindButtonByName(Transform root, string buttonName)
{
if (root == null || string.IsNullOrEmpty(buttonName))
return null;
Button[] buttons = root.GetComponentsInChildren<Button>(true);
for (int i = 0; i < buttons.Length; i++)
{
Button b = buttons[i];
if (b != null && string.Equals(b.name, buttonName, System.StringComparison.OrdinalIgnoreCase))
return b;
}
return null;
}
private static Button FindButtonByContainsName(Transform root, string token)
{
if (root == null || string.IsNullOrEmpty(token))
return null;
string normalizedToken = token.Replace(" ", "").ToLowerInvariant();
Button[] buttons = root.GetComponentsInChildren<Button>(true);
for (int i = 0; i < buttons.Length; i++)
{
Button b = buttons[i];
if (b == null)
continue;
string current = b.name.Replace(" ", "").ToLowerInvariant();
if (current.Contains(normalizedToken))
return b;
}
return null;
}
private static Canvas FindTopCanvasInActiveScene()
{
Scene scene = SceneManager.GetActiveScene();
Canvas[] canvases = UnityEngine.Object.FindObjectsByType<Canvas>(FindObjectsInactive.Include, FindObjectsSortMode.None);
Canvas best = null;
int bestOrder = int.MinValue;
for (int i = 0; i < canvases.Length; i++)
{
Canvas c = canvases[i];
if (c == null || c.gameObject.scene != scene)
continue;
int order = c.sortingOrder;
if (c.renderMode == RenderMode.ScreenSpaceOverlay)
order += 10000;
if (best == null || order > bestOrder)
{
best = c;
bestOrder = order;
}
}
return best;
}
private static Canvas CreateFallbackCanvas()
{
Scene scene = SceneManager.GetActiveScene();
if (!scene.IsValid() || !scene.isLoaded)
return null;
GameObject go = new GameObject("__UnimplementedPromptCanvas",
typeof(RectTransform),
typeof(Canvas),
typeof(CanvasScaler),
typeof(GraphicRaycaster));
try
{
SceneManager.MoveGameObjectToScene(go, scene);
}
catch
{
// keep default scene placement if move fails
}
Canvas canvas = go.GetComponent<Canvas>();
if (canvas != null)
{
canvas.renderMode = RenderMode.ScreenSpaceOverlay;
canvas.sortingOrder = 32700;
}
CanvasScaler scaler = go.GetComponent<CanvasScaler>();
if (scaler != null)
{
scaler.uiScaleMode = CanvasScaler.ScaleMode.ScaleWithScreenSize;
scaler.referenceResolution = new Vector2(1920f, 1080f);
scaler.matchWidthOrHeight = 0.5f;
}
return canvas;
}
private void EnsureMinimumPromptElements()
{
if (root == null)
return;
if (pressText == null)
{
GameObject textGo = new GameObject("Press an unimplemented feature", typeof(RectTransform), typeof(Text));
textGo.transform.SetParent(root.transform, false);
RectTransform textRt = textGo.GetComponent<RectTransform>();
textRt.anchorMin = new Vector2(0.5f, 0.5f);
textRt.anchorMax = new Vector2(0.5f, 0.5f);
textRt.sizeDelta = new Vector2(820f, 80f);
textRt.anchoredPosition = new Vector2(0f, 40f);
Text t = textGo.GetComponent<Text>();
t.font = Resources.GetBuiltinResource<Font>("LegacyRuntime.ttf");
t.fontSize = 40;
t.alignment = TextAnchor.MiddleCenter;
t.color = Color.white;
t.text = "Press an unimplemented feature";
pressText = textGo;
}
if (okayButton == null)
{
GameObject okayGo = new GameObject("okay", typeof(RectTransform), typeof(Image), typeof(Button));
okayGo.transform.SetParent(root.transform, false);
RectTransform okayRt = okayGo.GetComponent<RectTransform>();
okayRt.anchorMin = new Vector2(0.5f, 0.5f);
okayRt.anchorMax = new Vector2(0.5f, 0.5f);
okayRt.sizeDelta = new Vector2(200f, 60f);
okayRt.anchoredPosition = new Vector2(0f, -40f);
Image okBg = okayGo.GetComponent<Image>();
okBg.color = Color.white;
GameObject textGo = new GameObject("Text (Legacy)", typeof(RectTransform), typeof(Text));
textGo.transform.SetParent(okayGo.transform, false);
RectTransform textRt = textGo.GetComponent<RectTransform>();
textRt.anchorMin = Vector2.zero;
textRt.anchorMax = Vector2.one;
textRt.offsetMin = Vector2.zero;
textRt.offsetMax = Vector2.zero;
Text t = textGo.GetComponent<Text>();
t.font = Resources.GetBuiltinResource<Font>("LegacyRuntime.ttf");
t.fontSize = 30;
t.alignment = TextAnchor.MiddleCenter;
t.color = new Color(0.23f, 0.23f, 0.23f, 1f);
t.text = "okay";
okayButton = okayGo.GetComponent<Button>();
}
}
private void BringRootToFront()
{
if (root == null)
return;
Canvas canvas = root.GetComponent<Canvas>();
if (canvas == null)
canvas = root.AddComponent<Canvas>();
if (root.GetComponent<GraphicRaycaster>() == null)
root.AddComponent<GraphicRaycaster>();
canvas.overrideSorting = true;
canvas.sortingOrder = 32700;
if (root.transform.parent != null)
root.transform.SetAsLastSibling();
}
}
@@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: 39a418c2032c3cc4899163d987dfd3e1