게임을 개발하다 보면 다양한 종류의 툴팁이 필요하다.
하지만 이런 툴팁을 필요할 때 마다 새롭게 만들다보니 프로젝트가 복잡해지고, 개발 효율성도 떨어지는 것 같았다.
따라서 여러 종류의 툴팁을 유연하게 관리하고, 빠르게 사용할 수 있도록 프레임워크를 만들기로 했다.
우선, 툴팁은 마우스가 오버되면 보여지고, 아웃되면 숨겨져야 하기 때문에 IPointer 인터페이스로 TooltipTrigger 클래스를 만들어주었다.
public class TooltipTrigger : MonoBehaviour, IPointerEnterHandler, IPointerExitHandler
{
public void OnPointerEnter(PointerEventData eventData)
{
// 툴팁 보여주기
TooltipManager.Instance.Show(this);
}
public void OnPointerExit(PointerEventData eventData)
{
// 툴팁 숨기기
TooltipManager.Instance.Hide(this);
}
}
툴팁을 TooltipTrigger 클래스에서 관리해도 되지만, 최적화를 위해 최대한 툴팁이 재사용되었으면 좋겠기에 TooltipManager를 만들어 Dictionary로 관리하도록 하였다.
public class TooltipManager : Singleton<TooltipManager>
{
private Dictionary<GameObject, TooltipStyle> _tooltip = new Dictionary<GameObject, TooltipStyle>();
private Transform _parent;
internal void Show(TooltipTrigger trigger)
{
}
internal void Hide(TooltipTrigger trigger)
{
}
}
이후, 툴팁들에 데이터를 넣어주는 방식에 대해 고민하였다.
툴팁들은 적용되야하는 텍스트, 이미지 등의 개수 또한 달랐기에 어떻게 효율적으로 관리할 수 있을지 고민했다.
처음에는 무작정 TooltipStyle을 추상클래스로 만들고, 종류에 따라 TooltipStyle을 상속받은 클래스를 만들어보았다.
public abstract class TooltipStyle : UIBase
{
internal abstract void ApplyData(string str);
internal abstract void ApplyData(Sprite sprite)
}
public class DescriptionTooltipStyle : TooltipStyle
{
public TextMeshProUGUI descriptionText;
internal override void ApplyData(string str)
{
descriptionText.text = str;
}
internal override void ApplyData(Sprite sprite)
{
}
}
public class SpriteTooltipStyle : TooltipStyle
{
public Image image;
internal override void ApplyData(string str)
{
}
internal override void ApplyData(Sprite sprite)
{
image.sprite = sprite;
}
}
하지만 이렇게 구현한다면, 전달해야하는 데이터의 개수나 타입이 달라질 때 마다 자식 스크립트까지 모두 수정해야하였기에 추후 수정이 불편하였고, 인터페이스로 구현한다면 호출하는 부분에서 잦은 수정이 일어날 것이였기에 다른 방법을 찾아야 했다.
고심끝에 Dictionary로 관리하여 캐싱해둔 키 값에 맞는 string과 Sprite를 반환하도록 TooltipData를 만들기로 했다.
Dictionary는 직렬화가 되지 않기에 List에 키와 값을 저장해두고, 게임 실행 시 딕셔너리에 옮기도록 구현하였다.
[System.Serializable]
public class TooltipData
{
[SerializeField] private List<string> _stringKeys = new List<string>();
[SerializeField] private List<string> _spriteKeys = new List<string>();
[SerializeField] private List<string> _stringValues = new List<string>();
[SerializeField] private List<Sprite> _spriteValues = new List<Sprite>();
private Dictionary<string, string> _stringData = new Dictionary<string, string>();
private Dictionary<string, Sprite> _spriteData = new Dictionary<string, Sprite>();
internal Dictionary<string, string> getAllString => _stringData;
internal Dictionary<string, Sprite> getAllSprite => _spriteData;
public void InitializeData()
{
_stringData = _stringKeys.Zip(_stringValues, (key, value) => new { key, value })
.ToDictionary(x => x.key, x => x.value);
_spriteData = _spriteKeys.Zip(_spriteValues, (key, value) => new { key, value })
.ToDictionary(x => x.key, x => x.value);
}
}
이제 툴팁 스타일에서 ApplyData를 할 때, TooltipData를 넘겨주어 값을 설정해줄 수 있었다.
또한, 에디터에서 스타일에 맞는 데이터들만 보여주기 위해 CreateField 추상 메서드도 추가해주었다.
public abstract class TooltipStyle : UIBase
{
#if UNITY_EDITOR
internal abstract TooltipData CreateField();
#endif
internal abstract void ApplyData(TooltipData data);
}
public class DescriptionTooltipStyle : TooltipStyle
{
public TextMeshProUGUI descriptionText;
#if UNITY_EDITOR
internal override TooltipData CreateField()
{
var data = new TooltipData();
data.AddString("Description", "");
return data;
}
#endif
internal override async void ApplyData(TooltipData data)
{
descriptionText.text = data.GetString("Description");
// 다음 프레임까지 대기 ▶ 텍스트 정보 갱신할 시간을 주기 위해
await UniTask.Yield();
// 높이 조절
var newHeight = descriptionText.textInfo.lineCount * 50;
Vector2 sizeDelta = descriptionText.rectTransform.sizeDelta;
sizeDelta.y = newHeight;
descriptionText.rectTransform.sizeDelta = sizeDelta;
}
}
CreateField 메서드에서 TooltipData의 키-값 리스트에 데이터를 추가해 주어야 하기에 TooltipData에 데이터를 추가할 수 있는 메서드를 구현해 주었다.
[System.Serializable]
public class TooltipData
{
#if UNITY_EDITOR
#region 데이터 추가
internal void AddString(string key, string value)
{
if (_stringData.ContainsKey(key)) return;
_stringKeys.Add(key);
_stringValues.Add(value);
_stringData[key] = value;
}
internal void AddSprite(string key, Sprite value)
{
if (_spriteData.ContainsKey(key)) return;
_spriteKeys.Add(key);
_spriteValues.Add(value);
_spriteData[key] = value;
}
#endregion
#endif
}
TooltipTrigger에 툴팁 스타일을 넣으면 데이터를 변경할 수 있도록 변수로 추가해주고, CustomEditor를 사용해서 필요한 데이터만 이쁘게 보이도록 구현해주었다.
public class TooltipTrigger : MonoBehaviour, IPointerEnterHandler, IPointerExitHandler
{
[SerializeField] private TooltipStyle _tooltipStyle;
[SerializeField] private TipPosition _tooltipPosition;
[SerializeField] private Vector2 _tooltipOffset;
[HideInInspector] public TooltipData tooltipData;
internal TooltipStyle tooltipStyle { get => _tooltipStyle; set => _tooltipStyle = value; }
internal TipPosition tooltipPosition => _tooltipPosition;
internal Vector2 tooltipOffset => _tooltipOffset;
private void Awake()
{
tooltipData.InitializeData();
}
public void OnPointerEnter(PointerEventData eventData)
{
TooltipManager.Instance.Show(this);
}
public void OnPointerExit(PointerEventData eventData)
{
TooltipManager.Instance.Hide(this);
}
}
결과
'공부 > 유니티' 카테고리의 다른 글
[Unity] 툴팁 만들기 - part3. link 태그로 텍스트에 툴팁 넣기 (0) | 2025.05.22 |
---|---|
[Unity] 툴팁 만들기 - part2. 런타임 중에 툴팁에 데이터 넣기 (0) | 2025.05.22 |
[Unity] 백터의 내적과 외적 활용 - 적 탐색편 (0) | 2025.05.08 |
[Unity] Custom Editor - ReorderableList (0) | 2024.06.11 |
[Unity] 유니티 어트리뷰트 만들기 (0) | 2024.02.24 |