UDN
Search public documentation:

KismetExamplesKR
English Translation
日本語訳
中国翻译

Interested in the Unreal Engine?
Visit the Unreal Technology site.

Looking for jobs and company info?
Check out the Epic games site.

Questions about support via UDN?
Contact the UDN Staff

UE3 홈 > 키즈멧 비주얼 스크립팅 > 키즈멧 예제
UE3 홈 > 시네마틱 아티스트 > 키즈멧 예제

키즈멧 예제


문서 변경내역: Alan Willard 작성. Jeff Wilson 업데이트. 홍성진 번역.

개요


키즈멧은 레벨 디자이너가 비교적 쉽게 레벨에 동적이고 재밌는 게임플레이를 추가할 수 있도록 해 주는 강력한 비주얼 스크립팅 시스템입니다. 여기서는 새롭고 혁신적인 게임플레이 이벤트를 만드는 데 도움이 되는 개념과 기법을, 익히 알고 계시는 액션, 컨디션, 변수, 이벤트 와 조합해서 사용하는 법에 대해 다뤄보겠습니다.

키즈멧 사용법에 대해서는 Kismet User Guide KR, Kismet Reference KR 페이지를 참고하시기 바랍니다.

개념


여기서는 자주 쓰이는 함수를 실행하거나 키즈멧 시퀸스의 효율을 향상시키는 데 있어 꼭 알아둬야 할 여러가지 개념과 기법에 대해 설명하겠습니다.

시퀸스

키즈멧은 레벨 내 특정 이벤트나 컨디션에 반응하여 일련의 액션을 실행하는 식으로 작동합니다. 각 시리즈나 관련 시리즈 콜렉션은 하나의 시퀸스 라 생각해 볼 수 있습니다. 각 레벨은, 퍼시스턴트든 스트리밍이든, 디폴트로 베이스 시퀸스를 갖습니다. 이들은 계층 구조를 이루고, 스트리밍 레벨의 시퀸스는 부모 퍼시스턴트 레벨의 시퀸스에 있는 엘리먼트에 접근할 수 있다는 점만 빼고는 대부분의 경우 그 자체로 독립적입니다.

ex_sequence_hier.jpg

한 레벨의 베이스 시퀸스는 물론, 액션 / 이벤트 / 컨디션 / 변수 콜렉션도 새 시퀸스나 서브시퀸스 에 넣을 수도 있습니다.

ex_subsequence.jpg

또한 이들은 위쪽으로는 허용되나 옆으로는 허용되지 않는 계층구조를 이룹니다. 즉 다른 시퀸스에 있는 변수같은 것에 접근하려면, 계층구조에서 직계 부모/자손끼리만 가능하다는 뜻입니다. 만약 두 시퀸스 다 같은 부모 시퀸스를 갖는다면, 그 둘 다 부모(나 조부모 등의) 시퀸스에 포함된 네임드 변수만 접근할 수 있을 뿐, 다른 서브시퀸스에는 접근할 수 없습니다.

시퀸스는 키즈멧을 정리하기에 더없이 편리합니다. 새로 만든 시퀸스는 입/출력과 변수 링크를 (Sequence Activated 이벤트, Finish Sequence 액션, External Variable 변수 등을 사용하여) 몇이든 만들 수 있기에, 본질을 보면 커스텀 시퀸스 오브젝트라던가 작은 블랙 박스라고 볼 수도 있습니다.

절차주의

키즈멧에 있어서 절차주의(proceduralism)란, 입력에 연결된 리모트 이벤트 (Remote Event) 와 변수 링크에 연결된 글로벌 변수 (Global Variables) 를 통해 총체적으로 빌드된 시퀸스(, 이 경우 액션 시리즈 또는 복잡한 서브시퀸스)를 사용하여, 그 변수에 또는 그 변수로 어떠한 액션을 수행하는 것을 말합니다. 역시 본질을 보자면, 표준 프로그래밍에서 함수나 프로시져에 비슷한 함수성을 재생성해 내는 시퀸스 개념을 차용하고 있는 것입니다. 프로시저 시퀸스를 실행하기 위해서는 단지 글로벌 변수 값을 설정한 다음, 시퀸스를 활성화시키기 위해 Activate Remote Event 액션으로 관련 Remote Event 를 트리거시키면 됩니다.

이 개념을 그려보기 위해, 한 액터를 다른 액터의 위치와 로테이션으로 설정한 다음 어태치하는 작업을 빠르게 하고 싶다 칩시다. 일반적인 시퀸스는 이와 같습니다:

ex_proc_normal.jpg

이제 똑같은 액션 시리즈를 다른 액터에 반복할 필요가 생겼다 칩시다. 필요할 때마다 시퀸스를 복제했다간 감당도 안될 만큼 키즈멧 작업공간이 어지럽혀질 것은 불 보듯 뻔합니다.

ex_proc_clutter.jpg

비교를 위해, 이 시퀸스의 프로시저럴 버전은 이런 식입니다:

ex_proc_procedural.jpg

프로시저로 만들어 두면, 하나의 프로시저럴 시퀸스에다 변수를 설정하고 이벤트를 활성화시켜 주기만 하면 필요할 때마다 재사용할 수 있습니다.

이 기법의 장점은 시퀸스를 변경하고자 할 때 빛을 발합니다. 몇 쌍둥이를 전부 찾아내 변경하지 않고도, 한 곳에 있는 시퀸스 딱 하나만 변경해 주면 되는 것입니다.

이벤트

이벤트는 키즈멧의 기본입니다. 미리 결정되었거나 동적인 상황에 따라 트리거되어, 시퀸스 실행을 시작시키는 역할을 담당합니다. 기본 개념은 게임에 무언가가 발생했을 때 키즈멧 안에서 해당 이벤트가 트리거되면, 그 이벤트에 반응하여 액션 시퀸스가 실행되도록 하는 것입니다.

키즈멧의 시퀸스를 트리거하는 데 사용되는 이벤트에는 여러 종류가 있습니다. 가장 자주 사용되는 것은 아래와 같습니다:

Level 이벤트

Level Loaded 이벤트는 시퀸스를 포함하는 레벨의 상태에 따라 시퀸스를 트리거하기에 매우 좋습니다. 그 상태는:

  • Loaded and Visible - 레벨이 메모리에 로드되어 보이게 되었을 때 트리거됩니다. 레벨이 보이게 되었을 때 활성화시킬 시퀸스가 있는 스트리밍 레벨에 좋습니다.
  • Beginning of Level - 레벨이 처음 로드되었을 때 트리거됩니다. 레벨이 처음 시작될 때 한 번만 발생시킬 레벨 이벤트에 좋습니다.
  • Level Reset - 레벨이 리셋될 때마다 트리거됩니다. 레벨이 (재)시작될 때마다 발생시킬 이벤트에 좋습니다.

Player Interaction 이벤트

어떤 이벤트는 레벨에 있는 Trigger 나 TriggerVolume 과 교류하는 플레이어에 따라 발생합니다.

Touch 이벤트

Touch 이벤트는 액터가 다른 액터에 인크로치(encroah, 침입)할 때 (또는 "터치"할 때) 트리거됩니다. 엄밀히는 플레이어가 건드린 Trigger 또는 TriggerVolume 에 한정되지는 않지만, 이러한 이벤트 유형이 가장 자주 사용되는 방법입니다. 이러한 이벤트 유형은 플레이어의 접근에 따라 발동되는 시퀸스를 만들 때 사용합니다.

Used 이벤트

Used 이벤트는 특정 액터, 보통은 트리거와 일정한 범위 안에서 플레이어가 "사용"(디폴트는 'E') 키를 누르면 트리거됩니다. 이러한 이벤트 유형으로는, 버튼을 누른다든가 스위치를 켠다든가 플레이어가 의도적으로 시작시켜야 하는 시퀸스를 만들 수 있습니다.

Mover 이벤트

Mover 이벤트는 레벨의 어느 리프트에 플레이어가 서 있을때 활성화되는 리프트나 이동 플랫폼같은 것을 만드는 데 사용됩니다. "open", "close" 옵션이 따라붙는데, "닫히기" 전에 일정 기간동안 "열려" 있게 만듭니다.

먼저 콘텐츠 브라우저 에서 플랫폼으로 사용할 스태틱 메시를 선택합니다. 그런 다음 뷰포트에 우클릭 - Add InterpActor: ... 를 선택합니다.

ex_mover_1.jpg

그리고 InterpActor 를 더블클릭하여 프로퍼티를 띄운 다음 Collision 부분을 펼쳐 Collision TypeCOLLIDE_BlockAll 로 설정합니다.

ex_mover_2.jpg

InterpActor 를 선택한 상태로 키즈멧을 열고 작업공간에 우클릭 - InterpActor... 사용 새 이벤트 > Mover 를 선택합니다.

ex_mover_3.jpg

그러면 플랫폼을 이동시키는 데 쓸 수 있는, 완성된 상태의 마티네가 있는 특수 무버 이벤트가 생깁니다.

ex_mover_4.jpg

거기서 마티네 로 이동 키프레임을 놓으면 InterpActor 가 플레이어를 받쳐 움직입니다. 플레이어가 InterpActor 에 닿으면 플랫폼이 이동 시작할 것입니다.

비슷한 셋업 방식이 많이 있습니다. 키즈멧에서 우클릭하여 무버로 InterpActor 를 추가할 필요는 없습니다. 직접 마티네를 만들어서 편할 대로 키즈멧 액션을 통해 트리거시켜도 됩니다.

컨디션

컨디션은 시퀸스를 일정한 조건에 따라 둘 이상의 방향으로 갈라지게 만드는 특수 시퀸스 오브젝트입니다. 컨디션은 표준 프로그래밍의 If/Else 문이나 Switch 문과 같은 조건문과 유사합니다. 이를 통해 키즈멧 시퀸스에 기초적인 의사 결정 능력을 부여하여 훨씬 동적이고 매력적인 것으로 만들어 줍니다.

변수가 어떤 값을 가졌다거나 플레이어가 어떤 무기를 가졌다거나 했을 때만 시퀸스를 실행시키는 정도가 컨디션의 단순한 예라 하겠습니다.

ex_condition_weapon.jpg

조금 더 복잡한 사용 예제라면, 이벤트를 트리거한 액터가 특정 유형일 경우에만 실행되는 시퀸스가 여럿 있는 경우를 들 수 있겠습니다.

ex_condition_switch.jpg

루프

표준 프로그래밍에서 차용해 온 또다른 개념은, 한 액션을 특정 조건이 충족될 때까지 지정된 횟수만큼, 또는 무한 반복하는 루프 개념입니다. 루프의 종류에 따라 여러가지 방식으로 이루어 집니다.

단순한 무한 루프는 시퀸스 끝에 있는 액션의 출력을 시퀸스 처음에 있는 액션의 입력에 연결해 주기만 하면 됩니다. 시퀸스가 계속해서 반복되겠지요.

ex_loop_continuous.jpg

ALERT! 경고: 절대로 반복 루프 사이에 어떤 딜레이도 없이 연속 루프를 만들지 마십시오. Delay 액션을 사용하여 입/출력 링크 활성화를 지연시킬 수 있습니다. 휴면되는 방식으로(latently) 실행하는 액션도 있습니다. 즉 액션이 종료되기 전까지 출력되지 않는다는 뜻입니다. 이런 종류의 출력에는 딜레이가 내장되어 있으니, 딜레이 대신 또는 추가할 때 사용할 수 있습니다.

일정 횟수만큼 반복되는 (예를 들면 For) 루프는 Counter Int 또는 Float 를 사용하면 됩니다. 이 컨디션은 한 변수의 값을 증가 또는 감소시킨 다음 다른 변수와 비교하여, 그 결과에 따라 출력을 활성화시킵니다. 카운터에 연결된 시퀸스의 출력을 하나 이상 카운터의 입력에 연결하면 루프를 만들 수 있습니다. 루프 종료 조건을 나타내는 출력을 입력에 다시 연결한 것만 아니면 됩니다.

ex_loop_for.jpg

특정 조건이 참인 동안 반복되는 (예를 들면 While) 루프는 반복시킬 시퀸스의 처음이나 끝에, 출력 중 딱 하나만 시퀸스 반복을 허용하는 컨디션을 두는 식으로 만들 수 있습니다. 앞에 두면 While 루프가, 끝에 두면 Do-While 루프가 됩니다.

(Click for full size)

딜레이

시퀸스나 시퀸스 일부의 실행을 지연시키는 것은 키즈멧 시퀸스에서 꽤나 자주 있는 일인데, 특정 이벤트를 다른 이벤트와 관련해서 지정된 시간에 발생하도록 해야 하는 일이 빈번하기 때문입니다. 레벨이 시작될 때라든지, 플레이어가 스폰될 때라든지, 아니면 단순히 특정 액션을 실행할 때라든지요.

딜레이는 둘 중 한 가지 방식으로 줄 수 있습니다. 첫째, Delay 액션입니다. 이 액션으로 프로퍼티 안에 입력하거나 변수를 연결하는 식으로 기간을 지정할 수 있는데, 입력 링크가 활성화되면 출력 링크를 활성화기 전까지 이 기간만큼 대기하는 것입니다. 다른 액션의 결과가 나와야 딜레이 기간이 결정되게 하는 기능을, Delay 액션에 연결된 변수의 값을 설정하는 식으로 제공해 줍니다. 전용 액션이 있으니 시퀸스에 딜레이가 있다 명확히 밝히는 데도 좋습니다.

ex_delay.jpg

실행을 지연시키는 다른 방법은, 모든 입/출력 링크에 있는 Activate Delay 기능을 이용하는 것입니다. 링크에 우클릭하고 Set Activate Delay 를 선택한 다음 링크에 지연시킬 기간을 초로 지정하면 됩니다. 그러면 키즈멧 작업공간 안의 링크 위에 딜레이 기간이 표시됩니다. 본질적으로는 시퀸스 속에 Delay 액션을 추가하는 것과 같지만, 액션을 추가할 필요가 없습니다. 링크 자체적으로 딜레이가 처리됩니다. 물론 하드-코딩된 상수 값이니 가변 딜레이 기능이 상실됨을 뜻하기도 합니다. 딜레이가 어디에서 발생하는지 드러나지 않기야 합니다만, 공간을 절약하여 시퀸스를 깔끔해 보이게 할 수는 있습니다.

ex_activate_delay.jpg

글로벌 변수

키즈멧에서 글로벌 변수와 유사한 기능을 구현할 수는 있습니다. "글로벌" 이라는 용어 자체가 현재 퍼시스턴트와 스트리밍 레벨 영역에 한정되어 있기는 하지만 말입니다. 퍼시스턴트 레벨에 필요한 변수를 만들어 Var Name 프로퍼티에 고유한 이름을 지어주면, 네임드 변수를 사용하여 그 변수에 접근할 수 있습니다. 글로벌 변수 개념은 한 곳에 변수를 딱 하나만 두고도 다른 시퀸스에서 접근할 수 있을 뿐만 아니라, 모든 변수를 한 곳에 모아두고 네임드 변수를 여럿 사용하면 한 변수에서 나오는 선이 여러 액션에 얽히게 하지 않을 수 있으니 여러모로 좋습니다.

변수는 최상위(, 즉 퍼시스턴트 레벨의 베이스 키즈멧) 시퀸스, 아니면 최소한 변수가 접근해야 하는 모든 시퀸스의 부모 시퀸스에 위치해야 합니다. 또한 다른 시퀸스가 접근하려 할 때 로드되지 않은 상태일 수가 있는 스트리밍 레벨에 있으면 곤란하겠습니다.

스위치

게이트

가끔 다른 이벤트 시리즈가 이미 발생한 경우에만 특정 시퀸스가 실행되도록 하고 싶을 때가 있습니다. 한 이벤트를 어느 때고 몇 번이고 트리거되게 만들 수는 있지만, 다른 이벤트가 이미 트리거되기 전에는 전파되지 않도록 하고 싶은 경우, 예를 들면 잠긴 문은 따기 전까지는 열리지 않게 만들고자 하는 경우라 하겠습니다.

이런 종류의 관계를 구성하는 방법중 하나가 Gate 입니다. 이 액션은 열리거나 닫힌 상태일 수 있으며, 열린 상태에서 입력이 활성화되었을 때만 그 출력을 활성화시키는 것입니다.

ex_gate_switch.jpg

다른 방법으로는 조건의 상태를 기억하는 글로벌 Bool 변수를 두고, "unlock" 이벤트가 그 변수 값을 변경하도록 설정한 다음, 시퀸스를 활성화시키기 전 매번 변수 값을 검사하는 것입니다.

ex_gate_bool.jpg

훨씬 바람직하지 못합니다. 애초에 Gate 액션이 생긴 것도 바로 그 이유에서였죠. Gate 가 기능은 같으면서 훨씬 깔끔합니다.

오브젝트 리스트

Object Lists 는 이름 그대로, 오브젝트 목록입니다. 오브젝트 변수를 한 아름 액션에 연결해 줄 때, 그러면서도 변수 노드를 일일히 주렁주렁 매달고 싶지는 않을 때 좋습니다. 그러나 오브젝트 리스트에는 정리나 깔끔 이상의 무언가가 있습니다. 표준 프로그래밍에서 배열이나 기타 리스트 유형 식으로 사용할 수 있는 것입니다. 예를 들면, 월드에 스폰된 각 플레이어로의 참조를 오브젝트 리스트에 추가한 다음, 그 리스트를 반복처리하여 각 플레이어마다 특정 액션을 해줄 수 있습니다. 어느 볼륨에 들어간 오브젝트를 전부 리스트에 기록한 다음 다른 이벤트에 반응해서 그 리스트에 있는 것 전부에 대미지를 입힌다든가 할 수도 있습니다.

오브젝트 리스트 작업할 때 주로 사용되는 액션은 세 가지 있습니다: Access ObjectList, IsIn ObjectList, Modify ObjectList.

IsIn ObjectList 와 Modify ObjectList 는 보통 오브젝트 리스트에(서) 오브젝트를 추가/제거할 때 사용됩니다.

ex_objlist_setup.jpg

Access ObjectList 는 현재 항목에 대한 참조를 구하고자 리스트를 반복처리할 때 사용하는 액션입니다.

ex_objlist_access.jpg

타이머

Timer 액션은 맵을 테스트할 때나 디버깅할 때 주로 사용됩니다. 기어즈 오브 워의 싱글 플레이어 시나리오에서 적 그룹이 있을 때, 각 전투마다 시간이 얼마나 걸렸나를 알아볼 때 사용됩니다. 전투에 보통 시간이 얼마나 걸리는가를 알고 있으면, 전투에 관해 다른 이벤트를 언제 발동시킬지 결정하기가 쉬워집니다. 즉 전투가 보통 30 초 걸린다 칠 때, 15 초 쯤 벽이 닫히기 시작하게 하면 플레이어에게 압박감을 줄 수 있습니다. 타이머에 딱히 정해진 용도는 정말이지 별로 없으며, 시네마틱 타이밍을 재기 좋은 수단일 뿐입니다.

예제


여기서는 위에 설명한 여러가지 개념은 물론 흔한 키즈멧 사용법을 선보이는 예제 시퀸스를 알아보겠습니다.

자동문

(Proximity Door) 플레이어가 일정 범위안에 들어오면 자동으로 열리는 문에 대한 데모 시퀸스입니다.

ex_door_proximity.jpg

시퀸스는 문 위치에 있는 Trigger 에 연결된 Touch 이벤트에 의해 트리거됩니다. 트리거의 반경은 플레이어가 문에 얼마나 가까이 다가가야 트리거시킬 것인가를 결정합니다. 터치 이벤트의 Max Trigger Count 는 0 으로 설정하여 이벤트가 무한히 트리거되게 해 놨습니다.

터치 이벤트의 Touched 출력은 마티네의 Play 입력을 활성화시켜, 문 열기 애니메이션이 실행됩니다. UnTouched 출력은 마티네의 Reverse 입력을 활성화시켜 문을 닫습니다.

수동문

(Manual Door) 플레이어가 '사용'(E) 키를 눌러 수동으로 열어야 하는 문에 대한 데모 시퀸스입니다.

ex_door_manual.jpg

시퀸스는 문 위치에 있는 Trigger 에 연결된 Used 이벤트에 의해 트리거됩니다. 이벤트의 Max Trigger Count 는 0 으로 설정하여 이벤트가 무한 트리거되게 하였습니다. Interact Distance 를 조절하여 플레이어가 문을 열 수 있는 최대 거리를 설정할 수 있습니다.

터치 이벤트의 Used 출력은 마티네의 Play 입력을 활성화시켜 문 열이 애니메이션을 재생합니다. 마티네의 Completed 출력에 활성화 딜레이를 3 초 줘서 다시 Reverse 입력으로 연결합니다. 문을 열어둘 기간에 따라 값을 조절할 수 있습니다.

이러한 구성을 다르게 하는 방법은 Used 이벤트의 Used 출력과 마티네 사이에 출력 링크가 둘인 Switch 액션을 사용하면 됩니다. 첫 출력은 Play 입력에 연결하여 문을 열고, 둘째 출력은 Reverse 입력에 연결하여 문을 닫습니다. 그러면 루프나 액티브 딜레이를 사용할 필요 없이 문을 여닫을 수 있습니다.

ex_door_manual_alt.jpg

대미지 카메라 셰이크

플레이어의 카메라가 미리 결정된, Damage Camera Shake 같은 카메라 액션을 재생하도록 하는 시퀸스 데모입니다.

(Click for full size)

플레이어가 스폰되면 Attach To Event 액션에 의해 Take Damage 이벤트에 어태치됩니다. Take Damage 이벤트는 플레이어가 대미지를 입을 때마다 트리거되도록 설정되어 있습니다 (Damage Threshold = 1.0). 트리거 횟수는 무한 (Max Trigger Amount = 0) 이며, 토글될 떄마다 대미지 카운터를 리셋시킵니다 (Reset Damage On Toggle = True). Reset Damage On Toggle 가 중요한 이유는, Damage Taken 변수는 항상 이 번에 받은 대미지를 출력하도록 하더라도, 이벤트가 트리거될 때마다 대미지 카운터를 리셋시키도록 토글하지 않는 이상 이벤트의 대미지 카운터에 누산된 양을 출력할 것입니다.

Float 변수가 Damage Taken 변수 출력에 연결되어 받은 대미지 양을 담습니다.

트리거되면 Take Damage 이벤트가 두 토글 액션을 활설화시켜 Take Damage 이벤트를 토글시키고, 대미지 카운터를 리셋시킵니다.

또한 Take Damage 이벤트로 활성화된 것은 CameraAnim 재생시 사용할 intensity 값과 재생 속도 값을 구하는 데 사용된 일련의 계산식입니다. 대미지 양은 10.0 으로 나눕니다. 이 결과가 CameraAnim 의 intensity Scale 이 됩니다. 그리고 이 값을 invert 시켜 CameraAnim 의 재생 Rate 로 사용합니다.

Play Camera Animation 액션이 대미지 셰이크 CameraAnim 을 재생하는 데 사용됩니다. CameraAnim 의 Intensity ScaleRate 를 조절하기 위해, Play camera Animation 액션에 우클릭하고 Expose Variable > Intensity Scale and Expose Variable > Rate 를 선택하여 관련 변수를 노출시켰습니다. 그리고 두 Float 변수를 새로이 노출시켠 변수 입력에 연결해 주고, Player Spawned 이벤트의 Instigator 오브젝트 변수를 Target 변수 입력에 연결해 주었습니다.

주: 이 방법은 플레이어가 커스텀 카메라 클래스를 사용하고, CalcCamera() 메석드를 사용하여 카메라 시점을 계산하지 않을 때만 사용할 수 있습니다.

유도 신호

이 시퀸스는 플레이어와 타겟 사이의 거리에 따라 homing beacon(유도 신호)음의 피치와 볼륨을 조절하는 방법에 대한 데모 시퀸스입니다.

(Click for full size)

Level Loaded 이벤트를 통해 레벨 시작과 동시에 시퀸스가 시작됩니다. Get Distance 액션을 활성화시켜 플레이어와 유도 타겟 사이의 거리를 구한 다음 Float 변수에 저장합니다. 그리고 이 값을 HomingRadius 로 나눕니다. 거리 값을 정규화시킨 다음 편향시키고 invert 시켜 볼륨과 피치로 사용되는 최종 값 ModMultiplier 를 구합니다.

Play Sound 액션은 소리를 재생하는 데 사용됩니다. Play 입력은 모듈레이션 계산의 마지막 Divide 액션에 의해 활성화됩니다. Volume MultiplierPitch Multiplier 변수 입력을 노출시킨 다음 ModMultiplier 가 그 둘에 연결됩니다. Finished 출력이 다시 Get Distance 입력에 연결되어 프로세스를 처음부터 다시 시작합니다.

정찰 AI 리스폰하기

AI 개체를 스폰하고 제어하는 데 대한 시퀸스 데모입니다.

(Click for full size)

시퀸스는 Level Loaded 이벤트의 Beginning of Level 출력에 의해 트리거됩니다. 이는 지정된 PathNode 에 AI 개체를 하나 스폰시키는 UTActorFactoryAI Factory 를 가진 Actor Factory 를 활성화시킵니다. Spawned AI 로의 참조는 빈 오브젝트 변수에 저장되는데, 예제에서는 SpawnedBot 입니다.

별개의 두 루프가 액터 팩토리의 Finished 출력에 의해 활성화됩니다. 첫째 루프는 AI 개체의 발사 상태를 제어합니다. A = B 출력에 액티브 딜레이가 0.25 설정되어 있는 Compare Object 컨디션을 사용하여 SpawnedBot 변수를 먼저 빈 오브젝트 변수와 비교합니다. 비교에 실패하면, SpawnedBot 에서 플레이어까지 Trace 를 합니다. 걸리는 것이 없으면 SpawnedBot 은 Start Firing At 액션을 통해 플레이어에게 발사 시작합니다. Start Firing At 출력이 다시 Compare Object 컨디션으로 연결되어 루프가 재시작됩니다. Trace 에서 뭔가에 걸리면 SpawnedBot 은 발사를 중지하고, Stop Firing 액션의 출력이 다시 Compare Object 컨디션의 입력에 연결되어 루프를 재시작합니다.

둘째 루프는 AI 개체의 이동을 제어합니다. 다시금, Compare Object 컨디션을 사용하여 SpawnedBot 변수를 빈 오브젝트 변수와 비교합니다. 비교에 실패하면 Move To Actor 액션을 사용하여 SpawnedBot 가 다른 패쓰노드로 이동하도록 합니다. Finished 출력은 SpawnedBot 을 원래 패쓰노드로 되돌아가도록 하는 또하나의 Move To Actor 액션을 활성화시킵니다. 둘째 Move To Actor 의 Finished 출력이 다시 Compare Object 컨디션의 입력으로 연결되어 루프를 재시작합니다. Finished 출력을 사용하면 AI 개체가 한 위치에서 다른 위치로 이동하는 동안의 자연적인 딜레이가 내포되어 있기에, 이 연속 루프에는 별도의 딜레이가 필요치 않습니다.

Actor Factory 액션의 Finished 출력은 SpawnedBot 을 Death 이벤트와 연결해 주는 Attach To Event 액션 또한 활성화시킵니다. Death 이벤트는 SpawnedBot 의 참조를 비워 '루프가 루프가 아니야'로 만들어 버리는 Set Object 액션을 활성화시킵니다. Set Object 의 출력은 다시 액터 팩토리의 Spawn Actor 입력으로 연결하면서 3.0 초의 액티브 딜레이를 두고 새로운 AI 개체를 스폰하도록 합니다.

키즈멧 웨폰

순전히 키즈멧으로만 인스턴트-힛 (레이저처럼 쏘자마자 즉시 적중되는) 웨폰을 만드는 시퀸스 데모 한 쌍입니다. 트레이스, 액터 어태치먼트, 콘솔 명령, 콘솔 이벤트, 파티클 이벤트는 물론 액터에 대미지를 입히는 법 등을 참고할 수 있습니다.

ex_weapon.jpg

첫 시퀸스는 WeaponPoint 소켓에 이미터(는 이동가능 액터기만 하면 됩니다. 이미 레벨에 있는데다 발사 시퀸스에서 사용했을 때의 위치는 무관하기 때문에 사용한 것이 바로 이미터)를 Y 축으로 3000.0 의 Relative Offset (상대 오프셋)을 주고 어태치(부착)하여 플레이어를 구성하고 있습니다. 이 값은 무기의 유효 범위를 나타냅니다. 그리고 BEHINDVIEW 콘솔 명령을 실행하여 게임을 3인칭 시점으로 돌립니다. 어태치먼트가 카메라의 표적에 맞게 회전하도록 하는 데 필요한 것입니다.

MainFire 이벤트 이름으로 연결된 콘솔 이벤트가 발사를 처리하는 데 사용됩니다. 현재 무기 발사 바인딩에 CauseEvent MainFire 를 추가하도록 UDKInput.ini 를 수정하였습니다.

Bindings=(Name="GBA_Fire",Command="CauseEvent MainFire | StartFire | OnRelease StopFire")

이는 플레이어에서 어태치된 이미터로 트레이스하는 Trace 액션을 활성화시킵니다. 트레이스에 뭔가 걸렸다는 것은 중간에 뭐가 맞았다는 뜻이므로, 플레이어를 Instigator 로 사용하여 HitObject (맞은 오브젝트)에 Modify Health 액션으로 대미지를 입힙니다. 동시에 피튀기는 듯한 히트 이펙트를 흉내내기 위해, 이미터가 적중 위치에 파티클을 무더기로 스폰하도록 하는 데 Particle Event Generator 를 사용했습니다. 사용된 파티클 시스템에는 Spawn Event Receiver 모듈이 있어 HitEffect 이벤트를 기다리는데, 똑같은 이름이 Event Names 변수 입력에 전달되어 10 파티클을 스폰합니다.

그 이펙트를 확장하고자, Trace 액션의 Distance 변수 출력을 사용하여 액터의 적중 위치에서 플레이어까지의 거리에 따라 유동적인 대미지 양을 계산합니다. 웨폰 메시를 플레이어의 메시에 어태치하는 방식, 또는 픽업 시스템을 사용하여 현재 웨폰 메시를 디태치하고 플레이어에 새 웨폰 메시를 어태치한 다음 사용된 이미터를 바꾸는 식으로 완벽한 웨폰 인벤토리 시스템을 만들어낼 수도 있습니다. 이런 정도는 보통 글로벌 함수성이기에 스크립트를 통해서 구현하는 것이 정상이겠지만, 슈팅 비스무리한 미니게임 레벨이 딱 하나만 있을 경우라면 어떨까요? 바로 그럴 때 키즈멧 스크립팅이 빛을 발할 것입니다.

적 웨이브

이 시퀸스 예제는 이전 웨이브의 적이 모두 섬멸될 때마다 새 웨이브를 스폰하는 시스템을 구성하는 방법 중 하나입니다. 이 예제는 루프, 오브젝트 리스트, 컨디션을 활용합니다.

(Click for full size)

Level Loaded 이벤트의 Beginning of Level 출력으로 시퀸스가 초기에 활성화됩니다. 물론 어느 이벤트로도 트리거시킬 수는 있습니다. 그러면 몇 개의 문이 열리면서 그 뒤로 적이 스폰되는 마티네가 재생됩니다.

문이 열리고 마티네가 완료되면, UTActorFactoryAI Factory 를 가진 액터 팩터가 AI 개체를 스폰합니다. Spawned AI 는 Attach To Event 액션을 사용하여 Death 이벤트에 어태치됩니다. Spawned AI 는 Object List 에도 추가되며, 리스트의 항목 수를 검사합니다. 적 수가 최대보다 작으면, 시퀸스는 액터 팩터로 되돌아가며, 그 이상이 되면 마티네를 Reverse (역방향) 재생하여 문을 닫고 스폰 루프를 끝냅니다.

Death 이벤트 출력은 모든 적을 담는 Object List 에서 죽은 Pawn 을 제거합니다. 그런 다음 리스트의 적 수를 다시 검사합니다. 적이 없으면 (리스트 수가 0 이면) 마티네를 다시 재생하여 다음 웨이브를 시작합니다.

이 정도는 물론 기본 틀일 뿐입니다. 몇 번째 웨이브인지 기록하여 각 웨이브 시작이나 끝마다 메시지를 추가하는 기능 확장 정도는 식은 죽 먹기입니다. 각 웨이브마다 스폰되는 적의 수를 (MaxEnemies 변수를 통해) 조금씩 늘려 난도를 조금씩 올릴 수도 있습니다.