将Sprite打入图集时会默认去掉边缘的alpha=0的部分
Unity的Image.IsRaycastLocationValid在判断alphaHitTestMinimumThreshold的时候会使用图集中的点判断alpha而不是原Sprite中的点
所以会导致无法正确获取到alpha,要修复这个BUG可以重写Image类
主要是添加了这段代码 其他都是原装的
//计算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方法 只能拷贝出来了
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;
}
}
}