hch
2025-09-02 c5adf3e22a5cdfb185a4befc22ef0cd079a7eb33
117 【武将】武将系统 - 天赋显示,修复描边文字遇到mask问题
1 文件已重命名
12个文件已修改
1个文件已删除
1个文件已添加
682 ■■■■■ 已修改文件
Main/Component/UI/Core/OutlineEx.cs 418 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Main/Config/PartialConfigs/HeroAwakeConfig.cs 18 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Main/System/Hero/HeroInfo.Talent.cs 35 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Main/System/Hero/HeroTalentInfo.cs 26 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Main/System/HeroUI/GiftBaseCell.cs 18 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Main/System/HeroUI/HeroHeadBaseCell.cs 13 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Main/System/HeroUI/HeroShowBaseCell.cs 13 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Main/System/HeroUI/HeroTrainWin.cs 73 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Main/System/HeroUI/HeroUIManager.Gift.cs 31 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Main/System/HeroUI/HeroUIManager.Gift.cs.meta 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
Main/System/HeroUI/HeroUIManager.cs 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Main/System/SkillUI/SkillBaseCell.cs 13 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Main/System/SkillUI/SkillWordCell.cs 13 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Main/Utility/EnumHelper.cs 4 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
Main/Utility/UIHelper.cs 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Main/Component/UI/Core/OutlineEx.cs
@@ -40,66 +40,86 @@
    public int OutlineWidth = 10;    
    private static List<UIVertex> m_VetexList = new List<UIVertex>();
    // 材质池:Key为"颜色_宽度"格式的字符串,Value为对应的材质; 减少合批问题,又能保持不同的描边;共用材质会同时改变参数
    private static Dictionary<string, Material> m_MaterialPool = new Dictionary<string, Material>();
    static Shader m_tmpShader;
    private static Shader m_Shader
    protected override void Awake()
    {
        get
        base.Awake();
        if (base.graphic)
        {
            if (m_tmpShader == null)
            if (base.graphic.material == null || base.graphic.material.shader.name != "TSF Shaders/UI/OutlineEx")
            {
                m_tmpShader = Shader.Find("TSF Shaders/UI/OutlineEx");
// #if UNITY_EDITOR
                var texMaterial = ResManager.Instance.LoadAsset<Material>("Materials", "OutlineMat");
                if (texMaterial != null)
                {
                    base.graphic.material = texMaterial;
                }
                else
                {
                    Debug.LogError("没有找到材质OutlineMat.mat");
                }
// #else
//                 var shader = Shader.Find("TSF Shaders/UI/OutlineEx");
//                 base.graphic.material = new Material(shader);
// #endif
            }
            return m_tmpShader;
            if (base.graphic.canvas)
            {
                var v1 = base.graphic.canvas.additionalShaderChannels;
                var v2 = AdditionalCanvasShaderChannels.TexCoord1;
                if ((v1 & v2) != v2)
                {
                    base.graphic.canvas.additionalShaderChannels |= v2;
                }
                v2 = AdditionalCanvasShaderChannels.TexCoord2;
                if ((v1 & v2) != v2)
                {
                    base.graphic.canvas.additionalShaderChannels |= v2;
                }
                v2 = AdditionalCanvasShaderChannels.TexCoord3;
                if ((v1 & v2) != v2)
                {
                    base.graphic.canvas.additionalShaderChannels |= v2;
                }
                v2 = AdditionalCanvasShaderChannels.Tangent;
                if ((v1 & v2) != v2)
                {
                    base.graphic.canvas.additionalShaderChannels |= v2;
                }
                v2 = AdditionalCanvasShaderChannels.Normal;
                if ((v1 & v2) != v2)
                {
                    base.graphic.canvas.additionalShaderChannels |= v2;
                }
            }
            this._Refresh();
        }
    }
    protected override void Start()
    {
        base.Start();
        // 使用材质池获取或创建材质
        string key = GetMaterialKey(OutlineColor, OutlineWidth);
        if (!m_MaterialPool.TryGetValue(key, out Material material))
        {
            material = new Material(m_Shader);
            material.SetColor("_OutlineColor", this.OutlineColor);
            material.SetInt("_OutlineWidth", this.OutlineWidth);
            m_MaterialPool[key] = material;
        }
        base.graphic.material = material;
        var v1 = base.graphic.canvas.additionalShaderChannels;
        var v2 = AdditionalCanvasShaderChannels.TexCoord1;
        if ((v1 & v2) != v2)
        {
            base.graphic.canvas.additionalShaderChannels |= v2;
        }
        v2 = AdditionalCanvasShaderChannels.TexCoord2;
        if ((v1 & v2) != v2)
        {
            base.graphic.canvas.additionalShaderChannels |= v2;
        }
        this._Refresh();
    }
#if UNITY_EDITOR
    //在编辑器下打开也刷新下
    // protected override void OnEnable()
    // {
    //     base.OnEnable();
    //     this._Refresh();
    // }
    protected override void OnValidate()
    {
        base.OnValidate();
        if (base.graphic.material != null)
        {
            if (base.graphic.material.shader.name != "TSF Shaders/UI/OutlineEx")
            {
                var texMaterial = ResManager.Instance.LoadAsset<Material>("Materials", "OutlineMat");
                if (texMaterial != null)
                {
                    base.graphic.material = texMaterial;
                }
                else
                {
                    Debug.LogError("没有找到材质OutlineMat.mat");
                }
                //var shader = Shader.Find("TSF Shaders/UI/OutlineEx");
                //base.graphic.material = new Material(shader);
            }
            this._Refresh();
        }
    }
@@ -108,218 +128,144 @@
    private void _Refresh()
    {
        // 检查当前材质是否与所需属性匹配,如果不匹配则从池中获取或创建新材质
        string key = GetMaterialKey(OutlineColor, OutlineWidth);
        Material material;
        if (!m_MaterialPool.TryGetValue(key, out material))
        /*if (base.graphic.material.GetInt("_OutlineWidth") != this.OutlineWidth || base.graphic.material.GetColor("_OutlineColor") != this.OutlineColor)
        {
            // 如果池中没有对应的材质,创建新材质
            var shader = Shader.Find("TSF Shaders/UI/OutlineEx");
            material = new Material(shader);
            m_MaterialPool[key] = material;
        }
        if (material == null)
        {
            // 防范材质被删的情况,创建新材质
            material = new Material(m_Shader);
            m_MaterialPool[key] = material;
        }
        material.SetColor("_OutlineColor", this.OutlineColor);
        material.SetInt("_OutlineWidth", this.OutlineWidth);
        // 更新图形材质
        base.graphic.material = material;
            base.graphic.material.SetColor("_OutlineColor", this.OutlineColor);
            base.graphic.material.SetInt("_OutlineWidth", this.OutlineWidth);
        }*/
        base.graphic.SetVerticesDirty();
    }
    public override void ModifyMesh(VertexHelper vh)
    {
        vh.GetUIVertexStream(m_VetexList);
        this._ProcessVertices();
        vh.Clear();
        vh.AddUIVertexTriangleStream(m_VetexList);
    }
    private void _ProcessVertices()
    {
        for (int i = 0, count = m_VetexList.Count - 3; i <= count; i += 3)
public override void ModifyMesh(VertexHelper vh)
        {
            var v1 = m_VetexList[i];
            var v2 = m_VetexList[i + 1];
            var v3 = m_VetexList[i + 2];
            // 计算原顶点坐标中心点
            //
            var minX = _Min(v1.position.x, v2.position.x, v3.position.x);
            var minY = _Min(v1.position.y, v2.position.y, v3.position.y);
            var maxX = _Max(v1.position.x, v2.position.x, v3.position.x);
            var maxY = _Max(v1.position.y, v2.position.y, v3.position.y);
            var posCenter = new Vector2(minX + maxX, minY + maxY) * 0.5f;
            // 计算原始顶点坐标和UV的方向
            //
            Vector2 triX, triY, uvX, uvY;
            Vector2 pos1 = v1.position;
            Vector2 pos2 = v2.position;
            Vector2 pos3 = v3.position;
            if (Mathf.Abs(Vector2.Dot((pos2 - pos1).normalized, Vector2.right))
                > Mathf.Abs(Vector2.Dot((pos3 - pos2).normalized, Vector2.right)))
            {
                triX = pos2 - pos1;
                triY = pos3 - pos2;
                uvX = v2.uv0 - v1.uv0;
                uvY = v3.uv0 - v2.uv0;
            }
            else
            {
                triX = pos3 - pos2;
                triY = pos2 - pos1;
                uvX = v3.uv0 - v2.uv0;
                uvY = v2.uv0 - v1.uv0;
            }
            // 计算原始UV框
            //
            var uvMin = _Min(v1.uv0, v2.uv0, v3.uv0);
            var uvMax = _Max(v1.uv0, v2.uv0, v3.uv0);
            var uvOrigin = new Vector4(uvMin.x, uvMin.y, uvMax.x, uvMax.y);
            vh.GetUIVertexStream(m_VetexList);
            // 为每个顶点设置新的Position和UV,并传入原始UV框
            v1 = _SetNewPosAndUV(v1, this.OutlineWidth, posCenter, triX, triY, uvX, uvY, uvOrigin);
            v2 = _SetNewPosAndUV(v2, this.OutlineWidth, posCenter, triX, triY, uvX, uvY, uvOrigin);
            v3 = _SetNewPosAndUV(v3, this.OutlineWidth, posCenter, triX, triY, uvX, uvY, uvOrigin);
            this._ProcessVertices();
            // 获取 RectMask2D 的边界
            // 确保描边顶点扩展不会超出 RectMask2D 的边界
            var mask = GetComponentInParent<RectMask2D>();
            if (mask != null)
            {
                // 将局部坐标转换为屏幕坐标
                Transform uiTransform = this.transform;
                Vector3 worldPos1 = uiTransform.TransformPoint(v1.position);
                Vector3 worldPos2 = uiTransform.TransformPoint(v2.position);
                Vector3 worldPos3 = uiTransform.TransformPoint(v3.position);
                Vector2 screenPos1 = CameraManager.uiCamera.WorldToScreenPoint(worldPos1);
                Vector2 screenPos2 = CameraManager.uiCamera.WorldToScreenPoint(worldPos2);
                Vector2 screenPos3 = CameraManager.uiCamera.WorldToScreenPoint(worldPos3);
                // 确保描边顶点扩展不会超出 RectMask2D 的边界
                var clipRect = mask.canvasRect;
                //clipRect是中心点为坐标0,0,转成屏幕的
                var maskMinX = Screen.width / 2 + clipRect.xMin;
                var maskMaxX = Screen.width / 2 + clipRect.xMax;
                var maskMinY = Screen.height / 2 + clipRect.yMin;
                var maskMaxY = Screen.height / 2 + clipRect.yMax;
                // //screenPos1 超出clipRect范围不显示
                bool isout = false;
                if (screenPos3.x < maskMinX || screenPos3.x > maskMaxX || screenPos3.y < maskMinY || screenPos3.y > maskMaxY)
                {
                    isout = true;
                }
                else if (screenPos2.x < maskMinX || screenPos2.x > maskMaxX || screenPos2.y < maskMinY || screenPos2.y > maskMaxY)
                {
                    isout = true;
                }
                else if (screenPos1.x < maskMinX || screenPos1.x > maskMaxX || screenPos1.y < maskMinY || screenPos1.y > maskMaxY)
                {
                    isout = true;
                }
                if (isout)
                {
                    v1.position = new Vector3(10000, 10000, 10000);
                    v2.position = new Vector3(10000, 10000, 10000);
                    v3.position = new Vector3(10000, 10000, 10000);
                }
                // screenPos1.x = Mathf.Clamp(screenPos1.x, maskMinX, maskMaxX);
                // screenPos1.y = Mathf.Clamp(screenPos1.y, maskMinY, maskMaxY);
                // screenPos2.x = Mathf.Clamp(screenPos2.x, maskMinX, maskMaxX);
                // screenPos2.y = Mathf.Clamp(screenPos2.y, maskMinY, maskMaxY);
                // screenPos3.x = Mathf.Clamp(screenPos3.x, maskMinX, maskMaxX);
                // screenPos3.y = Mathf.Clamp(screenPos3.y, maskMinY, maskMaxY);
                // // 将屏幕坐标转换为局部坐标
                // RectTransformUtility.ScreenPointToLocalPointInRectangle(uiTransform.GetComponent<RectTransform>(), screenPos1, CameraManager.uiCamera, out Vector2 localPos1);
                // RectTransformUtility.ScreenPointToLocalPointInRectangle(uiTransform.GetComponent<RectTransform>(), screenPos2, CameraManager.uiCamera, out Vector2 localPos2);
                // RectTransformUtility.ScreenPointToLocalPointInRectangle(uiTransform.GetComponent<RectTransform>(), screenPos3, CameraManager.uiCamera, out Vector2 localPos3);
                // v1.position = localPos1;
                // v2.position = localPos2;
                // v3.position = localPos3;
            }
            // 应用设置后的UIVertex
            m_VetexList[i] = v1;
            m_VetexList[i + 1] = v2;
            m_VetexList[i + 2] = v3;
            vh.Clear();
            vh.AddUIVertexTriangleStream(m_VetexList);
        }
    }
    private static UIVertex _SetNewPosAndUV(UIVertex pVertex, int pOutLineWidth,
        Vector2 pPosCenter,
        Vector2 pTriangleX, Vector2 pTriangleY,
        Vector2 pUVX, Vector2 pUVY,
        Vector4 pUVOrigin)
    {
        // Position
        var pos = pVertex.position;
        var posXOffset = pos.x > pPosCenter.x ? pOutLineWidth : -pOutLineWidth;
        var posYOffset = pos.y > pPosCenter.y ? pOutLineWidth : -pOutLineWidth;
        pos.x += posXOffset;
        pos.y += posYOffset;
        pVertex.position = pos;
        // UV
        var uv = pVertex.uv0;
        private void _ProcessVertices()
        {
            for (int i = 0, count = m_VetexList.Count - 3; i <= count; i += 3)
            {
                var v1 = m_VetexList[i];
                var v2 = m_VetexList[i + 1];
                var v3 = m_VetexList[i + 2];
                // 计算原顶点坐标中心点
                //
                var minX = _Min(v1.position.x, v2.position.x, v3.position.x);
                var minY = _Min(v1.position.y, v2.position.y, v3.position.y);
                var maxX = _Max(v1.position.x, v2.position.x, v3.position.x);
                var maxY = _Max(v1.position.y, v2.position.y, v3.position.y);
                var posCenter = new Vector2(minX + maxX, minY + maxY) * 0.5f;
                // 计算原始顶点坐标和UV的方向
                //
                Vector2 triX, triY, uvX, uvY;
                Vector2 pos1 = v1.position;
                Vector2 pos2 = v2.position;
                Vector2 pos3 = v3.position;
                if (Mathf.Abs(Vector2.Dot((pos2 - pos1).normalized, Vector2.right))
                    > Mathf.Abs(Vector2.Dot((pos3 - pos2).normalized, Vector2.right)))
                {
                    triX = pos2 - pos1;
                    triY = pos3 - pos2;
                    uvX = v2.uv0 - v1.uv0;
                    uvY = v3.uv0 - v2.uv0;
                }
                else
                {
                    triX = pos3 - pos2;
                    triY = pos2 - pos1;
                    uvX = v3.uv0 - v2.uv0;
                    uvY = v2.uv0 - v1.uv0;
                }
                // 计算原始UV框
                var uvMin = _Min(v1.uv0, v2.uv0, v3.uv0);
                var uvMax = _Max(v1.uv0, v2.uv0, v3.uv0);
                //OutlineColor 和 OutlineWidth 也传入,避免出现不同的材质球
                var col_rg = new Vector2(OutlineColor.r, OutlineColor.g);       //描边颜色 用uv3 和 tangent的 zw传递
                var col_ba = new Vector4(0,0,OutlineColor.b, OutlineColor.a);
                var normal = new Vector3(0, 0, OutlineWidth);                   //描边的宽度 用normal的z传递
                // 为每个顶点设置新的Position和UV,并传入原始UV框
                v1 = _SetNewPosAndUV(v1, this.OutlineWidth, posCenter, triX, triY, uvX, uvY, uvMin, uvMax);
                v1.uv3 = col_rg;
                v1.tangent = col_ba;
                v1.normal = normal;
                v2 = _SetNewPosAndUV(v2, this.OutlineWidth, posCenter, triX, triY, uvX, uvY, uvMin, uvMax);
                v2.uv3 = col_rg;
                v2.tangent = col_ba;
                v2.normal = normal;
                v3 = _SetNewPosAndUV(v3, this.OutlineWidth, posCenter, triX, triY, uvX, uvY, uvMin, uvMax);
                v3.uv3 = col_rg;
                v3.tangent = col_ba;
                v3.normal = normal;
                // 应用设置后的UIVertex
                //
                m_VetexList[i] = v1;
                m_VetexList[i + 1] = v2;
                m_VetexList[i + 2] = v3;
            }
        }
        private static UIVertex _SetNewPosAndUV(UIVertex pVertex, int pOutLineWidth,
            Vector2 pPosCenter,
            Vector2 pTriangleX, Vector2 pTriangleY,
            Vector2 pUVX, Vector2 pUVY,
            Vector2 pUVOriginMin, Vector2 pUVOriginMax)
        {
            // Position
            var pos = pVertex.position;
            var posXOffset = pos.x > pPosCenter.x ? pOutLineWidth : -pOutLineWidth;
            var posYOffset = pos.y > pPosCenter.y ? pOutLineWidth : -pOutLineWidth;
            pos.x += posXOffset;
            pos.y += posYOffset;
            pVertex.position = pos;
            // UV
            var uv = pVertex.uv0;
        uv += new Vector4((pUVX / pTriangleX.magnitude * posXOffset * (Vector2.Dot(pTriangleX, Vector2.right) > 0 ? 1 : -1)).x, (pUVX / pTriangleX.magnitude * posXOffset * (Vector2.Dot(pTriangleX, Vector2.right) > 0 ? 1 : -1)).y, 0, 0);
        uv += new Vector4((pUVY / pTriangleY.magnitude * posYOffset * (Vector2.Dot(pTriangleY, Vector2.up) > 0 ? 1 : -1)).x, (pUVY / pTriangleY.magnitude * posYOffset * (Vector2.Dot(pTriangleY, Vector2.up) > 0 ? 1 : -1)).y, 0, 0);
        pVertex.uv0 = uv;
        // 原始UV框
        pVertex.uv1 = new Vector2(pUVOrigin.x, pUVOrigin.y);
        pVertex.uv2 = new Vector2(pUVOrigin.z, pUVOrigin.w);
            pVertex.uv0 = uv;
        return pVertex;
    }
            pVertex.uv1 = pUVOriginMin;     //uv1 uv2 可用  tangent  normal 在缩放情况 会有问题
            pVertex.uv2 = pUVOriginMax;
            return pVertex;
        }
    private static float _Min(float pA, float pB, float pC)
    {
        return Mathf.Min(Mathf.Min(pA, pB), pC);
    }
        private static float _Min(float pA, float pB, float pC)
        {
            return Mathf.Min(Mathf.Min(pA, pB), pC);
        }
    private static float _Max(float pA, float pB, float pC)
    {
        return Mathf.Max(Mathf.Max(pA, pB), pC);
    }
        private static float _Max(float pA, float pB, float pC)
        {
            return Mathf.Max(Mathf.Max(pA, pB), pC);
        }
    private static Vector2 _Min(Vector2 pA, Vector2 pB, Vector2 pC)
    {
        return new Vector2(_Min(pA.x, pB.x, pC.x), _Min(pA.y, pB.y, pC.y));
    }
        private static Vector2 _Min(Vector2 pA, Vector2 pB, Vector2 pC)
        {
            return new Vector2(_Min(pA.x, pB.x, pC.x), _Min(pA.y, pB.y, pC.y));
        }
    private static Vector2 _Max(Vector2 pA, Vector2 pB, Vector2 pC)
    {
        return new Vector2(_Max(pA.x, pB.x, pC.x), _Max(pA.y, pB.y, pC.y));
    }
        private static Vector2 _Max(Vector2 pA, Vector2 pB, Vector2 pC)
        {
            return new Vector2(_Max(pA.x, pB.x, pC.x), _Max(pA.y, pB.y, pC.y));
        }
    // 生成材质池的键
    private string GetMaterialKey(Color color, int width)
    {
        // 使用颜色的RGBA值和宽度生成唯一键
        return string.Format("{0}_{1}_{2}_{3}_{4}",
            color.r, color.g, color.b, color.a, width);
    }
}
Main/Config/PartialConfigs/HeroAwakeConfig.cs
@@ -48,4 +48,22 @@
    {
        return GetHeroAwakeConfig(heroID, awakeLv) == null;
    }
    public static int GetAwakeLVByUnLockGiftIndex(int heroID, int index)
    {
        Dictionary<int, HeroAwakeConfig> tempDic = null;
        if (!configDics.TryGetValue(heroID, out tempDic))
        {
            return 0;
        }
        foreach (var item in tempDic)
        {
            if (item.Value.UnlockTalentSlot == index + 1)
            {
                return item.Key;
            }
        }
        return 0;
    }
}
Main/System/Hero/HeroInfo.Talent.cs
@@ -16,21 +16,36 @@
        }
    }
    
    public List<HeroTalentInfo> talentList = new List<HeroTalentInfo>();
    // 75 # 英雄天赋洗炼锁定索引列表,对应71天赋ID索引
    // 77 # 英雄天赋洗炼随机ID列表
    // 79 # 英雄觉醒时随机天赋选项ID列表
    // 71 # 英雄天赋ID列表
    public List<int> talentIDList
    {
        get
        {
            if (itemHero == null)
                return null;
            return itemHero.GetUseData(71);
        }
    }
    // 73 # 英雄天赋ID等级列表,对应71天赋ID的等级
    public List<int> talentLvList
    {
        get
        {
            if (itemHero == null)
                return null;
            return itemHero.GetUseData(73);
        }
    }
    Dictionary<int, int> talentAttrDic = new Dictionary<int, int>();   //属性ID : 天赋属性值
                                                                       // 71 # 英雄天赋ID列表
                                                                       // 73 # 英雄天赋ID等级列表,对应71天赋ID的等级
                                                                       // 75 # 英雄天赋洗炼锁定索引列表,对应71天赋ID索引
                                                                       // 77 # 英雄天赋洗炼随机ID列表
                                                                       // 79 # 英雄觉醒时随机天赋选项ID列表
    protected void RefreshTalentAttr()
    {
        // 71 # 英雄天赋ID列表
        List<int> talentIDList = itemHero.GetUseData(71);
        // // 73 # 英雄天赋ID等级列表,对应71天赋ID的等级
        List<int> talentLvList = itemHero.GetUseData(73);
        talentAttrDic.Clear();
        for (int i = 0; i < talentIDList.Count; i++)
Main/System/Hero/HeroTalentInfo.cs
File was deleted
Main/System/HeroUI/GiftBaseCell.cs
@@ -105,14 +105,14 @@
    }
    //showState 0:不显示 1:新增 2:提升
    //giftID 0 :代表未激活灰色 -1:代表不能激活 棕色,其他根据配表
    //giftID 0 :代表灰色需升星激活 -1:代表棕色需觉醒激活,其他根据配表,没有天赋的外层控制显隐
    public void Init(int giftID, int lv, UnityAction onclick = null, int showState = 0)
    {
        giftBtn.AddListener(onclick);
        if (HeroTalentConfig.HasKey(giftID))
        {
            var config = HeroTalentConfig.Get(giftID);
            qualityBG.SetSprite("GiftQualityBG" + config.Quality);
            giftBtn.AddListener(onclick);
            giftName.text = config.Name;
            giftName.color = GetColor(config.Quality);
            textOutline.OutlineColor = GetOutlineColor(config.Quality);
@@ -125,7 +125,6 @@
        else
        {
            qualityBG.SetSprite("GiftQualityBG" + giftID);
            giftBtn.RemoveAllListeners();
            giftName.text = string.Empty;
            lvRect.SetActive(false);
            stateImg.SetActive(false);
@@ -209,7 +208,18 @@
        var scale = 1f;
        var rect = cellContainer.GetComponent<RectTransform>();
        var parentRect = transform.GetComponent<RectTransform>();
        scale = parentRect.sizeDelta.x / rect.sizeDelta.x;
        float width = parentRect.sizeDelta.x;
        if (width <= 0f)
        {
            //外部控制了尺寸获取为0
            GridLayoutGroup grid = GetComponentInParent<GridLayoutGroup>();
            if (grid != null)
            {
                width = grid.cellSize.x;
            }
        }
        scale = width / rect.sizeDelta.x;
        cellContainer.transform.localScale = new Vector3(scale, scale, scale);
    }
}
Main/System/HeroUI/HeroHeadBaseCell.cs
@@ -220,7 +220,18 @@
        var scale = 1f;
        var rect = cellContainer.GetComponent<RectTransform>();
        var parentRect = transform.GetComponent<RectTransform>();
        scale = parentRect.sizeDelta.x / rect.sizeDelta.x;
        float width = parentRect.sizeDelta.x;
        if (width <= 0f)
        {
            //外部控制了尺寸获取为0
            GridLayoutGroup grid = GetComponentInParent<GridLayoutGroup>();
            if (grid != null)
            {
                width = grid.cellSize.x;
            }
        }
        scale = width / rect.sizeDelta.x;
        cellContainer.transform.localScale = new Vector3(scale, scale, scale);
    }
}
Main/System/HeroUI/HeroShowBaseCell.cs
@@ -187,7 +187,18 @@
        var scale = 1f;
        var rect = cellContainer.GetComponent<RectTransform>();
        var parentRect = transform.GetComponent<RectTransform>();
        scale = parentRect.sizeDelta.x / rect.sizeDelta.x;
        float width = parentRect.sizeDelta.x;
        if (width <= 0f)
        {
            //外部控制了尺寸获取为0
            GridLayoutGroup grid = GetComponentInParent<GridLayoutGroup>();
            if (grid != null)
            {
                width = grid.cellSize.x;
            }
        }
        scale = width / rect.sizeDelta.x;
        cellContainer.transform.localScale = new Vector3(scale, scale, scale);
        heroNameOutline = nameText.GetComponent<OutlineEx>();
        heroLVOutline = lvText.GetComponent<OutlineEx>();
Main/System/HeroUI/HeroTrainWin.cs
@@ -64,6 +64,13 @@
    [SerializeField] Text[] fetterNameText;   //羁绊
    //天赋
    [SerializeField] GiftBaseCell[] giftBaseCells;
    [SerializeField] Button totalGiftBtn;
    [SerializeField] Button starUPBtn;
    [SerializeField] Button washBtn;
    string guid;
    HeroInfo hero;
@@ -132,7 +139,7 @@
        hero = HeroManager.Instance.GetHero(guid);
        unfoldState = false;
        addPerObject.SetActive(false);
        Refresh();
        Display();
    }
    protected override void OnPreClose()
@@ -154,7 +161,8 @@
            }
        }
    }
    public override void Refresh()
    public void Display()
    {
        roleLhModel.Create(hero.SkinID, HeroUIManager.lihuiScale, motionName: "", isLh: true);
        roleXsModel.Create(hero.SkinID);
@@ -184,6 +192,7 @@
        RefreshAttr();
        RefreshAllPotential();
        RefreshFetter();
        RefreshGift();
    }
    void RefreshItemLockEvent(PackType type, string guid, bool lockState)
@@ -196,7 +205,7 @@
    void RefreshHeroEvent(HeroInfo hero)
    {
        Refresh();
        Display();
    }
    void RefreshConn()
@@ -230,7 +239,7 @@
        }
        guid = HeroUIManager.Instance.heroSortList[resultIndex];
        hero = HeroManager.Instance.GetHero(guid);
        Refresh();
        Display();
    }
    void ResetBtnClick()
@@ -517,7 +526,7 @@
            else
            {
                //置灰
                allAttrStr += UIHelper.AppendColor(TextColType.Gray, Language.Get("herocard63", i + 1, string.Join(Language.Get("L1112"), attrStrArr))) + "\n";
                allAttrStr += UIHelper.AppendColor(TextColType.NavyGray, Language.Get("herocard63", i + 1, string.Join(Language.Get("L1112"), attrStrArr))) + "\n";
            }
        }
@@ -527,7 +536,7 @@
    //羁绊
    void RefreshFetter()
    {
    {
        for (int i = 0; i < fetterText.Length; i++)
        {
            if (i < hero.heroConfig.FetterIDList.Length)
@@ -563,7 +572,57 @@
                fetterText[i].SetActive(false);
            }
        }
    }
    void RefreshGift()
    {
        //传说以下只有4个
        int showCount = hero.Quality < 4 ? HeroUIManager.normalGiftMaxCnt : HeroUIManager.giftMaxCnt;
        for (int i = 0; i < giftBaseCells.Length; i++)
        {
            if (i >= showCount)
            {
                giftBaseCells[i].SetActive(false);
                continue;
            }
    }
            giftBaseCells[i].SetActive(true);
            if (i < hero.talentIDList.Count)
            {
                int giftID = hero.talentIDList[i];
                int giftLV = hero.talentLvList[i];
                giftBaseCells[i].Init(giftID, giftLV, () =>
                {
                    var giftConfig = HeroTalentConfig.Get(giftID);
                    SmallTipWin.showText = Language.Get("SmallTipFomat", giftConfig.Name + " " + Language.Get("L1113", giftLV),
                    Language.Get("HeroGift5", PlayerPropertyConfig.Get(giftConfig.AttrID).Name, PlayerPropertyConfig.GetValueDescription(giftConfig.AttrID, giftConfig.AttrValue)));
                    SmallTipWin.worldPos = CameraManager.uiCamera.ScreenToWorldPoint(Input.mousePosition);
                    UIManager.Instance.OpenWindow<SmallTipWin>();
                });
            }
            else
            {
                if (i < HeroUIManager.normalGiftMaxCnt)
                {
                    giftBaseCells[i].Init(0, 0, () =>
                    {
                        SmallTipWin.showText = Language.Get("HeroGift1");
                        SmallTipWin.worldPos = CameraManager.uiCamera.ScreenToWorldPoint(Input.mousePosition);
                        UIManager.Instance.OpenWindow<SmallTipWin>();
                    });
                }
                else
                {
                    int index = i;
                    giftBaseCells[i].Init(-1, 0, () =>
                    {
                        SmallTipWin.showText = Language.Get("HeroGift2", HeroAwakeConfig.GetAwakeLVByUnLockGiftIndex(hero.heroId, index));
                        SmallTipWin.worldPos = CameraManager.uiCamera.ScreenToWorldPoint(Input.mousePosition);
                        UIManager.Instance.OpenWindow<SmallTipWin>();
                    });
                }
            }
        }
    }
}
Main/System/HeroUI/HeroUIManager.Gift.cs
New file
@@ -0,0 +1,31 @@
using System;
using System.Collections;
using System.Collections.Generic;
using LitJson;
using UnityEngine;
//天赋
public partial class HeroUIManager : GameSystemManager<HeroUIManager>
{
    public const int normalGiftMaxCnt = 4;  //传说4以下
    public const int giftMaxCnt = 8;
    public int maxGiftLevel;    //天赋最高等级,其他功能可能会增加这个上限
    public int starLevelCanAwake;   //x星可以觉醒
    public int washItemID;
    public int[] washByLockUseCounts;
    void ParseGiftConfig()
    {
        var config = FuncConfigConfig.Get("HeroStarTalent");
        maxGiftLevel = int.Parse(config.Numerical2);
        starLevelCanAwake = int.Parse(config.Numerical4);
        config = FuncConfigConfig.Get("HeroWash");
        washItemID = int.Parse(config.Numerical1);
        washByLockUseCounts = JsonMapper.ToObject<int[]>(config.Numerical2);
    }
}
Main/System/HeroUI/HeroUIManager.Gift.cs.meta
File was renamed from Main/System/Hero/HeroTalentInfo.cs.meta
@@ -1,5 +1,5 @@
fileFormatVersion: 2
guid: 262ca07cf60e33946bf5fc0a9a1007ab
guid: fb636b74ad337ca439fb8205757fa6c1
MonoImporter:
  externalObjects: {}
  serializedVersion: 2
Main/System/HeroUI/HeroUIManager.cs
@@ -39,6 +39,7 @@
        var config = FuncConfigConfig.Get("HeroRebirth");
        payBackMoneyType = int.Parse(config.Numerical1);
        rebornAwakeHeroMaxCount = int.Parse(config.Numerical2);
        ParseGiftConfig();
    }
    public void OnBeforePlayerDataInitialize()
Main/System/SkillUI/SkillBaseCell.cs
@@ -109,7 +109,18 @@
        var scale = 1f;
        var rect = cellContainer.GetComponent<RectTransform>();
        var parentRect = transform.GetComponent<RectTransform>();
        scale = parentRect.sizeDelta.x / rect.sizeDelta.x;
        float width = parentRect.sizeDelta.x;
        if (width <= 0f)
        {
            //外部控制了尺寸获取为0
            GridLayoutGroup grid = GetComponentInParent<GridLayoutGroup>();
            if (grid != null)
            {
                width = grid.cellSize.x;
            }
        }
        scale = width / rect.sizeDelta.x;
        cellContainer.transform.localScale = new Vector3(scale, scale, scale);
    }
}
Main/System/SkillUI/SkillWordCell.cs
@@ -102,7 +102,18 @@
        var scale = 1f;
        var rect = cellContainer.GetComponent<RectTransform>();
        var parentRect = transform.GetComponent<RectTransform>();
        scale = parentRect.sizeDelta.x / rect.sizeDelta.x;
        float width = parentRect.sizeDelta.x;
        if (width <= 0f)
        {
            //外部控制了尺寸获取为0
            GridLayoutGroup grid = GetComponentInParent<GridLayoutGroup>();
            if (grid != null)
            {
                width = grid.cellSize.x;
            }
        }
        scale = width / rect.sizeDelta.x;
        cellContainer.transform.localScale = new Vector3(scale, scale, scale);
    }
}
Main/Utility/EnumHelper.cs
@@ -1077,10 +1077,12 @@
    lightYellow = 4,    //浅黄色
    Red = 5,
    Pink = 6,
    /// <summary>
    /// 深褐色 401c06 (64, 28, 6, 255)
    /// </summary>
    NavyBrown,
    NavyGray = 8, //深灰色 797979 (121, 121, 121, 255)
    Green = 9,//绿色
    Black = 10,
    /// <summary>
@@ -1096,7 +1098,7 @@
    /// <summary>
    /// (204, 204, 204, 255)
    /// </summary>
    Gray = 16,
    Gray = 16,  // 粗糙 灰色
    //物品品质颜色
    itemjingliang = 17, //精良
    itemxiyou = 18, //稀有
Main/Utility/UIHelper.cs
@@ -543,6 +543,8 @@
                return s_LightWhite;
            case TextColType.Gray:
                return s_Gray;
            case TextColType.NavyGray:
                return new Color32(121, 121, 121, 255);
            case TextColType.itemjingliang:
                // 729de4 精良
                return new Color32(114, 157, 228, 255);
@@ -716,6 +718,8 @@
                return StringUtility.Contact("<color=#8ddc11>", msg, "</color>");
            case TextColType.Gray:
                return StringUtility.Contact("<color=#bbbbbb>", msg, "</color>");
            case TextColType.NavyGray:
                return StringUtility.Contact("<color=#797979>", msg, "</color>");
            case TextColType.lightYellow:
                return StringUtility.Contact("<color=#fcedb9>", msg, "</color>");
            case TextColType.NavyYellow: