[C#/Unity] 부드럽게 가속하는 오브젝트 만들기

신지한·2024년 4월 11일
0

개발노트

목록 보기
12/15
post-thumbnail

📢 개발노트에 앞서서

본 개발노트는 혼자서 유니티 게임개발 독학하는 과정에서
유용하게 사용될만한 요소들을 구현 방법과 함께 기록&공유하는 게시글이며
부족한점이 있을 수 있어 참고해서 봐주시면 감사하겠습니다

부드럽게 가속하는 오브젝트 만들기


🔎 개요

게임안에서 UI의 움직임을 고안하는 과정에서
UI가 좀더 맛있게(?) 움직일수는 없을까 생각하면서 만들어낸 방법입니다

GIF를 만드는 과정에서 프레임 드랍이 생겼습니다. 원본은 좀더 부드럽게 움직입니다!

X축으로 움직이는 모션입니다

같은 매커니즘으로 구현한 Y축으로 움직이는 모션입니다

현재 개발중인 게임에서 실제로 사용되는 모습입니다
게임내에 조작감을 생각하여 오늘 구현한 코드보단 좀더 빠르게 되었고 프레임드랍때문에 조금 어색해보일수 있습니다! 스테이지를 넘기는 장면처럼 복합적으로 사용하면 다양한 연출을 보여줄 수 있는거 같습니다


📝 구현과정

#1 오브젝트 생성 및 스크립트 생성

전체 생성한 오브젝트와 스크립트입니다

오브젝트: Target1(Image), Target2(Image), Button1(Button), Button2(Button), ObjectManager(Empty)
스크립트: ObjectManager

ObjectManage : 오브젝트 변화 기능 관련 함수가 구현되어 있습니다

UI를 작업하는거라 Canvas 상에서 구현을 했습니다

#2 ObjectManager 스크립트 함수 구현

ObjectManager 전체코드 중 일부 관련코드 입니다

private GameObject target;
private bool check = false;

public void SetMovement_X()
{
    if (!check)
    {
        StartCoroutine(UIMovement_X(target, 목표위치값(Vector3), 현재위치값(Vector3), 0));
        check = true;
    }
    else
    {
        StartCoroutine(UIMovement_X(target, 목표위치값(Vector3), 현재위치값(Vector3), 2));
        check = false;
    }
}

private IEnumerator UIMovement_X(GameObject target, Vector3 targetPos, Vector3 orgPos, int count)
{
    //Set Origin Position
    target.transform.position = orgPos;
    Vector3 temp_pos = target.transform.position;

    //Set Direction
    float dir;
    if (targetPos.x < orgPos.x) dir = -1;
    else dir = 1;

    //Move to Target Position
    float x = 1, slope = 0.04f;
    yield return new WaitForSecondsRealtime(0.03f);
    while ((targetPos.x - target.transform.position.x) * dir > 0)
    {
        temp_pos.x = dir * slope * Mathf.Pow(x, 2) + orgPos.x;
        target.transform.position = temp_pos;
        x += 1f;
        yield return new WaitForSecondsRealtime(0.001f);
    }

    target.transform.position = targetPos;

    //Repeat for Vibrate
    if (count == 0) StartCoroutine(UIMovement_X(target, new Vector3(targetPos.x + 30f * -dir, target.transform.position.y, 0f), target.transform.position, count + 1));
    else if (count == 1) StartCoroutine(UIMovement_X(target, new Vector3(targetPos.x + 10f * -dir, target.transform.position.y, 0f), target.transform.position, count + 1));
}

Button을 클릭시 SetEmphasis가 호출되고 SetEmphasis에선 코루틴으로 Emphasis 함수를 실행합니다

코드가 동작하는 방법은 다음과 같습니다

  • 다음과 같은 코드로 UIMovement_X 함수를 호출합니다
StartCoroutine(UIMovement_X(target, 목표위치값(Vector3), 현재위치값(Vector3), 0));

UIMovement(GameObject, Vector3, Vector3, int) 파라미터를 가지고 순서대로
1.타겟이 될 오브젝트, 2.목표위치값, 3.현재위치값, 4.카운트 로 구성되어져있고
카운트는 모션 이후에 약간의 떨림을 주기위한 변수로 오브젝트 이동과는 크게 관련이 없습니다

  • 오브젝트의 위치를 본래의 위치로 보정하고 temp_pos로 임의의 Vector3 변수를 선언합니다
//Set Origin Position
target.transform.position = orgPos;
Vector3 temp_pos = target.transform.position;
  • 방향을 설정합니다. 이는 좌표계에서 타겟의 위치(x값)이 본래의 위치(x값)보다
    작을 경우 dir을 -1로 선언, 클 경우 dir을 1로 선언하여 계산에 사용합니다
//Set Direction
float dir;
if (targetPos.x < orgPos.x) dir = -1;
else dir = 1;
  • 오브젝트를 움직입니다 코드는 다음과 같습니다
//Move to Target Position
float x = 1, slope = 0.04f;
yield return new WaitForSecondsRealtime(0.03f);
while ((targetPos.x - target.transform.position.x) * dir > 0)
{
	temp_pos.x = dir * slope * Mathf.Pow(x, 2) + orgPos.x;
	target.transform.position = temp_pos;
	x += 1f;
	yield return new WaitForSecondsRealtime(0.001f);
}

오브젝트의 위치는 y = dir * slope * x^2 + orgPos 의 이차함수 형태를 갖는다
오브젝트가 점점 가속하는 느낌을 주려고 이차함수 형태의 값을 통해 오브젝트의 위치를 조절했다
속도를 조절하려면 slope(기울기)의 값 조절을 통해 조절한다

  • 마지막으로 미세하게 틀어진 위치값을 조정해준다
target.transform.position = targetPos;

반복문의 조건안에서 동작하지만 마지막에 미세하게 값이 틀어짐을 해당 코드로 보정해준다

  • 현재 코드는 X축을 이동하게 해주는 코드이고 Y축으로 이동을 원할 시에
    코드안에 x값들과 y값들을 바꿔주면 Y축으로 이동하는 코드가 완성된다

#3 ObjectManager, Button에 스크립트 Component로 추가하기

ObjectManagerObjectManager 스크립트를 Add Component를 하고 Object칸에 위치가 변화될 오브젝트 target1, target2를 추가합니다

OnClick()ObjectManager를 추가하고 해당 스크립트의 SetMovement_X 함수를 설정합니다

📌 추가적인 설명

  • 속도를 조절하려면 x값이 변하는 축을 설정하거나 WaitForSecondsRealtime의 값 조절, 기울기 조절 등의 방법들이 있습니다
  • 점점 가속하는 방법을 2차함수로 구현했지만 좀더 다양한 움직임을 다양한 함수를 통해 구현할 수 있을거 같습니다
  • 현재 UI에만 적용하고있지만 탄환같은 게임내의 오브젝트에도 같은 매커니즘을 통해 구현할 수 있을거 같습니다

이전 게시글에서 조금의 수정이 들어간 내용이므로 게시글의 양식이 거의 비슷함을 알려드립니다

이상으로 부드럽게 가속하는 오브젝트 구현에 대해서 포스팅 해보았습니다
궁금하신 점이 있으시거나 코드가 좀더 좋은방향으로 수정될 수 있다면
관련된 댓글 남겨주시면 감사하겠습니다!!🙇‍

profile
게임 개발자 지망생

0개의 댓글