新建参考
This commit is contained in:
8
Assets/Scripts/SDK.meta
Normal file
8
Assets/Scripts/SDK.meta
Normal file
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: W3JJ4HmvBS/vjHueZ73Q6T8UtkVemY3ssAsbaj3J2Xy9brdydFQg3EY=
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
94
Assets/Scripts/SDK/BasePanel.cs
Normal file
94
Assets/Scripts/SDK/BasePanel.cs
Normal file
@@ -0,0 +1,94 @@
|
||||
using UnityEngine;
|
||||
|
||||
namespace GameSDK
|
||||
{
|
||||
/// <summary>
|
||||
/// UI面板基类,支持淡入淡出动画
|
||||
/// </summary>
|
||||
public class BasePanel : MonoBehaviour
|
||||
{
|
||||
protected CanvasGroup canvasGroup;
|
||||
|
||||
public float fadeDuration = 0.25f;
|
||||
|
||||
private float fadeTarget = -1f;
|
||||
private float fadeTimer = 0f;
|
||||
private float fadeFrom = 0f;
|
||||
private System.Action fadeCallback;
|
||||
|
||||
/// <summary>
|
||||
/// 确保 CanvasGroup 存在(lazy init,应对 inactive 面板)
|
||||
/// </summary>
|
||||
protected void EnsureCanvasGroup()
|
||||
{
|
||||
if (canvasGroup == null)
|
||||
{
|
||||
canvasGroup = GetComponent<CanvasGroup>();
|
||||
if (canvasGroup == null)
|
||||
canvasGroup = gameObject.AddComponent<CanvasGroup>();
|
||||
}
|
||||
}
|
||||
|
||||
protected virtual void Awake()
|
||||
{
|
||||
EnsureCanvasGroup();
|
||||
}
|
||||
|
||||
protected virtual void Update()
|
||||
{
|
||||
if (fadeTarget < 0f) return;
|
||||
|
||||
fadeTimer += Time.deltaTime;
|
||||
float t = Mathf.Clamp01(fadeTimer / fadeDuration);
|
||||
canvasGroup.alpha = Mathf.Lerp(fadeFrom, fadeTarget, t);
|
||||
|
||||
if (t >= 1f)
|
||||
{
|
||||
canvasGroup.alpha = fadeTarget;
|
||||
|
||||
if (fadeTarget > 0f)
|
||||
canvasGroup.blocksRaycasts = true;
|
||||
|
||||
System.Action cb = fadeCallback;
|
||||
fadeTarget = -1f;
|
||||
fadeCallback = null;
|
||||
cb?.Invoke();
|
||||
}
|
||||
}
|
||||
|
||||
public virtual void OnEnter()
|
||||
{
|
||||
gameObject.SetActive(true);
|
||||
EnsureCanvasGroup();
|
||||
canvasGroup.blocksRaycasts = true;
|
||||
StartFade(1f);
|
||||
}
|
||||
|
||||
public virtual void OnPause()
|
||||
{
|
||||
StartFade(0f, () => gameObject.SetActive(false));
|
||||
}
|
||||
|
||||
public virtual void OnResume()
|
||||
{
|
||||
gameObject.SetActive(true);
|
||||
EnsureCanvasGroup();
|
||||
canvasGroup.blocksRaycasts = true;
|
||||
StartFade(1f);
|
||||
}
|
||||
|
||||
public virtual void OnExit()
|
||||
{
|
||||
StartFade(0f, () => gameObject.SetActive(false));
|
||||
}
|
||||
|
||||
private void StartFade(float targetAlpha, System.Action onComplete = null)
|
||||
{
|
||||
EnsureCanvasGroup();
|
||||
fadeFrom = canvasGroup.alpha;
|
||||
fadeTarget = targetAlpha;
|
||||
fadeTimer = 0f;
|
||||
fadeCallback = onComplete;
|
||||
}
|
||||
}
|
||||
}
|
||||
11
Assets/Scripts/SDK/BasePanel.cs.meta
Normal file
11
Assets/Scripts/SDK/BasePanel.cs.meta
Normal file
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: DitNvH+qASrZ3xHma0cii5/gjrwR7HYv1c/TA4orpBJNbH1O5TmEVGk=
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
98
Assets/Scripts/SDK/ChangePasswordPanel.cs
Normal file
98
Assets/Scripts/SDK/ChangePasswordPanel.cs
Normal file
@@ -0,0 +1,98 @@
|
||||
using UnityEngine;
|
||||
using UnityEngine.UI;
|
||||
using TMPro;
|
||||
|
||||
namespace GameSDK
|
||||
{
|
||||
/// <summary>
|
||||
/// 修改密码面板
|
||||
/// </summary>
|
||||
public class ChangePasswordPanel : BasePanel
|
||||
{
|
||||
[Header("UI References")]
|
||||
public TMP_InputField usernameInput;
|
||||
public TMP_InputField oldPasswordInput;
|
||||
public TMP_InputField newPasswordInput;
|
||||
public TMP_InputField confirmPasswordInput;
|
||||
public Button confirmBtn;
|
||||
public Button backBtn;
|
||||
public TMP_Text tipText;
|
||||
|
||||
private bool initialized;
|
||||
|
||||
private void OnEnable()
|
||||
{
|
||||
if (initialized) return;
|
||||
initialized = true;
|
||||
confirmBtn.onClick.AddListener(OnConfirmClick);
|
||||
backBtn.onClick.AddListener(OnBackClick);
|
||||
}
|
||||
|
||||
private void OnConfirmClick()
|
||||
{
|
||||
string username = usernameInput.text.Trim();
|
||||
string oldPassword = oldPasswordInput.text.Trim();
|
||||
string newPassword = newPasswordInput.text.Trim();
|
||||
string confirmPassword = confirmPasswordInput.text.Trim();
|
||||
|
||||
if (string.IsNullOrEmpty(username))
|
||||
{
|
||||
ShowTip("请输入账号");
|
||||
return;
|
||||
}
|
||||
if (string.IsNullOrEmpty(oldPassword))
|
||||
{
|
||||
ShowTip("请输入原密码");
|
||||
return;
|
||||
}
|
||||
if (string.IsNullOrEmpty(newPassword))
|
||||
{
|
||||
ShowTip("请输入新密码");
|
||||
return;
|
||||
}
|
||||
if (newPassword.Length < 6)
|
||||
{
|
||||
ShowTip("新密码长度不能少于6位");
|
||||
return;
|
||||
}
|
||||
if (newPassword != confirmPassword)
|
||||
{
|
||||
ShowTip("两次输入的新密码不一致");
|
||||
return;
|
||||
}
|
||||
if (oldPassword == newPassword)
|
||||
{
|
||||
ShowTip("新密码不能与旧密码相同");
|
||||
return;
|
||||
}
|
||||
|
||||
// TODO: 接入实际修改密码接口
|
||||
Debug.Log($"[SDK] 修改密码请求: 账号={username}");
|
||||
ShowTip("提交中...");
|
||||
|
||||
// 模拟成功
|
||||
Debug.Log("[SDK] 密码修改成功");
|
||||
SDKUIManager.Instance.PopPanel();
|
||||
}
|
||||
|
||||
private void OnBackClick()
|
||||
{
|
||||
SDKUIManager.Instance.PopPanel();
|
||||
}
|
||||
|
||||
private void ShowTip(string msg)
|
||||
{
|
||||
tipText.text = msg;
|
||||
}
|
||||
|
||||
public override void OnEnter()
|
||||
{
|
||||
base.OnEnter();
|
||||
usernameInput.text = "";
|
||||
oldPasswordInput.text = "";
|
||||
newPasswordInput.text = "";
|
||||
confirmPasswordInput.text = "";
|
||||
tipText.text = "";
|
||||
}
|
||||
}
|
||||
}
|
||||
11
Assets/Scripts/SDK/ChangePasswordPanel.cs.meta
Normal file
11
Assets/Scripts/SDK/ChangePasswordPanel.cs.meta
Normal file
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: C3pLs3moAH5Toh0op4hx6ZzPWLQttg1SE4L3LcF6s/cMS5Zd1Y8Mi9E=
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
513
Assets/Scripts/SDK/LoginPanel.cs
Normal file
513
Assets/Scripts/SDK/LoginPanel.cs
Normal file
@@ -0,0 +1,513 @@
|
||||
using UnityEngine;
|
||||
using UnityEngine.UI;
|
||||
using TMPro;
|
||||
|
||||
namespace GameSDK
|
||||
{
|
||||
/// <summary>
|
||||
/// 登录面板(miHoYo风格布局)
|
||||
/// 支持[ExecuteInEditMode],在编辑器模式下也能预览布局效果
|
||||
/// </summary>
|
||||
[ExecuteInEditMode]
|
||||
public class LoginPanel : BasePanel
|
||||
{
|
||||
[Header("UI References")]
|
||||
public TMP_InputField usernameInput;
|
||||
public TMP_InputField passwordInput;
|
||||
public Button loginBtn;
|
||||
public Button registerBtn;
|
||||
public Button changePasswordBtn;
|
||||
public Button guestLoginBtn;
|
||||
public TMP_Text tipText;
|
||||
|
||||
// 运行时创建的UI元素引用
|
||||
private GameObject subtitleObj; // 副标题 "TECH OTAKUS SAVE THE WORLD"
|
||||
private GameObject closeBtnObj; // 关闭按钮 X
|
||||
private GameObject agreementRowObj; // 协议勾选行
|
||||
|
||||
private bool initialized;
|
||||
|
||||
#if UNITY_EDITOR
|
||||
private int lastLayoutVersion = 0;
|
||||
#endif
|
||||
|
||||
protected override void Awake()
|
||||
{
|
||||
base.Awake();
|
||||
InitLayout();
|
||||
// 仅在运行模式下绑定按钮事件(编辑模式不需要)
|
||||
if (Application.isPlaying)
|
||||
BindButtons();
|
||||
}
|
||||
|
||||
#if UNITY_EDITOR
|
||||
/// <summary>
|
||||
/// 编辑器模式下,脚本加载、Inspector值变化、对象选中时都会触发
|
||||
/// 确保在Scene视图中也能看到正确布局
|
||||
/// </summary>
|
||||
private void OnValidate()
|
||||
{
|
||||
// 避免在非播放模式且对象未激活时执行(Awake不会触发的情况)
|
||||
if (!Application.isPlaying && gameObject.activeInHierarchy)
|
||||
{
|
||||
// 延迟一帧执行,确保所有序列化字段已就绪
|
||||
UnityEditor.EditorApplication.delayCall += () =>
|
||||
{
|
||||
if (this != null && gameObject != null)
|
||||
InitLayout();
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 右键菜单:手动刷新布局
|
||||
/// </summary>
|
||||
[UnityEditor.MenuItem("CONTEXT/LoginPanel/刷新布局")]
|
||||
private static void RefreshLayout(UnityEditor.MenuCommand command)
|
||||
{
|
||||
var panel = (LoginPanel)command.context;
|
||||
if (panel != null)
|
||||
{
|
||||
panel.initialized = false; // 强制重新初始化
|
||||
panel.InitLayout();
|
||||
UnityEditor.EditorUtility.SetDirty(panel);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
/// <summary>
|
||||
/// 初始化miHoYo风格布局(每次Awake调用,确保Play模式下修改也生效)
|
||||
/// </summary>
|
||||
private void InitLayout()
|
||||
{
|
||||
var card = transform.Find("Card");
|
||||
if (card == null)
|
||||
{
|
||||
Debug.LogError("[LoginPanel] Card not found!");
|
||||
return;
|
||||
}
|
||||
|
||||
var cardRt = card.GetComponent<RectTransform>();
|
||||
|
||||
// === 1. 标题: miHoYo + 副标题 ===
|
||||
SetupTitle(card);
|
||||
|
||||
// === 2. 输入框:去掉标签,更新placeholder ===
|
||||
SetupInputFields(card);
|
||||
|
||||
// === 3. 按钮文字与样式 ===
|
||||
SetupButtons(card);
|
||||
|
||||
// === 4. 隐藏游客登录按钮 ===
|
||||
var guestBtn = card.Find("游客登录Btn");
|
||||
if (guestBtn != null) guestBtn.gameObject.SetActive(false);
|
||||
|
||||
// === 5. 提示文字位置 ===
|
||||
var tip = card.Find("TipText");
|
||||
if (tip != null)
|
||||
{
|
||||
var tipRt = tip.GetComponent<RectTransform>();
|
||||
tipRt.anchorMin = new Vector2(0.5f, 0.5f);
|
||||
tipRt.anchorMax = new Vector2(0.5f, 0.5f);
|
||||
tipRt.pivot = new Vector2(0.5f, 0.5f);
|
||||
tipRt.sizeDelta = new Vector2(300f, 30f);
|
||||
tipRt.anchoredPosition = new Vector2(0f, -175f);
|
||||
}
|
||||
|
||||
// === 6. 创建协议勾选行 ===
|
||||
SetupAgreementRow(card);
|
||||
|
||||
// === 7. 创建关闭按钮(X) ===
|
||||
SetupCloseButton(card);
|
||||
}
|
||||
|
||||
#region 布局子方法
|
||||
|
||||
private void SetupTitle(Transform card)
|
||||
{
|
||||
var titleTf = card.Find("Title");
|
||||
if (titleTf == null) return;
|
||||
|
||||
var titleRt = titleTf.GetComponent<RectTransform>();
|
||||
titleRt.anchorMin = new Vector2(0.5f, 0.5f);
|
||||
titleRt.anchorMax = new Vector2(0.5f, 0.5f);
|
||||
titleRt.pivot = new Vector2(0.5f, 0.5f);
|
||||
titleRt.sizeDelta = new Vector2(380f, 50f);
|
||||
titleRt.anchoredPosition = new Vector2(0f, 220f);
|
||||
|
||||
var titleTxt = titleTf.GetComponent<TMP_Text>();
|
||||
if (titleTxt != null)
|
||||
{
|
||||
titleTxt.text = "miHoYo";
|
||||
titleTxt.fontSize = 28f;
|
||||
titleTxt.fontStyle = FontStyles.Bold;
|
||||
titleTxt.alignment = TextAlignmentOptions.Center;
|
||||
}
|
||||
|
||||
// 副标题
|
||||
subtitleObj = EnsureChild(card, "Subtitle", "Title");
|
||||
if (subtitleObj != null)
|
||||
{
|
||||
var subRt = subtitleObj.GetComponent<RectTransform>();
|
||||
ResetRectTransform(subRt,
|
||||
new Vector2(0.5f, 0.5f), new Vector2(0.5f, 0.5f),
|
||||
new Vector2(0.5f, 0.5f), new Vector2(380f, 20f),
|
||||
new Vector2(0f, 185f));
|
||||
|
||||
var subTxt = subtitleObj.GetComponent<TextMeshProUGUI>();
|
||||
if (subTxt == null)
|
||||
{
|
||||
subTxt = subtitleObj.AddComponent<TextMeshProUGUI>();
|
||||
subTxt.font = GetFont(card);
|
||||
}
|
||||
subTxt.text = "TECH OTAKUS SAVE THE WORLD";
|
||||
subTxt.fontSize = 10f;
|
||||
subTxt.color = new Color(0.6f, 0.6f, 0.6f);
|
||||
subTxt.alignment = TextAlignmentOptions.Center;
|
||||
}
|
||||
}
|
||||
|
||||
private void SetupInputFields(Transform card)
|
||||
{
|
||||
string accKey = "账号Group";
|
||||
string pwdKey = "密码Group";
|
||||
|
||||
// 账号输入框
|
||||
var accGroup = card.Find(accKey);
|
||||
if (accGroup != null)
|
||||
{
|
||||
// 隐藏标签
|
||||
var label = accGroup.Find("Label");
|
||||
if (label != null) label.gameObject.SetActive(false);
|
||||
|
||||
// 调整Group和InputField尺寸
|
||||
var grpRt = accGroup.GetComponent<RectTransform>();
|
||||
grpRt.anchorMin = new Vector2(0.5f, 0.5f);
|
||||
grpRt.anchorMax = new Vector2(0.5f, 0.5f);
|
||||
grpRt.pivot = new Vector2(0.5f, 0.5f);
|
||||
grpRt.sizeDelta = new Vector2(380f, 55f);
|
||||
grpRt.anchoredPosition = new Vector2(0f, 125f);
|
||||
|
||||
var inputField = accGroup.Find("InputField");
|
||||
if (inputField != null)
|
||||
{
|
||||
var inputRt = inputField.GetComponent<RectTransform>();
|
||||
inputRt.sizeDelta = new Vector2(360f, 50f);
|
||||
inputRt.anchoredPosition = Vector2.zero;
|
||||
|
||||
var placeholder = inputField.Find("Placeholder")?.GetComponent<TMP_Text>();
|
||||
if (placeholder != null) placeholder.text = "输入手机号/邮箱";
|
||||
|
||||
var inputImg = inputField.GetComponent<Image>();
|
||||
if (inputImg != null) inputImg.color = new Color(0.95f, 0.96f, 0.97f, 1f);
|
||||
}
|
||||
}
|
||||
|
||||
// 密码输入框
|
||||
var pwdGroup = card.Find(pwdKey);
|
||||
if (pwdGroup != null)
|
||||
{
|
||||
var label = pwdGroup.Find("Label");
|
||||
if (label != null) label.gameObject.SetActive(false);
|
||||
|
||||
var grpRt = pwdGroup.GetComponent<RectTransform>();
|
||||
grpRt.anchorMin = new Vector2(0.5f, 0.5f);
|
||||
grpRt.anchorMax = new Vector2(0.5f, 0.5f);
|
||||
grpRt.pivot = new Vector2(0.5f, 0.5f);
|
||||
grpRt.sizeDelta = new Vector2(380f, 55f);
|
||||
grpRt.anchoredPosition = new Vector2(0f, 60f);
|
||||
|
||||
var inputField = pwdGroup.Find("InputField");
|
||||
if (inputField != null)
|
||||
{
|
||||
var inputRt = inputField.GetComponent<RectTransform>();
|
||||
inputRt.sizeDelta = new Vector2(360f, 50f);
|
||||
inputRt.anchoredPosition = Vector2.zero;
|
||||
|
||||
var placeholder = inputField.Find("Placeholder")?.GetComponent<TMP_Text>();
|
||||
if (placeholder != null) placeholder.text = "输入密码";
|
||||
|
||||
var inputImg = inputField.GetComponent<Image>();
|
||||
if (inputImg != null) inputImg.color = new Color(0.95f, 0.96f, 0.97f, 1f);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void SetupButtons(Transform card)
|
||||
{
|
||||
// 登录按钮 -> 进入游戏(放在输入框下方)
|
||||
var loginBtnTf = card.Find("登录Btn");
|
||||
if (loginBtnTf != null)
|
||||
{
|
||||
var btnRt = loginBtnTf.GetComponent<RectTransform>();
|
||||
btnRt.sizeDelta = new Vector2(380f, 50f);
|
||||
btnRt.anchoredPosition = new Vector2(0f, 0f);
|
||||
|
||||
var btnImg = loginBtnTf.GetComponent<Image>();
|
||||
if (btnImg != null) btnImg.color = new Color(0.18f, 0.22f, 0.28f); // 深灰底色
|
||||
|
||||
var loginTxt = loginBtnTf.Find("Text")?.GetComponent<TMP_Text>();
|
||||
if (loginTxt != null)
|
||||
{
|
||||
loginTxt.text = "进入游戏";
|
||||
loginTxt.fontSize = 20f;
|
||||
loginTxt.fontStyle = FontStyles.Bold;
|
||||
loginTxt.color = Color.white;
|
||||
}
|
||||
}
|
||||
|
||||
// 注册按钮 -> 没有账号?立即注册 (橙色文字链接)
|
||||
var regBtnTf = card.Find("注册账号Btn");
|
||||
if (regBtnTf != null)
|
||||
{
|
||||
var regRt = regBtnTf.GetComponent<RectTransform>();
|
||||
regRt.sizeDelta = new Vector2(180f, 36f);
|
||||
regRt.anchoredPosition = new Vector2(-90f, -55f);
|
||||
|
||||
var regImg = regBtnTf.GetComponent<Image>();
|
||||
if (regImg != null) regImg.enabled = false; // 无背景
|
||||
|
||||
var regTxt = regBtnTf.Find("Text")?.GetComponent<TMP_Text>();
|
||||
if (regTxt != null)
|
||||
{
|
||||
regTxt.text = "没有账号?立即注册";
|
||||
regTxt.fontSize = 14f;
|
||||
regTxt.color = new Color(1f, 0.75f, 0f); // 橙色
|
||||
}
|
||||
}
|
||||
|
||||
// 修改密码按钮 -> 忘记密码 (灰色文字链接)
|
||||
var pwdBtnTf = card.Find("修改密码Btn");
|
||||
if (pwdBtnTf != null)
|
||||
{
|
||||
var pwdRt = pwdBtnTf.GetComponent<RectTransform>();
|
||||
pwdRt.sizeDelta = new Vector2(100f, 36f);
|
||||
pwdRt.anchoredPosition = new Vector2(130f, -55f);
|
||||
|
||||
var pwdImg = pwdBtnTf.GetComponent<Image>();
|
||||
if (pwdImg != null) pwdImg.enabled = false; // 无背景
|
||||
|
||||
var pwdTxt = pwdBtnTf.Find("Text")?.GetComponent<TMP_Text>();
|
||||
if (pwdTxt != null)
|
||||
{
|
||||
pwdTxt.text = "忘记密码";
|
||||
pwdTxt.fontSize = 14f;
|
||||
pwdTxt.color = new Color(0.55f, 0.45f, 0.35f); // 灰棕色
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void SetupAgreementRow(Transform card)
|
||||
{
|
||||
agreementRowObj = EnsureChild(card, "AgreementRow", "TipText");
|
||||
if (agreementRowObj == null) return;
|
||||
|
||||
var rowRt = agreementRowObj.GetComponent<RectTransform>();
|
||||
rowRt.anchorMin = new Vector2(0.5f, 0.5f);
|
||||
rowRt.anchorMax = new Vector2(0.5f, 0.5f);
|
||||
rowRt.pivot = new Vector2(0.5f, 0.5f);
|
||||
rowRt.sizeDelta = new Vector2(380f, 30f);
|
||||
rowRt.anchoredPosition = new Vector2(200f, -95f);
|
||||
|
||||
// === Toggle复选框 ===
|
||||
var toggleGo = EnsureChild(agreementRowObj.transform, "Toggle", null);
|
||||
var trt = toggleGo.GetComponent<RectTransform>();
|
||||
ResetRectTransform(trt, new Vector2(0f, 0.5f), new Vector2(0f, 0.5f),
|
||||
new Vector2(0f, 0.5f), new Vector2(20f, 20f), new Vector2(-190f, 0f));
|
||||
|
||||
var tgl = toggleGo.GetComponent<Toggle>();
|
||||
if (tgl == null) tgl = toggleGo.AddComponent<Toggle>();
|
||||
tgl.isOn = true;
|
||||
|
||||
var bgImg = toggleGo.GetComponent<Image>();
|
||||
if (bgImg == null) bgImg = toggleGo.AddComponent<Image>();
|
||||
bgImg.color = new Color(0.9f, 0.9f, 0.9f);
|
||||
|
||||
// Checkmark(仅在不存在时创建)
|
||||
if (toggleGo.transform.Find("Checkmark") == null)
|
||||
{
|
||||
var chk = new GameObject("Checkmark");
|
||||
chk.transform.SetParent(toggleGo.transform, false);
|
||||
var crt = chk.AddComponent<RectTransform>();
|
||||
crt.anchorMin = Vector2.zero;
|
||||
crt.anchorMax = Vector2.zero;
|
||||
crt.sizeDelta = new Vector2(18f, 18f);
|
||||
crt.anchoredPosition = Vector2.zero;
|
||||
crt.pivot = new Vector2(0.5f, 0.5f);
|
||||
var cki = chk.AddComponent<Image>();
|
||||
cki.color = new Color(0.15f, 0.55f, 1f); // 蓝色勾
|
||||
tgl.graphic = cki;
|
||||
}
|
||||
|
||||
// === 协议文本 ===
|
||||
var txtGo = EnsureChild(agreementRowObj.transform, "AgreeText", "Toggle");
|
||||
var txtRt = txtGo.GetComponent<RectTransform>();
|
||||
ResetRectTransform(txtRt, new Vector2(0f, 0.5f), new Vector2(1f, 0.5f),
|
||||
new Vector2(0.5f, 0.5f), new Vector2(340f, 25f), new Vector2(10f, 0f));
|
||||
|
||||
var agreeTxt = txtGo.GetComponent<TextMeshProUGUI>();
|
||||
if (agreeTxt == null)
|
||||
{
|
||||
agreeTxt = txtGo.AddComponent<TextMeshProUGUI>();
|
||||
agreeTxt.font = GetFont(card);
|
||||
}
|
||||
agreeTxt.text = "已同意《用户协议》和《隐私政策》";
|
||||
agreeTxt.fontSize = 13f;
|
||||
agreeTxt.color = new Color(0.65f, 0.65f, 0.65f);
|
||||
agreeTxt.alignment = TextAlignmentOptions.Left;
|
||||
}
|
||||
|
||||
private void SetupCloseButton(Transform card)
|
||||
{
|
||||
closeBtnObj = EnsureChild(card, "CloseBtn", null, insertAtFront: true);
|
||||
if (closeBtnObj == null) return;
|
||||
|
||||
var cRt = closeBtnObj.GetComponent<RectTransform>();
|
||||
ResetRectTransform(cRt, new Vector2(1f, 1f), new Vector2(1f, 1f),
|
||||
new Vector2(0.5f, 0.5f), new Vector2(30f, 30f), new Vector2(-20f, -20f));
|
||||
|
||||
if (closeBtnObj.GetComponent<Button>() == null)
|
||||
closeBtnObj.AddComponent<Button>().onClick.AddListener(() => Debug.Log("[LoginPanel] 关闭"));
|
||||
|
||||
var cImg = closeBtnObj.GetComponent<Image>();
|
||||
if (cImg == null) cImg = closeBtnObj.AddComponent<Image>();
|
||||
cImg.color = new Color(0.3f, 0.3f, 0.3f);
|
||||
|
||||
// X 文字(始终重置位置)
|
||||
var xTf = EnsureChild(closeBtnObj.transform, "XText", null);
|
||||
var xRt = xTf.GetComponent<RectTransform>();
|
||||
ResetRectTransform(xRt, Vector2.zero, Vector2.zero,
|
||||
new Vector2(0.5f, 0.5f), new Vector2(30f, 30f), Vector2.zero);
|
||||
|
||||
var xtxt = xTf.GetComponent<TextMeshProUGUI>();
|
||||
if (xtxt == null)
|
||||
{
|
||||
xtxt = xTf.AddComponent<TextMeshProUGUI>();
|
||||
xtxt.font = GetFont(card);
|
||||
}
|
||||
xtxt.text = "\u00D7"; // × 符号
|
||||
xtxt.fontSize = 18f;
|
||||
xtxt.color = Color.white;
|
||||
xtxt.alignment = TextAlignmentOptions.Center;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region 工具方法
|
||||
|
||||
/// <summary>确保子对象存在,不存在则创建。insertAfterName指定在哪个兄弟之后插入</summary>
|
||||
private GameObject EnsureChild(Transform parent, string name, string insertAfterName = null, bool insertAtFront = false)
|
||||
{
|
||||
var existing = parent.Find(name)?.gameObject;
|
||||
if (existing != null) return existing;
|
||||
|
||||
var go = new GameObject(name);
|
||||
go.transform.SetParent(parent, false);
|
||||
go.AddComponent<RectTransform>(); // 确保有RT组件
|
||||
|
||||
// 设置插入位置
|
||||
if (insertAtFront)
|
||||
go.transform.SetAsFirstSibling();
|
||||
else if (!string.IsNullOrEmpty(insertAfterName))
|
||||
{
|
||||
var afterTf = parent.Find(insertAfterName);
|
||||
if (afterTf != null)
|
||||
go.transform.SetSiblingIndex(afterTf.GetSiblingIndex() + 1);
|
||||
}
|
||||
|
||||
return go;
|
||||
}
|
||||
|
||||
/// <summary>完全重置RectTransform的所有属性(解决编辑模式下新建对象RT默认值异常的问题)</summary>
|
||||
private static void ResetRectTransform(RectTransform rt, Vector2 anchorMin, Vector2 anchorMax,
|
||||
Vector2 pivot, Vector2 sizeDelta, Vector2 anchoredPosition)
|
||||
{
|
||||
rt.anchorMin = anchorMin;
|
||||
rt.anchorMax = anchorMax;
|
||||
rt.pivot = pivot;
|
||||
rt.sizeDelta = sizeDelta;
|
||||
rt.anchoredPosition = anchoredPosition;
|
||||
// 注意:不要设offsetMin/offsetMax,它们会覆盖上面设置的sizeDelta和anchoredPosition
|
||||
}
|
||||
|
||||
private TMP_FontAsset GetFont(Transform card)
|
||||
{
|
||||
var titleTxt = card.Find("Title")?.GetComponent<TMP_Text>();
|
||||
if (titleTxt != null && titleTxt.font != null)
|
||||
return titleTxt.font;
|
||||
// fallback: 从全局资源找SimHei_SDF
|
||||
var font = Resources.Load<TMP_FontAsset>("Fonts/SimHei_SDF");
|
||||
if (font != null) return font;
|
||||
return null;
|
||||
}
|
||||
|
||||
private void BindButtons()
|
||||
{
|
||||
if (initialized) return;
|
||||
initialized = true;
|
||||
if (loginBtn != null) loginBtn.onClick.AddListener(OnLoginClick);
|
||||
if (registerBtn != null) registerBtn.onClick.AddListener(OnRegisterClick);
|
||||
if (changePasswordBtn != null) changePasswordBtn.onClick.AddListener(OnChangePasswordClick);
|
||||
if (guestLoginBtn != null) guestLoginBtn.onClick.AddListener(OnGuestLoginClick);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
private void OnLoginClick()
|
||||
{
|
||||
string username = usernameInput.text.Trim();
|
||||
string password = passwordInput.text.Trim();
|
||||
|
||||
if (string.IsNullOrEmpty(username))
|
||||
{
|
||||
ShowTip("请输入账号");
|
||||
return;
|
||||
}
|
||||
if (string.IsNullOrEmpty(password))
|
||||
{
|
||||
ShowTip("请输入密码");
|
||||
return;
|
||||
}
|
||||
|
||||
// TODO: 接入实际登录接口
|
||||
Debug.Log($"[SDK] 登录请求: 账号={username}, 密码={password}");
|
||||
ShowTip("登录中...");
|
||||
|
||||
// 模拟登录成功
|
||||
SDKManager.Instance.LoginSuccess(username);
|
||||
SDKUIManager.Instance.PopPanel();
|
||||
SDKUIManager.Instance.ShowPanel<RealNameAuthPanel>();
|
||||
}
|
||||
|
||||
private void OnRegisterClick()
|
||||
{
|
||||
SDKUIManager.Instance.ShowPanel<RegisterPanel>();
|
||||
}
|
||||
|
||||
private void OnChangePasswordClick()
|
||||
{
|
||||
SDKUIManager.Instance.ShowPanel<ChangePasswordPanel>();
|
||||
}
|
||||
|
||||
private void OnGuestLoginClick()
|
||||
{
|
||||
Debug.Log("[SDK] 游客登录");
|
||||
SDKManager.Instance.LoginSuccess("Guest_" + Random.Range(1000, 9999));
|
||||
SDKUIManager.Instance.PopPanel();
|
||||
SDKUIManager.Instance.ShowPanel<RealNameAuthPanel>();
|
||||
}
|
||||
|
||||
private void ShowTip(string msg)
|
||||
{
|
||||
tipText.text = msg;
|
||||
}
|
||||
|
||||
public override void OnEnter()
|
||||
{
|
||||
base.OnEnter();
|
||||
usernameInput.text = "";
|
||||
passwordInput.text = "";
|
||||
tipText.text = "";
|
||||
}
|
||||
}
|
||||
}
|
||||
11
Assets/Scripts/SDK/LoginPanel.cs.meta
Normal file
11
Assets/Scripts/SDK/LoginPanel.cs.meta
Normal file
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: Xi5NtHn4VH3blNa2yzsMjhHddSjv4pAjXWVdcpNdQC2XBAzFvtweUEI=
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
109
Assets/Scripts/SDK/RealNameAuthPanel.cs
Normal file
109
Assets/Scripts/SDK/RealNameAuthPanel.cs
Normal file
@@ -0,0 +1,109 @@
|
||||
using UnityEngine;
|
||||
using UnityEngine.UI;
|
||||
using TMPro;
|
||||
|
||||
namespace GameSDK
|
||||
{
|
||||
/// <summary>
|
||||
/// 实名认证面板
|
||||
/// </summary>
|
||||
public class RealNameAuthPanel : BasePanel
|
||||
{
|
||||
[Header("UI References")]
|
||||
public TMP_InputField realNameInput;
|
||||
public TMP_InputField idCardInput;
|
||||
public Button submitBtn;
|
||||
public Button skipBtn;
|
||||
public TMP_Text tipText;
|
||||
|
||||
private bool initialized;
|
||||
|
||||
private void OnEnable()
|
||||
{
|
||||
if (initialized) return;
|
||||
initialized = true;
|
||||
submitBtn.onClick.AddListener(OnSubmitClick);
|
||||
skipBtn.onClick.AddListener(OnSkipClick);
|
||||
}
|
||||
|
||||
private void OnSubmitClick()
|
||||
{
|
||||
string realName = realNameInput.text.Trim();
|
||||
string idCard = idCardInput.text.Trim();
|
||||
|
||||
if (string.IsNullOrEmpty(realName))
|
||||
{
|
||||
ShowTip("请输入真实姓名");
|
||||
return;
|
||||
}
|
||||
if (realName.Length < 2)
|
||||
{
|
||||
ShowTip("姓名格式不正确");
|
||||
return;
|
||||
}
|
||||
if (string.IsNullOrEmpty(idCard))
|
||||
{
|
||||
ShowTip("请输入身份证号码");
|
||||
return;
|
||||
}
|
||||
if (!ValidateIdCard(idCard))
|
||||
{
|
||||
ShowTip("身份证号码格式不正确");
|
||||
return;
|
||||
}
|
||||
|
||||
// TODO: 接入实际实名认证接口
|
||||
Debug.Log($"[SDK] 实名认证请求: 姓名={realName}, 身份证={MaskIdCard(idCard)}");
|
||||
ShowTip("认证中...");
|
||||
|
||||
// 模拟认证成功
|
||||
Debug.Log("[SDK] 实名认证成功");
|
||||
CloseSDK();
|
||||
}
|
||||
|
||||
private void OnSkipClick()
|
||||
{
|
||||
Debug.Log("[SDK] 跳过实名认证");
|
||||
CloseSDK();
|
||||
}
|
||||
|
||||
private void CloseSDK()
|
||||
{
|
||||
// 关闭SDK界面
|
||||
Debug.Log($"[SDK] 用户: {SDKManager.Instance.CurrentUser} 已进入游戏");
|
||||
// 实际项目中可销毁SDK UI的Canvas
|
||||
var canvas = GetComponentInParent<Canvas>();
|
||||
if (canvas != null) canvas.gameObject.SetActive(false);
|
||||
}
|
||||
|
||||
private bool ValidateIdCard(string idCard)
|
||||
{
|
||||
if (idCard.Length != 18) return false;
|
||||
for (int i = 0; i < 17; i++)
|
||||
{
|
||||
if (!char.IsDigit(idCard[i])) return false;
|
||||
}
|
||||
char last = idCard[17];
|
||||
return char.IsDigit(last) || last == 'X' || last == 'x';
|
||||
}
|
||||
|
||||
private string MaskIdCard(string idCard)
|
||||
{
|
||||
if (idCard.Length != 18) return idCard;
|
||||
return idCard.Substring(0, 4) + "**********" + idCard.Substring(14);
|
||||
}
|
||||
|
||||
private void ShowTip(string msg)
|
||||
{
|
||||
tipText.text = msg;
|
||||
}
|
||||
|
||||
public override void OnEnter()
|
||||
{
|
||||
base.OnEnter();
|
||||
realNameInput.text = "";
|
||||
idCardInput.text = "";
|
||||
tipText.text = "";
|
||||
}
|
||||
}
|
||||
}
|
||||
11
Assets/Scripts/SDK/RealNameAuthPanel.cs.meta
Normal file
11
Assets/Scripts/SDK/RealNameAuthPanel.cs.meta
Normal file
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: CC8f5nytWnn9BcO0gURVQqpFdbjumhEuvsiDMG8qioTNJ0qqjNAOgio=
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
90
Assets/Scripts/SDK/RegisterPanel.cs
Normal file
90
Assets/Scripts/SDK/RegisterPanel.cs
Normal file
@@ -0,0 +1,90 @@
|
||||
using UnityEngine;
|
||||
using UnityEngine.UI;
|
||||
using TMPro;
|
||||
|
||||
namespace GameSDK
|
||||
{
|
||||
/// <summary>
|
||||
/// 注册面板
|
||||
/// </summary>
|
||||
public class RegisterPanel : BasePanel
|
||||
{
|
||||
[Header("UI References")]
|
||||
public TMP_InputField usernameInput;
|
||||
public TMP_InputField passwordInput;
|
||||
public TMP_InputField confirmPasswordInput;
|
||||
public Button registerBtn;
|
||||
public Button backBtn;
|
||||
public TMP_Text tipText;
|
||||
|
||||
private bool initialized;
|
||||
|
||||
private void OnEnable()
|
||||
{
|
||||
if (initialized) return;
|
||||
initialized = true;
|
||||
registerBtn.onClick.AddListener(OnRegisterClick);
|
||||
backBtn.onClick.AddListener(OnBackClick);
|
||||
}
|
||||
|
||||
private void OnRegisterClick()
|
||||
{
|
||||
string username = usernameInput.text.Trim();
|
||||
string password = passwordInput.text.Trim();
|
||||
string confirmPassword = confirmPasswordInput.text.Trim();
|
||||
|
||||
if (string.IsNullOrEmpty(username))
|
||||
{
|
||||
ShowTip("请输入账号");
|
||||
return;
|
||||
}
|
||||
if (username.Length < 4 || username.Length > 20)
|
||||
{
|
||||
ShowTip("账号长度需在4-20个字符之间");
|
||||
return;
|
||||
}
|
||||
if (string.IsNullOrEmpty(password))
|
||||
{
|
||||
ShowTip("请输入密码");
|
||||
return;
|
||||
}
|
||||
if (password.Length < 6)
|
||||
{
|
||||
ShowTip("密码长度不能少于6位");
|
||||
return;
|
||||
}
|
||||
if (password != confirmPassword)
|
||||
{
|
||||
ShowTip("两次输入的密码不一致");
|
||||
return;
|
||||
}
|
||||
|
||||
// TODO: 接入实际注册接口
|
||||
Debug.Log($"[SDK] 注册请求: 账号={username}");
|
||||
ShowTip("注册中...");
|
||||
|
||||
// 模拟注册成功
|
||||
Debug.Log("[SDK] 注册成功");
|
||||
SDKUIManager.Instance.PopPanel();
|
||||
}
|
||||
|
||||
private void OnBackClick()
|
||||
{
|
||||
SDKUIManager.Instance.PopPanel();
|
||||
}
|
||||
|
||||
private void ShowTip(string msg)
|
||||
{
|
||||
tipText.text = msg;
|
||||
}
|
||||
|
||||
public override void OnEnter()
|
||||
{
|
||||
base.OnEnter();
|
||||
usernameInput.text = "";
|
||||
passwordInput.text = "";
|
||||
confirmPasswordInput.text = "";
|
||||
tipText.text = "";
|
||||
}
|
||||
}
|
||||
}
|
||||
11
Assets/Scripts/SDK/RegisterPanel.cs.meta
Normal file
11
Assets/Scripts/SDK/RegisterPanel.cs.meta
Normal file
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: B3IavSKrVC/xXwDniptviVynL8MsgiJ9ofPr3YVmz8oOpeVzqg2331A=
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
55
Assets/Scripts/SDK/SDKInit.cs
Normal file
55
Assets/Scripts/SDK/SDKInit.cs
Normal file
@@ -0,0 +1,55 @@
|
||||
using UnityEngine;
|
||||
|
||||
namespace GameSDK
|
||||
{
|
||||
/// <summary>
|
||||
/// SDK 入口脚本,挂到游戏中的任意 GameObject 即可调用
|
||||
/// 使用示例:
|
||||
/// 1. 在场景中创建空物体,挂载此脚本
|
||||
/// 2. 代码中调用 GameSDK.SDKInit.Show();
|
||||
/// </summary>
|
||||
public class SDKInit : MonoBehaviour
|
||||
{
|
||||
[Header("SDK 配置")]
|
||||
[Tooltip("SDK 服务器地址(后续接入用)")]
|
||||
public string serverUrl = "https://sdk.example.com/api";
|
||||
|
||||
/// <summary>
|
||||
/// 显示 SDK 登录界面
|
||||
/// </summary>
|
||||
public static void Show()
|
||||
{
|
||||
if (SDKManager.Instance == null)
|
||||
{
|
||||
Debug.LogWarning("[SDK] SDKRoot 未初始化,请确认场景中包含 SDK UI 对象");
|
||||
return;
|
||||
}
|
||||
SDKUIManager.Instance.ShowPanel<LoginPanel>();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 关闭 SDK 所有界面
|
||||
/// </summary>
|
||||
public static void Hide()
|
||||
{
|
||||
if (SDKUIManager.Instance != null)
|
||||
SDKUIManager.Instance.CloseAll();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取当前登录用户名(未登录返回 null)
|
||||
/// </summary>
|
||||
public static string GetCurrentUser()
|
||||
{
|
||||
return SDKManager.Instance != null ? SDKManager.Instance.CurrentUser : null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 是否已登录
|
||||
/// </summary>
|
||||
public static bool IsLoggedIn()
|
||||
{
|
||||
return SDKManager.Instance != null && SDKManager.Instance.IsLoggedIn;
|
||||
}
|
||||
}
|
||||
}
|
||||
11
Assets/Scripts/SDK/SDKInit.cs.meta
Normal file
11
Assets/Scripts/SDK/SDKInit.cs.meta
Normal file
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: C3MZvSukVHizZ2Xlg61Vg0e80CArhJH0zTs2e4vcoPRa7HPCDrBnEYw=
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
92
Assets/Scripts/SDK/SDKManager.cs
Normal file
92
Assets/Scripts/SDK/SDKManager.cs
Normal file
@@ -0,0 +1,92 @@
|
||||
using UnityEngine;
|
||||
using UnityEngine.Events;
|
||||
|
||||
namespace GameSDK
|
||||
{
|
||||
/// <summary>
|
||||
/// SDK 主入口,单例模式
|
||||
/// </summary>
|
||||
public class SDKManager : MonoBehaviour
|
||||
{
|
||||
public static SDKManager Instance { get; private set; }
|
||||
|
||||
public event UnityAction OnLoginSuccess;
|
||||
public event UnityAction OnLogout;
|
||||
|
||||
public bool IsLoggedIn { get; private set; }
|
||||
public string CurrentUser { get; private set; }
|
||||
|
||||
[Tooltip("是否在启动时自动弹出登录面板")]
|
||||
public bool autoShowLogin = true;
|
||||
|
||||
private bool panelsRegistered = false;
|
||||
|
||||
private void Awake()
|
||||
{
|
||||
if (Instance != null && Instance != this)
|
||||
{
|
||||
Destroy(gameObject);
|
||||
return;
|
||||
}
|
||||
Instance = this;
|
||||
|
||||
// 确保整个 SDK Canvas 不被销毁
|
||||
var canvas = GetComponentInParent<Canvas>();
|
||||
if (canvas != null)
|
||||
DontDestroyOnLoad(canvas.gameObject);
|
||||
}
|
||||
|
||||
private void Start()
|
||||
{
|
||||
// Start 在所有 Awake 之后执行,此时 SDKUIManager.Instance 一定已初始化
|
||||
AutoRegisterPanels();
|
||||
|
||||
if (autoShowLogin && panelsRegistered)
|
||||
{
|
||||
SDKUIManager.Instance.ShowPanel<LoginPanel>();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 自动发现 PanelContainer 下所有面板并注册
|
||||
/// </summary>
|
||||
private void AutoRegisterPanels()
|
||||
{
|
||||
var panelContainer = transform.Find("PanelContainer");
|
||||
if (panelContainer == null)
|
||||
{
|
||||
Debug.LogError("[SDK] PanelContainer not found under SDKRoot!");
|
||||
return;
|
||||
}
|
||||
|
||||
for (int i = 0; i < panelContainer.childCount; i++)
|
||||
{
|
||||
var child = panelContainer.GetChild(i);
|
||||
var panel = child.GetComponent<BasePanel>();
|
||||
if (panel != null)
|
||||
{
|
||||
SDKUIManager.Instance.RegisterPanel(child.name, panel);
|
||||
}
|
||||
}
|
||||
panelsRegistered = true;
|
||||
}
|
||||
|
||||
public void LoginSuccess(string username)
|
||||
{
|
||||
IsLoggedIn = true;
|
||||
CurrentUser = username;
|
||||
Debug.Log($"[SDK] 用户登录成功: {username}");
|
||||
OnLoginSuccess?.Invoke();
|
||||
}
|
||||
|
||||
public void Logout()
|
||||
{
|
||||
IsLoggedIn = false;
|
||||
CurrentUser = null;
|
||||
Debug.Log("[SDK] 用户已退出登录");
|
||||
OnLogout?.Invoke();
|
||||
SDKUIManager.Instance.CloseAll();
|
||||
SDKUIManager.Instance.ShowPanel<LoginPanel>();
|
||||
}
|
||||
}
|
||||
}
|
||||
11
Assets/Scripts/SDK/SDKManager.cs.meta
Normal file
11
Assets/Scripts/SDK/SDKManager.cs.meta
Normal file
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: Cn9MtS2oWy+bFhfAOMM1oD+1reNzjDJRmxSCRfACvUKJSbwYqqBjfHs=
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
107
Assets/Scripts/SDK/SDKUIManager.cs
Normal file
107
Assets/Scripts/SDK/SDKUIManager.cs
Normal file
@@ -0,0 +1,107 @@
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
|
||||
namespace GameSDK
|
||||
{
|
||||
/// <summary>
|
||||
/// UI面板管理器,负责面板的显示/隐藏切换
|
||||
/// </summary>
|
||||
public class SDKUIManager : MonoBehaviour
|
||||
{
|
||||
public static SDKUIManager Instance { get; private set; }
|
||||
|
||||
private Dictionary<string, BasePanel> panelDict = new Dictionary<string, BasePanel>();
|
||||
private Stack<BasePanel> panelStack = new Stack<BasePanel>();
|
||||
|
||||
private void Awake()
|
||||
{
|
||||
if (Instance != null && Instance != this)
|
||||
{
|
||||
Destroy(gameObject);
|
||||
return;
|
||||
}
|
||||
Instance = this;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 显示指定类型的面板,并压入栈(当前面板会暂停)
|
||||
/// </summary>
|
||||
public void ShowPanel<T>() where T : BasePanel
|
||||
{
|
||||
string panelName = typeof(T).Name;
|
||||
if (panelDict.TryGetValue(panelName, out BasePanel panel))
|
||||
{
|
||||
// 暂停当前面板(不弹栈)
|
||||
if (panelStack.Count > 0)
|
||||
{
|
||||
BasePanel topPanel = panelStack.Peek();
|
||||
if (topPanel != panel) topPanel.OnPause();
|
||||
}
|
||||
// 显示新面板并压栈
|
||||
panel.OnEnter();
|
||||
panelStack.Push(panel);
|
||||
}
|
||||
else
|
||||
{
|
||||
Debug.LogError($"[SDK] 面板未注册: {panelName}");
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 关闭当前面板并返回上一个面板
|
||||
/// </summary>
|
||||
public void PopPanel()
|
||||
{
|
||||
if (panelStack.Count > 0)
|
||||
{
|
||||
BasePanel top = panelStack.Pop();
|
||||
top.OnExit();
|
||||
}
|
||||
|
||||
if (panelStack.Count > 0)
|
||||
{
|
||||
BasePanel peek = panelStack.Peek();
|
||||
peek.OnResume();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 注册面板
|
||||
/// </summary>
|
||||
public void RegisterPanel(string panelName, BasePanel panel)
|
||||
{
|
||||
if (!panelDict.ContainsKey(panelName))
|
||||
{
|
||||
panelDict.Add(panelName, panel);
|
||||
// 注册时直接隐藏面板(面板此时 inactive,CanvasGroup 可能还不存在)
|
||||
panel.gameObject.SetActive(false);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 关闭所有面板并显示指定面板(清空栈后重新 Push)
|
||||
/// </summary>
|
||||
public void ShowOnlyPanel<T>() where T : BasePanel
|
||||
{
|
||||
// 清空栈并关闭所有面板
|
||||
while (panelStack.Count > 0)
|
||||
{
|
||||
BasePanel top = panelStack.Pop();
|
||||
top.OnExit();
|
||||
}
|
||||
ShowPanel<T>();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 关闭整个SDK UI
|
||||
/// </summary>
|
||||
public void CloseAll()
|
||||
{
|
||||
while (panelStack.Count > 0)
|
||||
{
|
||||
BasePanel top = panelStack.Pop();
|
||||
top.OnExit();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
11
Assets/Scripts/SDK/SDKUIManager.cs.meta
Normal file
11
Assets/Scripts/SDK/SDKUIManager.cs.meta
Normal file
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: XHwb53ipVXOeCFvcXVvr99Q8CzMIfKRxt5q3gXGZGNAq9DoBpMwJrGg=
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
64
Assets/Scripts/SDK/SDKUIStyle.cs
Normal file
64
Assets/Scripts/SDK/SDKUIStyle.cs
Normal file
@@ -0,0 +1,64 @@
|
||||
using UnityEngine;
|
||||
using UnityEngine.UI;
|
||||
using TMPro;
|
||||
using UnityEngine.EventSystems;
|
||||
|
||||
namespace GameSDK
|
||||
{
|
||||
/// <summary>
|
||||
/// UI 视觉增强工具 - 为按钮添加高亮色、为 InputField 添加选中边框效果
|
||||
/// 挂载到 SDKRoot 上即可自动生效
|
||||
/// </summary>
|
||||
public class SDKUIStyle : MonoBehaviour
|
||||
{
|
||||
[Header("颜色配置")]
|
||||
public Color buttonHoverColor = new Color(0.9f, 0.95f, 1f, 1f);
|
||||
public Color buttonPressedColor = new Color(0.7f, 0.8f, 0.9f, 1f);
|
||||
public Color inputSelectedColor = new Color(0.3f, 0.7f, 1f, 1f);
|
||||
public Color inputNormalColor = new Color(0.85f, 0.85f, 0.85f, 1f);
|
||||
public float transitionDuration = 0.15f;
|
||||
|
||||
private void Start()
|
||||
{
|
||||
ApplyStyles();
|
||||
}
|
||||
|
||||
private void ApplyStyles()
|
||||
{
|
||||
// 为所有按钮添加颜色过渡
|
||||
var buttons = transform.GetComponentsInChildren<Button>(true);
|
||||
foreach (var btn in buttons)
|
||||
{
|
||||
if (btn.colors.highlightedColor == Color.white && btn.colors.pressedColor == Color.white)
|
||||
{
|
||||
var colors = btn.colors;
|
||||
colors.highlightedColor = buttonHoverColor;
|
||||
colors.pressedColor = buttonPressedColor;
|
||||
colors.fadeDuration = transitionDuration;
|
||||
btn.colors = colors;
|
||||
}
|
||||
}
|
||||
|
||||
// 为所有 InputField 添加选中边框效果
|
||||
var inputs = transform.GetComponentsInChildren<TMP_InputField>(true);
|
||||
foreach (var input in inputs)
|
||||
{
|
||||
var img = input.targetGraphic as Image;
|
||||
if (img != null)
|
||||
{
|
||||
img.color = inputNormalColor;
|
||||
}
|
||||
input.onSelect.AddListener((s) =>
|
||||
{
|
||||
if (input.targetGraphic is Image im)
|
||||
im.color = inputSelectedColor;
|
||||
});
|
||||
input.onDeselect.AddListener((s) =>
|
||||
{
|
||||
if (input.targetGraphic is Image im)
|
||||
im.color = inputNormalColor;
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
11
Assets/Scripts/SDK/SDKUIStyle.cs.meta
Normal file
11
Assets/Scripts/SDK/SDKUIStyle.cs.meta
Normal file
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: DXoesimlU3PWXWWFMByKN5/o5J6iWJee2pJBNAiJHoGUTMhvguMxjkw=
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
Reference in New Issue
Block a user