技能主要更新,修复卡顿并加入动画,以及各种其他更新。

This commit is contained in:
FloatGaming
2026-02-07 21:05:17 +08:00
parent abeca51be5
commit 1ac3cd0104
1349 changed files with 1526749 additions and 24850 deletions
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,116 @@
using UnityEngine;
using UnityEngine.EventSystems;
using UnityEngine.UI;
public class BottomBarButtonHover : MonoBehaviour, IPointerEnterHandler, IPointerExitHandler, IPointerDownHandler, IPointerUpHandler, IPointerMoveHandler
{
public float hoverScale = 1.06f;
public float pressScale = 0.92f;
public float hoverWidthScale = 1.08f;
public float scaleLerp = 12f;
public float gyroAngle = 6f;
public float gyroLerp = 12f;
private RectTransform rect;
private LayoutElement layout;
private float basePreferredWidth;
private Vector3 baseScale;
private bool hovering;
private bool pressed;
private Vector3 targetScale;
private Quaternion targetRotation = Quaternion.identity;
private Camera eventCamera;
private RectTransform layoutRoot;
private void Awake()
{
rect = GetComponent<RectTransform>();
baseScale = transform.localScale;
targetScale = baseScale;
layout = GetComponent<LayoutElement>();
if (layout == null)
layout = gameObject.AddComponent<LayoutElement>();
basePreferredWidth = layout.preferredWidth;
if (basePreferredWidth <= 0f && rect != null)
basePreferredWidth = rect.rect.width;
if (basePreferredWidth <= 0f)
basePreferredWidth = 100f;
layout.preferredWidth = basePreferredWidth;
var group = GetComponentInParent<LayoutGroup>();
if (group != null)
layoutRoot = group.GetComponent<RectTransform>();
}
private void Update()
{
float dt = Time.unscaledDeltaTime;
transform.localScale = Vector3.Lerp(transform.localScale, targetScale, 1f - Mathf.Exp(-scaleLerp * dt));
if (hovering)
{
Vector2 localPoint;
if (rect != null && RectTransformUtility.ScreenPointToLocalPointInRectangle(rect, Input.mousePosition, eventCamera, out localPoint))
{
Vector2 size = rect.rect.size;
float nx = size.x > 0f ? localPoint.x / size.x : 0f;
float ny = size.y > 0f ? localPoint.y / size.y : 0f;
float rotX = -ny * gyroAngle * 2f;
float rotY = nx * gyroAngle * 2f;
targetRotation = Quaternion.Euler(rotX, rotY, 0f);
}
}
else
{
targetRotation = Quaternion.identity;
}
transform.localRotation = Quaternion.Slerp(transform.localRotation, targetRotation, 1f - Mathf.Exp(-gyroLerp * dt));
}
public void OnPointerEnter(PointerEventData eventData)
{
hovering = true;
eventCamera = eventData.pressEventCamera;
layout.preferredWidth = basePreferredWidth * hoverWidthScale;
RebuildLayout();
if (!pressed)
targetScale = baseScale * hoverScale;
}
public void OnPointerExit(PointerEventData eventData)
{
hovering = false;
layout.preferredWidth = basePreferredWidth;
RebuildLayout();
if (!pressed)
targetScale = baseScale;
}
public void OnPointerDown(PointerEventData eventData)
{
pressed = true;
targetScale = baseScale * pressScale;
}
public void OnPointerUp(PointerEventData eventData)
{
pressed = false;
targetScale = baseScale * (hovering ? hoverScale : 1f);
}
public void OnPointerMove(PointerEventData eventData)
{
eventCamera = eventData.pressEventCamera;
}
private void RebuildLayout()
{
if (layoutRoot != null)
LayoutRebuilder.ForceRebuildLayoutImmediate(layoutRoot);
}
}
@@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: a3c858fc56d8aa84daefcd0121bcadd8
File diff suppressed because it is too large Load Diff
@@ -16,6 +16,13 @@ public class btmandtopController : MonoBehaviour
public Button email_display;
public Button notice_display;
public Button button_Music;
[Header("MusicPic")]
public RectTransform musicPicRoot;
public bool showMusicPicInUI = false;
public string uiSceneName = "UI_UI";
public float musicPicFadeTime = 0.25f;
[Header("sig prefabs")]
public GameObject showLevel_prefab;
public GameObject store_prefab;
@@ -33,15 +40,37 @@ public class btmandtopController : MonoBehaviour
// cached reference to the settings instance to ensure only one exists
private GameObject settingsInstance;
private GameObject showLevelInstance;
private GameObject emailInstance;
private GameObject noticeInstance;
private CanvasGroup musicPicGroup;
private Coroutine musicPicFade;
private bool musicPicVisible = true;
void Awake()
{
EnsureMusicPicRoot();
}
void Start()
{
if (button_Music == null)
{
var btn = transform.Find("Button_Music") as RectTransform;
if (btn != null)
button_Music = btn.GetComponent<Button>();
if (button_Music == null)
{
var any = FindByName("Button_Music");
if (any != null) button_Music = any.GetComponent<Button>();
}
}
instantiateSettings = () => ToggleSettingsPrefab();
instantiateUserInfo = () => InstantiatePrefab(userInfo_prefab);
instantiateStore = () => InstantiatePrefab(store_prefab);
instantiateShowLevel = () => InstantiatePrefab(showLevel_prefab);
instantiateEmail = () => InstantiatePrefab(email_prefab);
instantiateNotice = () => InstantiatePrefab(notice_prefab);
instantiateShowLevel = () => ShowLevelPrefab();
instantiateEmail = () => ShowEmailPrefab();
instantiateNotice = () => ShowNoticePrefab();
if (settings_launch != null)
settings_launch.onClick.AddListener(instantiateSettings);
@@ -56,6 +85,17 @@ public class btmandtopController : MonoBehaviour
if (notice_display != null)
notice_display.onClick.AddListener(instantiateNotice);
EnsureMusicPicRoot();
SetupMusicPicDefault();
if (button_Music != null)
button_Music.onClick.AddListener(ToggleMusicPicLocal);
var binder = BgmUiBinder.Instance != null ? BgmUiBinder.Instance : Object.FindAnyObjectByType<BgmUiBinder>();
if (binder != null && musicPicRoot != null)
{
binder.SetMusicRoot(musicPicRoot);
}
// Pre-instantiate settings prefab and keep it inactive, ensuring only one exists
if (settings_prefab != null && putPrefabsHere != null)
{
@@ -80,7 +120,7 @@ public class btmandtopController : MonoBehaviour
Canvas c = settingsInstance.GetComponentInChildren<Canvas>(true);
if (c != null)
{
Camera[] cams = GameObject.FindObjectsOfType<Camera>();
Camera[] cams = Object.FindObjectsByType<Camera>(FindObjectsInactive.Exclude, FindObjectsSortMode.None);
if (cams != null && cams.Length > 0)
{
c.worldCamera = cams[0];
@@ -100,8 +140,160 @@ public class btmandtopController : MonoBehaviour
}
}
private void FixedUpdate()
{
if(Input.GetKeyDown(KeyCode.Escape))
{
//ToggleSettingsPrefab();
}
}
private void ToggleMusicPic()
{
var binder = BgmUiBinder.Instance != null ? BgmUiBinder.Instance : Object.FindAnyObjectByType<BgmUiBinder>();
if (binder != null)
{
binder.ToggleMusicPic();
var spectrum = binder.GetSpectrumRoot();
if (spectrum != null && binder.transform != null)
{
spectrum.localRotation = binder.transform.localRotation;
}
}
}
private void EnsureMusicPicRoot()
{
if (musicPicRoot != null)
return;
var child = transform.Find("MusicPic");
if (child != null)
{
musicPicRoot = child as RectTransform;
return;
}
var sceneMusic = GameObject.Find("MusicPic");
if (sceneMusic != null)
{
musicPicRoot = sceneMusic.GetComponent<RectTransform>();
if (musicPicRoot != null)
{
musicPicRoot.SetParent(transform, false);
}
}
}
private void SetupMusicPicDefault()
{
if (musicPicRoot == null)
return;
EnsureMusicPicGroup();
SetMusicPicVisible(false, true);
}
private void EnsureMusicPicGroup()
{
if (musicPicRoot == null)
return;
if (musicPicGroup == null)
musicPicGroup = musicPicRoot.GetComponent<CanvasGroup>();
if (musicPicGroup == null)
musicPicGroup = musicPicRoot.gameObject.AddComponent<CanvasGroup>();
}
private void ToggleMusicPicLocal()
{
EnsureMusicPicRoot();
var binder = BgmUiBinder.Instance != null ? BgmUiBinder.Instance : Object.FindAnyObjectByType<BgmUiBinder>();
if (musicPicRoot == null)
{
if (binder != null)
binder.ToggleMusicPic();
return;
}
SetMusicPicVisible(!musicPicVisible, false);
}
private void SetMusicPicVisible(bool visible, bool instant)
{
if (musicPicRoot == null)
return;
EnsureMusicPicGroup();
musicPicVisible = visible;
if (musicPicFade != null)
{
StopCoroutine(musicPicFade);
musicPicFade = null;
}
if (instant)
{
musicPicGroup.alpha = visible ? 1f : 0f;
musicPicGroup.interactable = visible;
musicPicGroup.blocksRaycasts = visible;
musicPicRoot.gameObject.SetActive(visible);
return;
}
musicPicRoot.gameObject.SetActive(true);
musicPicFade = StartCoroutine(FadeMusicPic(visible));
}
private System.Collections.IEnumerator FadeMusicPic(bool visibleAtEnd)
{
EnsureMusicPicGroup();
if (musicPicGroup == null)
yield break;
float start = musicPicGroup != null ? musicPicGroup.alpha : 0f;
float target = visibleAtEnd ? 1f : 0f;
float t = 0f;
while (t < 1f)
{
if (musicPicGroup == null || musicPicRoot == null)
yield break;
t += Time.unscaledDeltaTime / Mathf.Max(0.0001f, musicPicFadeTime);
float eased = Mathf.SmoothStep(0f, 1f, t);
musicPicGroup.alpha = Mathf.LerpUnclamped(start, target, eased);
yield return null;
}
if (musicPicGroup != null)
{
musicPicGroup.alpha = target;
musicPicGroup.interactable = visibleAtEnd;
musicPicGroup.blocksRaycasts = visibleAtEnd;
}
if (!visibleAtEnd && musicPicRoot != null)
{
musicPicRoot.gameObject.SetActive(false);
}
}
GameObject FindByName(string name)
{
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() || !t.gameObject.scene.isLoaded) continue;
if (t.name == name) return t.gameObject;
}
return null;
}
void OnDestroy()
{
if (musicPicFade != null)
{
StopCoroutine(musicPicFade);
musicPicFade = null;
}
musicPicGroup = null;
if (settings_launch != null)
settings_launch.onClick.RemoveListener(instantiateSettings);
if (userInfo_launch != null)
@@ -114,6 +306,9 @@ public class btmandtopController : MonoBehaviour
email_display.onClick.RemoveListener(instantiateEmail);
if (notice_display != null)
notice_display.onClick.RemoveListener(instantiateNotice);
if (button_Music != null)
button_Music.onClick.RemoveListener(ToggleMusicPicLocal);
}
private void ToggleSettingsPrefab()
@@ -131,7 +326,7 @@ public class btmandtopController : MonoBehaviour
Canvas c = settingsInstance.GetComponentInChildren<Canvas>(true);
if (c != null)
{
Camera[] cams = GameObject.FindObjectsOfType<Camera>();
Camera[] cams = Object.FindObjectsByType<Camera>(FindObjectsInactive.Exclude, FindObjectsSortMode.None);
if (cams != null && cams.Length > 0)
{
c.worldCamera = cams[0];
@@ -151,6 +346,97 @@ public class btmandtopController : MonoBehaviour
settingsInstance.SetActive(!active);
}
private void ShowLevelPrefab()
{
ShowPrefab(showLevel_prefab, ref showLevelInstance);
CloseInfoPanels(showLevelInstance);
}
private void ShowEmailPrefab()
{
ShowPrefab(email_prefab, ref emailInstance);
CloseInfoPanels(emailInstance);
}
private void ShowNoticePrefab()
{
ShowPrefab(notice_prefab, ref noticeInstance);
CloseInfoPanels(noticeInstance);
}
private void ShowPrefab(GameObject prefab, ref GameObject instance)
{
if (prefab == null || putPrefabsHere == null) return;
if (instance == null)
{
instance = FindExistingInstance(prefab);
if (instance == null)
{
instance = Instantiate(prefab, putPrefabsHere.transform);
TryAssignCanvasCamera(instance);
}
else
{
instance.transform.SetParent(putPrefabsHere.transform, false);
}
}
instance.SetActive(true);
instance.transform.SetAsLastSibling();
}
private void CloseInfoPanels(GameObject keep)
{
CloseInstance(ref showLevelInstance, keep);
CloseInstance(ref emailInstance, keep);
CloseInstance(ref noticeInstance, keep);
}
private void CloseInstance(ref GameObject instance, GameObject keep)
{
if (instance == null || instance == keep) return;
instance.SetActive(false);
}
private GameObject FindExistingInstance(GameObject prefab)
{
if (prefab == null || putPrefabsHere == null) return null;
Transform parent = putPrefabsHere.transform;
for (int i = 0; i < parent.childCount; i++)
{
Transform child = parent.GetChild(i);
if (child == null) continue;
if (child.name == prefab.name || child.name == prefab.name + "(Clone)")
{
return child.gameObject;
}
}
GameObject existing = GameObject.Find(prefab.name + "(Clone)");
return existing;
}
private void TryAssignCanvasCamera(GameObject instance)
{
if (instance == null) return;
try
{
Canvas c = instance.GetComponentInChildren<Canvas>(true);
if (c != null)
{
Camera[] cams = Object.FindObjectsByType<Camera>(FindObjectsInactive.Exclude, FindObjectsSortMode.None);
if (cams != null && cams.Length > 0)
{
c.worldCamera = cams[0];
}
}
}
catch { }
}
private void InstantiatePrefab(GameObject prefab)
{
if (prefab != null && putPrefabsHere != null)
@@ -5,6 +5,7 @@ public class loadtopandbottomPrefab: MonoBehaviour
[Header("father obj")]
public GameObject top_and_bottom_Panel;
public GameObject gameobject_to_Instantiate_below;
[SerializeField] bool notify_Main_Panel = true;
void Start()
{
@@ -17,11 +18,34 @@ public class loadtopandbottomPrefab: MonoBehaviour
Camera cam = Camera.main;
if (cam == null)
{
cam = FindObjectOfType<Camera>();
cam = Object.FindAnyObjectByType<Camera>();
}
canvas.worldCamera = cam;
cam = null;
}
if (notify_Main_Panel)
{
Bind_Main_Panel(instantiated);
}
}
}
void Bind_Main_Panel(GameObject instantiated)
{
if (instantiated == null)
{
return;
}
UI_Panel_Main main = Object.FindAnyObjectByType<UI_Panel_Main>();
if (main == null)
{
return;
}
RectTransform top = instantiated.transform.Find("TOP") as RectTransform;
RectTransform bottom = instantiated.transform.Find("BTM") as RectTransform;
if (top != null || bottom != null)
{
main.Bind_Top_Bottom(top, bottom);
}
}
}
+5 -1
View File
@@ -28,11 +28,15 @@ public class MusicPlayer : MonoBehaviour
Image_Cover.sprite = data.Cover;
Text_Title.text = data.Name;
}
private System.Text.StringBuilder _sb = new System.Text.StringBuilder();
private void Update()
{
if (Music_Source.clip != null)
{
Text_Time.text = Music_Mgr.Get_Time_Cur(Music_Source) + "/" + Music_Mgr.Get_Time_Max(Music_Source.clip);
_sb.Clear();
_sb.Append(Music_Mgr.Get_Time_Cur(Music_Source)).Append("/").Append(Music_Mgr.Get_Time_Max(Music_Source.clip));
Text_Time.text = _sb.ToString();
}
}
}
+24 -3
View File
@@ -14,14 +14,21 @@ public class Music_Mgr : Singleton_Mono<Music_Mgr>
{
return Get_Time((int)aus.time);
}
private static System.Text.StringBuilder _timeSb = new System.Text.StringBuilder();
public static string Get_Time(int time)
{
var currentHour = time / 3600;
var currentMinute = (time - currentHour * 3600) / 60;
var currentSecond = time - currentHour * 3600 - currentMinute * 60;
return string.Format("{0:D2}:{1:D2}:{2:D2} ",
currentHour, currentMinute, currentSecond);
_timeSb.Clear();
if (currentHour > 0)
{
_timeSb.Append(currentHour.ToString("D2")).Append(":");
}
_timeSb.Append(currentMinute.ToString("D2")).Append(":").Append(currentSecond.ToString("D2")).Append(" ");
return _timeSb.ToString();
}
public static float Get_Time_Cur_Prv(AudioSource aus)
{
@@ -37,7 +44,21 @@ public class Music_Mgr : Singleton_Mono<Music_Mgr>
{
AudioSource = gameObject.AddComponent<AudioSource>();
}
Music_Data_List = Resources.LoadAll<Music_Data>("Data/Music").ToList();
StartCoroutine(LoadMusicDataRoutine());
}
private System.Collections.IEnumerator LoadMusicDataRoutine()
{
var rawData = Resources.LoadAll<Music_Data>("Data/Music");
Music_Data_List = new List<Music_Data>();
for (int i = 0; i < rawData.Length; i++)
{
Music_Data_List.Add(rawData[i]);
// 每 10 个数据等待一帧
if (i > 0 && i % 10 == 0) yield return null;
}
if (Music_Data_List.Count > 0)
{
Play(Music_Data_List[0]);
@@ -38,7 +38,7 @@ public class SimpleAxisTween : MonoBehaviour
while (elapsed < duration)
{
elapsed += Time.deltaTime;
elapsed += Time.unscaledDeltaTime;
float t = Mathf.Clamp01(elapsed / duration);
float easedT = ease.Evaluate(t);
+15 -5
View File
@@ -1,5 +1,6 @@
using UnityEngine;
using System;
using System.Collections;
using UnityEngine.SceneManagement;
#if UNITY_EDITOR
using UnityEditor;
@@ -19,7 +20,7 @@ public class PauseManager : MonoBehaviour
public bool IsPaused { get; private set; } = false;
// 添加暂停状态改变事件
// ͣ״̬ı¼
public event Action<bool> OnPauseStateChanged;
void Awake()
@@ -52,13 +53,13 @@ public class PauseManager : MonoBehaviour
TogglePause();
}
// 当处于暂停状态且按下 Backspace 时返回主界面
// ͣ״̬Ұ Backspace ʱ
if (IsPaused && Input.GetKeyDown(KeyCode.Backspace))
{
// 恢复时间流并触发事件,然后加载主场景
// ָʱ¼Ȼ
Pause(false);
// 确保场景名称与项目中的主场景匹配
SceneManager.LoadScene("Main_main");
// ȷĿеƥ
StartCoroutine(LoadSceneAsync("Main_main"));
}
}
@@ -90,4 +91,13 @@ public class PauseManager : MonoBehaviour
{
Pause(!IsPaused);
}
private IEnumerator LoadSceneAsync(string sceneName)
{
AsyncOperation asyncLoad = SceneManager.LoadSceneAsync(sceneName);
while (!asyncLoad.isDone)
{
yield return null;
}
}
}
+293
View File
@@ -0,0 +1,293 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Text;
using UnityEngine;
#if UNITY_EDITOR
using UnityEditor;
#endif
[Serializable]
public class UI_FunctionHoverEntry
{
public string path;
[TextArea(2, 6)]
public string text;
public string iconPath;
public Sprite icon;
}
[CreateAssetMenu(menuName = "UI/Function Hover Config", fileName = "UI_FunctionHoverConfig")]
public class UI_FunctionHoverConfig : ScriptableObject
{
public List<UI_FunctionHoverEntry> entries = new List<UI_FunctionHoverEntry>();
#if UNITY_EDITOR
[ContextMenu("Import From 素材/指向")]
private void ImportFromDefaultFile()
{
ImportFromFile("素材/指向");
}
[ContextMenu("Import From UI_FunctionHoverConfig.json")]
private void ImportFromDefaultJson()
{
ImportFromJsonFile("Assets/Resources/UI_FunctionHoverConfig.json");
}
public void ImportFromFile(string relativePath)
{
if (string.IsNullOrEmpty(relativePath)) return;
string fullPath = Path.Combine(Application.dataPath, "..", relativePath);
if (!File.Exists(fullPath))
{
Debug.LogWarning("UI_FunctionHoverConfig: file not found: " + fullPath);
return;
}
string content = File.ReadAllText(fullPath, Encoding.UTF8);
var parsed = ParseConfig(content);
if (parsed.Count > 0)
{
entries = parsed;
EditorUtility.SetDirty(this);
AssetDatabase.SaveAssets();
}
}
public void ImportFromJsonFile(string relativePath)
{
if (string.IsNullOrEmpty(relativePath)) return;
string fullPath = Path.Combine(Application.dataPath, "..", relativePath);
if (!File.Exists(fullPath))
{
Debug.LogWarning("UI_FunctionHoverConfig: json not found: " + fullPath);
return;
}
string content = File.ReadAllText(fullPath, Encoding.UTF8);
var parsed = ParseJson(content);
if (parsed.Count > 0)
{
entries = parsed;
EditorUtility.SetDirty(this);
AssetDatabase.SaveAssets();
}
}
#endif
private static List<UI_FunctionHoverEntry> ParseConfig(string content)
{
var result = new List<UI_FunctionHoverEntry>();
if (string.IsNullOrEmpty(content)) return result;
var blocks = content.Split(new[] { "\r\n\r\n", "\n\n" }, StringSplitOptions.RemoveEmptyEntries);
foreach (var block in blocks)
{
string pathLine = null;
string textLine = null;
string iconLine = null;
var lines = block.Split(new[] { '\r', '\n' }, StringSplitOptions.RemoveEmptyEntries);
foreach (var line in lines)
{
if (line.StartsWith("路径")) pathLine = line;
else if (line.StartsWith("文本")) textLine = line;
else if (line.StartsWith("显示icon")) iconLine = line;
}
if (pathLine == null || textLine == null) continue;
string pathsRaw = GetValueAfterColon(pathLine);
string text = GetValueAfterColon(textLine);
string iconPath = iconLine != null ? GetValueAfterColon(iconLine) : null;
var paths = SplitPaths(pathsRaw);
var icon = LoadIcon(iconPath);
foreach (var p in paths)
{
if (string.IsNullOrWhiteSpace(p)) continue;
result.Add(new UI_FunctionHoverEntry
{
path = p.Trim(),
text = text,
iconPath = iconPath,
icon = icon
});
}
}
return result;
}
[Serializable]
private class JsonRoot
{
public List<JsonEntry> entries;
}
[Serializable]
private class JsonEntry
{
public List<string> paths;
public string text;
public string icon;
}
private static List<UI_FunctionHoverEntry> ParseJson(string content)
{
var result = new List<UI_FunctionHoverEntry>();
if (string.IsNullOrEmpty(content)) return result;
JsonRoot root = null;
try
{
root = JsonUtility.FromJson<JsonRoot>(content);
}
catch
{
root = null;
}
if (root == null || root.entries == null) return result;
for (int i = 0; i < root.entries.Count; i++)
{
var entry = root.entries[i];
if (entry == null || entry.paths == null) continue;
Sprite icon = LoadIcon(entry.icon);
for (int p = 0; p < entry.paths.Count; p++)
{
var path = entry.paths[p];
if (string.IsNullOrWhiteSpace(path)) continue;
result.Add(new UI_FunctionHoverEntry
{
path = path.Trim(),
text = entry.text,
iconPath = entry.icon,
icon = icon
});
}
}
return result;
}
private static string GetValueAfterColon(string line)
{
int idx = line.IndexOf('');
if (idx < 0) idx = line.IndexOf(':');
if (idx < 0) return line.Trim();
return line.Substring(idx + 1).Trim();
}
private static string[] SplitPaths(string raw)
{
if (string.IsNullOrEmpty(raw)) return Array.Empty<string>();
string tmp = raw.Replace("和", "|")
.Replace("、", "|")
.Replace("", "|")
.Replace(",", "|")
.Replace(";", "|")
.Replace("", "|");
return tmp.Split(new[] { '|' }, StringSplitOptions.RemoveEmptyEntries);
}
private static Sprite LoadIcon(string iconPath)
{
if (string.IsNullOrWhiteSpace(iconPath)) return null;
string path = NormalizeAssetPath(iconPath);
if (!path.StartsWith("Assets", StringComparison.OrdinalIgnoreCase))
path = "Assets/" + path;
#if UNITY_EDITOR
Sprite direct = TryLoadByPath(path);
if (direct != null) return direct;
string name = Path.GetFileName(path);
string folder = Path.GetDirectoryName(path);
List<string> searchFolders = new List<string>();
if (!string.IsNullOrEmpty(folder) && Directory.Exists(Path.Combine(Application.dataPath, "..", folder)))
searchFolders.Add(folder);
string uiUiFolder = "Assets/artworks/UI_UI";
if (Directory.Exists(Path.Combine(Application.dataPath, "..", uiUiFolder)))
searchFolders.Add(uiUiFolder);
string artworksFolder = "Assets/artworks";
if (Directory.Exists(Path.Combine(Application.dataPath, "..", artworksFolder)))
searchFolders.Add(artworksFolder);
string[] folders = searchFolders.Count > 0 ? searchFolders.ToArray() : null;
var guids = AssetDatabase.FindAssets(name + " t:Sprite", folders);
if (guids.Length == 0)
guids = AssetDatabase.FindAssets(name + " t:Texture2D", folders);
if (guids.Length > 0)
{
string best = PickBestAssetPath(guids, name, folder);
var sprite = AssetDatabase.LoadAssetAtPath<Sprite>(best);
if (sprite != null) return sprite;
var tex = AssetDatabase.LoadAssetAtPath<Texture2D>(best);
if (tex != null)
return Sprite.Create(tex, new Rect(0, 0, tex.width, tex.height), new Vector2(0.5f, 0.5f));
}
#endif
return null;
}
private static string NormalizeAssetPath(string raw)
{
if (string.IsNullOrWhiteSpace(raw)) return string.Empty;
string path = raw.Replace('>', '/').Replace('\\', '/').Trim();
path = path.Replace("Ul_Ul", "UI_UI");
path = path.Replace("", " (").Replace("", ")");
path = path.Replace(" ", " ").Trim();
return path;
}
#if UNITY_EDITOR
private static Sprite TryLoadByPath(string path)
{
if (string.IsNullOrWhiteSpace(path)) return null;
string[] candidates = path.IndexOf('.') >= 0
? new[] { path }
: new[]
{
path + ".png",
path + ".jpg",
path + ".jpeg"
};
for (int i = 0; i < candidates.Length; i++)
{
string p = candidates[i];
var sprite = AssetDatabase.LoadAssetAtPath<Sprite>(p);
if (sprite != null) return sprite;
var tex = AssetDatabase.LoadAssetAtPath<Texture2D>(p);
if (tex != null)
return Sprite.Create(tex, new Rect(0, 0, tex.width, tex.height), new Vector2(0.5f, 0.5f));
}
return null;
}
private static string PickBestAssetPath(string[] guids, string name, string preferredFolder)
{
if (guids == null || guids.Length == 0) return null;
string best = AssetDatabase.GUIDToAssetPath(guids[0]);
if (guids.Length == 1) return best;
string preferredLower = (preferredFolder ?? string.Empty).Replace('\\', '/').ToLowerInvariant();
string uiUiFolder = "assets/artworks/ui_ui";
for (int i = 0; i < guids.Length; i++)
{
string path = AssetDatabase.GUIDToAssetPath(guids[i]);
if (string.IsNullOrEmpty(path)) continue;
string lower = path.ToLowerInvariant();
if (!string.IsNullOrEmpty(preferredLower) && lower.Contains(preferredLower))
return path;
if (lower.Contains(uiUiFolder))
best = path;
}
return best;
}
#endif
}
@@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: 0db6d24442085814ca9a66f17b584840
+681
View File
@@ -0,0 +1,681 @@
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.EventSystems;
using UnityEngine.SceneManagement;
using UnityEngine.UI;
using TMPro;
using DG.Tweening;
public class UI_FunctionHoverGuide : MonoBehaviour
{
[Header("Scene")]
public bool onlyInUiUi = true;
public string uiUiSceneName = "UI_UI";
[Header("Config")]
public UI_FunctionHoverConfig config;
public string configResourcesName = "UI_FunctionHoverConfig";
public bool debugLogs = false;
public bool useManualHover = true;
[Header("Function References")]
public string functionRootName = "Function";
public string functionRootPath = "UI_Panel_Main_main/Content/Function";
public string targetBasePath = "UI_Panel_Main_main";
public string iconNameContains = "ICON";
public string textNameContains = "TEXT";
public RectTransform functionRoot;
public Image functionIcon;
public RawImage functionIconRaw;
public TMP_Text functionTextTmp;
public Text functionTextLegacy;
[Header("Animation")]
public float iconStartScale = 0.6f;
public float iconPopDuration = 0.35f;
public int iconFlashCount = 2;
public float iconFlashInterval = 0.05f;
public float textTypeInterval = 0.02f;
public bool useUnscaledTime = true;
[Header("Gyro")]
public bool enableGyro = false;
public float gyroMaxRotation = 4f;
public float gyroSmooth = 10f;
private Sprite defaultIcon;
private Texture defaultIconTexture;
private string defaultText;
private Vector3 iconBaseScale = Vector3.one;
private bool iconBaseScaleCached;
private bool initialized;
private Coroutine typeRoutine;
private Sequence iconSeq;
private UI_FunctionHoverEntry currentEntry;
private Coroutine retryRoutine;
private readonly List<HoverTarget> hoverTargets = new();
private class HoverTarget
{
public UI_FunctionHoverEntry entry;
public RectTransform rect;
public float area;
}
private void OnEnable()
{
SceneManager.sceneLoaded += OnSceneLoaded;
TryInit();
}
private void OnDisable()
{
SceneManager.sceneLoaded -= OnSceneLoaded;
}
private void Update()
{
if (!initialized || !useManualHover) return;
if (hoverTargets.Count == 0) return;
if (!IsUiUiScene()) return;
UI_FunctionHoverEntry entry = GetHoveredEntry();
if (entry == currentEntry) return;
if (entry != null)
ApplyEntry(entry);
else if (currentEntry != null)
ClearEntry(currentEntry);
}
private void OnSceneLoaded(Scene scene, LoadSceneMode mode)
{
initialized = false;
TryInit();
}
private void TryInit()
{
if (initialized) return;
if (onlyInUiUi && !IsUiUiScene()) return;
if (config == null && !string.IsNullOrEmpty(configResourcesName))
config = Resources.Load<UI_FunctionHoverConfig>(configResourcesName);
if (config == null)
{
Debug.LogWarning("UI_FunctionHoverGuide: config is missing. Create a UI_FunctionHoverConfig asset and assign it.");
return;
}
ResolveFunctionRefs();
if (functionRoot == null || functionIcon == null || (functionTextTmp == null && functionTextLegacy == null))
{
StartRetry();
return;
}
CacheDefault();
EnsureWrapping();
EnsureGyro();
int wired = WireTargets();
if (debugLogs)
Debug.Log($"UI_FunctionHoverGuide: wired targets = {wired}, functionRoot = {functionRoot?.name}");
if (wired == 0)
{
StartRetry();
return;
}
initialized = true;
}
private void StartRetry()
{
if (retryRoutine != null) return;
retryRoutine = StartCoroutine(RetryInit());
}
private IEnumerator RetryInit()
{
int tries = 0;
while (!initialized)
{
ResolveFunctionRefs();
if (functionRoot != null && functionIcon != null && (functionTextTmp != null || functionTextLegacy != null))
{
CacheDefault();
EnsureWrapping();
EnsureGyro();
int wired = WireTargets();
if (debugLogs)
Debug.Log($"UI_FunctionHoverGuide: retry wired targets = {wired}");
if (wired > 0)
{
initialized = true;
break;
}
}
tries++;
yield return new WaitForSecondsRealtime(0.25f);
}
retryRoutine = null;
}
private bool IsUiUiScene()
{
if (string.IsNullOrEmpty(uiUiSceneName)) return true;
var active = SceneManager.GetActiveScene().name;
return active.IndexOf(uiUiSceneName, StringComparison.OrdinalIgnoreCase) >= 0;
}
private void ResolveFunctionRefs()
{
if (functionRoot == null)
{
GameObject go = null;
if (!string.IsNullOrWhiteSpace(functionRootPath))
go = GameObject.Find(functionRootPath);
if (go == null && !string.IsNullOrWhiteSpace(targetBasePath))
go = GameObject.Find(CombinePath(targetBasePath, functionRootName));
if (go == null)
go = FindByNameContains(functionRootName);
if (go != null)
functionRoot = go.GetComponent<RectTransform>();
}
if (functionRoot == null) return;
if (functionIcon == null)
{
var icon = FindChildGraphic(functionRoot, iconNameContains);
if (icon != null) functionIcon = icon;
}
if (functionIconRaw == null && functionIcon == null)
{
var raw = FindChildRawImage(functionRoot, iconNameContains);
if (raw != null) functionIconRaw = raw;
}
if (functionTextTmp == null && functionTextLegacy == null)
{
var tmp = FindChildTmp(functionRoot, textNameContains);
if (tmp != null)
functionTextTmp = tmp;
else
functionTextLegacy = FindChildLegacyText(functionRoot, textNameContains);
}
}
private void CacheDefault()
{
if (functionIcon != null)
defaultIcon = functionIcon.sprite;
if (functionIconRaw != null)
defaultIconTexture = functionIconRaw.texture;
var iconGraphic = functionIcon != null ? (Graphic)functionIcon : functionIconRaw;
if (iconGraphic != null && iconGraphic.rectTransform != null)
{
var scale = iconGraphic.rectTransform.localScale;
if (IsFinite(scale) && scale != Vector3.zero)
{
iconBaseScale = scale;
iconBaseScaleCached = true;
}
}
if (functionTextTmp != null)
defaultText = functionTextTmp.text;
else if (functionTextLegacy != null)
defaultText = functionTextLegacy.text;
}
private void EnsureWrapping()
{
if (functionTextTmp != null)
{
functionTextTmp.textWrappingMode = TextWrappingModes.Normal;
functionTextTmp.overflowMode = TextOverflowModes.Overflow;
}
if (functionTextLegacy != null)
{
functionTextLegacy.horizontalOverflow = HorizontalWrapMode.Wrap;
functionTextLegacy.verticalOverflow = VerticalWrapMode.Overflow;
}
}
private void EnsureGyro()
{
if (functionRoot == null) return;
var gyro = functionRoot.GetComponent<BgmGyroRotator>();
if (gyro != null)
{
if (Application.isPlaying)
Destroy(gyro);
else
DestroyImmediate(gyro);
}
}
private int WireTargets()
{
if (config == null || config.entries == null) return 0;
hoverTargets.Clear();
int wired = 0;
for (int i = 0; i < config.entries.Count; i++)
{
var entry = config.entries[i];
if (entry == null || string.IsNullOrWhiteSpace(entry.path)) continue;
var target = FindByPath(entry.path);
if (target == null)
{
if (debugLogs)
Debug.LogWarning("UI_FunctionHoverGuide: target not found for path: " + entry.path);
continue;
}
if (AttachHoverTargets(target.transform, entry))
wired++;
}
return wired;
}
public void ApplyEntry(UI_FunctionHoverEntry entry)
{
if (entry == null) return;
if (currentEntry == entry) return;
currentEntry = entry;
if (functionIcon != null && entry.icon != null)
functionIcon.sprite = entry.icon;
if (functionIconRaw != null)
functionIconRaw.texture = entry.icon != null ? entry.icon.texture : defaultIconTexture;
PlayIconAnim();
PlayTypewriter(entry.text);
}
public void ClearEntry(UI_FunctionHoverEntry entry)
{
if (currentEntry != entry) return;
currentEntry = null;
if (functionIcon != null && defaultIcon != null)
functionIcon.sprite = defaultIcon;
if (functionIconRaw != null && defaultIconTexture != null)
functionIconRaw.texture = defaultIconTexture;
PlayIconAnim();
PlayTypewriter(defaultText);
}
private void PlayIconAnim()
{
Graphic iconGraphic = functionIcon != null ? (Graphic)functionIcon : functionIconRaw;
if (iconGraphic == null) return;
var rt = iconGraphic.rectTransform;
var baseScale = iconBaseScaleCached ? iconBaseScale : Vector3.one;
if (!iconBaseScaleCached && rt != null)
baseScale = rt.localScale;
if (!IsFinite(baseScale))
baseScale = Vector3.one;
if (iconSeq != null && iconSeq.IsActive())
iconSeq.Kill();
var color = iconGraphic.color;
iconGraphic.color = new Color(color.r, color.g, color.b, 0f);
if (rt != null)
rt.localScale = baseScale * iconStartScale;
iconSeq = DOTween.Sequence();
for (int i = 0; i < Mathf.Max(1, iconFlashCount); i++)
{
iconSeq.Append(iconGraphic.DOFade(1f, iconFlashInterval));
iconSeq.Append(iconGraphic.DOFade(0.25f, iconFlashInterval));
}
iconSeq.Append(iconGraphic.DOFade(1f, iconFlashInterval));
if (rt != null)
iconSeq.Join(rt.DOScale(baseScale, iconPopDuration).SetEase(Ease.OutBack));
}
private static bool IsFinite(Vector3 v)
{
return !(float.IsNaN(v.x) || float.IsNaN(v.y) || float.IsNaN(v.z)
|| float.IsInfinity(v.x) || float.IsInfinity(v.y) || float.IsInfinity(v.z));
}
private void PlayTypewriter(string text)
{
if (string.IsNullOrEmpty(text)) text = string.Empty;
if (typeRoutine != null)
StopCoroutine(typeRoutine);
if (functionTextTmp != null)
typeRoutine = StartCoroutine(TypeTmp(functionTextTmp, text));
else if (functionTextLegacy != null)
typeRoutine = StartCoroutine(TypeLegacy(functionTextLegacy, text));
}
private IEnumerator TypeTmp(TMP_Text tmp, string text)
{
tmp.text = text;
tmp.maxVisibleCharacters = 0;
tmp.ForceMeshUpdate();
int total = tmp.textInfo.characterCount;
for (int i = 0; i <= total; i++)
{
tmp.maxVisibleCharacters = i;
yield return Wait(textTypeInterval);
}
}
private IEnumerator TypeLegacy(Text txt, string text)
{
txt.text = string.Empty;
for (int i = 0; i <= text.Length; i++)
{
txt.text = text.Substring(0, i);
yield return Wait(textTypeInterval);
}
}
private IEnumerator Wait(float t)
{
if (useUnscaledTime)
yield return new WaitForSecondsRealtime(t);
else
yield return new WaitForSeconds(t);
}
private GameObject FindByPath(string path)
{
if (string.IsNullOrWhiteSpace(path)) return null;
var go = GameObject.Find(path);
if (go != null) return go;
if (!string.IsNullOrWhiteSpace(targetBasePath))
{
var combined = CombinePath(targetBasePath, path);
go = GameObject.Find(combined);
if (go != null) return go;
}
string normalized = NormalizePath(path);
if (string.IsNullOrEmpty(normalized)) return null;
var all = Resources.FindObjectsOfTypeAll<Transform>();
for (int i = 0; i < all.Length; i++)
{
var t = all[i];
if (t == null) continue;
if (!t.gameObject.scene.IsValid() || !t.gameObject.scene.isLoaded) continue;
string full = NormalizePath(GetFullPath(t));
if (string.Equals(full, normalized, StringComparison.OrdinalIgnoreCase) ||
full.EndsWith("/" + normalized, StringComparison.OrdinalIgnoreCase))
return t.gameObject;
}
string[] parts = path.Split('/');
string last = parts[parts.Length - 1];
return FindByNameContains(last);
}
private GameObject FindByNameContains(string name)
{
if (string.IsNullOrWhiteSpace(name)) return null;
var all = Resources.FindObjectsOfTypeAll<Transform>();
string target = name.Replace(" ", "");
for (int i = 0; i < all.Length; i++)
{
var t = all[i];
if (t == null) continue;
if (!t.gameObject.scene.IsValid() || !t.gameObject.scene.isLoaded) continue;
string n = t.name.Replace(" ", "");
if (n.IndexOf(target, StringComparison.OrdinalIgnoreCase) >= 0)
return t.gameObject;
}
return null;
}
private static string CombinePath(string basePath, string path)
{
if (string.IsNullOrWhiteSpace(basePath)) return path;
if (string.IsNullOrWhiteSpace(path)) return basePath;
string trimmedBase = basePath.Trim().TrimEnd('/', '\\');
string trimmedPath = path.Trim().TrimStart('/', '\\');
if (trimmedPath.StartsWith(trimmedBase, StringComparison.OrdinalIgnoreCase))
return trimmedPath;
return trimmedBase + "/" + trimmedPath;
}
private static string NormalizePath(string path)
{
if (string.IsNullOrEmpty(path)) return string.Empty;
return path.Replace('\\', '/').Replace(" ", "");
}
private static string GetFullPath(Transform t)
{
if (t == null) return string.Empty;
var parts = new List<string>();
var cur = t;
while (cur != null)
{
parts.Add(cur.name);
cur = cur.parent;
}
parts.Reverse();
return string.Join("/", parts);
}
private static Image FindChildGraphic(Transform root, string nameContains)
{
var imgs = root.GetComponentsInChildren<Image>(true);
if (imgs == null || imgs.Length == 0) return null;
if (!string.IsNullOrEmpty(nameContains))
{
string target = nameContains.Replace(" ", "");
for (int i = 0; i < imgs.Length; i++)
{
var img = imgs[i];
if (img == null) continue;
string n = img.name.Replace(" ", "");
if (n.IndexOf(target, StringComparison.OrdinalIgnoreCase) >= 0)
return img;
}
}
return imgs[0];
}
private static RawImage FindChildRawImage(Transform root, string nameContains)
{
var raws = root.GetComponentsInChildren<RawImage>(true);
if (raws == null || raws.Length == 0) return null;
if (!string.IsNullOrEmpty(nameContains))
{
string target = nameContains.Replace(" ", "");
for (int i = 0; i < raws.Length; i++)
{
var img = raws[i];
if (img == null) continue;
string n = img.name.Replace(" ", "");
if (n.IndexOf(target, StringComparison.OrdinalIgnoreCase) >= 0)
return img;
}
}
return raws[0];
}
private static TMP_Text FindChildTmp(Transform root, string nameContains)
{
var tmps = root.GetComponentsInChildren<TMP_Text>(true);
if (tmps == null || tmps.Length == 0) return null;
if (!string.IsNullOrEmpty(nameContains))
{
string target = nameContains.Replace(" ", "");
for (int i = 0; i < tmps.Length; i++)
{
var t = tmps[i];
if (t == null) continue;
string n = t.name.Replace(" ", "");
if (n.IndexOf(target, StringComparison.OrdinalIgnoreCase) >= 0)
return t;
}
}
return tmps[0];
}
private static Text FindChildLegacyText(Transform root, string nameContains)
{
var texts = root.GetComponentsInChildren<Text>(true);
if (texts == null || texts.Length == 0) return null;
if (!string.IsNullOrEmpty(nameContains))
{
string target = nameContains.Replace(" ", "");
for (int i = 0; i < texts.Length; i++)
{
var t = texts[i];
if (t == null) continue;
string n = t.name.Replace(" ", "");
if (n.IndexOf(target, StringComparison.OrdinalIgnoreCase) >= 0)
return t;
}
}
return texts[0];
}
private static void EnsureRaycastTarget(GameObject go)
{
var graphics = go.GetComponentsInChildren<Graphic>(true);
if (graphics != null && graphics.Length > 0)
{
for (int i = 0; i < graphics.Length; i++)
{
if (graphics[i] != null)
graphics[i].raycastTarget = true;
}
return;
}
var img = go.AddComponent<Image>();
img.color = new Color(1f, 1f, 1f, 0f);
img.raycastTarget = true;
}
private bool AttachHoverTargets(Transform root, UI_FunctionHoverEntry entry)
{
if (root == null || entry == null) return false;
Transform attachRoot = root;
Button button = root.GetComponent<Button>();
if (button == null)
button = root.GetComponentInParent<Button>();
if (button != null)
attachRoot = button.transform;
var hover = attachRoot.GetComponent<UI_FunctionHoverTarget>();
if (hover == null)
hover = attachRoot.gameObject.AddComponent<UI_FunctionHoverTarget>();
hover.guide = this;
hover.entry = entry;
if (button != null)
{
if (button.targetGraphic != null)
button.targetGraphic.raycastTarget = true;
else
EnsureRaycastTarget(attachRoot.gameObject);
}
else
{
var graphic = attachRoot.GetComponent<Graphic>();
if (graphic != null)
graphic.raycastTarget = true;
else
EnsureRaycastTarget(attachRoot.gameObject);
}
var rect = attachRoot as RectTransform;
if (rect != null)
{
hoverTargets.Add(new HoverTarget
{
entry = entry,
rect = rect,
area = Mathf.Abs(rect.rect.width * rect.rect.height)
});
}
return true;
}
private UI_FunctionHoverEntry GetHoveredEntry()
{
if (hoverTargets.Count == 0) return null;
Vector2 mouse = Input.mousePosition;
UI_FunctionHoverEntry best = null;
float bestArea = float.MaxValue;
for (int i = 0; i < hoverTargets.Count; i++)
{
var target = hoverTargets[i];
if (target == null || target.rect == null) continue;
if (!target.rect.gameObject.activeInHierarchy) continue;
var canvas = target.rect.GetComponentInParent<Canvas>();
Camera cam = canvas != null && canvas.renderMode != RenderMode.ScreenSpaceOverlay
? canvas.worldCamera
: null;
if (RectTransformUtility.RectangleContainsScreenPoint(target.rect, mouse, cam))
{
float area = target.area > 0f ? target.area : Mathf.Abs(target.rect.rect.width * target.rect.rect.height);
if (area < bestArea)
{
bestArea = area;
best = target.entry;
}
}
}
return best;
}
[RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.AfterSceneLoad)]
private static void Bootstrap()
{
SceneManager.sceneLoaded += BootstrapOnSceneLoaded;
int count = SceneManager.sceneCount;
for (int i = 0; i < count; i++)
{
var scene = SceneManager.GetSceneAt(i);
if (scene.isLoaded)
BootstrapOnSceneLoaded(scene, LoadSceneMode.Single);
}
}
private static void BootstrapOnSceneLoaded(Scene scene, LoadSceneMode mode)
{
if (!scene.IsValid()) return;
if (scene.name.IndexOf("UI_UI", StringComparison.OrdinalIgnoreCase) < 0) return;
if (UnityEngine.Object.FindAnyObjectByType<UI_FunctionHoverGuide>() != null) return;
var go = new GameObject("UI_FunctionHoverGuide");
go.AddComponent<UI_FunctionHoverGuide>();
}
}
public class UI_FunctionHoverTarget : MonoBehaviour, IPointerEnterHandler, IPointerExitHandler
{
public UI_FunctionHoverGuide guide;
public UI_FunctionHoverEntry entry;
public void OnPointerEnter(PointerEventData eventData)
{
if (guide != null && entry != null)
guide.ApplyEntry(entry);
}
public void OnPointerExit(PointerEventData eventData)
{
if (guide != null && entry != null)
guide.ClearEntry(entry);
}
}
@@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: aa941f3246d11454c9bb0f52d6a3087b
+14 -9
View File
@@ -8,20 +8,25 @@ public class UI_Show_Anim : MonoBehaviour
private void OnEnable()
{
Clear();
transform.localScale = new();
transform.DOScale(1, animTime_Scale);
transform.localScale = Vector3.zero;
transform.DOScale(1, animTime_Scale).SetUpdate(true);
gameObject.Try_Get_Component(out CanvasGroup canvasGroup);
float a = 0;
DOTween.To(() => a, (f) => { a = f; canvasGroup.alpha = f; }, 1, animTime_Alpha);
if (gameObject.Try_Get_Component(out CanvasGroup canvasGroup))
{
canvasGroup.alpha = 0;
float a = 0;
DOTween.To(() => a, (f) => { a = f; canvasGroup.alpha = f; }, 1, animTime_Alpha).SetUpdate(true);
}
}
public void Close()
{
Clear();
transform.DOScale(0, animTime_Scale);
gameObject.Try_Get_Component(out CanvasGroup canvasGroup);
float a = 1;
DOTween.To(() => a, (f) => { a = f; canvasGroup.alpha = f; }, 0, animTime_Alpha);
transform.DOScale(0, animTime_Scale).SetUpdate(true);
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);
}
}
void Clear()
{