유니티 2D) 부모 오브젝트 주위를 자식 오브젝트들이 원형으로 회전하게 하고 싶다면? (RotateAround 사용 버전도 포함)

2024. 12. 12. 11:37·기능 구현 방법 정리

1) 초기 배치,

원점(부모 오브젝트 좌표)를 기준으로 (x, y) 만큼 떨어진 지점(자식 오브젝트 위치)을 삼각형으로 그려보면 위의 그림과 같이 나옵니다.

 

그 빗변의 길이인 r (radius, 반지름)이 동일하게끔 하면 부모 오브젝트와 거리가 동일한 원형의 좌표가 나옵니다.

 

자식과 부모 오브젝트가 이루는 각도 θ

삼각함수의 정의에 따라,

 

cos θ = x / r => x = r * cos θ

sin θ = y / r => y = r * sin θ

 

이렇게 r, θ 가 있다면 자식 오브젝트의 로컬 x, y 좌표를 구할 수 있게 됩니다.

 

여기서 원의 반지름 r은 개발자가 지정하며

각도 θ는자식 오브젝트 수에 따라 초기 각도를 자동으로 부여하게끔 하도록 해보겠습니다.

원 한바퀴 360도를 라디안으로 표현하면 2 π 입니다.

 

2 π * ( 몇번째 자식인지 인덱스 / 자식 오브젝트의 수)

 

로 준다면 자식 오브젝트 수에 따라 자동으로 초기 각도를 줄 수 있습니다.

 

 

2) 회전 시켜주려고 할 때,

자식 오브젝트들의 트랜스폼으로부터 로컬포지션의 좌표를 받아올 수 있습니다.

현재 x, y 로컬 좌표가 있으므로 이를 통해 현재 각도  θ를 구해봅시다. 

 

아크탄젠트 atan2 는 2개의 인수(각각 y, x 좌표 차이)로 , 부호가 구분된 θ 를 구할 수 있는 함수입니다.

여기서 부모 오브젝트의 상대 좌표는 0, 0 원점이므로 자식 오브젝트의 로컬 x,y 좌표만 있으면 되는 것이지요.

atan는 역탄젠트 함수라고도 불리며 간단히 얘기하면 tan함수의 역입니다.

 

tan θ = y / x

atan ( tan θ ) = atan ( y / x )

θ = atan ( y / x )

이렇게 자식 오브젝트의 로컬 좌표를 이용해  현재 각도  θ를 구했습니다.

 

회전 속도에 따라 다음 각도로 θ를 증가/감소시켜주고,

이에 해당하는 새로운 x, y 좌표를 계산하여 이 좌표로 이동하면 원형 이동은 완성입니다.

 

원의 반지름 r은 주어진 수가 있고 변경한 θ 는 이미 값을 알고 있기에,

제일 위의 식을 다시 가져와서

x = r * cos θ

y = r * sin θ

새로 만들어진 좌표로 이동하면 끝납니다.

 

using UnityEngine;

// 부착된 오브젝트의 자식 오브젝트들이 주위를 회전하게 만들기
public class RotateAround : MonoBehaviour
{
    // 자식 트랜스폼들
    Transform[] childTrans;
    // 자식의 수
    int childNum;
    // 회전 속도
    public float rotateSpeed = 0.6f;
    // 회전 반경
    public float radius = 3;
    // Start is called before the first frame update
    void Start()
    {
        // 모든 자식의 트랜스폼
        childNum = transform.childCount;
        childTrans = new Transform[childNum];
        for (int i = 0; i < childNum; i++)
        {
            childTrans[i] = transform.GetChild(i);
        }

        // 초기 위치 설정: 자식들을 원형으로 배치
        for (int i = 0; i < childNum; i++)
        {
        	// 2Pi를 자식 수로 나누어 어느 각도에 위치할지
            float angle = i * Mathf.PI * 2 / childNum;
            // 삼각함수, 반지름 이용하여 초기 좌표
            Vector3 newPosition = new Vector3(Mathf.Cos(angle), Mathf.Sin(angle), 0) * radius;
            childTrans[i].localPosition = newPosition;
            // RotateAround_API를 쓸 때 주석 해제하면 각도 자동으로 부여
            // childTrans[i].localRotation = Quaternion.Euler(Vector3.forward * Mathf.Rad2Deg * angle);
        }
    }

    private void FixedUpdate()
    {
        RotateAround_OnlyPosChange(true);
    }

    // 유니티 api인 RotateAround를 사용하여 모든 자식 오브젝트를 회전하게끔
    // 자식들이 로컬포지션(sqrt(x^2+y^2))을 반지름 삼아 부모 오브젝트 주위를 공전
    // isClockWise = true > 시계 방향, false > 반시계 방향
    void RotateAround_API(bool isClockWise)
    {
        // 회전 방향
        Vector3 dir;
        if (isClockWise)
            dir = Vector3.back;
        else
            dir = Vector3.forward;
        // 모든 자식 오브젝트 공전
        for (int i = 0; i < childNum; i++)
        {
            // rotateSpeed에는 FixedDeltaTime인 0.02를 이미 곱해둔 값으로 설정하여 연산을 줄임
            childTrans[i].RotateAround(transform.position, dir, rotateSpeed);
        }
    }

    // 위의 api는 자식 오브젝트도 회전하는 것으로 보인다
    // 해당 메서드는 자식 오브젝트들을 부모 오브젝트 주위를 원형으로 그리며 이동만 하여 회전값은 그대로 유지합니다.
    // isClockWise = true : 시계 방향, false : 반시계 방향
    void RotateAround_OnlyPosChange(bool isClockWise)
    {
        // 자식 오브젝트들을 부모 오브젝트 중심으로 회전
        for (int i = 0; i < childNum; i++)
        {
            // 현재 좌표
            Vector3 currentPos = childTrans[i].localPosition;
            // 부모와 이루는 각도 계산
            float angle = Mathf.Atan2(currentPos.y, currentPos.x);

            // 회전 방향에 따른 각도 증감
            // rotateSpeed에는 FixedDeltaTime인 0.02를 이미 곱해둔 값으로 설정하여 연산을 줄임
            if (isClockWise)
                angle -= Mathf.Deg2Rad * rotateSpeed;
            else
                angle += Mathf.Deg2Rad * rotateSpeed;

            // 다음 좌표로 이동
            Vector3 newPosition = new Vector3(Mathf.Cos(angle), Mathf.Sin(angle), 0) * radius;
            childTrans[i].localPosition = newPosition;
        }
    }
}

 

결과

1) RotateAround_API(bool isClockWise)

Start()에서 angle을 부여하는 구문의 주석을 풀어서 초기 회전값을 준다면 이와 같이 나옵니다.

부모 오브젝트를 기준으로 자전+공전을 동시에 하게끔 하고 싶다면 RotateAround()를 이용한 함수를 쓰는 것이 좋습니다.

단순한 형태의 오브젝트가 부모를 기준으로 회전하게끔 하고 싶을 때 유용하며 모양도 예쁘게 나옵니다.

 

2) RotateAround_OnlyPosChange(bool isClockWise)

자식 오브젝트들의 회전값을 변화시키지 않고 부모 주변을 회전시키고자 할 때는 위치만 옮겨주는 해당 메서드를 사용하는 것이 좋습니다.

저작자표시 비영리 동일조건 (새창열림)

'기능 구현 방법 정리' 카테고리의 다른 글

유니티 UI 이미지 마스크  (0) 2025.01.27
유니티 UI에 스파인 애니메이션 넣기  (0) 2025.01.26
유니티) 레이어마스크(LayerMask) 사용법, 2D 가장 가까운 적 탐색  (0) 2024.12.02
유니티) 머티리얼(Material) 색상 곱하기  (0) 2024.11.25
유니티, 스파인) 머티리얼 교체 없이 색상만 바꾸고 싶을 때  (0) 2024.11.25
'기능 구현 방법 정리' 카테고리의 다른 글
  • 유니티 UI 이미지 마스크
  • 유니티 UI에 스파인 애니메이션 넣기
  • 유니티) 레이어마스크(LayerMask) 사용법, 2D 가장 가까운 적 탐색
  • 유니티) 머티리얼(Material) 색상 곱하기
ybbro
ybbro
대부분의 포스팅은 pc에서 작성되었습니다. 모바일에서 볼 때 설명이 잘리면 데스크탑 모드를 사용해보길 바랍니다.
  • ybbro
    어떻게든 굴리는 게임 공방
    ybbro
  • 전체
    오늘
    어제
    • 전체 N
      • 스파르타코딩클럽_Unity개발과정 N
      • Unity 2D
        • 카드게임
        • 플랫포머 게임
        • 뱀서라이크
      • Unity 3D
        • 닷지
        • 유니티 짱
        • 디펜스 게임
      • Unity 에러 노트
      • 기능 구현 방법 정리
      • 셰이더 그래프
        • 2D
        • 3D
      • 프로그래머스
      • 자료구조
      • 기타
  • 블로그 메뉴

    • 홈
    • 태그
    • 방명록
  • 링크

  • 공지사항

  • 인기 글

  • 태그

    UI
    다크모드
    앱이 휴대전화와 호환되지 않아 설치되지 않았습니다
    unity
    64비트
    sprite mask
    삭제
    스파인
    유니티 애니메이터 파라미터 초기화
    룰렛
    텍스트매시프로
    무료스킨
    세이브
    hello
    마스크
    대시
    직렬화
    갤럭시 S24
    잔상
    유니티
  • 최근 댓글

  • 최근 글

  • hELLO· Designed By정상우.v4.10.3
ybbro
유니티 2D) 부모 오브젝트 주위를 자식 오브젝트들이 원형으로 회전하게 하고 싶다면? (RotateAround 사용 버전도 포함)
상단으로

티스토리툴바