You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Unity UI精灵文本渲染器精灵间距无法正确对齐问题求助

Unity SpriteTextRenderer 字符间距过大问题

我正在编写Unity UI脚本SpriteTextRenderer,它通过自定义SpriteFont ScriptableObject(存储字符与对应精灵的映射)生成带Image组件的UI对象来渲染字符串。目前功能基本正常,但字符间距无法正确设置。

定位逻辑均在SetText()方法中,暂时无需关注对齐相关代码,先解决间距问题。

SpriteTextRenderer 脚本代码

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;

public class SpriteTextRenderer : MonoBehaviour
{
    [SerializeField] SpriteFont font;
    Dictionary<char, Sprite> characters;
    [SerializeField] Material material;
    public int pixelOverlap = 0;
    public bool useFontOverlap = true;
    [SerializeField] string currentText;
    public string Text { get { return currentText; } private set { currentText = value; } }
    GameObject[] displayText = new GameObject[0];
    [SerializeField] enum alignment
    {
        TopLeft, TopCenter, TopRight,
        MiddleLeft, Center, MiddleRight,
        BottomLeft, BottomCenter, BottomRight
    }
    const alignment topAlignments = alignment.TopLeft | alignment.TopCenter | alignment.TopRight;
    const alignment middleAlignments = alignment.MiddleLeft | alignment.Center | alignment.MiddleRight;
    const alignment bottomAlignments = alignment.BottomLeft | alignment.BottomCenter | alignment.BottomRight;
    const alignment leftAlignments = alignment.TopLeft | alignment.MiddleLeft | alignment.BottomLeft;
    const alignment centerAlignments = alignment.TopCenter | alignment.Center | alignment.BottomCenter;
    const alignment rightAlignments = alignment.TopRight | alignment.MiddleRight | alignment.BottomRight;

    void Start()
    {
        characters = new Dictionary<char, Sprite>{};
        FillDictionary();
        SetText(currentText);
    }

    void FillDictionary()
    {
        for(int i = 0; i < font.characters.Length; i++)
        {
            characters.Add(font.characters[i].character, font.characters[i].sprite);
        }
    }

    public void SetText(string newText)
    {
        GameObject currentCharacter;
        int oldLength = displayText.Length;
        int newLength = newText.Length;
        float characterPosition = 0;
        int overlap = useFontOverlap ? font.pixelOverlap : pixelOverlap;

        if(newLength > oldLength)
        {
            GameObject[] newDisplayText = new GameObject[newLength];
            displayText.CopyTo(newDisplayText, 0);
            displayText = newDisplayText;

            for(int i = oldLength; i < newLength; i++)
            {
                GameObject newCharacter = new("Character (" + newText[i] + ")", typeof(RectTransform), typeof(Image));
                newCharacter.transform.SetParent(this.transform, false);
                newCharacter.GetComponent<RectTransform>().anchorMin = new Vector2(0, 1);
                newCharacter.GetComponent<RectTransform>().anchorMax = new Vector2(0, 1);
                displayText[i] = newCharacter;
            }
        }
        
        for(int i = 0; i < newLength; i++)
        {
            currentCharacter = displayText[i];

            if(i + 1 > oldLength || currentText[i] != newText[i])
            {
                Sprite newSprite = characters[newText[i]];
                float newSpriteWidth = newSprite.rect.width;
                currentCharacter.GetComponent<Image>().sprite = newSprite;

                RectTransform rt = currentCharacter.GetComponent<RectTransform>();
                rt.localPosition = new Vector2(characterPosition, 0);
                currentCharacter.GetComponent<Image>().SetNativeSize();
                characterPosition += (newSpriteWidth - overlap) * newSprite.pixelsPerUnit;
            }
        }

        Text = newText;
        Debug.Log(currentText);
    }
}

SpriteFont 类代码

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

[CreateAssetMenu(fileName = "New Sprite Font", menuName = "Sprite Font")]
public class SpriteFont : ScriptableObject
{
    public int pixelOverlap;
    public SpriteCharacter[] characters;
}

[System.Serializable]
public class SpriteCharacter
{
    public char character;
    public Sprite sprite;
}

问题细节

overlap值用于指定每个UI精灵的像素重叠量。我使用的"Large Segment" SpriteFont将pixelOverlap设为1,脚本所在UI对象的useFontOverlap设为true,预期输入字符串"1:06.237"的显示效果为紧密排列,但实际显示间距过大。

已确认的信息:

  • 通过Debug.Log()确认overlap值设置正确
  • Sprite Font中的所有精灵在Sprite Editor中的矩形已精确适配可见像素(至少X轴方向)
  • 所有精灵的枢轴设为左上
  • 精灵图集的Pixels per Unit为19.2

内容的提问来源于stack exchange,提问作者TT87

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.11 23:55:12