Unity UGUI Image使用图集透明度点击过滤BUG

将Sprite打入图集时会默认去掉边缘的alpha=0的部分

Unity的Image.IsRaycastLocationValid在判断alphaHitTestMinimumThreshold的时候会使用图集中的点判断alpha而不是原Sprite中的点

所以会导致无法正确获取到alpha,要修复这个BUG可以重写Image类

主要是添加了这段代码 其他都是原装的

csharp 复制代码
 //计算local在图集中的位置
 Rect spriteRect = overrideSprite.textureRect;
 local.x = local.x - overrideSprite.textureRectOffset.x + spriteRect.x;
 local.y = local.y - overrideSprite.textureRectOffset.y + spriteRect.y;
 //判断是否在当前图的范围内
 if (!overrideSprite.textureRect.Contains(local))
 {
     return false;
 }

其实只重写了IsRaycastLocationValid方法,但是要访问private方法 只能拷贝出来了

csharp 复制代码
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;

public class OverrideImage : Image
{
    
    private void _PreserveSpriteAspectRatio(ref Rect rect, Vector2 spriteSize)
    {
        var spriteRatio = spriteSize.x / spriteSize.y;
        var rectRatio = rect.width / rect.height;

        if (spriteRatio > rectRatio)
        {
            var oldHeight = rect.height;
            rect.height = rect.width * (1.0f / spriteRatio);
            rect.y += (oldHeight - rect.height) * rectTransform.pivot.y;
        }
        else
        {
            var oldWidth = rect.width;
            rect.width = rect.height * spriteRatio;
            rect.x += (oldWidth - rect.width) * rectTransform.pivot.x;
        }
    }
    private Vector4 _GetAdjustedBorders(Vector4 border, Rect adjustedRect)
    {
        Rect originalRect = rectTransform.rect;

        for (int axis = 0; axis <= 1; axis++)
        {
            float borderScaleRatio;

            // The adjusted rect (adjusted for pixel correctness)
            // may be slightly larger than the original rect.
            // Adjust the border to match the adjustedRect to avoid
            // small gaps between borders (case 833201).
            if (originalRect.size[axis] != 0)
            {
                borderScaleRatio = adjustedRect.size[axis] / originalRect.size[axis];
                border[axis] *= borderScaleRatio;
                border[axis + 2] *= borderScaleRatio;
            }

            // If the rect is smaller than the combined borders, then there's not room for the borders at their normal size.
            // In order to avoid artefacts with overlapping borders, we scale the borders down to fit.
            float combinedBorders = border[axis] + border[axis + 2];
            if (adjustedRect.size[axis] < combinedBorders && combinedBorders != 0)
            {
                borderScaleRatio = adjustedRect.size[axis] / combinedBorders;
                border[axis] *= borderScaleRatio;
                border[axis + 2] *= borderScaleRatio;
            }
        }
        return border;
    }
    
    private Vector2 _MapCoordinate(Vector2 local, Rect rect)
    {
        Rect spriteRect = overrideSprite.rect;
        if (type == Type.Simple || type == Type.Filled)
            return new Vector2(spriteRect.position.x + local.x * spriteRect.width / rect.width, spriteRect.position.y + local.y * spriteRect.height / rect.height);

        Vector4 border = overrideSprite.border;
        Vector4 adjustedBorder = _GetAdjustedBorders(border / pixelsPerUnit, rect);

        for (int i = 0; i < 2; i++)
        {
            if (local[i] <= adjustedBorder[i])
                continue;

            if (rect.size[i] - local[i] <= adjustedBorder[i + 2])
            {
                local[i] -= (rect.size[i] - spriteRect.size[i]);
                continue;
            }

            if (type == Type.Sliced)
            {
                float lerp = Mathf.InverseLerp(adjustedBorder[i], rect.size[i] - adjustedBorder[i + 2], local[i]);
                local[i] = Mathf.Lerp(border[i], spriteRect.size[i] - border[i + 2], lerp);
            }
            else
            {
                local[i] -= adjustedBorder[i];
                local[i] = Mathf.Repeat(local[i], spriteRect.size[i] - border[i] - border[i + 2]);
                local[i] += border[i];
            }
        }

        return local + spriteRect.position;
    }
    
    public override bool IsRaycastLocationValid(Vector2 screenPoint, Camera eventCamera)
    {
        if (alphaHitTestMinimumThreshold <= 0)
            return true;

        if (alphaHitTestMinimumThreshold > 1)
            return false;

        if (overrideSprite == null)
            return true;

        Vector2 local;
        if (!RectTransformUtility.ScreenPointToLocalPointInRectangle(rectTransform, screenPoint, eventCamera, out local))
            return false;

        Rect rect = GetPixelAdjustedRect();

        if (preserveAspect)
            _PreserveSpriteAspectRatio(ref rect, new Vector2(overrideSprite.texture.width, overrideSprite.texture.height));

        // Convert to have lower left corner as reference point.
        local.x += rectTransform.pivot.x * rect.width;
        local.y += rectTransform.pivot.y * rect.height;

        local = _MapCoordinate(local, rect);
        
        //计算local在图集中的位置
        Rect spriteRect = overrideSprite.textureRect;
        local.x = local.x - overrideSprite.textureRectOffset.x + spriteRect.x;
        local.y = local.y - overrideSprite.textureRectOffset.y + spriteRect.y;
        //判断是否在当前图的范围内
        if (!overrideSprite.textureRect.Contains(local))
        {
            return false;
        }
        
        // Convert local coordinates to texture space.
        float x = local.x / overrideSprite.texture.width;
        float y = local.y / overrideSprite.texture.height;
    
        try
        {
            return overrideSprite.texture.GetPixelBilinear(x, y).a >= alphaHitTestMinimumThreshold;
        }
        catch (UnityException e)
        {
            Debug.LogError("Using alphaHitTestMinimumThreshold greater than 0 on Image whose sprite texture cannot be read. " + e.Message + " Also make sure to disable sprite packing for this sprite.", this);
            return true;
        }
    }
}
相关推荐
李永奉20 小时前
杰理可视化SDK开发-【BUG】配置“TWS两边同时按消息使能”功能后,按键单击功能无效失灵
开发语言·单片机·嵌入式硬件·物联网·bug
AI大模型-小雄1 天前
充值Codex + GPT-5.5 并发 Bug 调试实战:从时序分析到回归测试
gpt·log4j·bug
穷人小水滴2 天前
(科幻) 备用肉身虫 (Backup Body Bug, BBB) 系列设定 (202607 更新)
aigc·bug·科幻
玖玥拾2 天前
C# 语言进阶(十四)Unity UI界面开发 + 网络消息联动
服务器·开发语言·网络·ui·unity·c#·游戏引擎
野区捕龙为宠2 天前
Unity 持久化数据
unity·游戏引擎·lucene
郝学胜-神的一滴2 天前
[简化版 GAMES 101] 计算机图形学 17:纹理技术从基础原理到多场景实战应用
c++·unity·游戏引擎·图形渲染·three.js·opengl·unreal
_ZHOURUI_H_3 天前
MyFramework: 同样是 Unity 游戏开发框架,和 HTFramework 的设计取向有什么不同?(下)
unity·游戏引擎·游戏开发·游戏ui·手游开发
小贺儿开发4 天前
Unity 知识库智能问答系统(RAG)
人工智能·unity·ai·大模型·智能问答·知识库·互动
不爱记笔记4 天前
GPT-5.6 Sol 真实项目实测!Bug修复、UI重构与帆船游戏复刻
人工智能·gpt·ui·chatgpt·bug·openai
丁小未4 天前
基于MVVM框架的XUUI 扩展的UI管理系统教程
unity·mvvm·ui框架·xuui·ui管理器