Files
5.24BuYu/Assets/MyGame/aa/UI/Home/Sub/Activity/ChouJiangItem.cs
T
2026-09-23 19:33:45 +08:00

233 lines
9.7 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
using Assets.Framework.Tool;
using Assets.MyGame.Scripts.Net.API.GameConfig_SubClass;
using TMPro;
using UnityEngine;
using UnityEngine.UI;
/// <summary>
/// 抽奖 item 层(第三层):挂在 toggle 层里的每个奖品格子上,
/// 记录道具信息以及奖励的详细信息(prize:类型/数量/权重/库存/道具 product 等),
/// 并负责展示——图标 + 数量文本由代码动态生成在格子下;
/// 已抽中的奖项置灰(奖励不重复)。
///
/// itemId = 本格子的位置编号(对应 prizeId 后两位,如 588203 → 3),
/// 初始化时奖品按它对号入座,Inspector 里按美术摆放顺序填 1、2、3……
/// </summary>
public class ChouJiangItem : MonoBehaviour
{
[Tooltip("本格子的位置编号 = prizeId 后两位(如 588203 → 3),初始化时奖品按它对号入座")]
public int itemId;
[Tooltip("本格子的跑马灯方块预制体:抽奖动效经过/停在本格子时点亮,大小自动设成格子(背景)大小")]
public GameObject prefab_DrawEffect;
[Header("动态生成参数")]
[Tooltip("图标占格子短边的比例")]
public float iconRatio = 0.85f;
[Tooltip("图标中心相对格子中心的纵向偏移(0=居中,负数=往下贴)")]
public float iconOffsetY = 0f;
[Tooltip("数量文本字号")]
public float fontSize = 22f;
[Tooltip("已抽中置灰的颜色")]
public Color drawnColor = new Color(0.35f, 0.35f, 0.35f, 0.5f);
[Tooltip("遮罩蒙版图片(可选):适配不规则格子;蒙版大小=格子(背景)大小,图标放进蒙版里被裁出形状")]
public Sprite maskSprite;
[Header("奖励数据(Init 时由代码填充,Play 模式选中物体可实时查看)")]
[Tooltip("道具信息 + 奖励详细信息(prizeId/名称/图标/类型/数量/道具 product/权重/库存)")]
public LotteryPrize prize;
[Tooltip("是否已被抽中(奖励不重复,抽中后置灰)")]
[SerializeField] private bool isDrawn;
/// <summary>是否已被抽中</summary>
public bool IsDrawn => isDrawn;
private Image img_Icon; // 动态生成的图标
private TextMeshProUGUI tmp_Count; // 动态生成的数量文本
private GameObject maskObj; // 动态生成的遮罩蒙版(不规则裁剪用)
private GameObject effectObj; // 本格子的跑马灯方块实例(懒创建)
// 金币/钻石本地图标(Resources 根目录,与 BackPackPropItem 同一套),静态缓存避免重复加载
private static Sprite _goldSprite;
private static Sprite _diamondSprite;
/// <summary>记录奖励数据并展示(图标 + 数量)</summary>
public void Init(LotteryPrize prize)
{
this.prize = prize; // 记录道具信息以及奖励的详细信息
ClearUI();
if (prize == null) return;
RectTransform rt = transform as RectTransform;
if (rt == null)
{
Debug.LogWarning($"[ChouJiangItem] 格子不是 UI(缺 RectTransform):{name}");
return;
}
float w = rt.rect.width, h = rt.rect.height;
if (w < 1f || h < 1f) { w = 90f; h = 79f; } // 无尺寸兜底
// 遮罩蒙版:大小=格子(背景)大小,图标放进蒙版里被裁出形状(适配不规则格子)
RectTransform iconParent = rt;
if (maskSprite != null)
iconParent = CreateMask(rt, w, h);
// 图标:方形占短边 iconRatio,居中(iconOffsetY 可微调)
float side = Mathf.Min(w, h) * iconRatio;
img_Icon = CreateIcon(iconParent, side);
SetPrizeIcon(img_Icon, prize);
// 数量:压在图标底部(文字叠在图片上面,不进蒙版)
tmp_Count = CreateCountText(rt, w, side);
tmp_Count.text = prize.count.ToString();
// 新数据默认未抽中,已抽列表由面板 Init 后统一刷新
RefreshDrawnState(false);
}
/// <summary>置灰/恢复(奖励不重复,抽中后置灰)</summary>
public void RefreshDrawnState(bool drawn)
{
isDrawn = drawn;
if (img_Icon != null)
img_Icon.color = drawn ? drawnColor : Color.white;
}
/// <summary>
/// 显示/隐藏本格子的跑马灯方块:第一次点亮时用 prefab_DrawEffect 创建实例,
/// 大小自动设成格子(背景)大小、压在最上层。
/// </summary>
public void ShowEffect(bool show)
{
if (show && effectObj == null && prefab_DrawEffect != null)
{
RectTransform rt = transform as RectTransform;
if (rt != null)
{
effectObj = Instantiate(prefab_DrawEffect, rt, false);
RectTransform er = effectObj.transform as RectTransform;
if (er != null)
{
er.anchorMin = er.anchorMax = er.pivot = Vector2.one * 0.5f;
er.anchoredPosition = Vector2.zero;
er.localScale = Vector3.one;
er.sizeDelta = new Vector2(rt.rect.width, rt.rect.height); // 方块大小 = 背景大小
}
effectObj.transform.SetAsLastSibling();
}
}
if (effectObj != null)
effectObj.SetActive(show);
}
/// <summary>清掉动态生成的 UI(重复 Init 复用前调用)</summary>
public void ClearUI()
{
if (img_Icon != null) { Destroy(img_Icon.gameObject); img_Icon = null; }
if (tmp_Count != null) { Destroy(tmp_Count.gameObject); tmp_Count = null; }
if (maskObj != null) { Destroy(maskObj); maskObj = null; }
}
/// <summary>生成遮罩蒙版:Image(maskSprite)+ Mask,居中、大小=格子(背景)大小;图标放它下面被裁剪</summary>
private RectTransform CreateMask(RectTransform parent, float w, float h)
{
maskObj = new GameObject("Mask", typeof(RectTransform));
RectTransform r = (RectTransform)maskObj.transform;
r.SetParent(parent, false);
r.anchorMin = r.anchorMax = r.pivot = Vector2.one * 0.5f;
r.anchoredPosition = Vector2.zero;
// 遮罩 0.9 倍背景大小(试过比全尺寸好看)
r.sizeDelta = new Vector2(w * 0.9f, h * 0.9f);
Image maskImg = maskObj.AddComponent<Image>();
maskImg.sprite = maskSprite;
maskImg.raycastTarget = false;
// 只当裁剪形状用,不显示蒙版图本身
Mask mask = maskObj.AddComponent<Mask>();
mask.showMaskGraphic = false;
return r;
}
/// <summary>生成格子里的图标物体(往下贴 iconOffsetY)</summary>
private Image CreateIcon(RectTransform parent, float side)
{
GameObject go = new GameObject("Icon", typeof(RectTransform));
RectTransform r = (RectTransform)go.transform;
r.SetParent(parent, false);
r.anchorMin = r.anchorMax = r.pivot = Vector2.one * 0.5f;
r.anchoredPosition = new Vector2(0f, iconOffsetY);
r.sizeDelta = new Vector2(side, side);
Image img = go.AddComponent<Image>();
img.raycastTarget = false;
return img;
}
/// <summary>生成压在图标底部的数量文本</summary>
private TextMeshProUGUI CreateCountText(RectTransform parent, float w, float iconSide)
{
GameObject go = new GameObject("Count", typeof(RectTransform));
RectTransform r = (RectTransform)go.transform;
r.SetParent(parent, false);
r.anchorMin = r.anchorMax = r.pivot = Vector2.one * 0.5f;
// 图标底边往上 0.8 个字高:文字压在图片上面
r.anchoredPosition = new Vector2(0f, iconOffsetY - iconSide / 2f + fontSize * 0.8f);
r.sizeDelta = new Vector2(w, fontSize * 1.6f);
TextMeshProUGUI tmp = go.AddComponent<TextMeshProUGUI>();
TMP_FontAsset font = TMP_Settings.defaultFontAsset;
if (font != null) tmp.font = font;
tmp.fontSize = fontSize;
tmp.alignment = TextAlignmentOptions.Center;
tmp.color = Color.white;
tmp.raycastTarget = false;
return tmp;
}
/// <summary>
/// 设置奖励图标:1=金币 / 2=钻石 用 Resources 本地图,
/// 3=道具 / 4=道具碎片 下载 icon(为空时用 product.imageUrl)。
/// </summary>
private void SetPrizeIcon(Image img, LotteryPrize prize)
{
switch (prize.type)
{
case 1: // 金币
Sprite gold = _goldSprite != null ? _goldSprite
: (_goldSprite = Resources.Load<Sprite>("gold"));
if (gold != null) img.sprite = gold;
break;
case 2: // 钻石
Sprite diamond = _diamondSprite != null ? _diamondSprite
: (_diamondSprite = Resources.Load<Sprite>("diamond"));
if (diamond != null) img.sprite = diamond;
break;
default: // 道具/碎片:下载图标
string url = prize.icon;
if (string.IsNullOrEmpty(url) && prize.product != null)
url = prize.product.imageUrl;
if (!string.IsNullOrEmpty(url))
{
WebTool.DownImage(url, tex =>
{
// 回调触发时本物体可能已被销毁(关闭面板清空父节点),需判空
if (this == null || img == null) return;
if (tex != null)
img.sprite = Sprite.Create(tex, new Rect(0, 0, tex.width, tex.height),
Vector2.one * 0.5f);
});
}
break;
}
}
private void OnDestroy()
{
ClearUI();
}
}