728x90

이 글은 인프런 [따라하면서 배우는 고박사의 유니티 기초] 강의를 수강하고 정리한 글입니다. 

 

[지금 무료] 따라하면서 배우는 고박사의 유니티 기초 | 고박사 - 인프런

고박사 | 유니티로 게임을 개발하고 싶은 초보자를 대상으로 하며, 유니티 설치부터 2D/3D 게임 개발에 필요한 기초 지식까지 자세하게 설명합니다. (강의에 사용되는 모든 리소스는 영상 상단의

www.inflearn.com

 

CharacterController 컴포넌트

CharacterController 컴포넌트는 유니티에서 제공하는 컴포넌트로 3차원 게임에서 사람 형태의 캐릭터 움직임과 관련된 제어를 위해 사용하는 컴포넌트이다.

캡슐(Capsule) 형태의 collider이 포함되어 있기 때문에 따로 Collider 컴포넌트를 추가하지 않아도 충돌 처리 및 물리처리가 가능하다.

캐릭터의 움직임을 위해 제작된 컴포넌트이기 때문에 오브젝트가 이동할 수 있는 경사각도, 올라갈 수 있는 계단 높이와 같은 정보를 설정할 수 있으며, center, radius, height 정보를 설정해 collider을 설정할 수 있다. 

  • Slope Limit : 올라갈 수 있는 경사 한계 각
  • Step Offset : 설정 값보다 낮은 높이의 계단(그 외 오브젝트)을 오를 수 있다
  • Center : Capsule 충돌 범위의 중심점
  • Radius : Capsule 충돌 범위의 반지름 (x, z)
  • Height : Capsule 충돌 범위의 높이 (y)

 


게임 월드 구성, 플레이어 캐릭터 제작

영상 하단에 있는 게임월드 패키지를 프로젝트 내부로 가져온다. prefab 폴더에 GameWorld prefab을 Hirearchy view로 드래그한다.

 

한 눈에 볼 수 있도록 main camera를 다음과 같이 바꾸어 준다.

 

player로 사용할 3D 오브젝트를 생성한다.(GameObject > 3D Object > Capsule)

player의 색상을 변경할 때 3D에서는 Project View > “+” > Material로 meterial Asset을 생성하고 색상과 이미지를 정하고 오브젝트에 등록해야한다. 

 

설정이 완료되었다면 플레이어 오브젝트의 Mesh renderer 컴포넌트에서 등록을 해준다.

플레이어 오브젝트에 character controller 컴포넌트를 추가하고 capsule collider를 지워준다. scene view에서 확인을 해보면 캡슐 범위의 충돌 범위가 capsule collider에 의하여 설정된 것을 확인할 수 있다.


플레이어 캐릭터 이동

캐릭터 컨트롤러를 기반으로 이동을 제어하는 Movement3D 스크립트를 작성한다. 

using UnityEngine;

public class Movement3D : MonoBehaviour
{
	[SerializeField]
	private	float		moveSpeed = 5.0f;	// 이동 속도
	private	Vector3		moveDirection;		// 이동 방향

	private	CharacterController	characterController;

	private void Awake()
	{
		characterController = GetComponent<CharacterController>();
	}

	private void Update()
	{

		characterController.Move(moveDirection * moveSpeed * Time.deltaTime);
	}

	public void MoveTo(Vector3 direction)
	{
		moveDirection =  direction;
	}

}

플레이어를 제어하는 스크립트, PlayerController 를 생성한다. 

using UnityEngine;

public class PlayerController : MonoBehaviour
{
	private	Movement3D			movement3D;

	private void Awake()
	{
		movement3D = GetComponent<Movement3D>();
	}

	private void Update()
	{
		// x, z축 방향으로 이동
		float x = Input.GetAxisRaw("Horizontal");	// 방향키 좌/우 움직임
		float z = Input.GetAxisRaw("Vertical");		// 방향키 위/아래 움직임
		
		movement3D.MoveTo(new Vector3(x, 0, z));

	}
}

 

생성한 두 스크립트를 플레이어 오브젝트에 컴포넌트에 추가한다. 방향키의 방향에 따라 오브젝트가 움직이는 것을 확인할 수 있다. 


중력 적용

위에 플레이어 오브젝트의 y 축을 올렸을 때, 중력에 의해 떨어지지 않고 공중에서 이동을 하는데 캐릭터 컨트롤러 컴포넌트는 충돌 처리가 가능할 뿐 중력은 적용되지 않기 때문이다. 중력 적용을 위해 직접 스크립트를 통해 입력을 해야한다.

우선 Movement3D 스크립트 코드로 가서 중력 계수를 추가하였고, 업데이트 함수를 확인하면 characterController.isGrounded == false 즉 캐릭터의 발 위치의 충돌을 체크하여 충돌이 된다면 true, 아니라면 flase값을 나타내는 변수로 캐릭터가 땅에 닿아있을 때를 확인하는 변수로 사용하기 때문에 false로 설정했다.

공중에 있을 떄 moveDirection.y += gravity * Time.deltaTime; 를 통해 y축 이동 방향에 gravity * Time.deltaTime을 계속 더해준다. gravity가 음수이기에 y축 이동 방향은 계속 감소하게 되고, 계속 아래로 떨어지려고 하는 중력을 받는 것이 적용되게 될 것이다. 

private	float		gravity = -9.81f;	// 중력 계수

```

private void Update()
	{
		if ( characterController.isGrounded == false )
		{
			moveDirection.y += gravity * Time.deltaTime;
		}

		characterController.Move(moveDirection * moveSpeed * Time.deltaTime);
	}
public void MoveTo(Vector3 direction)
{
    moveDirection	= new Vector3(movedis.x, moveDirection.y, movedis.z);
}

플레이어 캐릭터 점프

[SerializeField] private float jumpForce = 3.0f; // 뛰어 오르는 힘

뛰는 힘을 변수를 생성하고 Jump To 함수를 public으로 선언하여 외부에서 호출하는 용도로 제작하였다. 

public void JumpTo() 
{ 
	if ( characterController.isGrounded == true ) 
	{ 
    	moveDirection.y = jumpForce; 
    } 
}

 

이 함수가 호출되면 characterController.isGrounded 값이 true일 때, 즉 캐릭터가 바닥에 있으면 moveDirection y값에 jumpforce가 대입한다. 즉 y축 방향이 3이 되어 위로 점프 된다.

update에 작성했던 위 코드에 의해 위로 점프를 하지만 y축 이동 방향 값이 서서히 감소하게 되어 0이 되는 시점이 점프 최고점이 될 것이고 다시 음수에 의해 떨어지게 된다.

// y축 방향으로 뛰어오름
		if ( Input.GetKeyDown(jumpKeyCode) )
		{
			movement3D.JumpTo();
		}

스페이스바를 눌렀을 때 movement3D에 있는 JumpTo() 함수를 호출해서 점프하게끔 설정하였다.

 


경사면 이동과 계단 이동

Slope Limit 변수는 경사 한계 각도를 설정할 수 있으며 현재 45도로 설정되어 있어 45도까지 경사를 오를 수 있다. 

Step Offset 변수는 인접한 계단 사이의 높이가 해당 변수 이하일 때 계단을 오를 수 있다. 

GameWorld에 경사면이 총 2개가 있고 하나는 39도 경사라 오를 수 있지만 다른 하나는 52도여서 올라갈 수 없다. 

인접한 계단의 높이 차가 0.4로 플레이어의 step offset 값을 0.4로 변경하면 계단에 올라갈 수 있다.


1인칭 카메라 제어

먼저 camera 오브젝트가 플레이어를 쫓아다니도록 player의 자식으로 설정한다. 그리고 카메라 transeform 정보를 초기화한 뒤에 y축을 0.6으로 바꾼다.

scene 뷰에서 카메라가 player 오브젝트 안에 있는 것을 확인할 수 있었다.

카메라의 회전을 설정하기 위한 스크립트를 하나 작성한다.

using UnityEngine;

public class CameraController : MonoBehaviour
{
	private	float	rotateSpeedX = 3;
	private	float	rotateSpeedY = 5;
	private	float	limitMinX = -80;
	private	float	limitMaxX = 50;
	private	float	eulerAngleX;
	private	float	eulerAngleY;

	public void RotateTo(float mouseX, float mouseY)
	{
		// 마우스를 좌/우로 움직이는 mouseX 값을 y축에 대입하는 이유는
		// 마우스를 좌/우로 움직일 때 카메라도 좌/우를 보려면 카메라 오브젝트의
		// y축이 회전되어야 하기 때문
		eulerAngleY += mouseX * rotateSpeedX;
		// 같은 개념으로 카메라가 위/아래를 보려면 카메라 오브젝트의 x축이 회전!
		eulerAngleX -= mouseY * rotateSpeedY;

		// x축 회전 값의 경우 아래, 위를 볼 수 있는 제한 각도가 설정되어 있다
		eulerAngleX = ClampAngle(eulerAngleX, limitMinX, limitMaxX);

		// 실제 오브젝트의 쿼터니온 회전에 적용
		transform.rotation = Quaternion.Euler(eulerAngleX, eulerAngleY, 0);
	}

	private float ClampAngle(float angle, float min, float max)
	{
		if ( angle < -360 )	angle += 360;
		if ( angle > 360 )	angle -= 360;

		// Mathf.Clamp()를 이용해 angle이 min <= angle <= max을 유지하도록 함
		return Mathf.Clamp(angle, min, max);
	}
}

RotateTo() 함수는 외부에서 마우스의 x,y축 움직임을 가져와 카메라의 로테이션에 적용해 카메라를 회전시키는 함수이다.

마우스를 좌/우로 움직일 때 카메라도 좌/우를 보려면 카메라 오브젝트의 y축이 회전해야하기 때문에 마우스를 좌/우로 움직이는 mouseX 값을 y축에 대입한다. 

		// 같은 개념으로 카메라가 위/아래를 보려면 카메라 오브젝트의 x축이 회전!
		eulerAngleX -= mouseY * rotateSpeedY;

위에 함수 코드 중에 위에 부분에서 더하지 않고 빼는 이유는 마우는 아래로 가는 것이 -이기 때문에 빼준다. 

 

playercontroller에서 카메라 제어하는 부분을 구현하도록 하자면, CamerController에 있는 Rotate To 함수를 호출하기 위해서 변수를 생성한다. 

[SerializeField]
private	CameraController	cameraController;

private void Update()
	{
		// x, z축 방향으로 이동
		float x = Input.GetAxisRaw("Horizontal");	// 방향키 좌/우 움직임
		float z = Input.GetAxisRaw("Vertical");		// 방향키 위/아래 움직임
		
		movement3D.MoveTo(new Vector3(x, 0, z));

		// y축 방향으로 뛰어오름
		if ( Input.GetKeyDown(jumpKeyCode) )
		{
			movement3D.JumpTo();
		}

		// 카메라 x, y축 회전
		float mouseX = Input.GetAxis("Mouse X");	// 마우스 좌/우 움직임
		float mouseY = Input.GetAxis("Mouse Y");	// 마우스 위/아래 움직임

		cameraController.RotateTo(mouseX, mouseY);
	}

위의 두 변수 값이 CameraController의 Rotate To 함수의 매개변수값으로 전달되면 마우스가 움직였을 때 Rotate To() 함수가 호출되어 실제 카메라가 회전하게 된다.

 

Movement3D 스크립트에서 카메라를 제어하는 부분을 추가하여 방향키를 눌러 이동 시 현재 카메라가 비추고 있는 전방 방향으로 이동할 수 있도록 설정한다. 

public void MoveTo(Vector3 direction)
	{
		// 카메라가 바라보고 있는 방향을 기준으로 방향키에 따라 이동할 수 있도록 함
		Vector3 movedis = cameraTransform.rotation * direction;
		moveDirection	= new Vector3(movedis.x, moveDirection.y, movedis.z);
	}

	public void JumpTo()
	{
		if ( characterController.isGrounded == true )
		{
			moveDirection.y = jumpForce;
		}
	}
}

 

이렇게 설정하면 게임 실행시 마우스가 움직이는 곳을 카메라가 비추고 캐릭터가 잘 움직이는 것을 확인할 수 있다.

+ Recent posts