Unity
[ Unity ] 원형 슬라이더, Radial Slider(Circular Slider)
거두절me
2024. 9. 4. 19:23
원하는 거: 그냥 단순히.. 슬라이더를 원형으로 하고 싶었고 핸들을 잡고 직접 돌리고 싶다.
아래 사진 참고.
내가 원하는 건 위 사진의 검은 점을 잡고 원형으로 돌렸을때, 그 위치를 따라오면서 원의 값이 바뀌었으면 했다.
원리를 쉽게 말하자면 아래 사진을 보면 된다.
내 마우스의 위치가 A에 있을때 B에 해당하는 위치에 슬라이더 값이 있어야 한다는 뜻이다.
소스를 바로 봐 보자.
Canvas의 Render Mode가 Camera인 경우
using UnityEngine;
using UnityEngine.EventSystems;
using UnityEngine.UI;
public class CircularSlider : MonoBehaviour, IDragHandler, IPointerDownHandler
{
public RectTransform handle; // 핸들 오브젝트
public RectTransform centerPoint; // 중심점 오브젝트(따로 깡통 오브젝트 만들기)
public Canvas canvas; // 현재 사용 중인 캔버스
public Text valueText; // 값을 표시할 텍스트
public Image fillImage; // 모드가 Radial 360 fill인 이미지
public int maxChips = 280; // 최대 값 (100%에 해당)
private float radius; // 중심점과 핸들 사이의 고정된 거리 (반지름)
private float maxAngle = 260f; // 최대 각도 (260도)
private float currentAngle = 0f; // 현재 핸들의 각도
void Start()
{
// 중심점과 핸들 사이의 초기 거리(반지름)를 계산
radius = Vector2.Distance(handle.anchoredPosition, centerPoint.anchoredPosition);
UpdateHandlePosition(maxAngle); // 초기 위치를 0%로 설정
}
public void OnPointerDown(PointerEventData eventData)
{
UpdateHandlePosition(eventData);
}
public void OnDrag(PointerEventData eventData)
{
UpdateHandlePosition(eventData);
}
private void UpdateHandlePosition(PointerEventData eventData)
{
// 마우스의 화면 좌표를 캔버스의 로컬 좌표로 변환
Vector2 localMousePosition;
RectTransformUtility.ScreenPointToLocalPointInRectangle(centerPoint, eventData.position, canvas.worldCamera, out localMousePosition);
// 중심점에서 마우스 위치 사이의 벡터를 계산
Vector2 direction = (localMousePosition - (Vector2)centerPoint.anchoredPosition).normalized;
// 마우스 위치로부터 각도 계산 (0~360도)
float angle = Mathf.Atan2(direction.y, direction.x) * Mathf.Rad2Deg;
if (angle < 0) angle += 360; // 각도를 0~360도로 조정
// 시계방향으로 돌 때 각도 제한
if (angle > maxAngle)
{
currentAngle = maxAngle; // 시계방향으로 최대값을 넘어가면 멈춤
}
else
{
currentAngle = Mathf.Clamp(angle, 0, maxAngle);
// 핸들의 새로운 위치 계산: 중심점에서 방향 벡터에 반지름을 곱한 거리만큼 이동
Vector2 newPosition = (Vector2)centerPoint.anchoredPosition + new Vector2(Mathf.Cos(currentAngle * Mathf.Deg2Rad), Mathf.Sin(currentAngle * Mathf.Deg2Rad)) * radius;
// 핸들의 위치를 업데이트
handle.anchoredPosition = newPosition;
// 현재 값 및 이미지 업데이트
UpdateValueText();
UpdateFillImage();
}
}
private void UpdateHandlePosition(float angle)
{
// 초기 위치 설정 함수
currentAngle = angle;
Vector2 newPosition = (Vector2)centerPoint.anchoredPosition + new Vector2(Mathf.Cos(currentAngle * Mathf.Deg2Rad), Mathf.Sin(currentAngle * Mathf.Deg2Rad)) * radius;
handle.anchoredPosition = newPosition;
UpdateValueText();
UpdateFillImage();
}
private void UpdateValueText()
{
// 각도를 최대 칩 수로 변환하여 텍스트 업데이트
// currentAngle이 최대일 때 0이 표시되도록 반대로 계산
int currentValue = Mathf.RoundToInt((1 - (currentAngle / maxAngle)) * maxChips);
valueText.text = currentValue.ToString();
}
private void UpdateFillImage()
{
// 각도를 0에서 1 사이의 값으로 변환하여 Radial Fill에 적용
// FillAmount는 핸들이 움직인 비율로 설정해야 합니다.
fillImage.fillAmount = currentAngle / 360;
}
}
주석을 친절히 써놨으니, 대강 알것이다...
결과물:
근데 지금 보니 내가 색상을 반대로 해놨네;; 숫자가 올라갈때 색상이 채워져야 하는데ㅇㅅㅇ ㅋㄷㅋㄷ
뭐 아무튼..
UI는 정말 딱 참고만 하시고...
내가 한 방법은.
두 개의 원 이미지를 만들고 레이어상 뒤에 원을 크게 만들어서 지금처럼 초록색을 넣고 모드를 radial 360 fill로 넣었다.
핸들은 0이어야 하는 지점에 미리 가져다 놓았다.