상세 컨텐츠

본문 제목

유니티 3D 오브젝트의 이동 방식

UNITY C#

by 오픈플레이 2019. 6. 15. 14:33

본문

오브젝트의 이동 방식은 크게 transform, rigidbody, 그리고 character controller 이들 3개의 속성에 따라 나뉩니다.

게임의 장르, 플레이 방식, 그리고 규칙에 이들 세 가지 컴포넌트 중 하나를 선택해야 하는데, 각 컴포넌트가 지원하는 함수 / 명령어가 다르고, 서로 지원이 되지 않기 때문에 게임 기획을 미리 잘 세워둬야 합니다. 잘 세워둔다고 하더라도 향후 게임 기획의 변화에 의해 캐릭터 이동 방식의 변화가 필요할 때도 있지요.


1. transform 이동

transform은 게임오브젝트의 로컬 위치, 회전각도, 크기 속성들을 포함하고 있습니다. 이동을 위해서라면 transform.position (Vector3 변수) 명령을 내리거나, 매 프레임 실시간으로 계속 움직인다면 transform.Translate(Vector3변수)를 쓰는 방법을 씁니다.

transform 이동은 당연히 지상 움직임이라던가 점프 등의 기능을 가진 캐릭터가 아닌, 공중에 떠 있는 캐릭터에 적합한 방식입니다. 혹은 캐릭터가 아니더라도 단순 오브젝트의 이동용에 적합하다고 봅니다.

public GameObject cubeTransform;
public float speed = 1.0f;

void Start ()
{
	// cubeTransform의 x위치 +2 만큼 이동 
	cubeTransform.transform.position = new Vector3 (2,0,0); 
}

void Update()
{
	float x = Input.GetAxis("Horizontal");
	float z = Input.GetAxis("Vertical");
    
	// 속도를 조절합니다.
	float translateMove = speed * Time.deltaTime;
    
	cubeTransform.transform.Translate
    	(x * translateMove , 0 , z * translateMove );
}

 


2. character controller 이동

캐릭터 컨트롤러 컴포넌트는 리지드바디 rigidbody를 사용하지 않는 1, 3인칭 캐릭터에 주로 쓰입니다. 바닥 위 이동, 경사 올라가기 기능 등이 기본적으로 포함되어 있죠. 이 컴포넌트를 통해 캐릭터를 이동할 시에는 Move 함수를 써야 하며, transform.position 등의 직접적인 transform 명령이 지원되지 않습니다. 앞서 말씀드렸듯이 rigidbody를 사용하지 않기 때문에, 중력효과의 연출을 위해서 별도의 처리과정이 필요하게 됩니다. 항상 -Y 포지션을 향해 가야 하며, 점프 시에는 +Y 포지션 값에 변화를 주는 형식이죠.

transform과 달리, Move 명령어는 별도 Vector3변수를 적용해야 합니다. Vector3 moveDirection 변수를 살펴보시기 바랍니다.

public CharacterController player; // 캐릭터 컨트롤러를 받아올 변수
public float speed = 2.0f; // 속도
Vector3 moveDirection = Vector3.zero; // 벡터 변수를 새로 만든후 초기화 해줍니다.

    void Start()
    {
    	// 캐릭터 컨트롤러 컴포넌트를 받습니다.
        player.GetComponent<CharacterController>();
    }

    void Update()
    {
        float x = Input.GetAxis("Horizontal");
        float z = Input.GetAxis("Vertical");

        moveDirection = new Vector3(x, 0, z) * speed;

        player.Move(moveDirection * Time.deltaTime);
    }

이렇게 작성만 하면 캐릭터는 지면으로 벗어나면 떨어지지 않거나 공중에 붕 뜬 상태가 됩니다. 중력을 만들어 보도록 하죠.

public CharacterController player;
public float speed = 2.0f;
public float gravity = 30.0f; // 중력을 추가
Vector3 moveDirection = Vector3.zero;

    void Start()
    {
        player.GetComponent<CharacterController>();
    }

    void Update()
    {
        float x = Input.GetAxis("Horizontal");
        float z = Input.GetAxis("Vertical");

        moveDirection = new Vector3(x, 0, z) * speed;

 	// 벡터 y 방향으로 중력을 계속 더합니다.
        moveDirection.y -= gravity * Time.deltaTime;
        
        player.Move(moveDirection * Time.deltaTime);
        
    }

이렇게 되면 캐릭터가 지면을 벗어날 경우 아래로 움직이는 것을 볼 수 있습니다. 중력이 적용된 것처럼 보이게 만드는 거죠. 그러나 떨어지는 속도가 너무 더딥니다. 캐릭터가 내부적으로는 땅을 밟지 않았기 때문인데요, 전용 함수인 isGround를 써서 물리엔진을 쓴 것처럼 떨어지게 만들어 보겠습니다.

public CharacterController player;
public float speed = 2.0f;
public float gravity = 30.0f;
Vector3 moveDirection = Vector3.zero;

    void Start()
    {
        player.GetComponent<CharacterController>();
    }

    void Update()
    {
    	 // 캐릭터가 지면에 닿았는가 리턴하는 함수를 적용
        if (player.isGrounded)
        {
            float x = Input.GetAxis("Horizontal");
            float z = Input.GetAxis("Vertical");

            moveDirection = new Vector3(x, 0, z) * speed;
        }

        moveDirection.y -= gravity * Time.deltaTime;
        player.Move(moveDirection * Time.deltaTime);
        
    }

캐릭터가 지면에서 벗어나면 '시원하게' 떨어지는 것을 볼 수 있습니다.

 


3. rigidbody 이동

리지드바디가 적용된 캐릭터의 경우 transform.position의 명령이 가능하지만, 물리엔진을 사용하기 때문에 마찰로 인해 지상에서 비정상적인 움직임을 가집니다. 리지드바디의 대표적인 이동은 Rigidbody.AddForce (힘 더하기) 또는. Velocity (가속 더하기) 이 두 가지에 의해 이루어지며, 리지드바디 속성과 물리 재질 (physic material)을 이용해 다양한 물리법칙을 만들 수 있습니다.

또한 transform 과 character controller 와는 달리 중력 여부 / 정도를 조절할 수 있기 때문에 별도의 코드 없이 간단하게 물리엔진을 사용할 수 있습니다만, 물리엔진에 필요한 연산이 많이 들어가기에, 최적화에 따른 여러 가지 공부가 필요합니다.

.AddForce를 적용한 예시

public Rigidbody playerRb; // 리지드바디 변수
public float speed = 2.0f;
Vector3 moveDirection;

    void Start()
    {
    	// 리지드바디 컴포넌트를 받습니다.
        playerRb.GetComponent<Rigidbody>();
    }

    void Update()
    {
        float x = Input.GetAxis("Horizontal");
        float z = Input.GetAxis("Vertical");

        moveDirection = new Vector3(x, 0, z);
        playerRb.AddForce(moveDirection * speed); // AddForce 적용
    }

움직임을 시도하면 초기 움직임은 느리지만 시간이 갈수록 속도가 증가되는 모습을 볼 수 있습니다. 즉각적인 방향 전환이 되지 않고 속도 또한 천천히 줄면서 다이내믹한 움직임을 보여주죠.

.velocity를 적용한 예시

public Rigidbody playerRb;
public float speed = 2.0f;
Vector3 moveDirection;
   
    void Start()
    {
        playerRb.GetComponent<Rigidbody>();
    }

    void Update()
    {
        float x = Input.GetAxis("Horizontal");
        float z = Input.GetAxis("Vertical");

        moveDirection = new Vector3(x, 0, z);
        //playerRb.AddForce(moveDirection * speed);
        playerRb.velocity = (moveDirection * speed); // 가속도를 적용
    }

보시는 바와 같이 .AddForce와 .velocity 용법이 조금 다름에 유의하세요.

여하튼 실행해서 움직이면 .AddForce를 적용한 것보다 즉각적인 반응이 나타납니다. 앞서 말씀드렸다시피, 게임 기획에 따라 움직이는 방식을 정하는 것이 좋겠죠. 방법이 여러 가지라, 무엇이 정답이 될지 모르니까요.'정답에 가까운 솔루션'을 정한다고나 할까요.

 


이렇게 간략하게 살펴보았습니다. 정말 간략하게 말이죠. ㅇㅅㅇ...

감사합니다.

관련글 더보기

댓글 영역