[Unity3D] 델리게이트 (Delegate)
델리게이트는 함수를 가리키는 변수라고 생각하면 쉽다.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 | public class DelegateTest : MonoBehaviour { delegate void NumDelegate(int Num); NumDelegate Del; void Start() { Del = FirstPlus; Del(5); Del = SecondPlus; Del(10); } void FirstPlus(int Num) { int Result = Num * Num; Debug.Log("FirstPlus : " + Result); } void SecondPlus(int Num) { int Result = Num * Num * Num; Debug.Log("SecondPlus : " + Result); } } | cs |
1. 델리게이트에 연결할 함수의 원형을 정의한다.
1 | delegate void NumDelegate(int Num); | cs |
Start() 함수 밑에 보면 2가지의 함수가 정의되어있다.
FirstPlus(인자)와 SecondPlus(인자)다.
2가지의 함수의 원형은 '자료형 함수이름(인자)' 이다.
즉, 밑의 2가지 함수를 델리게이트에 연결해서 사용하려면 델리게이트를 선언할 때
연결할 함수의 원형의 형태로 선언해야 한다.
델리게이트를 정의하는 방법은
delegate라는 키워드를 맨 앞에 적고 다음엔 자료형 그 다음에는 자신이 생각함 델리게이트의 함수이름을 정하고,
연결할 함수에 인자 값을 확인한 다음 똑같이 맞춰주면 된다.
delegate 자료형 함수이름(연결할 함수의 인자와 맞춤.)
2. 델리게이트 변수를 만든다.
델리게이트의 함수의 원형을 정의했으면 델리게이트 변수를 선언해야 한다.
1 | NumDelegate Del; | cs |
3. 델리게이트 변수에 함수를 연결.
1 2 3 4 5 6 7 8 | void Start() { Del = FirstPlus; Del(5); Del = SecondPlus; Del(10); } | cs |
연결 방법은 별거 없다.
변수 = 연결할 함수명.
이렇게 적어주면 되는데,
다만 조심해야 할 것은 '연결할 함수명'에 '()'를 붙이지 않는다.
델리게이트와 함수와의 연결이 끝났으면
델리게이트 변수를 함수를 사용하는 것처럼 사용하면 된다.
예제를 보면 사용하는 방법은 알겠는데 왜 쓰는거지?
그냥 함수명을 호출하면 되는거 아닌가? 라고 생각한다면
맞는 말이다. 다만, 이것은 예제이기 때문에 이렇게 사용한 것이지
적절한 사용법은 아니다.
그럼 언제 사용하는것이 좋을까?
예를 하나 들어보자
플레이어가 있고, 다수의 에너미가 있다고 하자.
다수의 에너미가 플레이어를 발견하고 공격하여 플레이어는 사망하였다.
플레이어가 사망하면 게속 공격할 필요가 없기 때문에 에너미는 공격을 멈추어야 한다.
즉, 플레이어가 죽었다는 사실을 알아야 한다.
그 사실을 알게하는 방법으로는 뭐가 있을 까?
방법은 많을 것이다.
보통으로 생각한다면 플레이어의 HP가 0이하로 떨어지는 순간
에너미들을 관리하는 리스트를 가지고와서 그 리스트를 차례대로 돌면서
플레이어가 죽었다는 사실을 알려주는 것이다.
하지만 에너미의 수가 아주 많다는 극단적인 상황이면 어떨까?
순차적인 호출 방법은 그리 효율적이지 않는 방법이 된다.
그렇기 때문에 델리게이트를 사용한다.
플레이어가 죽었을 때 엔진에게 '플레이어가 사망했다'라는 사실을 알려주어
이벤트를 발생시킨다. 이때 이 이벤트에 연결된 에너미에서 해당 동작을 수행하게 하면
순차적인 호출방식보다 속도면에서 효율적이게 될 것이다.
플레이어 스크립트
1. 델리게이트에 연결할 함수의 원형을 정의해준다.
2. 델리게이트 변수에 event키워드를 붙여 이벤트를 선언한다.
1 2 | public delegate void PlayerDieHandler(); public static event PlayerDieHandler OnPlayerDie; | cs |
이제 플레이어의 HP가 0이하가 되었을 때 OnPlayerDie()를 호출하면 된다.
그러면 OnPlayerDie에 연결된 함수가 대신 호출되게 된다.
1 2 | if (hp <= 0) OnPlayerDie(); | cs |
3. 델리게이트 OnPlayerDie에 함수를 연결한다.
2번의 OnplayerDie()가 호출되기 위해서는 델리게이트에 특정 함수가 연결되어야 한다.
그럼 연결은 언제 어디서 할것인가를 알아야 한다.
플레이어가 죽었을 때 에너미는 플레이어가 죽었다는 것을 알고 그에 맞게 행동해야 한다.
그에 맞게 행동하는 함수를 에너미 스크립트에 하나 만들자.
우리는 이 함수에 연결할 것이다.
그럼 연결하는 시점은 언제로 할 것인가?
1 2 | void OnEnable(); void OnDisable(); | cs |
※ 두 함수는 유니티에서 기본적으로 제공하는 함수다.
OnEnable() 함수가 호출되는 시점에서 델리게이트를 연결할 것이다.
OnEnable() 함수와 OnDisable()함수는 각각 스크립트가 활성화 되었을 때, 스크립트가 비활성화 되었을 때 호출된다.
연결하는 방법은 예제와는 다르게 이퀄 앞에다가 +을 붙여야 한다.
예제 - 델리게이트 변수 = 연결할 함수이름.
본문 - 이벤트가 선언된 클래스명.델리게이트 변수 += 연결할 함수이름.
반대로 에너미가 죽었을 경우 연결을 해제 시켜줘야할 필요가 있다.
이때에는 이벤트가 선언된 클래스명.델리게이트 변수 -= 연결된 함수이름.
으로 하면 된다.
그냥 말로만 듣는것보다 한 번 보는게 좋다고 생각한다.
Enemy Script
1 2 3 4 5 6 7 | void OnEnable() { PlayerCtrl.OnPlayerDie += this.OnPlayerDie; } void OnDisable() { PlayerCtrl.OnPlayerDie -= this.OnPlayerDie; } void OnPlayerDie() { // 추적 및 공격 중단. } | cs |
'Unity3D > Tip' 카테고리의 다른 글
[Unity3D] EventSystem (1) | 2017.05.03 |
---|---|
[Unity3D] 유니티 스플래시 스크린(로고 삽입) (0) | 2017.05.02 |
[Unity3D] 메카님으로 설정된 3D모델 최적화. (0) | 2017.04.29 |
[Unity3D] Shadow - 그림자 생성. (0) | 2017.04.27 |
[Unity3D] Trail Renderer - 궤적 (0) | 2017.04.27 |
[Unity3D] 메카님으로 설정된 3D모델 최적화.
메카님으로 설정된 캐릭터는 애니메이션을 수행하기 위해 Rig(본, 뼈대)가 설정돼 있다.
몬스터의 경우도 마찬가지로 Rig가 설정돼 있고, 하이러키뷰에서 확인할 수 있다.
Rig는 모두 GameObject이며, Transform컴포넌트를 가지고 있다. 이처럼 하나의 3D모델이 갖고 있는 많은 수의 Transform컴포넌트는 런타임 시 내부적으로 다양한 연산 처리를 하기 때문에 최적화가 필요하다.
따라서 실제 사용되는 Rig만 남겨두고 다른것을 노출되지 않도록 설정하면 속도 향상에 도움을 줄수 있다.
이처럼 하나의 모델에 애니메이션을 수행하기 위한 굉장히 많은 수의 GameObject가 존재한다.
이 모델의 필요한 부분만을 노출시키고 나머지 부분들은 숨겨주도록 하자.
이 모델같은 경우 양손으로 공격하기 때문에 오른손과 왼손에 Rigidbody와 Collider가 존재한다.
이 양손과 몇개의 부위만 빼고 나머지 부분들을 숨겨보도록 하자.
모델의 원본을 누르면 인스펙터 창에 이런식으로 나올 것이다.
Optimize Game Object의 체크박스를 눌러 체크하고 Apply를 눌러주자.
이 박스에 체크하면 모델의 기본적인 부분만 빼고 나머지를 자동으로 숨겨준다.
아까 많았던 GameObject들이 사라진것을 확인할 수 있다.
하지만 우리는 양손에 해당하는 GameObject는 노출시키고 싶다.
Optimize Game Object의 박스를 체크하면
밑의 Extra Transforms to Expose가 활성화 되는데
이곳에서 노출시킬 오브젝트를 추가하면 된다.
+버튼을 눌러 양손에 해당하는 오브젝트를 추가하고 Apply를 다시 눌러주자.
양손에 해당하는 GameObject가 노출되었다.
'Unity3D > Tip' 카테고리의 다른 글
[Unity3D] 유니티 스플래시 스크린(로고 삽입) (0) | 2017.05.02 |
---|---|
[Unity3D] 델리게이트 (Delegate) (0) | 2017.04.29 |
[Unity3D] Shadow - 그림자 생성. (0) | 2017.04.27 |
[Unity3D] Trail Renderer - 궤적 (0) | 2017.04.27 |
[Unity3D] 파티클의 반복여부, 지속시간 설정. (0) | 2017.04.27 |
[Unity3D] Shadow - 그림자 생성.
그림자를 만드는 방법은 크게 3가지 방법이 있다.
1. Directional Light를 이용한 실시간 그림자.
2. Projector를 이용한 그림자.
3. Plane Mesh를 이용한 그림자.
1.
유니티 5부터는 실시간 그림자가 기본적으로 적용돼 있다.
실시간 그림자는 Directional Light의 속성 중 Shadow Type 옵션으로 설정한다.
Shadow Type속성으로는 3가지가 있다.
- No Shadow : 실시간 그림자를 적용하지 않는다.
- Hard Shadow : 실시간 그림자를 표현하나 외곽선을 부드럽게 처리하지 못한다.
- Soft Shadow : 부드러운 실시간 그림자를 표현해준다. (가장 많은 부하를 준다.)
Hard Shadow
Soft Shadow
이렇듯 효과는 매우 탁월하지만 엔진에 많은 부하를 준다.
그렇기 때문에 그림자 효과가 필요없는 3D 모델은 실시간 그림자 영향에서 제외하는 설정을 빠뜨리면 안됀다.
3D 모델은 Mesh Renderer 또는 Skinned Mesh Renderer중 한 컴포넌트는 반드시 가지고 있다.
이 두 컴포넌트에는 실시간 그림자와 관련된 Cast Shadows와 Receive Shadowns속성이 있다.
Cast Shadows에는 4가지 속성이 있다.
- off : 그림자를 만들지 않는다.
- On : 그림자를 만든다.
- Two Sided : 백페이스 컬링을 무시하고 그림자를 양면으로 만든다.
- Shadows Only : 그림자를 만들지만 자신은 렌더링하지 않는다. 즉, 화면에 보이지 않는 특성이 있어 그림자 처리만을 위한 3D모델에 활용할 수 있다.
※ Two Sided
Quad같은 단면만 렌더링 하는 모델의 경우 Cast Shadows속성을 On으로 해도 그림자가 만들어지지 않는다.
그렇기 때문에 Two Sided로 설정하면 그림자를 생성할수 있게 된다.
2.
Projector기능은 빔 프로젝터가 스크린에 이미지를 투사하는 것을 생각하면 된다.
Projector는 주로 데칼을 구현할 때 유용하게 활용되며, 그림자, 총탄 흔적, 혈흔 등의 표현에 응용할 수 있다.
Projector는 유니티패키지로 기본적으로 제공하고 있다.
Assets -> Import Package -> Effect를 선택하면 된다.
모두 다 임포트 할 필요는 없고 Projectors폴더만 선택하여 임포트 하면 된다.
임포트가 완료되면 프리팹 Blob Shadow Projector를 꺼내 플래이어의 자식으로 넣는다.
그리고 사진과 같이 위치해놓고 수치도 사진과 같이 설정하면 된다.
Projector의
- Near Clip Plane
- Far Clip Plane
는 범위를 설정해주는 속성이다.
Near Clip Plane에 가까울수록 그림자가 진하게 표현되고,
Far Clip Plane로 갈수록 페이드 아웃 효과를 제공한다.
플레이어가 점프할 경우 바닥의 그림자의 농도는 자연스럽게 연해지게 된다.
Blob Shadow Projector 프리팹을 그냥 플레이어의 머리위에 올려놓으면
그림자가 바닥에만 보이는게 아니라 플레이어의 몸에도 그림자가 적용되어
하늘에 뭔가 떠 있어 플레이어를 가리고 있는것으로 보인다.
이러한 그림자를 플레이어만 적용되지 않게 하기 위해
Igore Layers속성을 설정하면 되는데.
Igore Layers속성은 우측 상단에 Layer에 있는 속성을 그대로 가져와 사용하게 된다.
PLAYER라는 레이어를 하나 추가해서
플레이어의 Layer를 PLAYER로 바꿔주고 모든 자식들도 적용해준다.
그리고 다시 Projector컴포넌트로 돌아와 Igore Layers속성을 PLAYER로 지정해주면
플레이어에게 그림자가 적용되자 않게 되고, 바닥에만 그림자가 보이게 된다.
3.
다음은 Plane Mesh을 이용한 그림자다.
위의 소개된 2개의 그림자보다 가장 부하가 적은 방법이다.
Quad를 이용해서 하는 방법인데,
GameObject -> 3D Object -> Quad를 통해 생성이 가능하다.
Quad를 생성하여 크기 및 위치를 조정하여 플레이어의 발 밑에 깐다.
마테리얼을 하나 생성한 뒤 마테리얼의 Rendering Mode을 Fade로 전환한다.
그리고 Albedo에 그림자 텍스쳐를 집어넣으면 그림자는 완성된다.
- 발 밑에 깔아넣는다.
- 마테리얼 하나 생성 후 렌더링 모드를 Fade로 변경 후 알베도에 그림자 텍스처 추가.
이 방법이 가장 부하가 적다는 장점이 있긴 하지만, 단점도 존재한다.
경사진 곳에 이동하게 된다면 그림자가 모델을 파고 들어가게 된다.
위의 소개된 그림자들을 각 상황에 맞게 이용하길 바란다.
'Unity3D > Tip' 카테고리의 다른 글
[Unity3D] 델리게이트 (Delegate) (0) | 2017.04.29 |
---|---|
[Unity3D] 메카님으로 설정된 3D모델 최적화. (0) | 2017.04.29 |
[Unity3D] Trail Renderer - 궤적 (0) | 2017.04.27 |
[Unity3D] 파티클의 반복여부, 지속시간 설정. (0) | 2017.04.27 |
[Unity3D] AddExplosionForce(); - 폭발 시 여파 적용. (0) | 2017.04.27 |