2023/08/04 TIL

김도현·2023년 8월 4일
0

TIL

목록 보기
14/76
post-thumbnail

레트로의 유니티 게임 프로그래밍 에센스 : C#으로 배우는 입문부터 4가지 게임

GameObject bullet = Instantiate(bulletPrefab, transform.position, transform.rotation);
bullet.transform.LookAt(target);

트랜스폼의 LookAt() 메서드는 입력으로 다른 게임 오브젝트의 트랜스폼을 받는다. LookAt() 메서드는 입력받는 트랜스폼의 게임 오브젝트를 바라보도록 자신의 트랜스폼 회전을 변경한다.

8장 닷지 게임 매니저와 UI, 최종 완성

8.2 바닥 회전

8.2.1 Rotator 스크립트 준비

void Update()
{
	transform.Rotate(0f, 60f, 0f);
}

문제 발생!
프레임당 60도씩 회전하기 때문에 1초에 3600도 회전함

8.2.2 속도와 시간 간격

Update() 메서드는 게임 화면(프레임)이 한 번 갱신될 때 1회 실행된다. 하지만 컴퓨터 성능에 따라 같은 코드가 다르게 동작할 수 있다. 이 문제와 관련된 흔한 현상으로 PC 게이머들이 '프레임 제한'을 해제했을 때 발생하는 문제가 있다.

프레임 제한 해제


위에 코드를 예시로 들면
초당 프레임이 60이면 Update() 메서드도 1초에 60번 실행됨, 한 번에 60도를 회전하는 코드가 1초 동안 60번 누적 실핼되면 총 3600도 회전한다.

그런데 강제로 프레임 제한을 해제하여 1초에 120번 게임 화면을 갱신한다고 가정해봅시다. 1초에 3600도 회전하던 게임 오브젝트가 1초에 7200도 회전합니다. Update() 메서드가 1초에 120번 실행되기 때문이다.

초당 프레임이 서로 다른 컴퓨터

해결하는 방법은 '시간 간격으로 쪼개서 누적하는 것'이다.
Update()가 1초에 60번 실행되는 환경을 기준으로 설명하면
1. 60도를 실행횟수인 60조각으로 나누기(1/60 곱하기) -> 1조각은 1도
2. Update()가 1초 동안 60번 실행 -> 한 번에 1조각(1도)씩 60번 누적
3. 1초 동안 누적된 회전은 60도
결론은 초당 프레임의 역수를 취한 값(프레임의 주기)을 곱하면 구현할 수 있다.

void Update()
{
	transform.Totate(0f, rotationSpeed * Time.deltaTime, 0f);
}

8.3 게임 UI 제작

유니티의 UI(UGUI) 시스템은 UI 요소를 게임 월드 속의 게임 오브젝트로 취급한다. 즉 하나의 UI 요소는 씬 속의 하나의 게임 오브젝트가 됩니다. UI 게임 오브젝트를 씬 내부에서 편집합니다. 그러므로 일반 게임 오브젝트를 다루는 방법과 같은 방법으로 UI 게임 오브젝트를 다룰 수 있단느 강력한 장점이 있다.

Text 게임 오브젝트를 만드는 순간 총 세 개의 게임 오브젝트가 생성된다. 텍스트(Text) 뿐만 아니라 캔버스(Canvas)와 이벤트 시스템(EventSystem) 게임 오브젝트가 함께 생성된다.

캔버스와 이벤트 시스템

Text 게임 오브젝트는 Cansvas 게임 오브젝트의 자식 오브젝트의 자식 오브젝트로 설정되어 있습니다. UI 요소들은 캔버스의 2차원 평면에 배치되기 때문입니다. UI 게임 오브젝트는 일반 게임 오브젝트와 달리 트랜스폼 컴포넌트를 확장한 사각 트랜스폼(Rect Transform)컴포넌트 를 가집니다. 즉 UI 요소는 자신이 배치될 2차원의 액자가 필요하고 Canvas 게임 오브젝트는 UI 요소가 배치될 수 있는 액자 역할을 한다.
EventSystem 게임 오브젝트는 이벤트 시스템 컴포넌트를 가진 게임 오브젝트로 UI게임 오브젝트에 클릭이나 터치, 드래그 같은 상호작용을 이벤트 메시지로 전달합니다. 이 게임 오브젝트가 씬에 없다면 UI 버튼이나 슬라이드 바르 클릭하고 드래그하는 등의 UI 상호작용을 할 수 없습니다.

8.3.2 텍스트 배치


씬 창의 캠버스와 게임 창의 게임 화면에서 Text 게임 오브젝트가 캔버스 상단 중앙(Top Center)에 배치된다.

앵커 프리셋(Anchor Presets)

UI 요소를 잘 배치하기 위해서 앵커(Anchor), 피벗(Pivot), 포지션(Position) 값을 조정해야 한다. 앵커 프리셋은 자주 사용되는 앵커, 피벗, 포지션값을 제공하여 UI 배치를 편하게 해주는 설정 모음 창입니다.

Horizontal Overflow와 Vertical Overflow


폰트 크기를 42로 증가시키면 글자가 글상자를 넘쳐서 잘리기 때문에 텍스트가 보이지 않게 된다. 이와 같이 표시할 글자 크기가 너무 크거나 표시할 글자 수가 너무 많으면 글이 글상자를 넘치게(오버플로) 된다.

텍스트 컴포넌트의 수평 오버플로(Horizontal Overflow)와 수직 오버플로(Vertical Overflow)는 글이 글상자를 넘칠 경우 해당 방향으로의 글자를 잘라낸 것인지 혹은 그대로 넘치게 표시할 것인지 결정합니다.

수평 오버플로의 기본값인 랩핑(Wrap)은 글자가 수평 방향으로 글상자를 넘칠 때 강제로 줄바꿈을 적용합니다. 램핑 대신 오버플로를 선택하면 수평 방향으로 글상자를 벗어난 글자들이 줄바꿈하지 않고 그대로 표시된다.

수직 오버플로의 기본값인 자르기(Truncate)는 글자가 수직 방향으로 글상자를 넘칠 때 넘친 글자들을 잘라냅니다. 자르기 대신 오버플로를 선택하면 수직 방향으로 글상자를 벗어난 글자들을 잘라내지 않고 그대로 표시한다.

8.4 게임 매니저 제작

텍스트 컴포넌트가 표시하는 텍스트 내용을 변경하고 싶다면 텍스트 컴포넌트를 Text 타입의 변수에 할당, 그리고 Text 타입에 내장된 text 필드에 접근하여 수정.
반대로, 텍스트 내용이 변경되지 않는 것은 GameObject타입으로 선언

8.4.3 게임 재시작 구현

게임을 재시작한다는 것은 현재 씬을 다시 로드한다는 의미이다. 유니티에서 씬은 하나의 게임 월드이다. 현재 활성화된 씬을 해제하고 새로운 씬을 로드하는 방식으로 어떤 게임 월드에서 다른 게임 월드로 전환할 수 있다.

새로운 씬이 로드되면 기존 씬에 있던 모든 게임 오브젝트가 파괴된다. 이것을 응용하면 현재 활성화된 씬을 다시 로드하는 방식으로 게임 재시작을 구현할 수 있다.
따라서 게임 재시작을 구현하려면 현재 활성화된 씬을 다시 로드하면 된다.

빌드에 등록된 씬

SceneManager.LoadScene() 메서드로 로드할 씬은 빌드 설정의 빌드 목록에 등록되어 있어야 한다. 유니티 프로젝트를 생성할 때 자동 생성되는 SampleScene 씬은 빌드 목록에 자동 등록되어 있으므로 따로 빌드 목록에 추가할 필요는 없다
빌드 설정 창과 빌드 목록은 유니티 상단 메뉴의 File > Build Settings... 로 확인할 수 있습니다.

SceneManager.LoadScene() 메서드는 씬 이름 외에도 씬의 빌드 순번을 사용해 씬을 로드할 수 있습니다. 씬의 빌드 순번은 빌드 설정에서 확인할 수 있습니다. 예를 들어 SampleScene 씬은 빌드 순번이 0으로 설정되어 있기 때문에 SceneManager.LoadScene("SamlpeScene"); 대신 SceneManager.LoadScene(0);을 실행하여 SampleScene 씬을 로드할 수 있습니다.

0개의 댓글