강께르의 개발일지

[유니티] 20210928_수업 2일차 본문

카테고리 없음

[유니티] 20210928_수업 2일차

강께르 2021. 9. 29. 01:55

입력에 대해

Input 클래스에 정의된 메소드를 활용해 입력을 받는다.

키 코드는 열거형으로 입력값이 설정되어 있다.

 

- q, w, e 위에 있는 숫자들은 Alpha0...에 해당된다.

 

사용법 : KeyCode.(코드에 해당되는 열거형)

 

Input 클래스에 속한 입력 방법(메소드)

 

GetKeyDown : 키 입력이 눌렸을 때

GetKey : 키 입력이 계속 눌려있을 때

GetKeyUp : 키 입력이 떼어졌을 때

anyKeyDown : 마우스를 포함한 입력이 눌렸을 때

anyKey : 마우스를 포함한 입력이 계속 눌려 있을 때

GetMouseButtonDown : 마우스 버튼이 눌렸을 때, 0 == 왼 / 1 == 오 / 2 == 가운데

 

Update() 함수에 보통 키 입력과 관련한 처리를 넣지만 FixedUpdate와 LateUpdate에는 입력 주기의 문제로 인해 입력 처리를 넣지 않는다고 한다.

 

- FixedUpdate : TimeStep에 설정한 일정한 간격마다 호출되는 Update 메소드, 컴퓨터 성능에 따라 프레임 호출 주기가 다른 Update와는 달리 일정한 간격마다 호출되어 물리 효과와 관련된 일을 처리하는데에 이용된다.

- LateUpdate : 모든 Update 메소드가 호출되고 난 다음 마지막에 호출되는 Update 메소드이다. 보통 카메라의 Update로 사용된다. 왜냐면 Update 중에 카메라가 target으로 삼는 오브젝트가 움직일 수 있기 때문이다.

 

GetAxis()

Edit - Project Setting - Axis에서 설정한 축을 기반으로 입력을 처리할 수 있다.

 

월드 좌표계와 스크린 좌표계

스크린 상에서 처리하는 좌표계와 월드 좌표계는 다르다.

스크린 상에서의 좌하단은 월드와 다르게 처리하여 0, 0으로 인식한다.

만약 스크린 상에서 클릭한 하나의 점이 있다고 한다면 스크린을 투영면으로 하여

직선으로 뻗어나가 충돌하는 vertex를 체크할 것이다.

역으로 스크린에 렌더되는 오브젝트들은 카메라가 갖고 있는 사각형의 투영면에 vertex로 투사하는 점이 모여 렌더되는 것이라고 봐도 될 것 같다.

 

3d 그래픽스에서는 직교 투영법, 원근 투영법으로 물체를 카메라에 투영하는 방법을 이야기하는 방법론들이 있다.

직교 투영법은 물체를 올곧이 일직선으로 평행하게 투영면에 투사하는 것이고

원근 투영법은 물체가 원근감이 느껴지도록 투사하는 것이다.

 

스크린 내에서 마우스 좌표 찾기

위의 좌표계를 왜 알아야하나?

앞으로 UI나 마우스 입력과 같은 스크린 상에서 하는 처리를 게임 오브젝트와 상호작용을 하려면 두 좌표계의 차이가 있다는 것을 알아야한다.

 

 

현재 마우스 좌표를 Input.MousePosition으로 찾을 수 있다.

 

Main Camera를 코드 상에서 바로 찾는 방법 : Camera.main

 

이 마우스의 좌표를 현재 월드상의 좌표로 어딘지 알려면

Camera.main.ScreenToWorldPoint(마우스 좌표);

 

정규화된 좌표계의 값을 알려면 (0.0 ~ 1.0)

Camera.main.ScreenToViewPortPoint(마우스 좌표);

 

Cursor

커서에 대한 처리를 제공하는 클래스

Cursor.SetCursor : 커서의 이미지를 변경시켜준다.

Cursor.lockState : 커서에 특정 상태를 할당할 수 있다

할당값 

CursorLockMode.locked :  정중앙에 커서를 고정한다.

CursorLockMode.Confined : 스크린을 이탈하지 못하게 제한한다.

 

EventSystem

이벤트란 게임 상에서 발생하는 입력 혹은 상호작용을 통틀어 의미한다.

게임 상에서 이벤트를 처리하는 방법으로 두 가지가 제공된다.

 

1. 이벤트 핸들러로 구현된 인터페이스를 상속해 특정 메소드를 재정의해준다.

2. 컴포넌트화된 Event System을 사용한다.

 

최근 레퍼런스에 의하면 인터페이스에 대한 내용은 업데이트가 안되고 있으니 2번 방법을 사용하도록 하자.

 

원하는 오브젝트에 Event Trigger 컴포넌트를 추가하고 원하는 이벤트가 발생 시 어떤 처리, 반응을 할지 연결해주면 된다.

 

예제로는 카메라에 추가한 PhisicsRay를 이용해 바라보는 물체 중에 boxCollider와 충돌되어 이벤트를 검사하는 것이 충족이 되는 오브젝트들에 한해서 오브젝트의 active를 false하는 것을 해봤다.

 

부모 오브젝트와 자식 오브젝트의 관계 상에서 팁

동적으로 무언가를 생성해서 관리하는 것이 아니면 GetChild() 메소드를 사용하기보다는

그냥 오브젝트를 드래그-드롭 방식으로 할당하는 게 명시적인 관계를 보여주는 면으로도 좋다.

 

Vector

원점으로부터 지점까지의 거리를 화살표로 표현할 수 있는 것.

방향과 길이가 의미있는 데이터.

 

프로퍼티

magnitude : 벡터의 길이를 의미

sqrMagnitude : 루트 처리하기 전의 길이를 의미. 대소 비교에 유용

nomalized : 방향 벡터를 구하기 위한 프로퍼티. 길이를 1로 정규화한다.

 

위치의 x, y, z를 바꾸고 싶다면 새 벡터를 생성해서 대입하는 방법밖에 없다.

 

벡터의 초기화로 아무것도 대입하지 않거나

기본 생성자를 사용하거나

zero 필드를 사용하는 게 있는데 후자가 명시적이어서 좋다.

 

가급적 static으로 선언된 필드를 활용해라

 

두 점 간의 거리 구하기

두 벡터의 차를 maginitude로 반환하거나

Vector3의 메소드 Distance를 사용

 

정규화란?

벡터를 길이로 나눈 값.

x, y, z는 길이로 나눠진 결과가 될 것이다.

이 3개의 수를 합치면 1이 될 것이다.

var norm = v / v.magnitude;

var norm = v.normalized;

v.Normalize();

 

내적

두 벡터의 요소마다 곱하고 곱한 값을 서로 더한 결과.

float형을 반환한다.

var dot = Vector3.Dot(v1, v2);

 

내적의 결과에 따라 두 벡터의 연관 관계를 유추할 수 있다.

 

서로 평행한 벡터 == 1

직교하는 벡터 == 0

반대 방향을 가지는 벡터 == -1

 

이를 이용해 해볼 수 있는 것은

 

1. 두 벡터 사이의 각도를 구하거나

-> 내적한 값을 Acos(dot) * Mathf.Rad2Deg를 수행하면 알 수 있다.

2. 시야각을 만들거나

3. 앞 뒤면을 판단할 수 있다.

 

외적

var cross = Vector3.Cross(v1, v2);

결과값이 Vector값이다.

두 개의 vector와 동시에 직교하는 vector를 반환

 

사용하는 곳은 좌우면 판단이 있다.

 

Vector3.Reflect()

벡터의 진행방향에 따라 평면에 부딪혔을 때, 반사되는 벡터를 알 수 있다.

필요한 매개변수(원본 벡터, 부딪힐 면의 법선)

법선 기준으로 반사되어 나오는 벡터를 구할 수 있다.

 

선형보간법

Lerp

LerpUnclamped : 최대, 최소값 제한이 없는 메소드

 

쿼터니언

3d 그래픽스에서 회전을 표현할 때, 오일러 대신 쿼터니언을 내부적으로 사용한다.

사람이 이해하기 직관적인 오일러 대신 사용하는 이유는

오일러가 가지고 있는 3d 회전 상의 한계가 있기 때문이다.

오일러 각도는 회전하는데 순서가 매우 중요하다.

어느 축을 먼저 회전하냐에 따라서 값은 회전값이어도 그 결과가 달라진다.

그래서 어느 회전을 먼저 하느냐의 순서를 정하면

특정 축의 회전이 일정 이상 값을 넘으면 그 축과 다른 하나의 축이 겹쳐지게된다.

그래서 전체 3개의 축이 아닌 2개의 축으로 회전하게 되어 원하는 회전 결과가 나오지 않을 수 있다.

이것을 '짐벌락' 현상이라고 하여 이 문제의 대안으로 쿼터니언을 쓴다.

 

그 외에도 연산 속도도 행렬에 비해 빠르고 메모리 양도 적고 정확하다는 장점이 있다.

 

Quternion.Euler(Vector3) : 오일러 각도를 쿼터니언으로 반환한다.

Quternion.identity : 기본 회전값을 반환한다.

 

오브젝트가 이동할 때 이동하고자 하는 이동량만큼 +를 해줬다면

회전값에는 회전하고자하는 회전량만큼 * 연산을 해줘야 한다.

 

쿼터니언과 벡터와의 * 연산이 가능하다.

하지만 무조건 쿼터니언이 좌변, 벡터가 우변일 때만 가능하다.

 

쿼터니언에서의 선형 보간법

Slerp() 메소드를 사용, 매개변수는 동일

회전과 관련된 애니메이션을 선형보간법으로 많이 사용한다.

var toRot = Quaternion.LookRotation(forward.normalized);
transform.rotation = Quaternion.Slerp(
            transform.rotation, 
            toRot, 
            Time.deltaTime);

 

카메라에 대한 선형보간법 구현이다.

현재 회전값을 계속 갱신하면서 카메라가 회전하는 속도를 점차 느려지게 조정해준다.

매개변수 a와 b의 값의 사이가 점차 좁아지기 때문에 세번째 매개변수로 넘겨주는 값은

그 비율을 의미하기에 반환하는 값은 점차 작아져서 속도가 줄어드는 것 같은 연출을 만들 수 있다.

 

LookRotation()으로 바라보는 벡터에 대한 회전값을 구할 수 있다.

 

프리팹

미리 만들어놓은 게임 오브젝트를 의미한다.

왜 쓰냐?

동적 생성이나 같은 오브젝트로 일괄적으로 관리하고 플 때 사용한다.

 

전자의 경우

게임 런타임 상에서 계속 생성되는 총알이 있다고 하자.

총알은 끊임없이 new 연산을 반복할 것이다. 오브젝트가 생성되고 그 컴포넌트들까지도 new할 것이다.

new 연산은 비용이 그렇게 적은 연산이 아니기에 그만큼 성능의 영향을 미칠 것이다.

이런 방법이 아닌 미리 만들어놓은 오브젝트를 생성하는 것이다.

 

후자의 경우

같은 오브젝트여서 하나의 색상으로 변경하거나 하는 일괄적인 수정에 용이하도록 사용되어진다.

만약 프리팹으로 설정한 오브젝트들 중 하나가 단독으로 수정되었다면 그것은 프리팹과의 연결이 끊어질 것이다.

 

프리팹은 게임 오브젝트 데이터형으로 사용되어져서

코드 상에서 GameObject로 할당 받아 접근가능하다.

 

프리팹을 이용해 동적 생성하는 방법

Initiate() 메소드를 사용한다.

프리팹만 매개변수 사용 시 프리팹에 설정된 위치 생성된다.

2, 3번째 매개변수로 위치와 회전값을 할당할 수 있다.

위치, 회전값 대신에 transform을 넘겨줄 수 있다.

부모 오브젝트의 transform을 넘겨줘서 부모를 리스폰처럼 사용할 수 있을 것 같다.

 

이 메소드는 프리팹 뿐만이 아니라 실시간 게임 상의 오브젝트도 복사할 수 있으니 다양하게 쓰자.

 

이 외에도 

new GameObject()로 생성도 가능하다.

자기 자신을 통으로 복제한다면 게임 오브젝트를 넣어야할 매개변수 자리에 gameObject를 넣자.

 

! ball 실습 때 알게 된 것 정리

부모 오브젝트와 자식 오브젝트의 회전을 따로줘서 회전하는 애니메이션과 움직임을 구분할 수 있다.

 

자신 기준으로 오브젝트가 앞인지 뒤인지 판별

 

1. 오브젝트와의 거리를 구한다.

2. 자신의 앞 방향을 의미하는 벡터와 거리의 정규화 값을 내적한다.

3. 내적한 값에 따라 판별

+ 시야각 45도를 구현한다면?

4. 내적한 값을 acos으로 계산한다.

5. 계산된 radian값을 degree로 변환한다.

-> 이것이 오브젝트 벡터(정확히는 오브젝트와의 거리벡터)와 나의 앞방향벡터의 각도

 

시야각을 가시화하자.

1. 시야각을 두개의 선으로 표현할 것이다.

2. 쿼터니언 메소드를 사용해 오일러 각 45도에 해당하는 쿼터니언을 구한다.

3. 자신 기준 앞방향에 해당하는 벡터에 시야 최대 범위 값을 곱한다 = 시야거리 벡터

4. 이를 자신 자신 포지션 + 구한 쿼터니언 * 시야거리 벡터 계산을 하면 포지션으로부터 시야거리 벡터까지

구한 쿼터니언만큼의 회전한 상태로 일직선을 그릴 수 있을 것이다.