Unity自适应瓦片模式下SpriteRenderer中心区域重复次数计算问题
如何计算Unity SpriteRenderer自适应瓦片模式下中心区域的重复次数
针对你遇到的这个问题,我先梳理下核心逻辑,再修正你的代码——毕竟Unity自适应瓦片的计算规则确实有点绕,尤其是adaptiveModeThreshold的作用容易理解偏差。
首先明确Unity文档里的关键规则:
拉伸值(Stretch Value)范围为0到1,值为1时表示图像被拉伸至原尺寸的两倍,此时该区域开始重复。
也就是说,当中心区域的可用空间比N倍原始中心尺寸多出阈值×原始中心尺寸时,才会触发第N+1次重复,而不是简单做减法后取整。
现有代码的问题分析
- 中心区域尺寸计算不够严谨:你通过
textureRect.size手动加减边框的方式容易出错,其实可以直接从Sprite的border和纹理尺寸推导更准确。 - 自适应模式的重复次数逻辑偏差:你用
Mathf.Ceil(countX - sr.adaptiveModeThreshold)的方式,虽然思路接近,但没有完全匹配Unity的触发规则,边界场景下可能出现计算误差。
修正后的完整方案
首先保留你写的FoundInnerTilledRect方法(这个方法的中心修正逻辑是对的,因为不对称边框需要调整Rect中心到局部坐标系原点),然后重构重复次数的计算逻辑:
辅助方法(保留你的实现)
public static void FoundInnerTilledRect(SpriteRenderer sr, out float szTopBorder, out float szBottomBorder, out float szLeftBorder, out float szRightBorder, out Rect innerRect) { var s = sr.sprite; float szX = sr.size.x; float szY = sr.size.y; szTopBorder = s.border.w / s.pixelsPerUnit; szBottomBorder = s.border.y / s.pixelsPerUnit; szLeftBorder = s.border.x / s.pixelsPerUnit; szRightBorder = s.border.z / s.pixelsPerUnit; innerRect = new Rect(); innerRect.xMin = szLeftBorder; innerRect.xMax = szX - szRightBorder; innerRect.yMin = szBottomBorder; innerRect.yMax = szY - szTopBorder; // 修正中心到SpriteRenderer局部坐标系原点 innerRect.center = -new Vector2((szRightBorder - szLeftBorder), (szTopBorder - szBottomBorder)) * 0.5f; }
核心计算方法
public static Vector2 GetAdaptiveTileRepeatCount(SpriteRenderer sr) { Sprite s = sr.sprite; if (s == null || sr.drawMode != SpriteDrawMode.Tiled) { return Vector2.one; // 非瓦片模式默认返回1次 } float topBorder, bottomBorder, leftBorder, rightBorder; Rect innerRect; FoundInnerTilledRect(sr, out topBorder, out bottomBorder, out leftBorder, out rightBorder, out innerRect); // 计算精灵原始中心区域的实际尺寸(转换为米) Vector2 originalCenterSize = new Vector2( (s.textureRect.width - s.border.x - s.border.z) / s.pixelsPerUnit, (s.textureRect.height - s.border.y - s.border.w) / s.pixelsPerUnit ); float countX, countY; if (sr.tileMode == SpriteTileMode.Adaptive) { float availableWidth = innerRect.size.x; float availableHeight = innerRect.size.y; // 先算基础的整数重复次数(向下取整) float baseCountX = Mathf.Floor(availableWidth / originalCenterSize.x); float baseCountY = Mathf.Floor(availableHeight / originalCenterSize.y); // 计算剩余空间占原始中心尺寸的比例(也就是文档里说的"拉伸值") float stretchRatioX = (availableWidth - baseCountX * originalCenterSize.x) / originalCenterSize.x; float stretchRatioY = (availableHeight - baseCountY * originalCenterSize.y) / originalCenterSize.y; // 如果拉伸值超过阈值,就多一次重复 countX = baseCountX + (stretchRatioX > sr.adaptiveModeThreshold ? 1 : 0); countY = baseCountY + (stretchRatioY > sr.adaptiveModeThreshold ? 1 : 0); } else { // 连续瓦片模式:直接取可用空间与原始中心尺寸的比值(向下取整,超过1倍就会重复) countX = Mathf.Floor(innerRect.size.x / originalCenterSize.x); countY = Mathf.Floor(innerRect.size.y / originalCenterSize.y); // 如果尺寸不足原始中心尺寸,默认返回1次(因为会拉伸填充) countX = Mathf.Max(countX, 1); countY = Mathf.Max(countY, 1); } return new Vector2(countX, countY); }
验证方式
你可以通过调整参数测试逻辑正确性:
- 把
adaptiveModeThreshold设为1,此时只有当可用空间≥2倍原始中心尺寸时,重复次数才会从1变成2,完全符合文档描述。 - 把阈值设为0.5,当可用空间≥1.5倍原始中心尺寸时,重复次数就会增加,这也符合自适应模式避免过度拉伸的设计逻辑。
内容的提问来源于stack exchange,提问作者Max
相关产品推荐
相关产品推荐

