using Assets.MyGame.Scripts.Net; using Assets.MyGame.Scripts.Net.API.GameConfig_SubClass; using Assets.MyGame.Scripts.Net.APIResponses; using DG.Tweening; using System; using System.Collections; using System.Collections.Generic; using TMPro; using UnityEngine; using UnityEngine.UI; public class UIHome_BY_UISignViewPanel : SubUIBase { //text_CoinNums是转盘各个位置的详细值 他从GameManager的activityConfig里面读取signConfigs后端配置的个数和text_CoinNums的个数是对应的 这里赋值的时候需要加上其他的数据公式是 值+值*GameManager的gameConfig的vip的signInAdd签到加成 /*签到API已封装在APIRequestList.SignIn(GET) 实测后端返回 {"data":440,"code":0,"info":null}——data直接是本次奖励的金币数字(不是SignInfo对象) 转盘停靠位置用奖励金额反查signConfigs得到(见FindSlotByReward)*/ //SLZPDieEvent这个脚本有之前写好的多层转盘的逻辑 签到这里只有单层 你可以直接看一下里面正确的 public List text_CoinNums; public List text_CoinNums_TMP; public TextMeshProUGUI tmp_VipJiaCheng; // 显示VIP签到加成百分比 public TextMeshProUGUI tmp_EndCoin; // 显示最终奖励金币数 public Button btn_ChouJiang; public GameObject zhuanPan; Dictionary order_singConfig; [Header("转盘参数(参照SLZPDieEvent)")] public int spinRounds = 5; // 到达目标前转的圈数 public float rotateDuration = 2f; // 旋转总时长 public float dir = -1f; // 旋转方向(-1逆时针,1顺时针) private bool isSpinning; public override void Awake() { base.Awake(); btn_ChouJiang.onClick.AddListener(OnChouJiangClick); } protected override void OnShow(object args = null) { base.OnShow(args); OnChouJiangClick(); RefreshPanel(); } private void RefreshPanel() { BuildOrderSignConfig(); UpdateSlotTexts(); UpdateBtnState(); UpdateVipAddText(); } /// 显示VIP签到加成百分比(signInAdd 0.15 → +15%) private void UpdateVipAddText() { if (tmp_VipJiaCheng == null) return; double add = GetSignInAdd(); tmp_VipJiaCheng.text = $"+{add * 100:0}%"; } /// 从GameManager的activityConfig读取signConfigs,按order建立字典 private void BuildOrderSignConfig() { order_singConfig = new Dictionary(); var signConfigs = GameManager.Instance.activityConfig?.signConfigs; if (signConfigs == null) return; foreach (var cfg in signConfigs) { if (cfg == null) continue; order_singConfig[cfg.order] = cfg; } } /// 当前用户的VIP签到加成(gameConfig.vipLevelConfigs按用户vipLevel匹配signInAdd) private double GetSignInAdd() { var vipConfigs = GameManager.Instance.gameConfig?.vipLevelConfigs; if (vipConfigs == null || vipConfigs.Count == 0) return 0; var user = GameManager.Instance.user; if (user?.assets == null) return 0; var vipCfg = vipConfigs.Find(v => v.level == user.assets.vipLevel); return vipCfg?.signInAdd ?? 0; } /// 转盘格子数量:UGUI Text列表有绑定就用它,否则用TMP列表 private int SlotCount() { if (text_CoinNums != null && text_CoinNums.Count > 0) return text_CoinNums.Count; return text_CoinNums_TMP != null ? text_CoinNums_TMP.Count : 0; } /// 给第index个转盘格子设置文本(兼容UGUI Text与TMP) private void SetSlotText(int index, string value) { if (text_CoinNums != null && index < text_CoinNums.Count) text_CoinNums[index].text = value; else if (text_CoinNums_TMP != null && index < text_CoinNums_TMP.Count) text_CoinNums_TMP[index].text = value; } /// 转盘格子赋值:值+值*signInAdd(VIP签到加成),按order排序后与text_CoinNums一一对应 private void UpdateSlotTexts() { int slotCount = SlotCount(); if (order_singConfig == null || order_singConfig.Count == 0 || slotCount == 0) return; var list = new List(order_singConfig.Values); list.Sort((a, b) => a.order - b.order); double add = GetSignInAdd(); int count = Mathf.Min(list.Count, slotCount); for (int i = 0; i < count; i++) { long gold = list[i].gold; long showGold = gold + (long)Math.Round(gold * add); SetSlotText(i, FormatGold(showGold)); } } /// 今日是否已签到 private bool IsSignedToday() { var sign = GameManager.Instance.user?.sign; return sign != null && sign.isSign; } private void UpdateBtnState() { btn_ChouJiang.interactable = !isSpinning && !IsSignedToday(); } private void OnChouJiangClick() { if (isSpinning) return; btn_ChouJiang.interactable = false; // 后端SignIn的data直接返回本次奖励的金币数(数字) APIRequestList.SignIn(reward => { int slot = FindSlotByReward(reward); if (slot < 0) { // 奖励金额匹配不到任何格子:不转转盘直接提示,避免停错位置 Debug.LogWarning($"[签到] 奖励{reward}在signConfigs里匹配不到对应格子"); OnSignInDone(reward); return; } Debug.Log($"[签到] 奖励{reward} → 转盘格子{slot}"); RotateToSlot(slot, () => OnSignInDone(reward)); }); } /// 签到完成:提示奖励并刷新用户数据 private void OnSignInDone(long reward) { UIManager.Instance.ShowBoardError($"签到成功,获得{FormatGold(reward)}金币"); if (tmp_EndCoin != null) tmp_EndCoin.text = FormatGold(reward); APIRequestList.GetUser(user => { GameManager.Instance.UpdataUserData(user); UpdateBtnState(); }); } /// 按奖励金额反查转盘格子:优先匹配加了VIP加成后的值,其次匹配原始配置值;匹配不到返回-1 private int FindSlotByReward(long reward) { if (order_singConfig == null || order_singConfig.Count == 0 || SlotCount() == 0) return -1; var list = new List(order_singConfig.Values); list.Sort((a, b) => a.order - b.order); double add = GetSignInAdd(); int count = Mathf.Min(list.Count, SlotCount()); int fallback = -1; for (int i = 0; i < count; i++) { long gold = list[i].gold; long withAdd = gold + (long)Math.Round(gold * add); if (withAdd == reward) return i; if (fallback < 0 && gold == reward) fallback = i; } return fallback; } /// 单层转盘旋转停靠(参照SLZPDieEvent:LocalAxisAdd增量旋转+OutCubic缓动+完成强制校正) private void RotateToSlot(int slot, Action onComplete) { isSpinning = true; int cellCount = Mathf.Max(SlotCount(), 1); float targetAngle = slot * (360f / cellCount); float curr = zhuanPan.transform.localRotation.eulerAngles.z; float deltaToTarget = AngleDiff(curr, targetAngle, dir); float totalDelta = dir * spinRounds * 360f + deltaToTarget; Tween tween = zhuanPan.transform.DOLocalRotate(new Vector3(0, 0, totalDelta), rotateDuration, RotateMode.LocalAxisAdd); tween.SetEase(Ease.OutCubic); tween.OnComplete(() => { // 强制校正到精确目标角度,消除浮点误差 zhuanPan.transform.localRotation = Quaternion.Euler(0, 0, targetAngle); isSpinning = false; onComplete?.Invoke(); }); } /// 从curr到target的同向角度差(参照SLZPDieEvent.AngleDiff) private float AngleDiff(float curr, float target, float dir) { float diff = (target - curr) % 360f; if (diff < 0) diff += 360f; if (dir < 0 && diff > 0) diff -= 360f; return diff; } /// 金币数值格式化(万/亿单位) private static string FormatGold(long gold) { if (gold >= 100000000) // 亿 return $"{(gold / 100000000f):F1}亿"; if (gold >= 10000) // 万 return $"{(gold / 10000f):F1}万"; return gold.ToString("N0"); } }