UDN
Search public documentation:

MasteringUnrealScriptDelegatesKR
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

제 12 장 - Delegate

Delegate란, 인스턴스 내부의 함수 참조로, 함수로 변수라고 하는 2 개의 프로그래밍 개념의 편성입니다. 변수가 특정 타입의 값을 어떠한 방법으로 보관 유지해, 실행시에 그 값이 얼마나 변화해 나갈까는 이미 아시는 일이지요. 값을 보관 유지해, 실행시로 그것을 변경할 수 있다고 하는 점으로써, Delegate는 변수와 같은 일면이 있습니다만, Delegate의 경우, 이 값과는 클래스내에서 선언된 다른 함수입니다. 그것과 동시에, Delegate는 실행 가능한 것으로부터 함수와 같이도 행동합니다. 적정한 상황아래에서 이용되는 Delegate가 강대한 힘을 발휘하는 것은, 이 변수와 함수의 편성이라고 하는 특성에 의하는 것입니다.

12. 1 - 개요

Delegate는, 실행시에 코드의 동적이고 신속한 실행이 요구되는 경우에 자주(잘) 사용됩니다. 종래의 메소드는 민첩성이 없고, 가끔 제약을 수반합니다. 다음의 코드를 봅시다.

var int GlobalVar;

function Foo(float value)
{
   GlobalVar = value;
   Bar();
}

function Bar()
{
   switch (GlobalVar)
   {
      case 0:
         DoThis();
         break;
      case 1:
         DoThat();
         break;
      default:
         DoDefault();
         break;
   }
}

이것은 런타임의 코드 실행을 동적으로 변경하는 방법이다, 라고 볼 수가 있습니다만, 신속히 실시하는 방법이 아닙니다. 그것은, 조건이 추가되면(자) Bar()를 관리하기 위한 노력이 증가하기 (위해)때문에입니다. 다음의 코드를 봅시다.

delegate Bar();

function Foo(float value)
{
   switch (value)
   {
      case 0:
         Bar = DoThis();
         break;
      case 1:
         Bar = DoThat();
         break;
      default:
         Bar = DoDefault();
         break;
   }

   Bar();
}

2 개의 문제를 해결했으므로, 전의 예 보다 좋아지고 있습니다. 최초로 글로벌 변수를 제외해, 따라 Bar()의 실행시에 그것을 체크하는 필요성도 없어졌습니다. 그러나, switch 스테이트먼트가 아직 존재하므로, 전례와 같은 관리 문제에 고민합니다. 관리가 어려웠던 Bar() 대신에, 이쪽에서는 Foo()의 관리가 어려워졌습니다. 다음의 코드를 봅시다.

delegate Bar();

function Foo(delegate<Bar> BarDelegate)
{
   Bar = BarDelegate;
   Bar();
}

switch 스테이트먼트를 제외했으므로, 좀 더 좋아졌습니다. 향후 추가되는 조건의 수에 관계없이, Foo()도 Bar()도 관리할 필요는 없습니다.

12. 2 - Delegate의 선언

Delegate는 함수와 방법으로 선언합니다만, function 라고 하는 키워드 대신에 delegate 를 사용합니다.

delegate Foo();

이 클래스에 Foo()라는 이름의 Delegate를 포함했습니다.

Delegate의 파라미터

함수와 같게, Delegate는 파라미터를 가질 수가 있습니다. Delegate와 함수를 조합해 사용할 때는, 함수에도 Delegate와 같은 파라미터를 포함할 필요가 있습니다. 다음의 코드를 봅시다.

delegate Foo(const float Bar, const float Doh);

function FooBoom(const float Bar, const float Doh);

function FooFail(const float Bar);

이 경우, FooBoom()를 Foo()에 대입하는 것은 유효합니다만, FooFail()를 Foo()에 대입하는 것은 무효입니다. 이 룰에는 예외가 1 개만 있어, 그것은 옵션의 파라미터입니다. 다음의 코드를 봅시다.

delegate Foo(const float Bar, const float Doh, optional float Moe);

function FooBoom(const float Bar, const float Doh);

이 경우도 Foo()에 FooBoom()를 대입할 수 있습니다만, 그 때는 FooBoom() 내에서 Moe 를 사용할 수 없습니다. 같이 Delegate에 반환값의 파라미터를 포함할 수도 있습니다.

디폴트의 동작

Delegate의 본체의 정의에서는, Delegate가 함수에 대입되어 있지 않을 때의 디폴트의 동작을 지정합니다. 다음의 코드를 봅시다.

delegate Foo()
{
   `Log(“Default behavior. ”);
}

function Bar()
{
   `Log(“Non default behavior. ”);
}

function Bing()
{
   Foo = Bar;
   Foo();
   Foo = none;
   Foo();
}

이것을 실행하면(자) 스크립트 로그에 다음과 같이 기입합니다.

ScriptLog: Non default behavior.
ScriptLog: Default behavior.

12. 3 - 변수로서의 Delegate

Delegate를 변수와 같이 사용할 수가 있습니다. 부동 소수나 정수와 같이 연산상에서 사용할 수 없습니다만, 대입이나 비교는 가능합니다. 그 구문은, UnrealScript (Unreal 스크립트) 외 변수를 할당하는 경우와 완전히 같습니다. 다음의 코드를 봅시다.

delegate Foo();

function Bar();

function PostBeginPlay()
{
   Foo = Bar;
}

현재 참조중의 함수를 확인하기 위해서, Delegate의 비교를 활용할 수 있는 경우가 있습니다. 다음의 코드를 봅시다.

delegate Foo();

function Bar();

function Rod();

function PostBeginPlay()
{
   Foo = Bar;

   if (Foo == Bar)
      `Log(“Foo is assigned to Bar()”);

   Foo = Rod;

   if (Foo ! = Bar)
      `Log(“Foo is not assigned to Bar()”);
}

비교 함수를 이와 같이 이용하는 것으로, 다른 글로벌 변수를 사용하지 않고 Delegate의 참조처를 추적할 수 있습니다.

12. 4 - Delegate를 함수에 건네준다

변수와 같게, Delegate를 함수 파라미터내에서 사용할 수도 있습니다. 이것은, 함수나 인스턴스간에 Delegate를 건네주고 싶을 때에 편리합니다. 다음의 코드를 봅시다.

delegate Foo();

function Bar();

function PassDelegate()
{
   ReceiveDelegate(Bar);
}

function ReceiveDelegate(delegate<Foo> FooDelegate)
{
   Foo = FooDelegate;
}

이 Delegate의 대입 방법은, Delegate 본체가 다른 클래스로부터 프로텍트 (보호) 또는 프라이빗화 되고 있는 경우에 중요합니다. Delegate를 private 또는 protected 지정되고와 통상 다른 클래스로부터는 액세스 할 수 없습니다. 다음의 코드를 봅시다.

class Pizza extends Object;

private delegate Eat();

function EatMe()
{
   Eat();
}

function HowToEat(delegate<Eat> EatDelegate)
{
   Eat = EatDelegate;
}

class Mushroom extends Object;

function SpitOut()
{
   `Log(“I spit out the mushrooms, as they are disgusting. ”);
}

function EatPizza(Pizza pizza)
{
   if (pizza ! = none)
   {
      pizza.HowToEat(SpitOut);
      pizza.EatMe();
   }
}

12. 5 - Delegate와 메모리

Delegate가, 월드내에서 다른 먼지 인스턴스에 존재하는 함수를 참조할 때는, 그 인스턴스를 파괴하는 것이 안전책입니다. 다만, 다른 오브젝트 인스턴스에 있는 함수를 참조하는 경우는, Delegate를 none 로 설정할 필요가 있습니다. UnrealScript 에서는 오브젝트 인스턴스를 On Demand로 파괴할 수 없기 때문에, 모든 순환 참조를 소거해 두지 않으면, 오브젝트 인스턴스의 garbage collection를 실행하지 못하고, 레벨 변경시 또는 게임 종료시에 메모리 리크가 발생하므로 조심합시다.

12. 6 - UISCENE 및 UIOBJECT Delegate

UIScenes 와 그 내부에서 사용되는 UIObjects 는, Delegate를 이용해 원가요소의 기능을 간단하게 커스터마이즈 하는 수단을 제공하고 있습니다. MOD 작자는 이 상황하로 Delegate를 가장 자주(잘) 사용하게 되므로, 이하에 이러한 클래스내에 있는 Delegate의 일람과 그 설명을 나타냅니다.

UISCENE Delegate

  • OnSceneActivated(UIScene ActivatedScene, bool bInitialActivation) - 신이 액티브 신이 되면(자) 불려 갑니다. ActivatedScene 는 액티브하게 된 UIScene 입니다. 장면이 처음으로 액티브하게 되었을 경우, bInitialActivation 는 True 로 설정됩니다.

  • OnSceneDeactivated(UIScene DeactivatedScene) - 신이 비액티브하게 되면(자) 불려 갑니다. DeactivatedScene 는, 비액티브하게 된 UIScene 입니다.

  • OnTopSceneChanged(UIScene NewTopScene) - 이 UIScene 가 최상정도의 장면으로서 사용되고 있을 때, 다른 UIScene 가 다음에 최상정도 신이 될 때 불려 갑니다. NewTopScene 는 새롭게 최상정도 신이 되는 UIScene 입니다. UIScenes 는 서로 거듭할 수가 있어 이 계층화의 특징을 사용해 다른 장면을 정리해 조합할 수가 있습니다. 예를 들면, 거의 변화하지 않는 배경의 UIScene 를 작성해, 대화형의 UIScene 를 그 위에 쌓아올릴 수가 있습니다.

  • bool ShouldModulateBackgroundAlpha(out float AlphaModulationPercent) - 이것을 사용해, UIScenes 의 친신을 렌더링 할 때의 투명도량을 변경할 수 있습니다. AlphaModulationPercent 는, 하위의 장면을 렌더링 할 경우에, 알파치를 변조하는데 사용되는 값입니다. 하위의 장면의 렌다린크에 알파 변조가 적용되는 경우는 True 를 돌려줍니다.

UIOBJECT Delegate

  • OnCreate(UIObject CreatedWidget, UIScreenObject CreatorContainer) - UIObject 의 작성시에 불려 갑니다. CreatedWidget 은 작성된 UIObject, UIScreenObject 는 위제트의 작성원의 컨테이너입니다.

  • OnValueChanged(UIObject Sender, int PlayerIndex) - 이 UIObject 의 값이 변경되면(자) 불려 갑니다. 데이터치를 격납하는 UIObjects 만을 대상으로 합니다. Sender 는 이 Delegate를 호출한 UIObject, PlayerIndex 은 Engine.GamePlayers 내의 인덱스로, 이벤트를 방아쇠 한 플레이어를 참조하고 있습니다.

  • bool OnRefreshSubscriberValue(UIObject Sender, int BindingIndex) - UIObject 가 RefreshSubscriberValue 의 호출을 받으면(자) 불려 갑니다. Sender 는 이 Delegate를 호출한 UIObject, BindingIndex 는 UIObjects 가 복수의 데이터 스토어 바인딩을 가지는 경우에 갱신되는 데이터 스토어 바인딩을 나타내, 그 사용법은, 이 Delegate를 실장하는 클래스에 의존합니다. 이 UIObject 가 값을 수동으로 갱신하는 경우는 True 를 돌려줍니다.

  • OnPressed(UIScreenObject EventObject, int PlayerIndex) - UIObject 가 선택되면(자) 불려 갑니다. 이것이 실장되어 있지 않은 UIObject 타입도 있습니다. EventObject 는, 이 Delegate를 호출한 UIScreenObject, PlayerIndex 은 Engine.GamePlayers 내의 인덱스로, 이벤트를 방아쇠 한 플레이어를 참조하고 있습니다.

  • OnPressRepeat(UIScreenObject EventObject, int PlayerIndex) - 위제트가 밀려 유저가 버튼을 압하 상태로 하고 있을 때 불려 갑니다. 이것이 실장되어 있지 않은 위제트타이프도 있습니다. EventObject 는, 이 Delegate를 호출한 UIScreenObject 입니다. PlayerIndex 은 Engine.GamePlayers 내의 인덱스로, 이벤트를 방아쇠 한 플레이어를 참조하고 있습니다.

  • OnPressRelease(UIScreenObject EventObject, int PlayerIndex) - 위제트의 선택이 해제되면(자) 불려 갑니다. 이것이 실장되어 있지 않은 위제트타이프도 있습니다. EventObject 는, 이 Delegate를 호출한 UIScreenObject 입니다. PlayerIndex 은 Engine.GamePlayers 내의 인덱스로, 이벤트를 방아쇠 한 플레이어를 참조하고 있습니다.

  • bool OnClicked(UIScreenObject EventObject, int PlayerIndex) - 위제트의 선택이 해제되면(자) 불려 갑니다. 이것이 실장되어 있지 않은 위제트타이프도 있습니다. 이 Delegate와 OnPressRelease 와의 차이는, 대응하는 키의 압하를 받은 UIObject 상에서 불려 가는 점에 있습니다. OnPressRelease 는, 키가 해방되었을 때에 커서아래에 있는 UIObject 상에서 불려 가므로, 그 오브젝트가 키의 압하를 받은 UIObject 와 같지 않은 것이 있습니다. EventObject 는 이 Delegate를 호출한 UIObject 입니다. PlayerIndex 은 Engine.GamePlayers 내의 인덱스로, 이벤트를 방아쇠 한 플레이어를 참조하고 있습니다.

  • OnDoubleClick(UIScreenObject EventObject, int PlayerIndex) - 위제트가 더블 클릭 이벤트를 받으면(자) 불려 갑니다. 이것이 실장되어 있지 않은 위제트타이프도 있습니다. EventObject 는, 이 Delegate를 호출한 UIScreenObject 입니다.

  • bool OnQueryToolTip(UIObject Sender, out UIToolTip CustomToolTip) - 자의 클래스 또는 컨테이너로 이것을 사용해, 표시되는 표준의 툴 힌트를 오버라이드(override) 할 수가 있습니다. Sender 는 툴 힌트를 표시하는 UIObject 입니다. CustomToolTip 는 표시되는 툴 힌트입니다. 툴 힌트가 표시되는 경우는 True 를 돌려주어, 툴 힌트가 표시되지 않는 경우는 False 를 돌려줍니다.

  • bool OnOpenContextMenu(UIObject Sender, int PlayerIndex, out UIContextMenu CustomContextMenu) - 스크립트로 이것을 사용해, 커스텀의 context menu (유저가 오른쪽 클릭하면(자) pop-up 표시되는 메뉴)를 표시할 수가 있습니다. Sender 는 context menu를 표시하는 UIObject 입니다. PlayerIndex 은 Engine.GamePlayers 내의 인덱스로, 이벤트를 방아쇠 한 플레이어를 참조하고 있습니다. CustomContextMenu 는, 표시되는 커스텀 context menu입니다. 커스텀 context menu가 표시되는 경우는 True 를 돌려주어, context menu가 표시되지 않는 경우는 False 를 돌려줍니다.

  • OnCloseContextMenu(UIContextMenu ContextMenu, int PlayerIndex) - 시스템이 현재 액티브한 context menu를 닫을 필요가 있을 때 불려 갑니다. ContextMenu 는 닫혀지는 context menu입니다. PlayerIndex 은 Engine.GamePlayers 내의 인덱스로, 이벤트를 방아쇠 한 플레이어를 참조하고 있습니다.

  • OnContextMenuItemSelected(UIContextMenu ContextMenu, int PlayerIndex, int ItemIndex) - 유저가 context menu로부터 항목을 선택하면(자) 불려 갑니다. ContextMenu 는, 이 Delegate를 호출한 context menu입니다. PlayerIndex 은 Engine.GamePlayers 내의 인덱스로, 이벤트를 방아쇠 한 플레이어를 참조하고 있습니다. ItemIndex 는, context menu의 MenuItems 배열의 인덱스입니다.

  • OnUIAnimEnd(UIObject AnimTarget, int AnimIndex, UIAnimationSeq AnimSeq) - UI 애니메이션이 종료하면(자) 반드시 불려 갑니다. AnimTarget 는 이 Delegate를 호출한 UIObject, AnimIndex 는 애니메이션의 인덱스, UIAnimationSeq 는 애니메이션 순서입니다.

12. 7 - Unreal Engine 3 및 Unreal Tournament 3 에 있어서의 다른 Delegate

Unreal Engine 3 및 Unreal Tournament 3 내의 Delegate는, 다양한 기회에 도움이 되는 실마리를 주므로 일견의 가치가 있습니다. 이 서브 섹션에는, Unreal Engine 3 및 Unreal Tournament 3 에 존재하는 Delegate의 리스트를 제공합니다.

AUDIOCOMPONENT

  • OnAudioFinished(AudioComponent AC) - AudioComponent 가 현재의 SoundCue 의 재생을 종료하면(자) (재생이 끝났는지, 또는 Stop()가 불려 가고) 불려 갑니다. AC 는, 이 Delegate를 호출한 AudioComponent 의 참조입니다.

GAMEINFO

  • bool CanUnpause() - 이것은, 게임의 일시정지 해제 (unpause)를 가능하게 할지 어떨지에 임해서보다 구체적인 조건을 실장할 필요가 있을 때 이용할 수 있습니다. 디폴트 상태에서는 단순한 타글입니다.

GAMEVIEWPORTCLIENT

  • bool HandleInputKey(int ControllerId, name Key, EInputEvent EventType, float AmountDepressed, optional bool bGamepad) - 이것을 사용해, 뷰포트로부터 받은 키 입력 이벤트를 아이 클래스에서 처리할 수가 있습니다. 이벤트 처리를 위해서(때문에) interactions 배열에 키 이벤트가 건네받기 전에 불려 갑니다. ControllerId 는, event key를 방아쇠 한 콘트롤러 참조, Key 는 압하키, EventType 는 파생한 이벤트의 타입입니다. AmountDepressed 는 아날로그 타입의 콘트롤러의 경우에 사용되어 bGamepad 는 게임패드 디바이스로부터의 이벤트의 경우에 True 가 됩니다.

  • bool HandleInputAxis(int ControllerId, name Key, float Delta, float DeltaTime, bool bGamepad) - 이것을 사용해, 뷰포트로부터 받은 좌표축 입력 이벤트를 아이 클래스에서 처리할 수가 있습니다. 이벤트 처리를 위해서(때문에) interactions 배열에 좌표축 이벤트가 건네받기 전에 불려 갑니다. ControllerId 는, event key를 방아쇠 한 콘트롤러 참조, Key 는 관련 키, Delta 는 이동 델타 (간격), DeltaTime 는 마지막에 좌표축이 갱신되고 나서 경과한 시간 (초), bGamepad 는 게임패드 디바이스로부터의 이벤트의 경우에 True 가 됩니다.

  • bool HandleInputChar(int ControllerId, string Unicode) - 이것을 사용해, 뷰포트로부터 받은 문자 입력 이벤트를 아이 클래스에서 처리할 수가 있습니다. 이벤트 처리를 위해서(때문에) interactions 배열에 문자 이벤트가 건네받기 전에 불려 갑니다. ControllerId 는 이벤트를 방아쇠 한 콘트롤러를 참조해, Unicode 는 입력된 문자입니다.

INTERACTION

  • bool OnReceivedNativeInputKey(int ControllerId, name Key, EInputEvent EventType, optional float AmountDepressed = 1. f, optional bool bGamepad) - GameViewportClient.HandleInputKey 와 같습니다만, GameViewportClient 로부터의 네이티브 호출의 경우만 불려 갑니다.

  • bool OnReceivedNativeInputAxis(int ControllerId, name Key, float Delta, float DeltaTime, optional bool bGamepad) - GameViewportClient.HandleInputAxix 와 같습니다만, GameViewportClient 로부터의 네이티브 호출의 경우만 불려 갑니다.

  • bool OnReceivedNativeInputChar(int ControllerId, string Unicode) - GameViewportClient.HandleInputChar 와 같습니다만, GameViewportClient 로부터의 네이티브 호출의 경우만 불려 갑니다.

  • OnInitialize() - 네이티브 실장된 Init() 함수내로부터, (네이티브의 초기화가 종료한 후에) 불려 갑니다.

ONLINEACCOUNTINTERFACE

  • OnCreateOnlineAccountCompleted(EOnlineAccountCreateStatus ErrorStatus) - 어카운트 작성 루틴의 완료 후에 불려 갑니다. ErrorStatus 는, 어카운트 작성에 성공했는지 어떠했는지를 선언합니다.

ONLINECONTENTINTERFACE

  • OnContentChange() - 임의의 유저에 관한 컨텐츠가 변경되면(자) 불려 갑니다.

  • OnReadContentComplete(bool bWasSuccessful) - 컨텐츠의 읽기 요구가 완료하면(자) 불려 갑니다. 읽기에 성공했을 경우, bWasSuccessful 는 True 로 설정됩니다.

  • OnQueryAvailableDownloadsComplete(bool bWasSuccessful) - 컨텐츠의 다운로드 쿠에리-가 완료하면(자) 불려 갑니다. 쿠에리-가 성공했을 경우, bWasSuccessful 는 True 로 설정됩니다.

ONLINEGAMEINTERFACE

  • OnCreateOnlineGameComplete(bool bWasSuccessful) - 온라인 게임 작성 루틴이 완료하면(자) 불려 갑니다. 게임 작성에 성공했을 경우, bWasSuccessful 는 True 로 설정됩니다.

  • OnDestroyOnlineGameComplete(bool bWasSuccessful) - 온라인 게임의 파기 루틴이 완료하면(자) 불려 갑니다. 게임 파기에 성공했을 경우, bWasSuccessful 는 True 로 설정됩니다.

  • OnFindOnlineGamesComplete(bool bWasSuccessful) - 온라인 게임의 검색 루틴이 완료하면(자) 불려 갑니다. 게임 검색 루틴에 성공했을 경우, bWasSuccessful 는 True 로 설정됩니다.

  • OnCancelFindOnlineGamesComplete(bool bWasSuccessful) - 온라인 게임의 검색 루틴이 캔슬되면(자) 불려 갑니다. 게임 검색 루틴의 캔슬에 성공했을 경우, bWasSuccessful 는 True 로 설정됩니다.

  • OnJoinOnlineGameComplete(bool bWasSuccessful) - 온라인 게임의 참가 루틴이 완료하면(자) 불려 갑니다. 게임 참가에 성공했을 경우, bWasSuccessful 는 True 로 설정됩니다.

  • OnRegisterPlayerComplete(bool bWasSuccessful) - 플레이어 등록 루틴이 완료하면(자) 불려 갑니다. 등록에 성공했을 경우, bWasSuccessful 는 True 로 설정됩니다.

  • OnUnregisterPlayerComplete(bool bWasSuccessful) - 플레이어 등록 해제 루틴이 완료하면(자) 불려 갑니다. 등록 해제에 성공했을 경우, bWasSuccessful 는 True 로 설정됩니다.

  • OnStartOnlineGameComplete(bool bWasSuccessful) - 게임 스테이트가 started 로 변경되면(자) 불려 갑니다. 이 비동기 루틴에 성공했을 경우, bWasSuccessful 는 True 로 설정됩니다.

  • OnEndOnlineGameComplete(bool bWasSuccessful) - 게임 스테이트가 ended 로 변경되면(자) 불려 갑니다. 이 비동기 루틴에 성공했을 경우, bWasSuccessful 는 True 로 설정됩니다.

  • OnArbitrationRegistrationComplete(bool bWasSuccessful) - 게임이 아비트레이션 등록을 완료하면(자) 불려 갑니다. 이 비동기 루틴에 성공했을 경우, bWasSuccessful 는 True 로 설정됩니다.

  • OnGameInviteAccepted(OnlineGameSettings GameInviteSettings) - 유저가 게임에의 초대를 받아들이면(자) 불려 갑니다. 이것을 사용해, 초대를 받아들이기 전에 기존 스테이트를 코드내에서 클린 업 할 수가 있습니다.

ONLINENEWSINTERFACE

  • OnReadGameNewsCompleted(bool bWasSuccessful) - 뉴스 읽기 루틴이 완료하면(자) 불려 갑니다. 이 루틴에 성공했을 경우, bWasSuccessful 는 True 로 설정됩니다.

  • OnReadContentAnnouncementsCompleted(bool bWasSuccessful) - 컨텐츠 발표 루틴이 완료하면(자) 불려 갑니다. 이 루틴에 성공했을 경우, bWasSuccessful 는 True 로 설정됩니다.

ONLINEPLAYERINTERFACE

  • OnLoginChange() - 로그인이 변경되면(자) 불려 갑니다.

  • OnLoginCancelled() - 로그인 요구가 삭제되면(자) 불려 갑니다.

  • OnMutingChange() - 뮤트 리스트가 변경되면(자) 불려 갑니다.

  • OnFriendsChange() - 프렌즈 리스트가 변경되면(자) 불려 갑니다.

  • OnLoginFailed(byte LocalUserNum, EOnlineServerConnectionStatus ErrorCode) - 무엇으로의 이유로써 로그인이 실패하면(자) 불려 갑니다. LocalUserNum 는 콘트롤러 ID 의 참조입니다. ErrorCode 는 발생한 에러를 나타냅니다.

  • OnLogoutCompleted(bool bWasSuccessful) - 로그아웃이 완료하면(자) 불려 갑니다. 이 비동기 호출이 적절히 종료했을 경우, bWasSuccessful 는 True 로 설정됩니다.

  • OnReadProfileSettingsComplete(bool bWasSuccessful) - 마지막 프로파일 설정의 읽기 요구가 완료하면(자) 불려 갑니다. 이 비동기 호출이 적절히 종료했을 경우, bWasSuccessful 는 True 로 설정됩니다.

  • OnWriteProfileSettingsComplete(bool bWasSuccessful) - 마지막 프로파일 설정의 기입 요구가 완료하면(자) 불려 갑니다. 이 비동기 호출이 적절히 종료했을 경우, bWasSuccessful 는 True 로 설정됩니다.

  • OnReadFriendsComplete(bool bWasSuccessful) - 프렌즈의 읽기 요구가 완료하면(자) 불려 갑니다. 이 읽기 요구가 적절히 종료했을 경우, bWasSuccessful 는 True 로 설정됩니다.

  • OnKeyboardInputComplete(bool bWasSuccessful) - 키보드 입력 요구가 완료하면(자) 불려 갑니다. 이 비동기 호출이 적절히 종료했을 경우, bWasSuccessful 는 True 로 설정됩니다.

  • OnAddFriendByNameComplete(bool bWasSuccessful) - 이름에 의한 프렌즈 추가가 완료하면(자) 불려 갑니다. 이 비동기 호출이 적절히 종료했을 경우, bWasSuccessful 는 True 로 설정됩니다.

  • OnFriendInviteReceived(byte LocalUserNum, UniqueNetId RequestingPlayer, string RequestingNick, string Message) - 로컬 플레이어의 프렌즈 초대가 도착하면(자) 불려 갑니다. LocalUserNum 는 로컬 유저의 참조, RequestingPlayer 는 해당 로컬 유저에게 초대장을 송신한 플레이어를 일의에 식별하는 ID, RequestingNick 는 요구를 송신한 플레이어의 닉네임, Message 는 추가 메세지입니다.

  • OnReceivedGameInvite(byte LocalUserNum, string InviterName) - 로컬 유저가 게임에의 초대를 받으면(자) 불려 갑니다. LocalUserNum 는 로컬 유저의 참조, InviterName 는 초대측의 이름입니다.

  • OnJoinFriendGameComplete(bool bWasSuccessful) - 로컬 유저가 프렌즈의 게임 참가를 완료하면(자) 불려 갑니다. 세션이 검출되고 참가가 완료했을 경우, bWasSuccessful 는 True 로 설정됩니다.

  • OnFriendMessageReceived(byte LocalUserNum, UniqueNetId SendingPlayer, string SendingNick, string Message) - 로컬 유저의 프렌즈 메세지가 도착하면(자) 불려 갑니다. LocalUserNum 는 로컬 유저의 참조, RequestingPlayer 는 해당 로컬 유저에게 초대장을 송신한 플레이어를 일의에 식별하는 ID, RequestingNick 는 요구를 송신한 플레이어의 닉네임, Message 는 추가 메세지입니다.

ONLINEPLAYERINTERFACEEX

  • OnDeviceSelectionComplete(bool bWasSuccessful) - 디바이스 선택 요구가 완료하면(자) 불려 갑니다. 디바이스 선택이 정상적으로 종료했을 경우, bWasSuccessful 는 True 로 설정됩니다.

  • OnUnlockAchievementComplete(bool bWasSuccessful) - 성적의 락 해제 요구가 완료하면(자) 불려 갑니다. 락 해제가 정상적으로 종료했을 경우, bWasSuccessful 는 True 로 설정됩니다.

  • OnProfileDataChanged() - 플레이어의 프로파일 데이터에 대한 외부로부터의 변경이 완료하면(자) 불려 갑니다.

ONLINESTATSINTERFACE

  • OnReadOnlineStatsComplete(bool bWasSuccessful) - 온라인 통계의 읽기가 완료하면(자) 불려 갑니다. 이 비동기 호출이 적절히 종료했을 경우, bWasSuccessful 는 True 로 설정됩니다.

  • OnFlushOnlineStatsComplete(bool bWasSuccessful) - 온라인 통계의 소거가 완료하면(자) 불려 갑니다. 이 비동기 호출이 적절히 종료했을 경우, bWasSuccessful 는 True 로 설정됩니다.

  • OnRegisterHostStatGuidComplete(bool bWasSuccessful) - 호스트 통계의 GUID 등록이 완료하면(자) 불려 갑니다. 이 비동기 호출이 적절히 종료했을 경우, bWasSuccessful 는 True 로 설정됩니다.

ONLINESTATSREAD

  • OnStatsReadComplete() - 통계 읽기가 완료하면(자) 불려 갑니다.

ONLINESTATSWRITE

  • OnStatsWriteComplete() - 통계 서두가 완료하면(자) 불려 갑니다.

ONLINESYSTEMINTERFACE

  • OnLinkStatusChange(bool bIsConnected) - 넷트워크리크스테이타스가 변화하면(자) 불려 갑니다. 어떠한 접속이 검출되었을 경우, bIsConnected 는 True 로 설정됩니다.

  • OnExternalUIChange(bool bIsOpening) - 외부 UI 표시가 그 스테이트를 변경하면(자) 불려 갑니다. UI 열려 있는 경우, IsOpening 는 True 로 설정됩니다.

  • OnControllerChange(int ControllerId, bool bIsConnected) - 콘트롤러의 접속 스테이트가 변화하면(자) 불려 갑니다. ControllerId 는, 접속 스테이트가 바뀐 콘트롤러의 참조입니다. 콘트롤러가 접속되고 있는 경우, bIsConnected 는 True 로 설정됩니다.

  • OnConnectionStatusChange(EOnlineServerConnectionStatus ConnectionStatus) - 온라인 서버의 접속 스테이트가 변화하면(자) 불려 갑니다. ConnectionStatus 에는, 신규 접속 스테이터스가 격납됩니다.

  • OnStorageDeviceChange() - storage device의 변경이 검출되면(자) 불려 갑니다.

ONLINEVOICEINTERFACE

  • OnPlayerTalking(UniqueNetId Player) - 플레이어가 로컬 또는 리모트로 회화하고 있을 때 불려 갑니다. 각 액티브 발가락 카 (회화자), 각 프레임 마다 1 번 불려 갑니다. Player 는 회화중의 플레이어 참조입니다.

  • OnRecognitionComplete() - 지정 플레이어의 음성인식이 완료하면(자) 불려 갑니다. 이 다음에 GetRecognitionResults()를 호출해, 인식된 말을 취득할 수가 있습니다.

PARTICLESYSTEMCOMPONENT

  • OnSystemFinished(ParticleSystemComponent Psystem) - 파티클 시스템이 지정 파티클 효과의 「재생」을 종료하면(자) 불려 갑니다. Psystem 는 자기를 참조하고 있으므로, 이 Delegate를 다른 인스턴스내에서 오버라이드(override) 하면(자), Delegate를 호출한 ParticleSystemComponent 에 액세스 할 수 있습니다.

PLAYERCONTROLLER

  • bool CanUnpause() - 플레이어의 콘트롤러가 게임을 일시정지 해제할 수 있는 조건을, 다른 논리를 이용해 확정할 필요가 있는 경우는, 이것을 오버라이드(override) 합니다.

UICOMBOBOX

  • UIEditBox CreateCustomComboEditbox(UIComboBox EditboxOwner) - 다른 논리를 이용해 편집 박스를 작성할 필요가 있는 경우, 이것을 오버라이드(override) 합니다. EditboxOwner 는, Delegate를 호출한 UIComboBox 입니다. 작성된 편집 박스를 돌려줍니다.

  • UIToggleButton CreateCustomComboButton(UIComboBox ButtonOwner) - 다른 논리를 이용해 타글 재즈 악단 버튼을 작성할 필요가 있는 경우, 이것을 오버라이드(override) 합니다. ButtonOwner 는, Delegate를 호출한 UIComboBox 입니다. 작성된 토글버튼을 돌려줍니다.

  • UIList CreateCustomComboList(UIComboBox ListOwner) - 다른 논리를 이용해 리스트를 작성할 필요가 있는 경우, 이것을 오버라이드(override) 합니다. ListOwner 는 Delegate를 호출한 UIComboBox 입니다. 작성된 리스트를 돌려줍니다.

UICOMP_DRAWCOMPONENTS

  • OnFadeComplete(UIComp_DrawComponents Sender) - 페이드가 완료하면(자) 불려 갑니다. Sender 는 Delegate를 호출한 UIComp_DrawComponent 입니다.

UIDATAPROVIDER

  • OnDataProviderPropertyChange(UIDataProvider SourceProvider, optional name PropTag) - 프롭퍼티가 변경되면(자) 불려 갑니다. 대신에 사용할 수 있는 다른 콜백이 있으므로, 이것은 데이터 프로바이더와 데이터를 소유하는 데이터 스토어의 사이에 사용되도록(듯이) 설계되고 있습니다. SourceProvider 는, Delegate를 호출한 UIDataProvider, PropTag 는 변경된 프롭퍼티의 이름입니다.

UIDATASTORE

  • OnDataStoreValueUpdated(UIDataStore SourceDataStore, bool bValuesInvalidated, name PropertyTag, UIDataProvider SourceProvider, int ArrayIndex) - 이 데이터 스토어가 공개하는 값이 갱신되면(자) 불려 갑니다. 이것을 사용해, 이 데이터 스토어의 값이 갱신되었을 때에, 데이터 스토어의 사브스크라이바에 통지 일이 생깁니다. SourceDataStore 는 Delegate를 호출한 데이터 스토어입니다. bValuesInvalidated 는, 모든 데이터치가 무효이기 위해서(때문에) 완전 갱신이 필요한 경우에 True 가 됩니다. PropertyTag 는 갱신된 데이터 필드의 태그, SourceProvider 는 변경된 데이터를 포함한 데이터 스토어, ArrayIndex 는, 데이터 필드가 데이터 콜렉션의 경우는 변경된 배열 요소를 참조해, 그 외의 경우는 INDEX_NONE (-1)가 됩니다.

UIDATASTORE_GAMESTATE

  • OnRefreshDataFieldValue() - 데이터 필드가 갱신되면(자) 불려 갑니다.

UIEDITBOX

  • bool OnSubmitText(UIEditBox Sender, int PlayerIndex) - 편집 박스에 포커스가 있는 동안에, 유저가 Enter 를 누르든가 또는 UIKey_SubmitText 에 바인드 된 다른 액션을 실행하면(자) 불려 갑니다. Sender 는 이 Delegate를 호출한 편집 박스, PlayerIndex 은 Engine.GamePlayers 내의 인덱스로, 이벤트를 방아쇠 한 플레이어를 참조하고 있습니다. 종료시에 편집 박스를 클리어 하고 싶은 경우는 True 를 돌려줍니다.

UIEVENT

  • AllowEventActivation(int ControllerIndex, UIScreenObject InEventOwner, Object InEventActivator, bool bActivateImmediately, out const array IndicesToActivate) - UILIST

  • OnSubmitSelection(UIList Sender, optional int PlayerIndex = GetBestPlayerIndex()) - 리스트에 포커스가 있는 동안에, 유저가 Enter 를 누르든가 또는 UIKey_SubmitText 에 바인드 된 다른 액션을 실행하면(자) 불려 갑니다. Sender 는 이 Delegate를 호출한 리스트, PlayerIndex 은 Engine.GamePlayers 내의 인덱스로, 이벤트를 생성한 플레이어를 참조하고 있습니다.

  • OnListElementsSorted(UIList Sender) - 리스트의 요소가 소트 된 다음에 불려 갑니다. Sender 는 이 Delegate를 호출한 리스트입니다.

UIOPTIONLISTBASE

  • UIOptionListButton CreateCustomDecrementButton(UIOptionListBase ButtonOwner) - 독자적인 감소 (감 분) 버튼을 작성하고 싶은 경우는 이것을 오버라이드(override) 합니다. ButtonOwner 는 옵션으로, 이 Delegate를 호출한 리스트 베이스입니다. 작성한 UIOptionListButton 를 돌려줍니다.

  • UIOptionListButton CreateCustomIncrementButton(UIOptionListBase ButtonOwner) - 독자적인 인크리먼트(increment) (증분) 버튼을 작성하고 싶은 경우는 이것을 오버라이드(override) 합니다. ButtonOwner 는 옵션으로, 이 Delegate를 호출한 리스트 베이스입니다. 작성한 UIOptionListButton 를 돌려줍니다.

UISCREENOBJECT

  • NotifyActiveSkinChanged() - 액티브 스킨이 변경되면(자) 불려 갑니다. 이 위제트의 스타일을 재차 적용해, 모든 아이에게 통지를 프로파게이트 합니다. 이 Delegate는, 멤버 함수에 실제로 대입되었을 경우 밖에 불려 가지 않습니다.

  • bool OnRawInputKey(const out InputEventParameters EventParms) - 이것을 사용해, UnrealScript 로 실제의 입력 키명을 사용해 입력에 응답할 수가 있습니다. 이 위제트가 응답하는 입력 키 이벤트를 받아, 위제트가 이벤트를 처리할 수 있는 스테이트에 있는 경우에 불려 갑니다. 위제트가 입력을 받는 대상이 되는 키와 그 스테이트는, UI 에디터의 키 바인드 다이얼로그 (F8)로 관리합니다. 이 Delegate는 Kismet 의 전에 불려 갑니다. EventParams 에는 입력 이벤트 정보를 격납합니다. 반환값의 True 는, 이 입력 키가 처리된 이후의 처리가 모두 정지되는 것을 나타냅니다.

  • bool OnRawInputAxis(const out InputEventParameters EventParms) - OnRawInputKey 와 같다.

  • OnProcessInputKey(const out SubscribedInputEventParameters EventParms) - 이것을 사용해, UnrealScript 로 UI 의 입력 앨리어스(alias)를 사용해 입력에 응답할 수가 있습니다. 이 위제트가 응답하는 입력 키 이벤트를 받아, 위제트가 이벤트를 처리할 수 있는 스테이트에 있는 경우에 불려 갑니다. 위제트가 입력을 받는 대상이 되는 키와 그 스테이트는, UI 에디터의 키 바인드 다이얼로그 (F8)로 관리합니다. 이 Delegate는, Kismet의 전, 및 Native (네이티브) 코드가 입력을 처리하기 전에 불려 갑니다. EventParams 에는 이벤트 정보를 격납합니다. 반환값의 True 는, 이 키가 처리된 이후의 처리가 정지되는 것을 나타냅니다.

  • OnProcessInputAxis(const out SubscribedInputEventParameters EventParms) - OnProcessInputKey 와 같다.

  • NotifyPositionChanged(UIScreenObject Sender) - UIScreenObject 의 위치가 변경되면(자) 불려 갑니다. Sender 는, 위치가 변경된 UIScreenObject 입니다.

  • NotifyResolutionChanged(const out Vector2D OldViewportsize, const out Vector2D NewViewportSize) - 이 UIScreenObject 를 렌더링 하는 뷰포트가 해상도를 변경하면(자) 불려 갑니다. OldViewportSize 는 전의 해상도, NewViewportSize 는 새로운 해상도입니다.

  • NotifyActiveStateChanged(UIScreenObject Sender, int PlayerIndex, UIState NewlyActiveState, optional UIState PreviouslyActiveState) - 모든 액티베이션 논리가 발생한 후에, UIScreenObject 의 UIState 가 변경되면(자) 불려 갑니다. Sender 는 스테이트가 변경된 UIScreenObject, PlayerIndex 은 Engine.GamePlayers 내의 인덱스로, 이 스테이트를 액티브하게 한 플레이어를 참조하고 있습니다. NewlyActiveState 는 현재 액티브한 스테이트, PreviouslyActiveState 은 UIScreenObject 의 전의 스테이트입니다.

  • NotifyVisibilityChanged(UIScreenObject SourceWidget, bool bIsVisible) - UIScreenObject 의 시인성이 변경되면(자) 불려 갑니다. SourceWidget 는 시인성이 변경된 위제트로, UIScreenObject 가 보이는 경우는 bIsVisible 가 True 로 설정됩니다.

  • OnPreRenderCallBack() - 렌더링의 전에 불려 갑니다.

UISCROLLBAR

  • OnScrollActivity(UIScrollbar Sender, float PositionChange, optional bool bPositionMaxed = false) - 스크롤 액티버티가 검출되면(자) 불려 갑니다. Sender 는 이벤트를 송신한 UIScrollBar, PositionChange 는 스크롤 버튼에 의해 변경되는 단위치의 수입니다. 마커가 최대 위치에 이르렀을 경우는 bPositionMaxed 는 True 가 됩니다. 반환값은 현재로서는 사용되지 않습니다.

  • OnClickedScrollZone(UIScrollbar Sender, float PositionPerc, int PlayerIndex) - 유저가 스크롤 존의 임의의 위치를 클릭하면(자) 불려 갑니다. Sender 는 이벤트를 송신한 UIScrollBar, PositionPerc 는 0. f 로부터 1. f 까지의 범위의 값으로, 인크리먼트(increment) 버튼과 감소 버튼의 사이의 클릭 위치를 나타냅니다. 0. F 는 감소 버튼에 근처, 1. F 는 인크리먼트(increment) 버튼에 가까운 위치입니다. PlayerIndex 은 Engine.GamePlayers 내의 인덱스로, 이벤트를 방아쇠 한 플레이어를 참조하고 있습니다.

UISCROLLBARMARKERBUTTON

  • OnButtonDragged(UIScrollbarMarkerButton Sender, int PlayerIndex) - 유저가 버튼을 눌러, 마우스를 사용해 그것을 드러그 하면(자) 불려 갑니다. Sender 는 이 Delegate를 호출한 UIScrollbarMarkerButton, PlayerIndex 은 Engine.GamePlayers 내의 인덱스로, 이벤트를 방아쇠 한 플레이어를 참조하고 있습니다.

UITABBUTTON

  • IsActivationAllowed(UITabButton Sender, int PlayerIndex) - 이것을 사용해, 다른 UI 위제트에 이 버튼의 액티브화를 오버라이드(override) 시킬 수가 있습니다. Sender 는 액티브하게 된 UITabButton, PlayerIndex 은 Engine.GamePlayers 내의 인덱스로, 이벤트를 방아쇠 한 플레이어를 참조하고 있습니다.

UITABCONTROL

  • OnPageActivated(UITabControl Sender, UITabPage NewlyActivePage, int PlayerIndex) - 신규 페이지가 액티브하게 되면(자) 불려 갑니다. Sender 는 이 Delegate를 호출한 UITabControl, NewlyActivePage 는 현재 액티브한 UITabPage, PlayerIndex 은 Engine.GamePlayers 내의 인덱스로, 이벤트를 방아쇠 한 플레이어를 참조하고 있습니다.

  • OnPageInserted(UITabControl Sender, UITabPage NewPage, int PlayerIndex) - 신규 페이지가 삽입되면(자) 불려 갑니다. Sender 는 이 Delegate를 호출한 UITabControl, NewPage 는 새롭게 삽입된 UITabPage, PlayerIndex 은 Engine.GamePlayers 내의 인덱스로, 이벤트를 방아쇠 한 플레이어를 참조하고 있습니다.

  • OnPageRemoved(UITabControl Sender, UITabPage OldPage, int PlayerIndex) - 페이지가 삭제되면(자) 불려 갑니다. Sender 는 이 Delegate를 호출한 UITabControl, OldPage 는 삭제될 예정의 UITabPage, PlayerIndex 은 Engine.GamePlayers 내의 인덱스로, 이벤트를 방아쇠 한 플레이어를 참조하고 있습니다.

UITOOLTIP

  • ActivateToolTip(UIToolTip Sender) - 툴 힌트가 액티브하게 될 때 불려 갑니다. Sender 는 Delegate를 호출한 UIToolTip 입니다.

  • DeactivateToolTip() - 툴 힌트가 비액티브하게 될 때 불려 갑니다.

  • bool CanShowToolTip(UIToolTip Sender) - 툴 힌트가 표시 가능한가 어떤가를 자기 확인할 필요가 있을 때 불려 갑니다. 이것을 사용해, 다른 위제트로 툴 힌트가 표시되지 않게 할 수가 있습니다. Sender 는 대상의 UIToolTip 입니다. 툴 힌트를 표시하고 싶은 경우는 True 를 돌려줍니다.

ONLINEGAMEINTERFACEIMPL

  • OnFindOnlineGamesComplete(bool bWasSuccessful) - Engine.OnlineGameInterface.OnFindOnlineGamesComplete()와 같다.

  • OnCreateOnlineGameComplete(bool bWasSuccessful) - Engine.OnlineGameInterface.OnCreateOnlineGameComplete()와 같다.

  • OnDestroyOnlineGameComplete(bool bWasSuccessful) - Engine.OnlineGameInterface.OnDestroyOnlineGameComplete()와 같다.

  • OnCancelFindOnlineGamesComplete(bool bWasSuccessful) - Engine.OnlineGameInterface.OnCancelFindOnlineGamesComplete()와 같다.

  • OnJoinOnlineGameComplete(bool bWasSuccessful) - Engine.OnlineGameInterface.OnJoinOnlineGameComplete()와 같다.

  • OnRegisterPlayerComplete(bool bWasSuccessful) - Engine.OnlineGameInterface.OnRegisterPlayerComplete()와 같다.

  • OnUnregisterPlayerComplete(bool bWasSuccessful) - Engine.OnlineGameInterface.OnUnregisterPlayerComplete()와 같다.

  • OnStartOnlineGameComplete(bool bWasSuccessful) - Engine.OnlineGameInterface.OnStartOnlineGameComplete()와 같다.

  • OnEndOnlineGameComplete(bool bWasSuccessful) - Engine.OnlineGameInterface.OnEndOnlineGameComplete()와 같다.

  • OnArbitrationRegistrationComplete(bool bWasSuccessful) - Engine.OnlineGameInterface.OnArbitrationRegistrationComplete()와 같다.

  • OnGameInviteAccepted(OnlineGameSettings GameInviteSettings) - Engine.OnlineGameInterface.OnGameInviteAccepted()와 같다.

ONLINEGAMEINTERFACEGAMESPY

  • OnGameInviteAccepted(OnlineGameSettings GameInviteSettings) - Engine.OnlineGameInterface.OnGameInviteAccepted()와 같다.

  • OnRegisterPlayerComplete(bool bWasSuccessful) - Engine.OnlineGameInterface.OnRegisterPlayerComplete()와 같다.

  • OnUnregisterPlayerComplete(bool bWasSuccessful) - Engine.OnlineGameInterface.OnUnregisterPlayerComplete()와 같다.

ONLINESUBSYSTEMGAMESPY

  • OnLoginChange() - Engine.OnlinePlayerInterface.OnLoginChange()와 같다.

  • OnLoginCancelled() - Engine.OnlinePlayerInterface.OnLoginCancelled()와 같다.

  • OnMutingChange() - Engine.OnlinePlayerInterface.OnMutingChange()와 같다.

  • OnFriendsChange() - Engine.OnlinePlayerInterface.OnFriendsChange()와 같다.

  • OnLoginFailed(byte LocalUserNum, EOnlineServerConnectionStatus ErrorCode) - Engine.OnlinePlayerInterface.OnLoginFailed()와 같다.

  • OnLogoutCompleted(bool bWasSuccessful) - Engine.OnlinePlayerInterface.OnLogoutCompleted()와 같다.

  • OnReadProfileSettingsComplete(bool bWasSuccessful) - Engine.OnlinePlayerInterface.OnReadProfileSettingsComplete()와 같다.

  • OnWriteProfileSettingsComplete(bool bWasSuccessful) - Engine.OnlinePlayerInterface.OnWriteProfileSettingsComplete()와 같다.

  • OnReadFriendsComplete(bool bWasSuccessful) - Engine.OnlinePlayerInterface.OnReadFriendsComplete()와 같다.

  • OnPlayerTalking(UniqueNetId Player) - Engine.OnlineVoiceInterface.OnPlayerTalking()와 같다.

  • OnRecognitionComplete() - Engine.OnlineVoiceInterface.OnRecognitionComplete()와 같다.

  • OnReadOnlineStatsComplete(bool bWasSuccessful) - Engine.OnlineStatsInterface.OnReadOnlineStatsComplete()와 같다.

  • OnFlushOnlineStatsComplete(bool bWasSuccessful) - Engine.OnlineStatsInterface.OnFlushOnlineStatsComplete()와 같다.

  • OnLinkStatusChange(bool bIsConnected) - Engine.OnlineSystemInterface.OnLinkStatusChange()와 같다.

  • OnExternalUIChange(bool bIsOpening - Engine.OnlineSystemInterface.OnExternalUIChange()와 같다.

  • OnControllerChange(int ControllerId, bool bIsConnected) - Engine.OnlineSystemInterface.OnControllerChange()와 같다.

  • OnConnectionStatusChange(EOnlineServerConnectionStatus ConnectionStatus) - Engine.OnlineSystemInterface.OnConnectionStatusChange()와 같다.

  • OnStorageDeviceChange() - Engine.OnlineSystemInterface.OnStorageDeviceChange()와 같다.

  • OnCreateOnlineAccountCompleted(EOnlineAccountCreateStatus ErrorStatus) - Engine.OnlineAccountInterface.OnCreateOnlineAccountCompleted()와 같다.

  • OnKeyboardInputComplete(bool bWasSuccessful) - Engine.OnlinePlayerInterface.OnKeyboardInputComplete()와 같다.

  • OnAddFriendByNameComplete(bool bWasSuccessful) - Engine.OnlinePlayerInterface.OnAddFriendByNameComplete()와 같다.

  • OnFriendInviteReceived(byte LocalUserNum, UniqueNetId RequestingPlayer, string RequestingNick, string Message) - Engine.OnlinePlayerInterface.OnFriendInviteReceived()와 같다.

  • OnReceivedGameInvite(byte LocalUserNum, string InviterName) - Engine.OnlinePlayerInterface.OnReceivedGameInvite()와 같다.

  • OnJoinFriendGameComplete(bool bWasSuccessful) - Engine.OnlinePlayerInterface.OnJoinFriendGameComplete()와 같다.

  • OnFriendMessageReceived(byte LocalUserNum, UniqueNetId SendingPlayer, string SendingNick, string Message) - Engine.OnlinePlayerInterface.OnJoinFriendGameComplete()와 같다.

  • OnRegisterHostStatGuidComplete(bool bWasSuccessful) - Engine.OnlineStatsInterface.OnRegisterHostStatGuidComplete()와 같다.

  • OnReadGameNewsCompleted(bool bWasSuccessful) - Engine.OnlineNewsInterface.OnReadGameNewsCompleted()와 같다.

  • OnReadContentAnnouncementsCompleted(bool bWasSuccessful) - Engine.OnlineNewsInterface.OnReadContentAnnouncementsCompleted()와 같다.

ONLINESUBSYSTEMLIVE

  • OnLoginChange() - Engine.OnlinePlayerInterface.OnLoginChange()와 같다.

  • OnLoginCancelled() - Engine.OnlinePlayerInterface.OnLoginCancelled()와 같다.

  • OnMutingChange() - Engine.OnlinePlayerInterface.OnMutingChange()와 같다.

  • OnFriendsChange() - Engine.OnlinePlayerInterface.OnFriendsChange()와 같다.

  • OnLoginFailed(byte LocalUserNum, EOnlineServerConnectionStatus ErrorCode) - Engine.OnlinePlayerInterface.OnLoginFailed()와 같다.

  • OnLogoutCompleted(bool bWasSuccessful) - Engine.OnlinePlayerInterface.OnLogoutCompleted()와 같다.

  • OnKeyboardInputComplete(bool bWasSuccessful) - Engine.OnlinePlayerInterface.OnKeyboardInputComplete()와 같다.

  • OnLinkStatusChange(bool bIsConnected) - Engine.OnlineSystemInterface.OnLinkStatusChange()와 같다.

  • OnExternalUIChange(bool bIsOpening) - Engine.OnlineSystemInterface.OnExternalUIChange()와 같다.

  • OnControllerChange(int ControllerId, bool bIsConnected) - Engine.OnlineSystemInterface.OnControllerChange()와 같다.

  • OnConnectionStatusChange(EOnlineServerConnectionStatus ConnectionStatus) - Engine.OnlineSystemInterface.OnConnectionStatusChange()와 같다.

  • OnStorageDeviceChange() - Engine.OnlineSystemInterface.OnStorageDeviceChange()와 같다.

  • OnFindOnlineGamesComplete(bool bWasSuccessful) - Engine.OnlineGameInterface.OnFindOnlineGamesComplete()와 같다.

  • OnCreateOnlineGameComplete(bool bWasSuccessful) - Engine.OnlineGameInterface.OnCreateOnlineGameComplete()와 같다.

  • OnDestroyOnlineGameComplete(bool bWasSuccessful) - Engine.OnlineGameInterface.OnDestroyOnlineGameComplete()와 같다.

  • OnCancelFindOnlineGamesComplete(bool bWasSuccessful) - Engine.OnlineGameInterface.OnCancelFindOnlineGamesComplete()와 같다.

  • OnJoinOnlineGameComplete(bool bWasSuccessful) - Engine.OnlineGameInterface.OnJoinOnlineGameComplete()와 같다.

  • OnRegisterPlayerComplete(bool bWasSuccessful) - Engine.OnlineGameInterface.OnRegisterPlayerComplete()와 같다.

  • OnUnregisterPlayerComplete(bool bWasSuccessful) - Engine.OnlineGameInterface.OnUnregisterPlayerComplete()와 같다.

  • OnReadProfileSettingsComplete(bool bWasSuccessful) - Engine.OnlinePlayerInterface.OnReadProfileSettingsComplete()와 같다.

  • OnWriteProfileSettingsComplete(bool bWasSuccessful) - Engine.OnlinePlayerInterface.OnWriteProfileSettingsComplete()와 같다.

  • OnDeviceSelectionComplete(bool bWasSuccessful) - Engine.OnlinePlayerInterfaceEx.OnDeviceSelectionComplete()와 같다.

  • OnUnlockAchievementComplete(bool bWasSuccessful) - Engine.OnlinePlayerInterfaceEx.OnUnlockAchievementComplete()와 같다.

  • OnProfileDataChanged() - Engine.OnlinePlayerInterfaceEx.OnProfileDataChanged()와 같다.

  • OnStartOnlineGameComplete(bool bWasSuccessful) - Engine.OnlineGameInterface.OnStartOnlineGameComplete()와 같다.

  • OnEndOnlineGameComplete(bool bWasSuccessful) - Engine.OnlineGameInterface.OnEndOnlineGameComplete()와 같다.

  • OnArbitrationRegistrationComplete(bool bWasSuccessful) - Engine.OnlineGameInterface.OnArbitrationRegistrationComplete()와 같다.

  • OnReadFriendsComplete(bool bWasSuccessful) - Engine.OnlinePlayerInterface.OnReadFriendsComplete()와 같다.

  • OnGameInviteAccepted(OnlineGameSettings InviteSettings) - Engine.OnlineGameInterface.OnGameInviteAccepted()와 같다.

  • OnContentChange() - Engine.OnlineContentInterface.OnContentChange()와 같다.

  • OnReadContentComplete(bool bWasSuccessful) - Engine.OnlineContentInterface.OnReadContentComplete()와 같다.

  • OnQueryAvailableDownloadsComplete(bool bWasSuccessful) - Engine.OnlineContentInterface.OnQueryAvailableDownloadsComplete()와 같다.

  • OnPlayerTalking(UniqueNetId Player) - Engine.OnlineVoiceInterface.OnPlayerTalking()와 같다.

  • OnRecognitionComplete() - Engine.OnlineVoiceInterface.OnRecognitionComplete()와 같다.

  • OnReadOnlineStatsComplete(bool bWasSuccessful) - Engine.OnlineStatsInterface.OnReadOnlineStatsComplete()와 같다.

  • OnFlushOnlineStatsComplete(bool bWasSuccessful) - Engine.OnlineStatsInterface.OnFlushOnlineStatsComplete()와 같다.

  • OnAddFriendByNameComplete(bool bWasSuccessful) - Engine.OnlinePlayerInterface.OnAddFriendByNameComplete()와 같다.

  • OnFriendInviteReceived(byte LocalUserNum, UniqueNetId RequestingPlayer, string RequestingNick, string Message) - Engine.OnlinePlayerInterface.OnFriendInviteReceived()와 같다.

  • OnReceivedGameInvite(byte LocalUserNum, string InviterName) - Engine.OnlinePlayerInterface.OnReceivedGameInvite()와 같다.

  • OnJoinFriendGameComplete(bool bWasSuccessful) - Engine.OnlinePlayerInterface.OnJoinFriendGameComplete()와 같다.

  • OnFriendMessageReceived(byte LocalUserNum, UniqueNetId SendingPlayer, string SendingNick, string Message) - Engine.OnlinePlayerInterface.OnFriendMessageReceived()와 같다.

  • OnRegisterHostStatGuidComplete(bool bWasSuccessful) - Engine.OnlineStatsInterface.OnRegisterHostStatGuidComplete()와 같다.

UTBOT

  • bool CustomActionFunc(UTBot B) - 보트가 CustomAction 스테이트내에 있을 때 불려 갑니다. B 는 이 Delegate를 호출한 보트입니다.

UTDATASTORE_ONLINESTATS

  • OnStatsReadComplete(bool bWasSuccessful) - 통계 읽기가 완료하면(자) 불려 갑니다. 이 비동기 호출이 적절히 종료했을 경우, bWasSuccessful 는 True 로 설정됩니다.

UTDEPLOYEDACTOR

  • OnDeployableUsedUp(actor ChildDeployable) - 데프로이 (배치) 된 먼지가 파괴되려고 할 경우에 불려 갑니다. ChildDeployable 는 자기 파괴하는 먼지입니다.

UTDRAWMAPPANEL

  • OnActorSelected(Actor Selected, UTPlayerController SelectedBy) - 노드가 더블 클릭 되면(자) 불려 갑니다. Selected 는 선택된 먼지, SelectedBy 는 선택을 실시한 UTPlayerController 입니다.

UTEXPLOSIONLIGHT

  • OnLightFinished(UTExplosionLight Light) - 라이트가 종료해, 미츠루를 추방하지 않게 되었을 때에 불려 갑니다. Light 는 이 Delegate를 호출한 먼지입니다.

UTKACTOR

  • OnBreakApart() - 물리 먼지가 분열할 경우에 불려 갑니다.

  • bool OnEncroach(actor Other) - 물리 먼지가 엔크로치 (침해) 될 때 불려 갑니다. Other 는, 이 물리 먼지를 침해하는 먼지입니다.

UTMISSIONGRI

  • OnBinkMovieFinished() - 무비 재생이 종료하면(자) 불려 갑니다.

UTSCOREBOARDPANEL

  • OnSelectionChange(UTScoreboardPanel TargetScoreboard, UTPlayerReplicationInfo PRI) - 선택이 변경되면(자) 불려 갑니다. TargetScoreboard 는 이 Delegate를 호출한 기록 게시판, PRI 는 선택된 플레이어 복제 정보 i입니다.

UTSIMPLEIMAGELIST

  • bool OnDrawItem(UTSimpleImageList SimpleList, int ItemIndex, float Xpos, out float Ypos) - 아이템이 그려질 때 불려 갑니다. SimpleList 는 Delegate를 호출한 리스트, ItemIndex 는 List 배열의 인덱스, Xpos 는 아이템의 묘화 위치의 X 좌표치, Ypos 는 같은 위치의 Y 좌표입니다. 디폴트의 방법으로 아이템을 묘화 하는 경우는 False 를 돌려줍니다.

  • OnItemChosen(UTSimpleImageList SourceList, int SelectedIndex, int PlayerIndex) - 리스트내의 항목이 선택되었을 때에 불려 갑니다. SourceList 는 이 Delegate를 호출한 리스트, SelectedIndex 는 새롭게 선택된 인덱스, PlayerIndex 은 Engine.GamePlayers 내의 인덱스로, 이벤트를 방아쇠 한 플레이어를 참조하고 있습니다.

  • OnSelectionChange(UTSimpleImageList SourceList, int NewSelectedIndex) - 선택 인덱스가 변경되면(자) 불려 갑니다. SourceList 는 Delegate를 호출한 리스트, NewSelectedIndex 는 신규 선택된 인덱스입니다.

UTSIMPLELIST

  • bool OnDrawItem(UTSimpleList SimpleList, int ItemIndex, float XPos, out float Ypos) - 아이템이 그려질 때 불려 갑니다. SimpleList 는 Delegate를 호출한 리스트, ItemIndex 는 List 배열의 인덱스, Xpos 는 아이템의 묘화 위치의 X 좌표치, Ypos 는 같은 위치의 Y 좌표입니다. 디폴트의 방법으로 아이템을 묘화 하는 경우는 False 를 돌려줍니다.

  • bool OnDrawSelectionBar(UTSimpleList SimpleList, float Ypos) - 선택 바가 그려질 때 불려 갑니다. SimpleList 는 Delegate를 호출한 리스트, Ypos 는 아이템을 묘화 하는 위치의 Y 좌표입니다. 디폴트의 방법으로 선택 바를 묘화 하는 경우는 False 를 돌려줍니다.

  • bool OnPostDrawSelectionBar(UTSimpleList SimpleList, float YPos, float Width, float Height) - 선택 바가 그려진 다음에 불려 갑니다. SimpleList 는 Delegate를 호출한 리스트, Ypos 는 선택 바가 그려진 위치의 Y 좌표, Width 는 그려진 선택 바의 폭, Height 는 같이 그 높이입니다. 반환값을 사용하고 있습니다.

  • OnItemChosen(UTSimpleList SourceList, int SelectedIndex, int PlayerIndex) - 리스트내의 항목이 선택되었을 때에 불려 갑니다. SourceList 는 이 Delegate를 호출한 리스트, SelectedIndex 는 새롭게 선택된 인덱스, PlayerIndex 은 Engine.GamePlayers 내의 인덱스로, 이벤트를 방아쇠 한 플레이어를 참조하고 있습니다.

  • OnSelectionChange(UTSimpleList SourceList, int NewSelectedIndex) - 선택 인덱스가 변경되면(자) 불려 갑니다. SourceList 는 Delegate를 호출한 리스트, NewSelectedIndex 는 신규 선택된 인덱스입니다.

UTSKELCONTROL_CANTILEVERBEAM

  • vector EntireBeamVelocity() - 빔 전체의 이동 속도를 돌려줍니다.

UTSKELCONTROL_TURRETCONSTRAINED

  • OnTurretStatusChange(bool bIsMoving) - Turret (포대)의 스테이터스가 변경되면(자) 불려 갑니다. 이동하고 있다고 판단되었을 경우, bIsMoving 는 True 로 설정됩니다.

UTSLOWVOLUME

  • OnDeployableUsedUp(actor ChildDeployable) - UTGame.UTDeployedActor.OnDeployableUsedUp()와 같다.

UTTABPAGE.UC

  • OnTick(float DeltaTime) - 틱마다 불려 갑니다. DeltaTime 는, 각 틱이벤트의 간격 (초)입니다.

UTUIFRONTEND_BINDKEYS360

  • MarkDirty() - 프로파일을 dirty 와 마크 하는 목적으로 불려 갑니다.

UTUIFRONTEND_BINDKEYSPC

  • MarkDirty() - 프로파일을 dirty 와 마크 하는 목적으로 불려 갑니다.

UTUIFRONTEND_BINDKEYSPS3

  • MarkDirty() - 프로파일을 dirty 와 마크 하는 목적으로 불려 갑니다.

UTUIFRONTEND_BOTSELECTION

  • OnAcceptedBots() - 유저가 현재의 보트 선택 설정을 받아들이면(자) 불려 갑니다.

UTUIFRONTEND_SETTINGSPANELS

  • OnMarkProfileDirty(optional bool bDirty = true) - 유저 이외의 누군가에게 따라 프로파일이 편집되어 옵션치가 변경되면(자) 불려 갑니다. 프로파일 dirty 와 마크 하려면 bDirty 를 True 로 설정합니다.

  • OnNotifyOptionChanged(UIScreenObject InObject, name OptionName, int PlayerIndex) - 유저가 옵션 리스트내의 몇개의 옵션을 변경하면(자) 불려 갑니다. InObject 는 이 Delegate를 호출한 UIScreenObject, OptionName 는 변경된 옵션의 이름, PlayerIndex 은 Engine.GamePlayers 내의 인덱스로, 이벤트를 방아쇠 한 플레이어를 참조하고 있습니다. ---+++UTUIFRONTEND_WEAPONPREFERENCE

  • MarkDirty() - 프로파일을 dirty 와 마크 하는 목적으로 불려 갑니다.

UTUIMENULIST

  • OnSubmitSelection(UIObject Sender, optional int PlayerIndex = GetBestPlayerIndex()) - 포커스가 리스트에 있을 때, 유저가 Enter 키 또는 UIKey_SubmitListSelection 에 바인드 되고 있는 다른 액션 버튼을 누르면(자) 불려 갑니다. Sender 는 이 Delegate를 호출한 UIObject, PlayerIndex 은 Engine.GamePlayers 내의 인덱스로, 이벤트를 방아쇠 한 플레이어를 참조하고 있습니다.

UTUIOPTIONLIST

  • OnOptionFocused(UIScreenObject InObject, UIDataProvider OptionProvider) - 옵션이 포커스를 얻으면(자) 불려 갑니다. InObject 는 이 Delegate를 호출한 UIScreenObject, OptionProvider 는 옵션의 데이터 프로바이더입니다.

  • OnOptionChanged(UIScreenObject InObject, name OptionName, int PlayerIndex) - 옵션이 변경되면(자) 불려 갑니다. InObject 는, 이 Delegate를 호출한 UIScreenObject, PlayerIndex 은 Engine.GamePlayers 내의 인덱스로, 이벤트를 방아쇠 한 플레이어를 참조하고 있습니다.

  • OnAcceptOptions(UIScreenObject InObject, int PlayerIndex) - 옵션 리스트의 [Accept] (적용) 버튼이 밀렸을 때에 불려 갑니다. InObject 는, 이 Delegate를 호출한 UIScreenObject, PlayerIndex 은 Engine.GamePlayers 내의 인덱스로, 이벤트를 방아쇠 한 플레이어를 참조하고 있습니다.

UTUIPANEL_MAPCYCLE

  • OnMapSelected() - 유저가 이 페이지로 맵을 선택하면(자) 불려 갑니다.

UTUIPANEL_SINGLEMAP

  • OnMapSelected() - 유저가 이 페이지로 맵을 선택하면(자) 불려 갑니다.

UTUIPRESSBUTTON

  • OnBeginPress(UIScreenObject InObject, int InPlayerIndex) - 유저가 버튼을 누르는 것과 동시에 불려 갑니다. InObject 는, 이 Delegate를 호출한 UIScreenObject, InPlayerIndex 는 Engine.GamePlayers 내의 인덱스로, 이벤트를 방아쇠 한 플레이어를 참조하고 있습니다.

  • OnEndPress(UIScreenObject InObject, int InPlayerIndex) - 유저가 버튼 위에서 왼쪽 mouse button를 해방하면(자) 불려 갑니다. InObject 는, 이 Delegate를 호출한 UIScreenObject, InPlayerIndex 는 Engine.GamePlayers 내의 인덱스로, 이벤트를 방아쇠 한 플레이어를 참조하고 있습니다.

UTUISCENE

  • OnShowAnimationEnded() - 신의 Show animation (애니메이션 표시) 가 종료되었을 때에 불려 갑니다.

  • OnHideAnimationEnded() - 신의 Hide animation (애니메이션비표시) 가 종료되었을 때에 불려 갑니다.

  • OnSceneOpened(UIScene OpenedScene, bool bInitialActivation) - 최상정도의 장면을 비표시로 한 다음에 장면이 열렸을 때에 불려 갑니다. OpenedScene 는 이 Delegate를 호출한 장면입니다. 연 장면이 최초로 액티브하게 되었을 때는, bInitialActivation 가 True 로 설정됩니다.

UTUISCENE_MESSAGEBOX

  • OnSelection(UTUIScene_MessageBox MessageBox, int SelectedOption, int PlayerIndex) - 이용 가능한 선택사항으로부터 유저가 항목을 선택하면(자) 불려 갑니다. MessageBox 는 이 함수를 호출한 UTUIScene_MessageBox, SelectionOption 는 선택된 항목, PlayerIndex 은 Engine.GamePlayers 내의 인덱스로, 이벤트를 방아쇠 한 플레이어를 참조하고 있습니다.

  • OnClosed() - 메시지 박스가 완전하게 닫혀지면(자) 불려 갑니다.

  • bool OnMBInputKey(const out InputEventParameters EventParms) - 메시지 박스가 임의의 입력을 받으면(자) 불려 갑니다. EventParams 에는 입력 이벤트 정보를 격납합니다. 입력 데이터가 처리필 보고로, 그 이상의 처리가 불필요한 경우는 True 를 돌려줍니다.

UTUISCENE_SAVEPROFILE

  • OnSaveFinished() - 프로파일의 보존이 완료하면(자) 불려 갑니다.

UTUITABPAGE_CHARACTERPART

  • transient OnPartSelected(ECharPart PartType, string InPartID) - 유저가 이 페이지로 파츠를 선택하면(자) 불려 갑니다. PartType 에는 선택된 파츠의 정보, PartID 는 지정 PartType 의 ID 입니다.

  • transient OnPreviewPartChanged(ECharPart PartType, string InPartID) - 유저가 이 페이지상에서 선택 파츠를 변경하면(자) 불려 갑니다. PartType 에는 선택된 파츠의 정보, PartID 는 지정 PartType 의 ID 입니다.

UTUITABPAGE_FINDQUICKMATCH

  • OnSearchComplete(bool bWasSuccessful) - 검색이 완료하면(자) 불려 갑니다. 이 비동기 호출이 정상적으로 완료했을 경우, bWasSuccessful 는 True 로 설정됩니다.

UTUITABPAGE_GAMEMODESELECTION

  • OnGameModeSelected(string InGameMode, string InDefaultMap, string GameSettingsClass, bool bSelectionSubmitted) - 게임 모드가 이 페이지로부터 선택되면(자) 불려 갑니다. InGameMode 는 선택된 게임 모드, InDefaultMap 는 선택된 게임 모드의 디폴트 맵, GameSettingsClass 는 게임 설정의 클래스명입니다. 선택 항목이 송신되고 있는 경우, bSelectionSubmitted 는 True 로 설정됩니다.

UTUITABPAGE_MAPSELECTION

  • OnMapSelected() - 유저가 이 페이지로 맵을 선택하면(자) 불려 갑니다.

UTUITABPAGE_MUTATORS

  • OnAcceptMutators(string InEnabledMutators) - 유저가 현재의 뮤테이타셋트를 받아들이면(자) 불려 갑니다. InEnabledMutators 는 승낙된 뮤테이타의 리스트입니다.

UTUITABPAGE_OPTIONS

  • OnAcceptOptions(UIScreenObject InObject, int PlayerIndex) - 현재의 옵션이 받아들여지면(자) 불려 갑니다. InObject 는, 이 Delegate를 호출한 UIScreenObject, PlayerIndex 은 Engine.GamePlayers 내의 인덱스로, 이벤트를 방아쇠 한 플레이어를 참조하고 있습니다.

  • OnOptionChanged(UIScreenObject InObject, name OptionName, int PlayerIndex) - This is called when one of the options on the page has changed. 페이지상의 옵션의 1 개가 변경되면(자) 불려 갑니다. InObject 는 이 Delegate를 호출한 UIScreenObject, OptionName 는 옵션의 이름, PlayerIndex 은 Engine.GamePlayers 내의 인덱스로, 이벤트를 방아쇠 한 플레이어를 참조하고 있습니다.

  • OnOptionFocused(UIScreenObject InObject, UIDataProvider OptionProvider) - 옵션의 1 개가 포커스를 얻으면(자) 불려 갑니다. InObject 는 이 Delegate를 호출한 UIScreenObject, OptionProvider 는 포커스를 얻은 옵션의 데이터 프로바이더입니다.

UTUITABPAGE_SERVERBROWSER

  • transient OnBack() - 유저가 돌아올 때 불려 갑니다.

  • transient OnSwitchedGameType() - 유저가 combobox를 사용해 게임 타입을 변경하면(자) 불려 갑니다.

  • transient OnPrepareToSubmitQuery(UTUITabPage_ServerBrowser Sender) - 유저가 서버 쿠에리-를 실행할 경우에 불려 갑니다. Sender 는 이 Delegate를 호출한 UTUITabPage_ServerBrowser 입니다.

UTUITABPAGE_SERVERFILTER

  • transient OnSwitchedGameType() - 유저가 게임 타입을 변경하면(자) 불려 갑니다.

튜토리얼 12.1 - 란담이벤트뮤테이타, 파트 I: 입문 & 클래스의 초기설정

이하의 일련의 튜토리얼에 따라, 대전중에 플레이어의 랜덤 이벤트를 작성하는 뮤테이타를 작성합니다.

*1. * 임의의 텍스트 문자 편집기를 열어, UTMutator_RandomEvents.UC 라는 이름의 신규 파일을 작성합니다.

*2. * 스크립트의 클래스 선언으로부터 개시합니다. 뮤테이타를 작성하므로, Engine 내의 Mutator 클래스의 서브 클래스를 작성합니다. 선두행은 다음과 같이 됩니다.

class UTMutator_RandomEvent extends UTMutator;

*3. * 작업을 진행시키기 전에, Unreal Tournament 3 을 좀 더 재미있게 하는 이벤트를 검토할 필요가 있습니다만, 시간을 절약하기 위해서, 여기에서는 나의 아이디어를 몇개인가 소개합니다.

  • 모든 플레이어가 리디마 (redeemer)를 받는다.
  • 플레이어 전원을 조사해, 현재의 체력이 50 이상의 경우에 아모를 준다.
  • 맵상의 모든 아이템의 재스폰을 강제한다.

*4. * defaultproperties 블록도 작성합시다. 이 뮤테이타에는 글로벌 변수가 없기 때문에, 내용이 없는 것 처럼 보입니다.

defaultproperties
{
   Name=”Default__UTMutator_RandomEvent”
}

여기서 이 클래스를 컴파일 할 수 있습니다.

튜토리얼 12.2 - 란담이벤트뮤테이타, 파트 II: 타이밍 논리

다음에, 타이밍 코드를 쓸 필요가 있습니다. 뮤테이타 본체의 임무는, 60 초 마다 랜덤 이벤트를 방아쇠 하는 것입니다.

*1. * PostBeginPlay() 함수의 오버라이드(override)로부터 시작합니다. PostBeginPlay()는 레벨이 초기화되어 준비가 완료해, 게임 개시전, 로드 직후에 불려 가는 것을 생각해 내 주세요.

function PostBeginPlay()
{
   super.PostBeginPlay();
}

*2. * 랜덤 이벤트의 방아쇠에는 이벤트 타이머를 사용합니다.

function PostBeginPlay()
{
   super.PostBeginPlay();

   SetTimer(60. f, true);
}

*3. * 다음에, Timer 라는 이름의 새로운 함수를 작성합니다.

function Timer()
{
}

뮤테이타가 PostBeginPlay()를 호출하면(자), 60 초 마다 방아쇠 하는 새로운 타이머를 작성해 할당합니다. 타이머 정지의 지시를 받을 때까지 연속 루프 하도록(듯이), True 인수가 제공되고 있습니다. 디폴트에서는, SetTimer()는 이 함수를 호출한 인스턴스내에서 Timer()라고 하는 함수를 호출합니다.

튜토리얼 12.3 - 란담이벤트뮤테이타, 파트 III: Delegate의 사용

*1. * Delegate 함수를 작성했으므로, 다음은 Timer 함수를 변경합니다.

delegate RandomEvent();

function Timer()
{
   RandomEvent();
}

Timer() 함수가 불려 가면(자), Delegate RandomEvent()가 불려 갑니다.

*2. * 다음에, 전술한 개개의 랜덤 이벤트의 논리를 처리하는 3 개의 함수를 작성해, 실행되는 이벤트의 변경 논리에도 대처합니다.

function GiveBonusArmor()
{
}

function GiveRedeemerToAll()
{
}

function ForceRespawn()
{
}

*3. * 다음에, 이벤트의 랜덤인 선택을 처리하기 위해서, Timer() 함수를 변경합니다.

function Timer()
{
   switch (Rand(3))
   {
      case 0:
         RandomEvent = GiveBonusArmor;
         break;

      case 1:
         RandomEvent = GiveRedeemerToAll;
         break;

      case 2:
         RandomEvent = ForceRespawn;
         break;

      default:
         RandomEvent = GiveBonusArmor;
         break;
   }

   RandomEvent();
}

상기의 코드로부터, Timer()가 불려 갈 때마다, switch 내에서 랜덤 호출이 실행되는 것이 압니다. 랜덤화의 결과에 응해 RandomEvent()를 몇개의 함수에 할당하고 나서, RandomEvent()를 호출해 Delegate를 할당한 함수를 순서에 호출하고 있습니다.

튜토리얼 12.4 - 란담이벤트뮤테이타, 파트 IV: GIVEBONUSARMOR()

*1. * WorldInfo 인스턴스내에 있는 이테레이타 (반복자) 함수를 사용하면(자), 월드내에 기존 하는 모든 폰을 반복 처리할 수가 있습니다. 이 반복자를 사용해, 맵내의 모든 프레이야폰을 찾아냅니다. GiveBonusArmor() 함수를 다음과 같이 변경합시다.

function GiveBonusArmor()
{
   local UTPawn P;

   foreach WorldInfo.AllPawns(class'UTPawn', P)
   {
   }
}

이것에 의해, GiveBonusArmor() 함수가 실행되면(자), 레벨내에서 UTPawn 클래스인가, 또는 UTPawn 의 아이 클래스의 멤버인 폰을 모두 반복 처리해, 그 결과를 로컬 변수 P 에 출력합니다.

*2. * 다음에, 반복자로부터 얻을 수 있던 폰을 필터 해, 목적의 조건에 일치하는 것을 선택할 필요가 있습니다. 이 조건이란, 폰이 보너스 아모의 보수를 받으려면 , 그 체력이 50 이상이 아니면 안되는, 이라는 것입니다. 거기서, 다음과 같이 조건문의 if 스테이트먼트를 추가합니다.

function GiveBonusArmor()
{
   local UTPawn P;

   foreach WorldInfo.AllPawns(class'UTPawn', P)
   {
      if (P ! = none && P.Health >= 50)
      {
      }
   }
}

반복자가 P 를 돌려주는 경우, 이것이 none 인 것은 통상 있을 수 없습니다만, 항상 none 체크를 실시하는 것은 좋은 일입니다. 이것이 좋은 습관인 이유는, 이 체크는 몇 안 되는 코스트로 Access None 에러를 완벽하게 방지하기 (위해)때문에입니다. none 체크의 다음에, 폰의 체력을 체크하고 있습니다.

*3. * Unreal Tournament 3 에는 플레이어에게 3 종류의 아모를 줄 수가 있습니다. 체력이 많은 플레이어에게 주는 아모를 늘릴 수가 있습니다.

function GiveBonusArmor()
{
   local UTPawn P;

   foreach WorldInfo.AllPawns(class'UTPawn', P)
   {
      if (P ! = none && P.Health >= 50)
      {
         P.ThighpadArmor = Max(class'UTArmorPickup_Thighpads'. default.ShieldAmount, P.ThighpadArmor);

         if (P.Health >= 80)
            P.VestArmor = Max(class'UTArmorPickup_Vest'. default.ShieldAmount, P.VestArmor);

         if (P.Health >= 90)
            P.HelmetArmor = Max(class'UTArmorPickup_Helmet'. default.ShieldAmount, P.HelmetArmor);
      }
   }
}

이것에 의해, 최초의 체력 요건 (50 이상)을 만 한 플레이어에게는, 항상 코뿔소 패드 (허벅지 패드)가 주어집니다. 체력이 80 점이상의 경우는 베스트 아모도 제공해, 90 점이상의 플레이어에게는 헬멧 아모도 제공합니다.

*4. * 사운드도 추가해, 플레이어가 보너스를 받을 때 무엇이 들리도록(듯이) 합니다. 다음과 같이 함수를 변경합시다.

function GiveBonusArmor()
{
   local UTPawn P;
   local SoundCue S;

   foreach WorldInfo.AllPawns(class'UTPawn', P)
   {
      if (P ! = none && P.Health >= 50)
      {
         P.ThighpadArmor = Max(class'UTArmorPickup_Thighpads'. default.ShieldAmount, P.ThighpadArmor);
         S = class'UTArmorPickup_Thighpads'. default.PickupSound;

         if (P.Health >= 80)
         {
            P.VestArmor = Max(class'UTArmorPickup_Vest'. default.ShieldAmount, P.VestArmor);
            S = class'UTArmorPickup_Vest'. default.PickupSound;
         }

         if (P.Health >= 90)
         {
            P.HelmetArmor = Max(class'UTArmorPickup_Helmet'. default.ShieldAmount, P.HelmetArmor);
            S = class'UTArmorPickup_Helmet'. default.PickupSound;
         }

         if (S ! = none)
            P.PlaySound(S);
      }
   }
}

로컬 SoundCue 변수를 추가해, 아모를 줄 때 이것을 설정할 수 있도록(듯이) 했습니다. 플레이어가 여러 가지의 요건을 채운 결과에 맞추어, 이 변수를 재생하고 싶은 SoundCue 의 1 개로 설정해 있습니다. 마지막으로, 변수 S 에 할당할 수 있었던 사운드 큐가 있을지 어떨지를 체크해 (디폴트 변수에, 항상 none 이외의 값을 할당할 필요는 없는 점을 생각해 내 주세요), 할당할 수 있고 있는 경우는, 보너스를 준 폰에 그것을 재생하도록(듯이) 지시하고 있습니다.

튜토리얼 12.5 - 란담이벤트뮤테이타, 파트 V: GIVEREDEEMERTOALL

*1. * GiveBonusArmor() 함수와 같게, 이 함수도 월드내의 모든 폰을 반복 처리하는 함수의 작성으로부터 개시합시다.

function GiveRedeemerToAll()
{
   locale UTPawn P;

   foreach WorldInfo.AllPawns(class'UTPawn', P)
   {
   }
}

*2. * 플레이어는 전원 리디마를 받으므로, 그 조건을 쓸 필요는 없습니다. 리디마를 주는 만큼 합니다. 이것에는 리디마의 목록 항목을 스폰 하고 나서, 각 폰에 그것을 제공하지 않으면 안되어, 거기서 리디마를 스폰 해, 변수에 참조를 할당해 사용할 수 있도록(듯이) 합니다. 상기의 함수를 다음과 같이 변경합니다.

function GiveRedeemerToAll()
{
   local UTPawn P;
   local UTWeap_Redeemer_Content R;

   foreach WorldInfo.AllPawns(class'UTPawn', P)
   {
      R = Spawn(class'UTWeap_Redeemer_Content');
   }
}

다만, 이것만으로는 그다지 성과는 얻을 수 있지 않습니다. 리디마가 어디에서 스폰 되는지 모르기 때문에, 운이 있고 1 명만이 우연히도 그것들을 모두 획득해 버릴 가능성이 있습니다 (실제로는, 플레이어는 무기 그 자체는은 아니고, 무기의 픽업을 수집하므로 그 가능성은 아마 없습니다만).

*3. * 리디마를 스폰 했으므로, 다음은 이것을 플레이어에게 줄 필요가 있습니다. 최초로, 리디마를 주는 플레이어가 존재할지 어떨지를 실제로 체크합니다. 폰의 존재를 조사하는 김에, 그것이 유효한 폰일지 어떨지도 조사해 둡시다. 그리고, 적절한 파라미터를 지정해 리디마를 스폰 합니다.

function GiveRedeemerToAll()
{
   local UTPawn P;
   local UTWeap_Redeemer_Content R;

   foreach WorldInfo.AllPawns(class'UTPawn', P)
   {
      if (P ! = none && P.bCanPickupInventory && P.Health > 0 && P.Controller ! = none)
         R = Spawn(class'UTWeap_Redeemer_Content', P, , P.Location, P.Rotation);
   }
}

조건절은 꽤 복잡하게 보이므로, 여기서 확인해 둡시다.

  • P 는 none 일지 어떨지?
  • P 는 목록 아이템을 수집할 수 있을지 어떨지?
  • P 에 체력이 있을까?
  • P 는 유효한 콘트롤러를 가지고 있을까?

*4. * 여기서 점구플레이어에게 리디마를 줄 수가 있습니다. 이것은 다음과 같이 실시합니다.

function GiveRedeemerToAll()
{
   local UTPawn P;
   local UTWeap_Redeemer_Content R;

   foreach WorldInfo.AllPawns(class'UTPawn', P)
   {
      if (P ! = none && P.bCanPickupInventory && P.Health > 0 && P.Controller ! = none)
      {
         R = Spawn(class'UTWeap_Redeemer_Content', P, , P.Location, P.Rotation);

         if (R ! = none)
         {
            if (WorldInfo.Game.PickupQuery(P, class'UTWeap_Redeemer_Content', R))
               R.GiveTo(P);
            else
               R.Destroy();
         }
      }
   }
}

한번 더, R 가 실제로 스폰 되었는지 어떠했는지를 체크합니다. 다양한 이유로써 스폰이 실패에 끝나는 일이 있어, R 가 none 가 될 가능성이 있기 (위해)때문에입니다. Access None 에러를 회피하기 위해서 R 의 유효성을 확인합니다. 마지막에 한번 더 체크해, 폰이 리디마를 수집할 수 있을지 어떨지를 확인합니다. 수집할 수 있는 경우는, 폰에 이것을 건네주어, 스폰 한 리디마를 파괴합니다.

튜토리얼 12.6 - 란담이벤트뮤테이타, 파트 VI: FORCERESPAWN

*1. * 최초로 실행 해야 할것의 1 개는, 동적 배열을 작성해, 거기에 픽업 팩토리의 참조를 삽입하는 작업입니다. 뮤테이타크라스에 글로벌 동적 배열을 추가하는 것으로부터 시작합시다.

class UTMutator_RandomEvent extends UTMutator;

private var array<UTPickupFactory> PickupFactories;

이 글로벌 변수를 프라이빗으로 한 이유는, 다른 클래스가 배열을 변경할 수 없게 하기 (위해)때문에입니다.

*2. * 픽업 팩토리 참조를 격납하는 글로벌 변수가 생겼으므로, 다음으로 PostBeginPlay()를 변경해, 이 동적 배열에 삽입합니다.

function PostBeginPlay()
{
   local UTPickupFactory pickup_factory;

   super.PostBeginPlay();
   SetTimer(60. f, true);

   foreach AllActors(class'UTPickupFactory', pickup_factory)
   {
   }
}

이것은 UTPickupFactory 또는 그 서브 클래스의 어느 쪽인가에 속하는 모든 먼지를 대상으로, 레벨 전체를 반복 처리합니다.

*3. * 이 반복 처리내에서, 각 결과를 검증하고 나서 격납하기로 하겠습니다.

function PostBeginPlay()
{
   local UTPickupFactory pickup_factory;

   super.PostBeginPlay();
   SetTimer(60. f, true);

   foreach AllActors(class'UTPickupFactory', pickup_factory)
   {
      if (pickup_factory ! = none)
         PickupFactories.AddItem(pickup_factory);
   }
}

사용하는 픽업 팩토리의 동적 배열을 이와 같이 설정한 (뜻)이유입니다만, 설정의 이유는 이 AllActors 반복자가 매우 늦고, 강제적으로 재스폰 시키고 싶을 때에 항상 이것을 사용하면(자) 쓸데없게 되기 (위해)때문에입니다.

*4. * 다음에, ForceRespawn 함수를 씁니다.

function ForceRespawn()
{
   local int i;

   for (i = 0; i < PickupFactories.length; ++i)
   {
   }
}

*5. * 마지막으로, 모든 픽업 팩토리를 리셋트 합니다.

function ForceRespawn()
{
   locale int i;

   for (i = 0; i < PickupFactories.length; ++i)
      if (PickupFactories[i] ! = none)
         PickupFactories[i]. Reset();
}

튜토리얼 12.6 - 란담이벤트뮤테이타, 실험

*1. * 코드를 컴파일 해, Unreal Tournament 3 을 기동합니다.

*2. * 로그인하는지, 오프 라인 플레이를 선택합니다.

*3. * [Instant Action] (인스턴트 액션) 게임을 선택합니다.

*4. * 게임 타입에 [Deathmatch] (데스 매치)를 선택해, 임의의 맵을 선택합니다.

*5. * [Settings] (설정) 패널에 진행되어,[Mutators] 버튼을 누릅니다.


그림 12.1 - Mutators 버튼을 누르면(자), Mutator 의 선택 및 설정용의 화면이 열립니다.

*6. * [Enabled Mutators] (유효한 뮤테이타)의 리스트에 [UTMutator_RandomEvent] 뮤테이타를 추가합니다.


그림 12.2 - 뮤테이타가 추가되었습니다.

*7. * 당분간 대기하면(자), 3 개의 랜덤 이벤트중 한쪽이 발생하는 것이 알 수 있습니다. 여기에서는 보수로 해서 쉴드(shield)가 주어졌습니다.


그림 12.3 - 플레이어에게 쉴드(shield)가 주어졌습니다.

이 튜토리얼에서는, 1 개의 인스턴스에 있어서의 Delegate의 작성 및 사용 방법으로 접했습니다. 이 상태로부터 Mutator 를 기능확장 해, 머지않아 발생할 이벤트를 간단하게 작성할 수도 있습니다. 타이밍 논리의 보수는 그다지 걱정할 필요가 없기 때문에, 이 방법으로 유연하게 일을 옮길 수가 있습니다.

튜토리얼 12.8 - 무기의 뮤테이타, 파트 I: 입문 & 클래스의 초기설정

이 튜토리얼에서는, 플레이어가 발사 타입을 변경할 수 있는 무기를 작성합니다. 각 발사 타입은 각각 기존의 무기 (로켓 발사기, Phrack 캐논 (고사포), 쇼크 라이플, 바이오 라이플)을 시뮬레이트 합니다. 로켓 발사기 (rocket launcher) 스타일은 즉발성의 폭약, Phrack 캐논 (flak cannon) 스타일은 대공포화 (flak)도 발사하는 즉발성의 폭약, 쇼크 라이플 (shock rifle) 스타일은 즉발성의 쇼크 재즈 악단, 바이오 라이플 스타일은 goo blob (한 덩어리)도 떨어뜨리는 즉발성의 점착성 폭약이 됩니다.

*1. * 최초로,..\MasteringUnrealScript\Classes 폴더에, 신규 Unrealscript 파일 (UTWeap_MultiEnforcer.uc, MultiEnforcer_Base.uc, MultiEnforcer_Bio.uc, MultiEnforcer_Flak.uc, MultiEnforcer_Rocket.uc 및 MultiEnforcer_Shock.uc)을 작성합니다.

*2. * UTWeap_MultiEnforcer 의 클래스 및 디폴트 프롭퍼티를 선언합니다. 새로운 무기의 설정에 필요한 작업을 가능한 한 줄이고 싶기 때문에, UTWeap_Enforcer 의 서브 클래스로 합니다.

class UTWeap_MultiEnforcer extends UTWeap_Enforcer

defaultproperties
{
   Name=”Default__ UTWeap_MultiEnforcer”
}

*3. * MultiEnforcer_Base 의 클래스 및 디폴트 프롭퍼티를 선언합니다.

class MultiEnforcer_Base extends Object;

defaultproperties
{
   Name=”Default__MultiEnforcer_Base"
}

*4. * MultiEnforcer_Bio 의 클래스 및 디폴트 프롭퍼티를 선언합니다. 기본적인 기능은 MultiEnforcer_Base 내에서 처리하므로, MultiEnforcer_Base 의 서브 클래스로 합니다.

class MultiEnforcer_Bio extends MultiEnforcer_Base;

defaultproperties
{
   Name="Default__MultiEnforcer_Bio"
}

*5. * MultiEnforcer_Flak 의 클래스 및 디폴트 프롭퍼티를 선언합니다.

class MultiEnforcer_Flak extends MultiEnforcer_Base;

defaultproperties
{
   Name="Default__MultiEnforcer_Flak"
}

*6. * MultiEnforcer_Rocket 의 클래스 및 디폴트 프롭퍼티를 선언합니다.

class MultiEnforcer_Rocket extends MultiEnforcer_Base;

defaultproperties
{
   Name="Default__MultiEnforcer_Rocket"
}

*7. * MultiEnforcer_Shock 의 클래스 및 디폴트 프롭퍼티를 선언합니다.

class MultiEnforcer_Shock extends MultiEnforcer_Base;

defaultproperties
{
   Name="Default__MultiEnforcer_Shock"
}

*8. * 새로운 스크립트를 모두 보존합니다.

튜토리얼 12.8 - 무기의 뮤테이타, 파트 II: UTWEAP_MULTIENFORCER 의 설정

이 클래스는 무기 그 자체를 나타내, 무기로 관련하는 것을 거의 모두 처리합니다. 이것에는, 플레이어가 무기를 짓고 있도록(듯이) 메쉬를 표시하는 등의 비주얼 관계, 무기에 의해 생성되는 사운드 효과, 무기의 발사의 관리등이 포함됩니다. UTWeap_Enforcer 를 서브 클래스화했으므로, 작업의 대부분은 이미 완료하고 있습니다. 거기서, 이쪽이 의도했던 대로 무기가 동작하도록(듯이) 변경하는 작업에 시간을 소비할 수가 있습니다.

*1. * 이 무기는 4 개의 발사 클래스 (MultiEnforcer_Bio, MultiEnforcer_Flak, MultiEnforcer_Rocket 및 MultiEnforcer_Shock)에 의존합니다. 모두 MultiEnforcer_Base 의 서브 클래스이므로, MultiEnforcer_Base 와의 종속 관계를 설정할 뿐입니다.

class UTWeap_MultiEnforcer extends UTWeap_Enforcer
   dependson(MultiEnforcer_Base);

*2. * 발사 타입의 데이터를 격납하기 위해서, 글로벌 변수를 몇개인가 확보할 필요가 있습니다.

var private array<MultiEnforcer_Base> FireTypes;
var private int CurrentIndex;
var const array< class<MultiEnforcer_Base> > FireTypeClasses;

FireTypes 는, MultiEnforcer_Base 의 오브젝트 인스턴스를 보관 유지하는 프라이빗 배열로, MultiEnforcer_Base 의 아이 클래스도 보관 유지합니다. FireTypes 가 사적인의는, 다른 클래스의 액세스를 블록 하기 (위해)때문에입니다. CurrentIndex 는, FireTypes 내의 현재의 인덱스를 보관 유지하는 정수로, 이것으로 플레이어가 사용하고 싶은 발사 타입을 설정합니다. CurrentIndex 가 사적인의는, 다른 클래스의 액세스를 블록 하기 (위해)때문에입니다. FireTypeClasses 는, 무기를 사용할 수 있는 발사 타입의 클래스를 보관 유지하는 배열입니다. 이것은 정수이며, 실행중에 이 배열을 변경할 필요는 없습니다. 「> >」의 사이의 공백 문자에 주의해 주세요. 이 공백이 없으면 UnrealScript 컴파일러는 에러를 생성하므로 잊지 말아 주세요.

*3. * 디폴트 프롭퍼티의 정의를 추가합시다.

defaultproperties
{
   CurrentIndex=0
   FireTypeClasses(0) =class'MultiEnforcer_Rocket'
   FireTypeClasses(1) =class'MultiEnforcer_Shock'
   FireTypeClasses(2) =class'MultiEnforcer_Flak'
   FireTypeClasses(3) =class'MultiEnforcer_Bio'
   InventoryGroup=3
   ItemName="MultiEnforcer"
   PickupMessage="MultiEnforcer"
   FiringStatesArray(1)="WeaponSwitching"
   Name="Default__UTWeap_MultiEnforcer"
   ObjectArchetype=UTWeap_Enforcer'UTGame.Default__UTWeap_Enforcer'
}

CurrentIndex 는 최초 0 으로 설정합니다. FireTypeClasses 의 배열 항목은 모두 실행시에 일정이므로, 여기서 정의해 둡니다. InventoryGroup 는 친클래스에서 정의되는 변수로, 이 무기의 소속 그룹을 결정합니다. ItemName 는 무기의 이름입니다. PickupMessage 는, 무기의 수집시에 나오는 메세지로, 여기에서는 우선 「MultiEnforcer」라고 부르고 있습니다. FiringStatesArray 는 발사 모드의 실행시의 무기의 스테이트명의 리스트입니다. WeaponSwitching 라고 하는 이차적인 발사 스테이트도 작성해, 이 배열에 포함해 둡니다. Name 는 이 오브젝트의 이름으로, 다른 클래스에서 참조하는 경우에 사용합니다. ObjectArchetype 는 이 오브젝트의 친클래스에서, 다른 디폴트 프롭퍼티의 대부분은 여기로부터 파생시킵니다.

*4. * 무기의 초기설정을 처리하는 PostBeginPlay() 함수의 작성을 시작합시다.

function PostBeginPlay()
{
   super.PostBeginPlay();
}

*5. * 이 무기가 적절히 동작하도록(듯이), PostBeginPlay()에 발사 타입의 오브젝트의 인스턴스를 작성할 필요가 있습니다.

function PostBeginPlay()
{
   local int i;

   super.PostBeginPlay();

   if (FireTypeClasses.length > 0)
   {
      for (i = 0; i < FireTypeClasses.length; ++i)
         if (FireTypeClasses[i] ! = none)
            FireTypes.AddItem(new FireTypeClasses[i]);
   }
}

여기에서는, 최초로 FireTypeClasses 배열에 무엇인가 항목이 포함되어 있는지 어떤지를 조사합니다. 아무것도 존재하지 않으면, 그 전에 진행되는 의미가 없기 때문입니다. 다음에, 배열을 반복 처리해 각 발사 타입의 새로운 오브젝트 인스턴스를 작성하는 것과 동시에, 그것들을 FireTypes 배열에 추가합니다. 여기에서는 키워드 new 가 사용되고 있습니다만, 그 이유는 최종적으로는 이러한 클래스를 Actor 는 아니고 오브젝트로부터 파생하는 (거기에 따라 Spawn()를 사용할 수 있다) 유익입니다.

*6. * 최종적으로 Delegate를 사용해 발사 타입 오브젝트를 바인드 하므로, 메모리 리크 하지 않는 방법으로 이것을 클린 업 할 필요가 있습니다(섹션 12.5 의 Delegate와 메모리에 관한 설명을 참조해 주세요). 그 때문에(위해), Destroyed() 함수를 오버라이드(override) 합니다. Destroyed()는, Destroy()에 의해 인스턴스가 파괴되었을 때, 또는 Unreal Engine 에 의해 인스턴스가 파괴되었을 때에 자동적으로 불려 갑니다.

simulated function Destroyed()
{
   super.Destroyed();
}

*7. * 오브젝트 인스턴스를 파괴할 수 없기 때문에, 여기서 필요한 것은, 인스턴스 참조를 소거해, Unreal Engine 의 garbage collection에 의해 메모리로부터 그것들을 모두 삭제할 수 있도록(듯이) 하는 것입니다.

simulated function Destroyed()
{
   local int i;

   super.Destroyed();

   if (FireTypes.length > 0)
   {
      for (i = 0; i < FireTypes.length; ++i)
         FireTypes[i] = none;
   }
}

*8. * 메모리 문제의 처리가 끝났으므로, 무기의 발사 방식의 변경하러 진행됩니다. Enforcer 는 히트 (명중) 시에 무기를 스캔 해 설정되어 그 때문에 무기가 트레이스를 완료하면(자) ProcessInstantHit()를 호출합니다. 여기에서는 이것을 오버라이드(override) 해, 히트의 처리가 필요한 때의 무기의 행동하는 방법을 신규 논리로서 추가합니다.

simulated function ProcessInstantHit(byte FiringMode, ImpactInfo Impact)
{
}

이 특수한 케이스에서는 친측의 논리를 발생시킬 필요가 없기 때문에, 슈퍼 클래스의 호출은 추가하고 있습니다.

*9. * 다음에 Delegate를 선언합니다. 이 Delegate는, 무기가 히트를 처리할 필요가 있을 때 불려 갑니다.

delegate OnProcessInstantHit(UTWeapon Weapon, byte FiringMode, ImpactInfo Impact);

simulated function ProcessInstantHit(byte FiringMode, ImpactInfo Impact)
{
   OnProcessInstantHit(self, FiringMode, Impact);
}

*10. * 이 무기가 발사되었을 때에 무엇인가 일어나는지를 처리했으므로, 다음의 태스크로서 플레이어가 발사 타입을 변경하는 방법을 처리하는 코드를 추가합니다. 디폴트 프롭퍼티로, 2 번째의 발사 스테이트를 WeaponSwitching 로 변경하는 행을 추가한 것을 기억하고 있습니까? 이 디폴트 프롭퍼티는, 이 이차적인 발사 모드가 액티브하게 되면(자) 무기가 들어가는 스테이트의 이름입니다. 통상 이것은 오른쪽 mouse button에 바인드 되고 있으므로, 플레이어에 의한 발사 타입의 변환은, 이것을 사용해 처리합니다.

simulated state WeaponSwitching
{
}

*11. * 이 스테이트내에서 다소의 관리 작업을 실시할 필요가 있으므로, UTWeap_Enforcer 내의 WeaponBursting 의 내부에 같은 함수의 부분집합을 추가합니다.

simulated state WeaponSwitching
{
   simulated function TrackShotCount();

   simulated function RefireCheckTimer();

   simulated function bool TryPutDown()
   {
      bWeaponPutDown = true;
      return true;
   }
}

*12. * 무기는 타이머를 이용해 애니메이션을 처리합니다. 타이머를 사용하면, 예를 들면 Tick() 내에서 실시되는 고비용의 추적에 의지하는 일 없이, UnrealScript 의 내부에 이벤트 베이스의 아키텍쳐를 작성할 수 있습니다. 플레이어가 발사 타입을 변경했을 때에, 플레이어가 엔포서를 아래에 두어, 탄창을 교환해 재충전하는 동작을 발생시키고 싶습니다만, 꼭 좋은 것에, Unreal Tournament 3 에는 엔포서에 의한 이러한 애니메이션이 있습니다.

simulated state WeaponSwitching
{
   simulated function TrackShotCount();

   simulated function RefireCheckTimer();

   simulated function bool TryPutDown()
   {
      bWeaponPutDown = true;
      return true;
   }

   simulated function BeginState(name PrevStateName)
   {
      TimeWeaponPutDown();
   }
}

TimeWeaponPutDown()는 친클래스내에 있는 함수로, 타이머의 방아쇠를 설정할 뿐만 아니라, 무기를 두는 애니메이션을 재생합니다. 이 함수는 UTWeapon 및 Weapon 에 실장되고 있어, 간단하게 설명하면(자), 무기를 두는 애니메이션을 처리해, 애니메이션이 종료하면(자) WeaponIsDown()를 호출합니다.

*13. * 무기를 내리면(자) WeaponIsDown()가 방아쇠 되게 되었으므로, 다음은 재충전의 애니메이션과 동시에 무기가 원래의 위치로 돌아가도록(듯이) 합니다. 이 단계에서, 발사 타입 변경 스테이트도 처리할 필요가 있습니다.

simulated state WeaponSwitching
{
   simulated function TrackShotCount();
   simulated function RefireCheckTimer();

   simulated function bool TryPutDown()
   {
      bWeaponPutDown = true;
      return true;
   }

   simulated function WeaponIsDown()
   {
      ClearTimer('WeaponIsDown');
      bLoaded = false;
      TimeWeaponEquipping();
      CurrentIndex++;

      if (CurrentIndex >= FireTypes.length)
         CurrentIndex = 0;

      AssignFireType();
   }

   simulated function BeginState(name PrevStateName)
   {
      TimeWeaponPutDown();
   }
}

여기에서는, 이 스테이트에 고유의 WeaponIsDown() 함수를 추가했습니다. 이 함수가 불려 가는 것과 동시에, 함수에 관련지을 수 있었던 타이머를 클리어 합니다. bLoaded 는 False 로 설정되어 있습니다만, 그것은 UTWeap_Enforcer 이고 이것을 False 로 설정하면(자) 무기의 재충전 애니메이션이 재생되기 (위해)때문에입니다. 다음에, TimeWeaponPutDown()와 같은 TimeWeaponEquipping()을 호출해, 애니메이션을 재생해, 타이머에 근거해 함수를 방아쇠 합니다. 이 함수 WeaponEquipped()라고 이름 붙이고 있습니다. 게다가 CurrentIndex 변수를 인크리먼트(increment) 해 사용중의 발사 타입의 인덱스를 비켜 놓아, CurrentIndex 가 FireTypes 배열의 길이와 같은가 그 이상으로 되면(자) 리셋트 하고 있습니다. 이것에 의해, 플레이어가 사용하는 루프 선택 시스템을 작성합니다. 다음은 AssignFireType()라고 하는 미정도리의 함수를 호출합니다만, 다른 장소에서 CurrentIndex 에 근거하는 발사 타입의 할당을 처리해야 하는 가능성이 있으므로, 이 개소는 다른 함수내에서 실시했습니다.

*14. * 마지막으로, 무기의 재충전 애니메이션이 종료하면(자), 액티브 스테이트에 돌아올 필요가 있습니다. 이것을 실시하지 않으면 무기는 이 스테이트로부터 영구히 나올 수 있지 않게 되어, 다시 발사할 수 없게 됩니다.

simulated state WeaponSwitching
{
   simulated function TrackShotCount();
   simulated function RefireCheckTimer();

   simulated function bool TryPutDown()
   {
      bWeaponPutDown = true;
      return true;
   }

   simulated function WeaponIsDown()
   {
      ClearTimer('WeaponIsDown');
      bLoaded = false;
      TimeWeaponEquipping();
      CurrentIndex++;

      if (CurrentIndex >= FireTypes.length)
         CurrentIndex = 0;

      AssignFireType();
   }

   simulated function WeaponEquipped()
   {
      ClearTimer('WeaponEquipped');
      bLoaded = true;
      GotoState('Active');
   }

   simulated function BeginState(name PrevStateName)
   {
      TimeWeaponPutDown();
   }
}

관련 타이머를 클리어 할 뿐(만큼)의 WeaponEquipped()라고 하는 새로운 함수를 추가해, bLoaded 를 True 로 설정하고 나서 (즉, 플레이어가 다른 무기로 바꾸고 나서 이것에 돌아왔을 때에, 재충전 애니메이션을 재생하지 않게 한다), 액티브 스테이트에 진행됩니다.

*15. * 다음은 AssignFireType() 함수의 정의입니다. 이 함수가 실시하는 것은, CurrentIndex 가 FireTypes 내의 인덱스로서 유효하게 사용할 수 있을지 어떨지, 및 그 CurrentIndex 가 참조하고 있는 FireType 가 유효한가 어떤가의 체크입니다.

function AssignFireType()
{
   if (CurrentIndex >= 0 && CurrentIndex < FireTypes.length && FireTypes[CurrentIndex] ! = none && FireTypes[CurrentIndex]. WeaponClass ! = none)
   {
   }
}

*16. * 이 체크에는 더할 나위 없습니다만, 이것이 실제로 적용되기 위해서(때문에) 여기서 Delegate에 대입할 필요가 있습니다.

function AssignFireType()
{
   if (CurrentIndex >= 0 && CurrentIndex < FireTypes.length && FireTypes[CurrentIndex] ! = none && FireTypes[CurrentIndex]. WeaponClass ! = none)
      OnProcessInstantHit = FireTypes[CurrentIndex]. OnProcessInstantHit;
}

무기를 최초로 작성했을 때는, CurrentIndex 가 0 에서도 발사 타입에 할당할 수 있지 않은 것을 생각해 내 주세요. 그 때문에, PostBeginPlay() 함수에서도 AssignFireType()를 호출해 이것을 실시합니다.

simulated function PostBeginPlay()
{
   local int i;

   super.PostBeginPlay();

   if (FireTypeClasses.length > 0)
   {
      for (i = 0; i < FireTypeClasses.length; ++i)
         if (FireTypeClasses[i] ! = none)
            FireTypes.AddItem(new FireTypeClasses[i]);
   }

   AssignFireType();
}

*17. * 이상으로 필요한 논리가 모두 완성했습니다만, 이 무기가 어느 발사 타입으로 설정되었는지를 플레이어에게 전할 방법이 없습니다. 다행히도, HUD 에 정보를 표시하기 위해서 이용할 수 있는 훅이, Weapon 내에서 작성되고 있습니다.

simulated function ActiveRenderOverlays(HUD H)
{
   super.ActiveRenderOverlays(H);
}

*18. * 선택되고 있는 발사 타입을 플레이어에게 알리기 위해서(때문에), 발사 타입이 재현 하는 무기의 아이콘을 묘화 합니다. 이 아이콘이 그려지는 것은, 탄창 위치의 HUD 위입니다. 그 때문에, 탄창 뼈의 위치를 취득해, HUD 상에 투사 해 유효한 HUD 좌표를 획득하고 나서, 렌더링 할 필요가 있습니다. 최초로, 최초의 무기 메쉬의 골격 메쉬 컴퍼넌트에 액세스 합니다.

simulated function ActiveRenderOverlays(HUD H)
{
   local SkeletalMeshComponent SkelMesh;

   super.ActiveRenderOverlays(H);

   if (H ! = none && H.Canvas ! = none)
   {
      SkelMesh = SkeletalMeshComponent(Mesh);

      if (SkelMesh ! = none)
      {
      }
   }
}

*19. * 골격 메쉬에 액세스 했으므로, 다음은 Bullet5 라고 하는 뼈의 위치를 취득해 (Unreal 에디터를 기동해, Animation 에디터내에서 골격 메쉬를 참조하면(자), 뼈의 이름을 알 수 있습니다), HUD 에 투사 합니다. 아이콘을 그릴 때 해상도에 근거해 퍼센트치를 산출해, 최적인 폭과 높이를 계산하면(자), 최고의 결과를 얻을 수 있습니다. 먼저 계산해 둔 위치에 근거해 아이콘의 중심을 결정하고 나서, 화면에 아이콘을 그립니다. Weapon 클래스에는 아이콘의 좌표가 격납되어 아이콘 자체는 합성 아이콘 texture의 내부에 격납됩니다.

simulated function ActiveRenderOverlays(HUD H)
{
   local SkeletalMeshComponent SkelMesh;
   local vector BoneLocation;
   local float i_w;
   local float i_h;
   local color CanvasColor;

   super.ActiveRenderOverlays(H);

   if (H ! = none && H.Canvas ! = none)
   {
      SkelMesh = SkeletalMeshComponent(Mesh);

      if (SkelMesh ! = none)
      {
         BoneLocation = H.Canvas.Project(SkelMesh.GetBoneLocation('Bullet5', 0));
         i_w = H.Canvas.ClipX * 0.05f;
         i_h = H.Canvas.ClipY * 0.05f;

         CanvasColor = H.Canvas.DrawColor;
         H.Canvas.DrawColor =  class'UTHUD'. default.WhiteColor;
         H.Canvas.SetPos(BoneLocation.x - (i_w * 0.5f), BoneLocation.y - (i_h * 0.5f));
         H.Canvas.DrawTile(class'UTHUD'. default.IconHudTexture, i_w, i_h, FireTypes[CurrentIndex]. WeaponClass.default.IconCoordinates.U, FireTypes[CurrentIndex]. WeaponClass.default.IconCoordinates.V, FireTypes[CurrentIndex]. WeaponClass.default.IconCoordinates.UL, FireTypes[CurrentIndex]. WeaponClass.default.IconCoordinates.VL);
         H.Canvas.DrawColor = CanvasColor;
      }
   }
}

튜토리얼 12.8 - 무기의 뮤테이타, 파트 III: MULTIENFORCER_BASE

기본 클래스 그 자체는 복잡하지 않고, 어디까지나 다른 클래스가 서브 클래스화하기 위한 기본 클래스에 지나지 않습니다.

*1. * UTWeap_MultiEnforcer 가 화면에 아이콘을 렌더링 할 경우에, Weapon 클래스의 발사 타입을 요구합니다만, 이것을 글로벌 정수 변수로서 정의해, 서브 클래스의 디폴트 프롭퍼티로 정의할 수 있도록(듯이) 합니다.

var const class<UTWeapon> WeaponClass;

*2. * UTWeap_MultiEnforcer 가 그 Delegate에의 할당에 사용하는 함수의 정의가 필요합니다.

function OnProcessInstantHit(UTWeapon Weapon, byte FiringMode, ImpactInfo Impact);

튜토리얼 12.8 - 무기의 뮤테이타, 파트 IV: MULTIENFORCER_BIO

이것은 바이오 발사 타입입니다. 총알이 무언가에 명중하면(자), bio goo (점성의 바이오 약제)가 발생해, bio goo 를 떨어뜨립니다.

*1. * 최초로, 디폴트 프롭퍼티에 WeaponClass 를 설정합니다.

defaultproperties
{
   WeaponClass=class'UTWeap_BioRifle_Content'
   Name="Default__MultiEnforcer_Bio"
}

*2. * 다음에 OnProcessInstantHit() 함수를 오버라이드(override) 합니다.

function OnProcessInstantHit(UTWeapon Weapon, byte FiringMode, ImpactInfo Impact)
{
}

*3. * 임펙트로부터 유효한 HitActor 를 얻을 수 있었는지 어떠했는지의 체크가 필요합니다.

function OnProcessInstantHit(UTWeapon Weapon, byte FiringMode, ImpactInfo Impact)
{
   if (Impact.HitActor ! = none)
   {
   }
}

*4. * 폭발의 파티클 효과의 작성으로부터 시작합시다.

function OnProcessInstantHit(UTWeapon Weapon, byte FiringMode, ImpactInfo Impact)
{
   local EmitterSpawnable es;

   if (Impact.HitActor ! = none)
   {
      es = Weapon.Spawn(class'EmitterSpawnable', , , Impact.HitLocation);

      if (es ! = none)
         es.SetTemplate(ParticleSystem'WP_BioRifle.Particles.P_WP_Bio_Alt_Blob_POP');
   }
}

Weapon 를 사용해 EmitterSpawnable 를 스폰 합니다만, 이것은 Spawn() 함수가 Object는 아니고 Actor 에 있기 때문입니다.

*5. * 다음에, 폭발음을 추가합니다.

function OnProcessInstantHit(UTWeapon Weapon, byte FiringMode, ImpactInfo Impact)
{
   local EmitterSpawnable es;

   if (Impact.HitActor ! = none)
   {
      Weapon.PlaySound(SoundCue'A_Weapon_BioRifle.Weapon.A_BioRifle_FireAltImpactExplode_Cue', , , , Impact.HitLocation);
      es = Weapon.Spawn(class'EmitterSpawnable', , , Impact.HitLocation);

      if (es ! = none)
         es.SetTemplate(ParticleSystem'WP_BioRifle.Particles.P_WP_Bio_Alt_Blob_POP');
   }
}

*6. * 다음에, 방사상의 (radial) 데미지를 추가합니다.

function OnProcessInstantHit(UTWeapon Weapon, byte FiringMode, ImpactInfo Impact)
{
   local EmitterSpawnable es;

   if (Impact.HitActor ! = none)
   {
      Weapon.PlaySound(SoundCue'A_Weapon_BioRifle.Weapon.A_BioRifle_FireAltImpactExplode_Cue', , , , Impact.HitLocation);
      es = Weapon.Spawn(class'EmitterSpawnable', , , Impact.HitLocation);

      if (es ! = none)
         es.SetTemplate(ParticleSystem'WP_BioRifle.Particles.P_WP_Bio_Alt_Blob_POP');

      Weapon.HurtRadius(class'UTProj_BioGlob'. default.Damage, class'UTProj_BioGlob'. default.DamageRadius, class'UTProj_BioGlob'. default.MyDamageType, class'UTProj_BioGlob'. default.MomentumTransfer, Impact.HitLocation);
   }
}

*7. * 마지막으로, bio goo 를 스폰 해 이 발사 타입을 완성시킵니다.

function OnProcessInstantHit(UTWeapon Weapon, byte FiringMode, ImpactInfo Impact)
{
   local int g;
   local UTProj_BioShot NewGlob;
   local EmitterSpawnable es;

   if (Impact.HitActor ! = none)
   {
      Weapon.PlaySound(SoundCue'A_Weapon_BioRifle.Weapon.A_BioRifle_FireAltImpactExplode_Cue', , , , Impact.HitLocation);
      es = Weapon.Spawn(class'EmitterSpawnable', , , Impact.HitLocation);

      if (es ! = none)
         es.SetTemplate(ParticleSystem'WP_BioRifle.Particles.P_WP_Bio_Alt_Blob_POP');

      for (g = 0; g < 6; ++g)
      {
         NewGlob = Weapon.Spawn(class'UTProj_BioGlobling', , , Impact.HitLocation);

         if (NewGlob ! = None)
            NewGlob.Velocity = (FRand() * 150. f) * (VRand() * 0.8f);
      }

      Weapon.HurtRadius(class'UTProj_BioGlob'. default.Damage, class'UTProj_BioGlob'. default.DamageRadius, class'UTProj_BioGlob'. default.MyDamageType, class'UTProj_BioGlob'. default.MomentumTransfer, Impact.HitLocation);
   }
}

튜토리얼 12.8 - 무기의 뮤테이타, 파트 V: MULTIENFORCER_FLAK

이것은 Phrack 발사 타입입니다. 총알이 무언가에 명중하면(자), 고사포탄 (flak shell)을 폭발시켜 파편을 일면에 발합니다.

*1. * 최초로, 디폴트 프롭퍼티에 WeaponClass 변수를 설정합니다.

defaultproperties
{
   WeaponClass=class'UTWeap_FlakCannon'
   Name="Default__MultiEnforcer_Flak"
}

*2. * 다음에 OnProcessInstantHit() 함수를 오버라이드(override) 합니다.

function OnProcessInstantHit(UTWeapon Weapon, byte FiringMode, ImpactInfo Impact)
{
}

*3. * 임펙트로부터 유효한 HitActor 를 얻을 수 있었는지 어떠했는지의 체크가 필요합니다.

function OnProcessInstantHit(UTWeapon Weapon, byte FiringMode, ImpactInfo Impact)
{
   if (Impact.HitActor ! = none)
   {
   }
}

*4. * 폭발의 파티클 효과를 추가합니다.

function OnProcessInstantHit(UTWeapon Weapon, byte FiringMode, ImpactInfo Impact)
{
   local EmitterSpawnable es;

   if (Impact.HitActor ! = none)
   {
      es = Weapon.Spawn(class'EmitterSpawnable', , , Impact.HitLocation);

      if (es ! = none)
         es.SetTemplate(ParticleSystem'WP_FlakCannon.Effects.P_WP_Flak_Alt_Explosion');
   }
}

Weapon 를 사용해 EmitterSpawnable 를 스폰 합니다만, 이것은 Spawn() 함수가 Object는 아니고 Actor 에 있기 때문입니다.

*5. * 다음에, 재생하는 사운드를 짜넣습니다.

function OnProcessInstantHit(UTWeapon Weapon, byte FiringMode, ImpactInfo Impact)
{
   local EmitterSpawnable es;

   Weapon.PlaySound(SoundCue'A_Weapon_FlakCannon.Weapons.A_FlakCannon_FireAltImpactExplodeCue', , , , Impact.HitLocation);

   if (Impact.HitActor ! = none)
   {
      es = Weapon.Spawn(class'EmitterSpawnable', , , Impact.HitLocation);

      if (es ! = none)
         es.SetTemplate(ParticleSystem'WP_FlakCannon.Effects.P_WP_Flak_Alt_Explosion');
   }
}

*6. * 다음에, 방사상의 (radial) 데미지를 추가합니다.

function OnProcessInstantHit(UTWeapon Weapon, byte FiringMode, ImpactInfo Impact)
{
   local EmitterSpawnable es;

   Weapon.PlaySound(SoundCue'A_Weapon_FlakCannon.Weapons.A_FlakCannon_FireAltImpactExplodeCue', , , , Impact.HitLocation);

   if (Impact.HitActor ! = none)
   {
      es = Weapon.Spawn(class'EmitterSpawnable', , , Impact.HitLocation);

      if (es ! = none)
         es.SetTemplate(ParticleSystem'WP_FlakCannon.Effects.P_WP_Flak_Alt_Explosion');
   }

   Weapon.HurtRadius(class'UTProj_FlakShell'. default.Damage, class'UTProj_FlakShell'. default.DamageRadius, class'UTProj_FlakShell'. default.MyDamageType, class'UTProj_FlakShell'. default.MomentumTransfer, Impact.HitLocation);
}

*7. * 마지막으로, 도달하는 장소에 뛰쳐나오는 랜덤인 고사포탄을 생성합니다. 이것에는, 반복자를 설정해 발사물이 5 개 생성되도록(듯이) 합니다.

function OnProcessInstantHit(UTWeapon Weapon, byte FiringMode, ImpactInfo Impact)
{
   local int i;
   local UTProj_FlakShard NewChunk;
   local EmitterSpawnable es;

   if (Impact.HitActor ! = none)
   {
      Weapon.PlaySound(SoundCue'A_Weapon_FlakCannon.Weapons.A_FlakCannon_FireAltImpactExplodeCue', , , , Impact.HitLocation);

      es = Weapon.Spawn(class'EmitterSpawnable', , , Impact.HitLocation);

      if (es ! = none)
         es.SetTemplate(ParticleSystem'WP_FlakCannon.Effects.P_WP_Flak_Alt_Explosion');

      for (i = 0; i < 5; ++i)
      {
         NewChunk = Weapon.Spawn(class'UTProj_FlakShard', , , Impact.HitLocation);

         if (NewChunk ! = None)
         {
            NewChunk.bCheckShortRangeKill = false;
            NewChunk.Init((FRand() * 150. f) * (VRand() * 0.8f));
         }
      }

      Weapon.HurtRadius(class'UTProj_FlakShell'. default.Damage, class'UTProj_FlakShell'. default.DamageRadius, class'UTProj_FlakShell'. default.MyDamageType, class'UTProj_FlakShell'. default.MomentumTransfer, Impact.HitLocation);
   }
}

튜토리얼 12.8 - 무기의 뮤테이타, 파트 VI: MULTIENFORCER_ROCKET

이것은 로켓 발사 타입입니다. 총알이 무언가에 명중하면(자), 강렬한 폭발을 생성합니다.

*1. * 최초로, 디폴트 프롭퍼티에 WeaponClass 를 설정합니다.

defaultproperties
{
   WeaponClass=class'UTWeap_RocketLauncher'
   Name="Default__MultiEnforcer_Rocket"
}

*2. * 다음에 OnProcessInstantHit() 함수를 오버라이드(override) 합니다.

function OnProcessInstantHit(UTWeapon Weapon, byte FiringMode, ImpactInfo Impact)
{
}

*3. * 임펙트로부터 유효한 HitActor 를 얻을 수 있었는지 어떠했는지의 체크가 필요합니다.

function OnProcessInstantHit(UTWeapon Weapon, byte FiringMode, ImpactInfo Impact)
{
   if (Impact.HitActor ! = none)
   {
   }
}

*4. * 폭발의 파티클 효과를 스폰 합니다.

function OnProcessInstantHit(UTWeapon Weapon, byte FiringMode, ImpactInfo Impact)
{
   local EmitterSpawnable es;

   if (Impact.HitActor ! = none)
   {
      es = Weapon.Spawn(class'Engine.EmitterSpawnable', , , Impact.HitLocation, Rotator(Impact.HitNormal));

      if (es ! = none)
         es.SetTemplate(ParticleSystem'WP_RocketLauncher.Effects.P_WP_RocketLauncher_RocketExplosion');
   }
}

Weapon 를 사용해 EmitterSpawnable 를 스폰 합니다만, 이것은 Spawn() 함수가 Object는 아니고 Actor 에 있기 때문입니다.

*5. * 다음에, 큰 폭발음을 재생합니다.

function OnProcessInstantHit(UTWeapon Weapon, byte FiringMode, ImpactInfo Impact)
{
   local EmitterSpawnable es;

   if (Impact.HitActor ! = none)
   {
      es = Weapon.Spawn(class'Engine.EmitterSpawnable', , , Impact.HitLocation, Rotator(Impact.HitNormal));

      if (es ! = none)
         es.SetTemplate(ParticleSystem'WP_RocketLauncher.Effects.P_WP_RocketLauncher_RocketExplosion');

      Weapon.PlaySound(SoundCue'A_Weapon_RocketLauncher.Cue.A_Weapon_RL_Impact_Cue', , , , Impact.HitLocation);
   }
}

*6. * 이 발사 타입을 완성시키기 위해서(때문에), 방사상에 데미지를 여.

function OnProcessInstantHit(UTWeapon Weapon, byte FiringMode, ImpactInfo Impact)
{
   local EmitterSpawnable es;

   if (Impact.HitActor ! = none)
   {
      es = Weapon.Spawn(class'Engine.EmitterSpawnable', , , Impact.HitLocation, Rotator(Impact.HitNormal));

      if (es ! = none)
         es.SetTemplate(ParticleSystem'WP_RocketLauncher.Effects.P_WP_RocketLauncher_RocketExplosion');

      Weapon.PlaySound(SoundCue'A_Weapon_RocketLauncher.Cue.A_Weapon_RL_Impact_Cue', , , , Impact.HitLocation);
      Weapon.HurtRadius(class'UTProj_Rocket'. default.Damage, class'UTProj_Rocket'. default.DamageRadius, class'UTProj_Rocket'. default.MyDamageType, class'UTProj_Rocket'. default.MomentumTransfer, Impact.HitLocation);
   }
}

튜토리얼 12.8 - 무기의 뮤테이타, 파트 VII: MULTIENFORCER_SHOCK

이것은 쇼크 발사 타입입니다. 총알이 무언가에 명중하면(자), 강렬한 쇼크 재즈 악단 폭발을 생성합니다.

*1. * 최초로, 디폴트 프롭퍼티에 WeaponClass 를 설정합니다.

defaultproperties
{
   WeaponClass=class'UTWeap_ShockRifle'
   Name="Default__MultiEnforcer_Shock"
}

*2. * 다음에 OnProcessInstantHit() 함수를 오버라이드(override) 합니다.

function OnProcessInstantHit(UTWeapon Weapon, byte FiringMode, ImpactInfo Impact)
{
}

*3. * 임펙트로부터 유효한 HitActor 를 얻을 수 있었는지 어떠했는지의 체크가 필요합니다.

function OnProcessInstantHit(UTWeapon Weapon, byte FiringMode, ImpactInfo Impact)
{
   if (Impact.HitActor ! = none)
   {
   }
}

*4. * 재즈 악단 폭발의 파티클 효과를 스폰 합니다.

function OnProcessInstantHit(UTWeapon Weapon, byte FiringMode, ImpactInfo Impact)
{
   if (Impact.HitActor ! = none)
   {
      Weapon.Spawn(Class'UTGame.UTEmit_ShockCombo', , , Impact.HitLocation);
   }
}

파티클 효과의 생성에는 Weapon 를 사용할 필요가 있습니다만, 이것은 Spawn()가 Object는 아니고 Actor 의 네이티브 함수이기 때문입니다. Impact 는, 다수의 유익한 데이터를 격납하는 struct 로, 여기에서는 HitLocation 를 사용하고 있습니다.

*5. * 폭탄음이 없으면 시시하기 때문에, 여기서 사운드를 재생합니다.

function OnProcessInstantHit(UTWeapon Weapon, byte FiringMode, ImpactInfo Impact)
{
   if (Impact.HitActor ! = none)
   {
      Weapon.Spawn(Class'UTGame.UTEmit_ShockCombo', , , Impact.HitLocation);
      Weapon.PlaySound(SoundCue'A_Weapon_ShockRifle.Cue.A_Weapon_SR_ComboExplosionCue', , , , Impact.HitLocation);
   }
}

*6. * 이 발사 타입을 완성시키기 위해서(때문에), 방사상의 데미지도 여.

function OnProcessInstantHit(UTWeapon Weapon, byte FiringMode, ImpactInfo Impact)
{
   if (Impact.HitActor ! = none)
   {
      Weapon.Spawn(Class'UTGame.UTEmit_ShockCombo', , , Impact.HitLocation);
      Weapon.PlaySound(SoundCue'A_Weapon_ShockRifle.Cue.A_Weapon_SR_ComboExplosionCue', , , , Impact.HitLocation);
      Weapon.HurtRadius(class'UTProj_ShockBall'. default.ComboDamage, class'UTProj_ShockBall'. default.ComboRadius, class'UTProj_ShockBall'. default.ComboDamageType, class'UTProj_ShockBall'. default.ComboMomentumTransfer, Impact.HitLocation);
   }
}

클래스의 디폴트치를 사용해, 값을 덧쓰기 카피하는 수고를 생략하고 있습니다.

튜토리얼 12.8 - 무기의 뮤테이타, 테스트 실시

*1. * 인스턴스 액션의 데스 매치 게임을 개시합니다.

*2. * Tab 를 눌러 콘솔을 엽니다. 콘솔로, 「giveweapon MasteringUnrealScript.UTWeap_Multienforcer」라고 입력합니다. 이 커멘드로 무기가 주어집니다.


그림 12.4 - 이 콘솔 커멘드는, 플레이어에게 목적의 무기를 즉석에서 줍니다.

*3. * 무기가 주어졌으므로,[3] 키를 눌러 거기에 바꿉니다.


그림 12.5 - MultiEnforcer 무기가 액티브하게 되었습니다.

*4. * 무기의 선택을 끝마치면(자), 다음은 주위를 점검해 이미 기능하고 있을지 어떨지를 확인합니다. 최초로 HUD 아이콘을 보면(자), 로켓 발사 타입이 선택되고 있는 것을 나타내고 있습니다. 확인을 위해서(때문에) 이 무기를 발사해 보겠습니다.


그림 12.6 - 무기는 로켓 타입을 발사합니다.

*5. * 다음에, 발사 타입의 바꾸기 기능 을 테스트합니다. 오른쪽 클릭해 다른 타입으로 전환합니다.


그림 12.7 - 무기의 발사 타입이 바뀝니다.

*6. * 최상을 할 수 있고입니다. 쇼크 발사 타입으로 전환할 수 있던 것 같습니다. 발사해 봐, 기능할지 어떨지를 확인합니다.


그림 12.8 - 이번은 쇼크 타입을 발사합니다.

이 튜토리얼에서는, 플레이어가 2차 발사 버튼을 사용해 발사 타입을 바꾸고 할 수 있는 무기를 작성했습니다. 그방법으로서 Delegate를 이용했습니다만, 물론 다른 방법도 다수 있습니다. 이 예로부터 배운 중요한 레슨은, Delegate를 오브젝트와 사용했을 때에, 반드시 참조를 클린 업 하는 것의 중요함입니다.

튜토리얼 12.16 - Delegate & KISMET, 파트 I: 입문 & 클래스의 초기설정

이 튜토리얼에서는, Delegate를 Kismet 내에서 사용할 수 있도록(듯이) 하는 방법을 설명합니다. 구체적인 작업으로서 레벨 디자이너전용으로 효과 제네레이터를 작성하기로 하겠습니다. 디자이너는, Kismet 논리에 의해 생성하는 효과를 온더 플라이로 변경할 수 있습니다. 여기서 최초로 생각하지 않으면 안 되는 점은, 여러가지의 장대한 장치 중(안)에서, 이것을 얼마나 기능시키는가 하는 것입니다. Kismet 나 레벨의 디자이너는 배치 가능 먼지나 브러쉬를 취급하는 작업에 자주(잘) 종사하므로, 벨 디자이너가 레벨내에 배치 조정할 수 없는 것을 사용하는 것은 아마 피해야 합니다. 이것에 대처하려면 , 배치 가능한 효과 제네레이터인 것, 그 효과도 배치 가능하다라고 하는 것이 가장 자주(잘), 거기에 따라 몇개의 문제를 해결할 수 있습니다. 레벨 디자이너는 임의의 위치에 싱글 효과 제네레이터를 배치해 효과의 스폰 위치와 회전을 정의해, 맵 내부에 효과를 배치해, 목적의 결과를 얻을 수 있도록(듯이) 효과를 조정합니다. 레벨 디자이너는 이 방법론에 충분히 정통하고 있습니다. 게다가 Kismet 대응 노드를 기술해, 레벨 디자이너가 효과 제네레이터내에 출로 Delegate를 설정할 수 있도록(듯이) 합니다. Kismet 노드의 리스트를 보았는데, 먼지를 「사용」하는 노드가 존재하지 않기 때문에, 그것도 작성할 필요가 있습니다. 즉 정리하면(자), effects generator 클래스, effect base 클래스, set effect Kismet 클래스, use actor Kismet 클래스 및 작성하고 싶은 효과의 클래스를 작성할 필요가 있습니다. 이 튜토리얼에서는, 폭발, 환상 구조로 스폰 하는 수류탄, 지브 (gib, 내장) 생성의 3 개 효과를 작성합니다.

*1. * 임의의 텍스트 문자 편집기를 열어,..\MasteringUnrealScript\Classes 디렉토리에 UTEffectsGenerator.uc, UTEffect.uc, SeqAct_SetEffect.uc, SeqAct_Use.uc, UTEffect_Explosion.uc, UTEffect_GrenadeRing.uc 및 UTEffect_Gibbage.uc 라는 이름의 신규 파일을 작성합니다.

*2. * UTEffectsGenerator 의 클래스 및 디폴트 프롭퍼티를 선언합니다.

class UTEffectsGenerator extends Actor
   placeable;

defaultproperties
{
   Name=”Default__UTEffectsGenerator”
}

UTEffectsGenerator 는, 레벨 디자이너가 레벨내에 배치할 수 있도록(듯이) 배치 가능 (placeable)으로 하고 있습니다.

*3. * UTEffect 의 클래스 및 디폴트 프롭퍼티를 선언합니다.

class UTEffect extends Actor
   abstract;

defaultproperties
{
   Name=”Default__UTEffect”
}

UTEffect 는 abstract 입니다만, 그 이유는 아이 클래스 (UTEffect_Explosion, UTEffect_GrenadeRing 및 UTEffect_Gibbage)를 작성하기 (위해)때문에입니다. 레벨 디자이너 또는 프로그래머가 UTEffect 를 스폰 또는 배치할 것은 없습니다.

*4. * SeqAct_SetEffect 의 클래스 및 디폴트 프롭퍼티를 선언합니다.

class SeqAct_SetEffect extends SeqAct_SetSequenceVariable;

defaultproperties
{
   VariableLinks(1)=(ExpectedType=Class'Engine.SeqVar_Object', LinkDesc="Effect", PropertyName="Value", MinVars=1, MaxVars=255)
   ObjClassVersion=2
   ObjName="Set Effect"
   ObjCategory=”Effect Generator”
   Name=”Default__ SeqAct_SetEffect”
   ObjectArchetype=SeqAct_SetSequenceVariable'Engine.Default__SeqAct_SetSequenceVariable'
}

같이 SeqAct_SetEffect 는 Kismet 로 사용하게 되므로, SeqAct_SetSequenceVariable 의 아이 클래스가 되어 있습니다. VariableLinks(1)는, Unreal 에디터의 Kismet 에디터로 사용할 수 있는 lynx (links) 로트를 지정해, ObjName 는 Kismet 에디터내에 나타나는 Kismet 노드의 이름입니다.

*5. * SeqAct_Use 의 클래스 및 디폴트 프롭퍼티를 선언합니다.

class SeqAct_Use extends SequenceAction;

defaultproperties
{
   ObjName=”Use”
   ObjCategory=”Effect Generator”
   Name=”Default__SeqAct_Use”
   ObjectArchetype=SequenceAction'Engine.Default__SequenceAction'
}

같이 SeqAct_Use 는 Kismet 로 사용하게 되므로, SequenceAction 의 아이 클래스가 되어 있습니다. ObjName 는 Kismet 에디터내에 나타나는 Kismet 노드의 이름, ObjCategory 는 Kismet 에디터내에서 Kismet 노드의 소트에 사용됩니다.

*6. * UTEffect_Explosion 의 클래스 및 디폴트 프롭퍼티를 선언합니다.

class UTEffect_Explosion extends UTEffect
   placeable;

defaultproperties
{
   Name=”Default_UTEffect_Explosion”
}

UTEffect_Explosion 는, 레벨 디자이너를 배치할 수 있도록(듯이) 배치 가능하게 되어 있습니다.

*7. * UTEffect_GrenadeRing 의 클래스 및 디폴트 프롭퍼티를 선언합니다.

class UTEffect_GrenadeRing extends UTEffect
   placeable;

defaultproperties
{
   Name=”Default__UTEffect_GrenadeRing”
}

UTEffect_GrenadeRing 는, 레벨 디자이너를 배치할 수 있도록(듯이) 배치 가능하게 되어 있습니다.

*8. * UTEffect_Gibbage 의 클래스 및 디폴트 프롭퍼티를 선언합니다.

class UTEffect_Gibbage extends UTEffect
   placeable;

defaultproperties
{
   Name=”Default__UTEffect_Gibbage”
}

UTEffect_Gibbage 는, 레벨 디자이너를 배치할 수 있도록(듯이) 배치 가능하게 되어 있습니다.

튜토리얼 12.16 - Delegate & KISMET, 파트 II: UTEFFECTSGENERATOR

*1. * 우선, 효과 제네레이터가 사용하는 Delegate 함수의 선언으로부터 시작합시다.

delegate OnGenerateEffects(UTEffectsGenerator InGenerator);

이 Delegate에는 UTEffectsGenerator 에의 참조를 보관 유지하는 파라미터가 포함되어 있어, 이 경우는 항상 Delegate를 호출한 UTEffectsGenerator 의 참조를 보관 유지합니다. 이 선언에 의해, 다른 클래스 인스턴스는 Delegate의 최초의 호출 바탕으로 액세스 할 수 있습니다.

*2. * Delegate 함수를 작성했으므로, 다음에 실제로 그것을 호출하기 위한 논리를 쓸 필요가 있습니다.

function GenerateEffects()
{
   OnGenerateEffects(self);
}

GenerateEffects() 내에 OnGenerateEffects()를 캡슐화하는 이유는, 장래에의 준비입니다. 지금은 무의미합니다만, 효과 생성을 무효화하는 메소드나 다른 무엇이지가 아마 필요하게 되었을 때에, 다른 아이 클래스를 변경하는 수고를 들이지 않고, GenerateEffects()만을 조정하는 것만으로 끝마치도록(듯이) 하는 점을 고려하고 있습니다.

*3. * 다음은, GenerateEffects() 함수를 호출하는 메소드가 필요합니다. 이 특수한 케이스에서는, Actor 내의 UsedBy() 훅을 사용합니다. UsedBy()는, 플레이어가 [Use] 버튼을 눌러 먼지를 사용할 경우에 불려 갑니다만, 여기에서는 Kismet 와 대화하기 위한 공통 훅의 목적만을 과연 있습니다.

function bool UsedBy(Pawn User)
{
   GenerateEffects();
   return super.UsedBy(User);
}

이것에 의해, 플레이어가 효과 제네레이터를 사용하면(자), 제네레이터는 GenerateEffects()을 호출해, 계속되어 이 함수가 OnGenerateEffects() Delegate를 호출합니다.

*4. * 다음에, Delegate를 임의로 설정할 수 있도록(듯이) 하는 수단이 필요합니다.

function SetEffect(delegate<OnGenerateEffects> NewEffect)
{
   OnGenerateEffects = NewEffect;
}

엄밀하게는, 이 Delegate는 변수와 같이 다른 클래스로부터도 액세스 할 수 있으므로, 함수 내부에 이것을 캡슐화할 이유는 없습니다만, 이와 같이 해 두면, 만일 이 Delegate를 private 또는 protected Delegate로 변경하고 싶어졌을 경우에서도, 그것이 사용되고 있는 클래스를 변경 하지 않아도 되는, 이라고 할 뿐(만큼)입니다.

*5. * 레벨 디자이너는 이 먼지를 월드에 배치하게 되므로, 효과 제네레이터가 디자이너로부터 보이도록(듯이) 할 필요가 있습니다. 거기서, 에디터 내부에서만 보이는 렌더링 컴퍼넌트를 디폴트 프롭퍼티에 추가합니다.

defaultproperties
{
   Begin Object Class=SpriteComponent Name=Sprite ObjName=Sprite Archetype=SpriteComponent'Engine.Default__SpriteComponent'
      HiddenGame=True
          AlwaysLoadOnClient=False
          AlwaysLoadOnServer=False
          Name="Sprite"
          ObjectArchetype=SpriteComponent'Engine.Default__SpriteComponent'
     End Object
     Components(0) =Sprite

   Begin Object Class=ArrowComponent Name=Arrow ObjName=Arrow Archetype=ArrowComponent'Engine.Default__ArrowComponent'
      ArrowColor=(B=255, G=200, R=150, A=255)
      Name="Arrow"
      ObjectArchetype=ArrowComponent'Engine.Default__ArrowComponent'
   End Object
   Components(1) =Arrow

   Name=”Default__UTEffectsGenerator”
}

튜토리얼 12.8 - Delegate & Kismet, 파트 III: UTEFFECT

*1. * 최초로 행 나누면 안 되는 것은, 이 클래스의 앞에 UTEffectGenerator 가 항상 컴파일 되도록(듯이) 하는 것입니다. 거기서, dependson(UTEffectsGenerator)를 아이의 정의에 추가합니다.

class UTEffect extends Actor
   dependson(UTEffectsGenerator)
   abstract;

*2. * 다음에, 모든 아이 클래스의 그루터기 함수로서 기능하는 함수를 작성할 필요가 있습니다. 이 그루터기 함수는, UTEffectsGenerator 내에서 정의되는 Delegate의 오버라이드(override)에도 사용됩니다.

function Effect(UTEffectsGenerator InGenerator);

*3. * 다음에 Kismet 로 이 효과를 효과 제네레이터로 설정하기 위해서 호출하는 함수를 작성합니다.

function SetEffect(UTEffectsGenerator InGenerator)
{
   if (InGenerator ! = none)
      InGenerator.SetEffect(Effect);
}

먼저도 말했던 대로, InGenerator.OnGenerateEffects = Effect 로서 Delegate의 대입을 처리하는 일도 가능합니다만, 그방법에서는 Delegate가 private 또는 protected 로 변경되었을 경우에 이 클래스로부터 액세스 할 수 없게 되므로, 그다지 유연성이 있다고는 말할 수 없습니다. 그 때문에, 만약을 위해 대입 함수가 사용되고 있습니다.

*4. * UTEffectsGenerator 와 같이, 레벨 디자이너가 레벨내에서 렌더링 컴퍼넌트를 배치할 수 있도록(듯이), 디폴트 프롭퍼티에 이것들을 추가할 필요가 있습니다.

defaultproperties
{
     Begin Object Class=SpriteComponent Name=Sprite ObjName=Sprite Archetype=SpriteComponent'Engine.Default__SpriteComponent'
      HiddenGame=True
      AlwaysLoadOnClient=False
      AlwaysLoadOnServer=False
      Name="Sprite"
      ObjectArchetype=SpriteComponent'Engine.Default__SpriteComponent'
   End Object
   Components(0) =Sprite

   Name="Default_UTEffect"
}

튜토리얼 12.16 - Delegate & KISMET, 파트 III: SEQACT_SETEFFECT

*1. * Kismet 노드는 주로 Native (네이티브) 코드에 의해 제어됩니다만, Native 코드가 호출하는 이벤트안에는, UnrealScript 로 사용할 수 있는 것이 있습니다. 이 특별한 케이스에서는, 노드가 액티브하게 되면(자) 항상 Native 코드가 Activated() 이벤트를 호출하므로, 그것을 오버라이드(override) 해 액세스 할 수 있도록(듯이) 합니다.

event Activated()
{
}

*2. * 에디터내에서 Kismet 노드를 링크하면(자), LinkedVariables ( 각 VariableLinks 내의 것)에서는 그러한 오브젝트 변수에의 참조를 보관 유지합니다. 이러한 오브젝트 변수에는, UTEffectsGenerator 및 필요한 UTEffect 오브젝트의 참조를 격납할 필요가 있습니다. 우선, 이러한 전제 조건이 올바른지 어떤지의 확인만을 실시합니다.

event Activated()
{
   if (VariableLinks.length >= 2 && VariableLinks[0]. LinkedVariables.length > 0 && VariableLinks[0]. LinkedVariables[0] ! = none && VariableLinks[1]. LinkedVariables.length > 0 && VariableLinks[1]. LinkedVariables[0] ! = none)
   {
   }
}

이 스테이트먼트에서는, 최초로 VariableLinks 배열이 2 이상인가 어떤가를 체크합니다. 2 개의 오브젝트 (UTEffectsGenerator 및 UTEffect)가 필요해서, 2 개의 VariableLinks 의 존재가 필요합니다. 각 VariableLinks 의 LinkedVariables 배열도 2 이상인 것이 필요합니다. 마지막으로, LinkedVariables 내의 최초의 인덱스에 오브젝트 참조가 포함되지 않으면 안됩니다.

*3. * LinkedVariables 는 SequenceVariables 로서 격납되고 있습니다만, 실제로는 SeqVar_Objects 이므로, 우선 발견된 LinkedVariables 를 SeqVar_Objects 에 타입 캐스트 할 필요가 있습니다. 이것에 의해, SeqVar_Objects 에 UTEffectGenerators 와 UTEffect 의 참조가 포함되게 됩니다.

event Activated()
{
   local SeqVar_Object sv_obj;

   if (VariableLinks.length >= 2 && VariableLinks[0]. LinkedVariables.length > 0 && VariableLinks[0]. LinkedVariables[0] ! = none && VariableLinks[1]. LinkedVariables.length > 0 && VariableLinks[1]. LinkedVariables[0] ! = none)
   {
      sv_obj = SeqVar_Object(VariableLinks[0]. LinkedVariables[0]);

      if (sv_obj ! = none)
      {
      }

      sv_obj = SeqVar_Object(VariableLinks[1]. LinkedVariables[0]);

      if (sv_obj ! = none)
      {
      }
   }
}

여기에서는, 타입 캐스트의 결과를 일시적으로 격납하기 위한 로컬 변수를 추가했습니다. 이것은 타입 캐스트가 유효한가 어떤가를 실제로 확인해, 다음에 트러블에 말려 들어가지 않게 하기 (위해)때문에입니다 (예를 들면, 레벨 디자이너가 링크에 무엇인가 예기 할 수 없는 것을 할당하는 등).

*4. * SeqVar_Object 에의 타입 캐스트에게 이어, 이 Kismet 노드에 링크되고 있는 UTEffectsGenerator 와 UTEffect 의 레벨 인스턴스의 취득을 시도합니다. UTEffectsGenerator 및 UTEffect 의 참조를 보관 유지하는 2 개의 로컬 변수를 작성해, GetObjectValue() 함수를 이용해 sv_obj 로부터 그것들을 취득합니다. GetObjectValue()는 오브젝트 참조를 돌려주므로, 그것들을 적절한 타입에 캐스트 할 필요가 있습니다.

event Activated()
{
   local SeqVar_Object sv_obj;
   local UTEffectsGenerator ut_effects_generator;
   local UTEffect ut_effects;

   if (VariableLinks.length >= 2 && VariableLinks[0]. LinkedVariables[0] ! = none && VariableLinks[1]. LinkedVariables[0] ! = none)
   {
      sv_obj = SeqVar_Object(VariableLinks[0]. LinkedVariables[0]);

      if (sv_obj ! = none)
         ut_effects_generator = UTEffectsGenerator(sv_obj.GetObjectValue());

      sv_obj = SeqVar_Object(VariableLinks[1]. LinkedVariables[0]);

      if (sv_obj ! = none)
         ut_effects = UTEffect(sv_obj.GetObjectValue());
   }
}

*5. * 마지막에 등장하는 것이, UTEffectsGenerator 및 UTEffect 의 레벨 인스턴스입니다. 그러나, 그러한 참조를 사용하기 전에 실제로 아직 유효한가 어떤가의 확인을 실시하는 것이 좋은 관행입니다. 거기서, 참조가 none 화도인가의 체크를 실시해, none 가 아니면, UTEffect 참조에의 지시로서 그 효과를 UTEffectsGenerator 참조상으로 설정합니다. UTEffect 내에서 SetEffect() 함수를 호출하면(자), 이 함수가 UTEffectsGenerator 내에서 SetEffect() 함수를 호출합니다.

event Activated()
{
   local SeqVar_Object sv_obj;
   local UTEffectsGenerator ut_effects_generator;
   local UTEffect ut_effects;

   if (VariableLinks.length >= 2 && VariableLinks[0]. LinkedVariables[0] ! = none && VariableLinks[1]. LinkedVariables[0] ! = none)
   {
      sv_obj = SeqVar_Object(VariableLinks[0]. LinkedVariables[0]);

      if (sv_obj ! = none)
         ut_effects_generator = UTEffectsGenerator(sv_obj.GetObjectValue());

      sv_obj = SeqVar_Object(VariableLinks[1]. LinkedVariables[0]);

      if (sv_obj ! = none)
         ut_effects = UTEffect(sv_obj.GetObjectValue());

      if (ut_effects_generator ! = none && ut_effects ! = none)
         ut_effects.SetEffect(ut_effects_generator);
   }
}

이상으로 이 Kismet 노드의 작업은 종료입니다.

튜토리얼 12.16 - Delegate & KISMET, 파트 V: SEQACT_USE

*1. * SeqAct_SetEffect 의 경우와 같게, Activated() 이벤트를 오버라이드(override) 합니다.

event Activated()
{
}

*2. * SeqAct_SetEffect 와 거의 같이 VariableLinks 와 그 LinkedVariables 를 조사해, 이 Kismet 노드에 연결되고 있는 Actor 인스턴스를 찾아냅니다.

event Activated()
{
   local SeqVar_Object sv_obj;
   local Actor a;

   if (VariableLinks.length >= 1 && VariableLinks[0]. LinkedVariables.length > 0 && VariableLinks[0]. LinkedVariables[0] ! = none)
   {
      sv_obj = SeqVar_Object(VariableLinks[0]. LinkedVariables[0]);

      if (sv_obj ! = none)
      {
         a = Actor(sv_obj.GetObjectValue());
      }
   }
}

*3. * 먼지의 참조가 검출되었더니, none 체크를 실행해 UsedBy() 함수를 호출합니다. 이것은 유틸리티의 Kismet 노드로, 이 함수를 실장하는 임의의 Actor 에 대해서 사용할 수 있습니다.

event Activated()
{
   local SeqVar_Object sv_obj;
   local Actor a;

   if (VariableLinks.length >= 1 && VariableLinks[0]. LinkedVariables.length > 0 && VariableLinks[0]. LinkedVariables[0] ! = none)
   {
      sv_obj = SeqVar_Object(VariableLinks[0]. LinkedVariables[0]);

      if (sv_obj ! = none)
      {
         a = Actor(sv_obj.GetObjectValue());

         if (a ! = none)
            a.UsedBy(none);
      }
   }
}

*4. * 필요한 기본 클래스와 Kismet 노드가 완성했으므로, 다음은 효과를 작성하고 즐깁시다.

튜토리얼 12.16 - Delegate & KISMET, 파트 VI: UTEFFECT_EXPLOSION

*1. * 초에, 친클래스 (UTEffect)에 있는 Effect 함수를 오버라이드(override) 합니다.

function Effect(UTEffectsGenerator InGenerator)
{
}

*2. * 이 효과에 관해서 실행하고 싶은 것은, 로켓 폭발을 닮은 폭발의 파티클 효과를 스폰 해, 더해 폭발음도 재생하는 것입니다. 이 효과는, 예를 들면 빌딩의 붕괴 등 특정의 대상물의 시한 폭발등을 실시하는 경우에 능숙하게 기능합니다. 거기서, 파티클의 스폰을 처리하는 이미터의 참조를 보관 유지하는 로컬 변수를 작성합니다.

function Effect(UTEffectsGenerator InGenerator)
{
   local EmitterSpawnable es;
}

*3. * 여기로부터 이미터를 스폰 해 파티클 시스템 템플릿을 설정합시다. UTEffectsGenerator 의 위치에서 이미터를 스폰 하고 싶기 때문에, UTEffectsGenerator 의 위치와 회전을 사용하기로 하겠습니다. 여기에서도 같이 먼저 none 체크를 실시합니다.

function Effect(UTEffectsGenerator InGenerator)
{
   local EmitterSpawnable es;

   if (InGenerator ! = none)
   {
      es = Spawn(class'EmitterSpawnable', , , InGenerator.Location, InGenerator.Rotation);

      if (es ! = none)
         es.SetTemplate(ParticleSystem'WP_RocketLauncher.Effects.P_WP_RocketLauncher_RocketExplosion');
   }
}

*4. * 폭발음의 효과를 추가하면(자), 효과가 완성입니다.

function Effect(UTEffectsGenerator InGenerator)
{
   local EmitterSpawnable es;

   if (InGenerator ! = none)
   {
      InGenerator.PlaySound(SoundCue'A_Weapon_RocketLauncher.Cue.A_Weapon_RL_Impact_Cue');
      es = Spawn(class'EmitterSpawnable', , , InGenerator.Location, InGenerator.Rotation);

      if (es ! = none)
         es.SetTemplate(ParticleSystem'WP_RocketLauncher.Effects.P_WP_RocketLauncher_RocketExplosion');
   }
}

*5. * 최초의 효과가 완성했습니다. 추가 연습 문제로서 사운드 큐와 파티클 시스템의 양쪽 모두를, 에디터로 구성 가능하게 해 보는 것을 추천합니다.

힌트: 이것을 실시하려면 , 사운드 큐와 파티클 시스템에의 참조를 보관 유지하는, 편집 가능한 글로벌 변수를 작성합니다.

튜토리얼 12.16 - Delegate & KISMET, 파트 VII: UTEFFECT_GRENADERING

이 효과에서는, UTEffectsGenerator 로부터 고리의 형태를 그리도록(듯이) 수류탄을 던집니다. 각 수류탄의 스텝각도는, 레벨 디자이너를 설정할 수 있도록(듯이) 합니다.

*1. * 시작해에, 에디터의 글로벌 변수를 선언합니다.

var(GrenadeRing) int Angle;

이것에 의해, 레벨 디자이너가 프롭퍼티 윈도우를 열면(자) [GrenadeRing] 카테고리의 내부에 [Angle] 가 표시됩니다.

*2. * 전의 순서와 같게, 친클래스의 Effect 함수를 오버라이드(override) 합니다.

function Effect(UTEffectsGenerator InGenerator)
{
}

*3. * UTEffectsGenerator 에 스폰링의 중앙을 맞추고 싶기 때문에, none 체크의 후에 Angle 치를 조사해, 사용할 수 없는 값을 레벨 디자이너가 입력하고 있지 않는지 어떤지 확인합니다.

function Effect(UTEffectsGenerator InGenerator)
{
   if (InGenerator ! = none && Angle > 0 && Angle < 65535)
   {
   }
}

*4. * 사운드 효과를 먼저 정리합시다.

function Effect(UTEffectsGenerator InGenerator)
{
   if (InGenerator ! = none && Angle > 0 && Angle < 65535)
   {
      InGenerator.PlaySound(SoundCue'A_Weapon_RocketLauncher.Cue.A_Weapon_RL_GrenadeFire_Cue');
   }
}

*5. * 최초로 해야 할 (일)것은, 레벨 디자이너가 설정한 각도 스텝에 근거해 고리를 형성하는 것입니다. 수류탄은 던지는 것이므로, 그것들을 한 개소에서 스폰 해, 속도를 바꾸어 고리의 형태를 그리도록(듯이) 보이게 하는 만큼 합니다 (아무래도 그러한 차면, 환상의 개시 위치에서 수류탄을 스폰 할 수도 있습니다). Unreal Engine 내에서의 최대 회전치는 65535 이므로 65535 까지 세는 for 반복자를 추가합니다. 각 이타레이션이 각도 스텝을 가산해 갈 것입니다.

function Effect(UTEffectsGenerator InGenerator)
{
   local int i;

   if (InGenerator ! = none && Angle > 0 && Angle < 65535)
   {
      InGenerator.PlaySound(SoundCue'A_Weapon_RocketLauncher.Cue.A_Weapon_RL_GrenadeFire_Cue');

      for (i = 0; i < 65535; i = i + Angle)
      {
      }
   }
}

*6. * 완벽합니다. 반복자를 설정했으므로, 다음에 개개의 수류탄을 스폰 해 그 회전을 계산할 수 있습니다. 반복마다 회전치를 보관 유지하는 로컬 변수를 설정해, 각 반복시에 로테이타의 Yaw 치만을 변경합니다. 또, 스폰 하는 수류탄의 참조를 보관 유지하는 로컬 변수도 작성합니다.

function Effect(UTEffectsGenerator InGenerator)
{
   local int i;
   local rotator r;
   local UTProj_Grenade grenade;

   if (InGenerator ! = none && Angle > 0 && Angle < 65535)
   {
      InGenerator.PlaySound(SoundCue'A_Weapon_RocketLauncher.Cue.A_Weapon_RL_GrenadeFire_Cue');
      r.Pitch = 0;
      r.Roll = 0;

      for (i = 0; i < 65535; i = i + Angle)
      {
         r.Yaw = i;
         grenade = Spawn(class'UTGame.UTProj_Grenade', , , InGenerator.Location, r);
      }
   }
}

*7. * 마지막으로, 각 수류탄의 속도를 설정합니다. 로테이타의 값을 사용해, 벡터로 변경해 float 로 곱셈해, 속도치를 요구합니다. 이 float 치를 크고 또는 작게 설정하면(자), 수류탄의 투척 속도가 상승 또는 저하합니다.

function Effect(UTEffectsGenerator InGenerator)
{
   local int i;
   local rotator r;
   local UTProj_Grenade grenade;

   if (InGenerator ! = none && Angle > 0 && Angle < 65535)
   {
      InGenerator.PlaySound(SoundCue'A_Weapon_RocketLauncher.Cue.A_Weapon_RL_GrenadeFire_Cue');
      r.Pitch = 0;
      r.Roll = 0;

      for (i = 0; i < 65535; i = i + Angle)
      {
         r.Yaw = i;
         grenade = Spawn(class'UTGame.UTProj_Grenade', , , InGenerator.Location, r);

         if (grenade ! = none)
            grenade.Velocity = vector(r) * 300. f;
      }
   }
}

이상으로, 수류탄을 고리를 그리도록(듯이) 던지는 효과를 준비할 수 있었습니다.

튜토리얼 12.16 - Delegate & KISMET, 파트 VIII: UTEFFECT_GIBBAGE

이 효과에서는, 랜덤인 방향으로 뛰쳐나오는 지브를 다수 스폰 합니다. 지브의 양은 레벨 디자이너를 제어할 수 있도록(듯이) 합니다.

*1. * 에디터의 글로벌 변수의 선언으로부터 시작합시다.

var(Gibbage) int Amount;

이것에 의해, 레벨 디자이너가 프롭퍼티 윈도우를 열면(자),[Gibbage] 카테고리에 [Amount] 변수가 표시됩니다.

*2. * 전의 순서와 같게, 친클래스의 Effect 함수를 오버라이드(override) 합니다.

function Effect(UTEffectsGenerator InGenerator)
{
}

*3. * 지브는 모두 UTEffectsGenerator 인스턴스로부터 스폰 되므로, none 체크에 이어 Amount 가 제로보다 큰 값일지 어떨지의 체크를 실시합니다.

function Effect(UTEffectsGenerator InGenerator)
{
   if (InGenerator ! = none && Amount > 0)
   {
   }
}

*4. * 제로로부터 Amount 치까지 반복 처리하는 반복자를 설정할 필요가 있습니다.

function Effect(UTEffectsGenerator InGenerator)
{
   local int i;

   if (InGenerator ! = none && Amount > 0)
   {
      for (i = 0; i < Amount; ++i)
      {

      }
   }
}

*5. * 스폰 가능한 지브의 범위를 설정했으므로, 다음은 사용하는 지브의 부류를 랜덤에 선택하는 다른 함수를 작성합시다. GetRandomGibClass()라는 이름의 새로운 함수를 작성합니다. 이것은 UTGib_Human 클래스를 돌려줍니다.

function class<UTGib_Human> GetRandomGibClass()
{
}

*6. * Rand(5)를 파라미터에 가지는 switch 스테이트먼트를 추가합니다. 여기에서는 5 종류의 지브 (장물)를 사용할 수 있으므로, 5 를 사용하고 있습니다.

function class<UTGib_Human> GetRandomGibClass()
{
   switch(Rand(5))
   {
   }
}

*7. * 5 종류의 지브로부터 선택할 수 있으므로, 랜덤치에 응해 5 개의 부류를 모두 돌려주는 만큼 합니다.

function class<UTGib_Human> GetRandomGibClass()
{
   switch(Rand(5))
   {
      case 0:
         return class'UTGib_HumanArm';

      case 1:
         return class'UTGib_HumanBone';

      case 2:
         return class'UTGib_HumanChunk';

      case 3:
         return class'UTGib_HumanHead';

      case 4:
      default:
         return class'UTGib_HumanTorso';
   }
}

*8. * 드디어 지브를 스폰 해 봅시다. 로컬 변수 gib 를 작성해, 작성한지 얼마 안된 지브의 일시 참조를 이것에 격납할 수 있도록(듯이) 합니다.

function Effect(UTEffectsGenerator InGenerator)
{
   local int i;
   local UTGib_Human gib;

   if (InGenerator ! = none && Amount > 0)
   {
      for (i = 0; i < Amount; ++i)
      {
         gib = Spawn(GetRandomGibClass(), , , InGenerator.Location, InGenerator.Rotation);
      }
   }
}

*9. * Unreal Tournament 3 에서는, 실제로는 물리 엔진인 PhysX 를 이용해 지브를 물리적으로 시뮬레이트 합니다. 이것은, 현실적인 물리 법칙이 적용되어 (튀어서) 되돌아옴이나 월드와의 충돌이 발생하는 것을 의미합니다. 그 때문에, 지브의 속도를 설정해, PhysX 로 시뮬레이트 할 수 있도록(듯이) 초기화할 필요가 있습니다.

function Effect(UTEffectsGenerator InGenerator)
{
   local int i;
   local UTGib_Human gib;

   if (InGenerator ! = none && Amount > 0)
   {
      for (i = 0; i < Amount; ++i)
      {
         gib = Spawn(GetRandomGibClass(), , , InGenerator.Location, InGenerator.Rotation);

         if (gib ! = none)
         {
            gib.Velocity = Vector(RotRand()) * RandRange(200. f, 400. f);

            if (gib.GibMeshComp ! = none)
            {
               gib.GibMeshComp.WakeRigidBody();
               gib.GibMeshComp.SetRBLinearVelocity(gib.Velocity, false);
               gib.GibMeshComp.SetRBAngularVelocity(VRand() * 50. f, false);
            }
         }
      }
   }
}

최초로 랜덤인 회전수에 200 에서 400 의 범위의 랜덤인 값을 걸어 지브의 랜덤 속도를 설정합니다. 다음에, 지브가 PhysX 로 필요한 메쉬 컴퍼넌트를 갖추고 있는지 어떤지를 조사합니다. 컴퍼넌트가 있는 경우, 그것을 액티브하게 해 PhysX 에 계승해 랜덤인 속도를 설정할 수 있도록(듯이) 합니다. SetRBLinearVelocity()는 오브젝트의 이동 속도를 설정합니다. SetRBAngularVelocity()는 오브젝트의 선회 속도를 설정합니다. 생각보다는 정교한 구조의 지브에페크트가 이것으로 완성입니다.

튜토리얼 12.16 - Delegate & KISMET, 파트 IX테스트 침대의 설정

*1. * 코드를 컴파일 해, Unreal 에디터를 기동합니다.

*2. * Unreal 에디터가 로드 되면(자), DM-Chapter12-Kismet 를 엽니다. 장식용의 정적 메쉬, 라이트와 플레이어 스타트 지점을 포함할 뿐(만큼)의, 꾸밈이 없는 레벨인 것을 압니다.


그림 12.9 - DM-CH_12_Kismet 맵

*3. * 맵이 로드 되면(자), 다음에 코드 패키지내의 클래스에 액세스 해 새로운 클래스 (UTEffectsGenerator, UTEffect_Explosion, UTEffect_Gibbage, UTEffect_GrenadeRing)를 맵에 추가할 수 있도록(듯이) 합니다. 이것들은 Actor 브라우저로부터 자동적으로 액세스 할 수 있을 것입니다만, 할 수 없는 경우는 스크립트 패키지를 로드할 필요가 있습니다. 그 경우는 Generic 브라우저가 열려 있지 않은 경우는 이것을 열어,[Actor Classes] 탭으로 전환해,[File],[Open] 의 순서에 클릭하면(자), 열고 싶은 패키지를 선택하기 위한 다이얼로그가 열립니다.


그림 12.10 - File->Open 커멘드를 사용해, 스크립트 패키지를 로드합니다.

패키지가 로드 되면(자), Actor 브라우저에 새로운 클래스가 표시되는 것이 압니다.


그림 12.11 - Actor 브라우저의 클래스 트리내에 클래스가 나타납니다.

*4. * 다음에, UTEffectGenerator 를 선택해 맵내의 어디엔가 배치합니다. 딱 좋은 느낌의 메쉬가 오른쪽의 방의 플로어 중앙에 배치되고 있으므로, 그 바로 위에 UTEffectsGenerator 를 둡시다. ActorBrowser 로 [UTEffectsGenerator] 를 선택해, 레베르뷰포트내에서 이것을 배치하고 싶은 위치를 오른쪽 클릭합니다. context menu로,[Add UTEffectsGenerator Here] 를 클릭하면(자) 배치할 수 있습니다.


그림 12.12 - UTEffectGenerator 가 맵에 추가되었습니다.

*5. * 새롭게 추가한 UTEffectsGenerator 는, 메쉬와 같이 튜브 위를 타고 있을 것입니다.


그림 12.13 - UTEffectGenerator 먼지의 배치.

*6. * UTEffectsGenerator 의 회전 프롭퍼티에 손볼 필요가 있습니다. 이 오브젝트가 선택되고 있으므로 (그렇지 않은 경우는 선택해 주세요), F4 를 누르면(자) 프롭퍼티 윈도우가 표시됩니다.


그림 12.14 - UTEffectGenerator 의 Rotation 프롭퍼티를 조정합니다.

*7. * 다음에, 레벨내에 UTEffect 인스턴스를 추가합니다. 레벨의 한쪽 구석에 배치해, 간단하게 찾아낼 수 있도록(듯이) 합니다. UTEffectsGenerator 의 경우와 같게, Actor 브라우저로 각 인스턴스를 선택하고 나서, 레벨을 오른쪽 클릭해 문맥을 사용해 추가합니다.


그림 12.15 - 레베르지오메트리의 외측에 UTEffect 먼지가 배치되었습니다.

*8. * 이 예에는, UTEffectsGenerator 를 방아쇠 하는 물리 볼륨이 필요합니다. 호구와 같은 장소를 가리는 비르다브라시의 배치로부터 시작합시다. 설정을 조정해 호구에 능숙하게 맞춥니다.


그림 12.16 - Red Builder 브러쉬의 배치

*9. * 비르다브라시를 목적의 위치에 배치했으므로, 좌측의 메뉴에 있는 [Add Volume] 버튼을 오른쪽 클릭해,[PhysicsVolume] 를 선택해 맵에 추가합니다.


그림 12.17 - [Add Volume] 메뉴로부터 PhysicsVolume 가 선택되었습니다.

*10. * 맵에 물리 볼륨을 배치했습니다. 클릭해 선택해 주세요. 3D 뷰포트로 선택하기 어려운 경우는, 2D 뷰포트로 전환하고 나서 선택합니다.


그림 12.18 - PhysicsVolume 가 선택되었습니다.

*11. * Unreal 에디터의 메인 툴바에 있는 [Kismet] 버튼을 클릭해, Kismet 를 엽니다. Kismet 에디터가 표시됩니다.


그림 12.19 - Kismet 에디터

*12. * 오른쪽 클릭해 context menu를 엽니다. 물리 볼륨을 사용해 Touch 이벤트를 작성합시다 (이것을 실행하기 전에, 잊지 않고 물리 볼륨을 선택해 주세요). 이것에 의해, 물리 볼륨에 접촉하면(자) 방아쇠 하는 Kismet 이벤트 노드가 작성되어 2 개의 엔진 고유의 이벤트 (touched 와 untouched)에 반응합니다. Touched 는, 먼지의 충돌이 오너의 충돌 범위내에서 접촉하면(자) 방아쇠 되어 Untouched 는 그 역입니다. Touched 와 Untouched 는 한 번만 불려 갑니다. 즉, 다른 먼지에 이어 접촉할 것은 없습니다.


그림 12.20 - Touch 이벤트가 작성되었습니다.

*13. * Touched 이벤트 노드의 조정이 필요합니다. 디폴트에서는, 이것은 MaxTriggerCount 를 1 으로 설정해, 즉 한 번만 방아쇠 한 후 무효가 됩니다만, 이 특별한 케이스에서는 영구히 방아쇠 가능하게 하고 싶습니다. 좌하에는, 선택된 각 노드의 프롭퍼티 섹션이 있어, 그 섹션을 아래에 스크롤 하면(자) [MaxTriggerCount] 라고 하는 값이 있습니다. 이것을 0 으로 설정합니다.


그림 12.21 - MaxTriggerCount 를 0 으로 설정합니다.

*14. * 다음에, 물리 볼륨에 접촉했을 때의 반응을 실장합니다. 무엇인가를 사용하는 액션 노드를 작성합시다. 실은, 이것이 전에 작성한 SEQACT_USE 노드입니다. 한번 더 context menu를 참조해,[Effect Generator] 카테고리로부터 [Use] 액션 노드를 추가합니다.


그림 12.22 - Use 액션이 추가되었습니다.

*15. * 다음에, 몇개의 레베르뷰포트로 UTEffectsGenerator 를 선택합니다.


그림 12.23 - UTEffectGenerator 가 선택되었습니다.

*16. * Kismet 에디터 윈도우에 돌아와, 워크 스페이스내에서 오른쪽 클릭해 [New Object Var Using UTEffectGenerator_0] (새로운 오브젝트 변수 (UTEffectGenerator_0 를 사용))를 선택해, 선택한 UTEffectsGenerator 의 참조를 Kismet 내에 추가합니다.

주의: 실제의 맵내의 먼지의 이름이 다를 가능성이 있습니다.


그림 12.24 - UTEffectGenerator 오브젝트 변수가 작성되었습니다.

*17. * 다음에 모든 것을 이읍시다. PhysicsVolume_0 Touch 노드의 Touched 의 우측에 있는 블랙 박스를 클릭해 드러그 해, Use 노드의 In 의 좌측에 있는 블랙 박스에 잇습니다. 다음에, Use 노드의 Target 아래에 있는 보라색의 박스를 클릭해 드러그 해, 이것을 UTEffectsGenerator_1 에 잇습니다. 이 접속에 의해, 물리 볼륨에 접촉하면(자) Kismet 가 Use 노드를 방아쇠 해, Use 노드는 UTEffectsGenerator_1 를 사용합니다.


그림 12.25 - 관련짓고를 적절히 실시했습니다.

*18. * 잘 할 수 있었습니다. 필요한 기본 액션은 이것으로 처리됩니다. 그러나, UTEffectsGenerator 에 효과를 잇는 프로세스가 아직 처리되고 있지 않습니다. 3 방법의 효과가 있으므로, 그것들을 랜덤에 UTEffectsGenerator 에 이읍시다. 효과의 선택에는 랜덤 스윗치를 사용합니다. 오른쪽 클릭해 context menu를 열어,[Action]->[Switch] ->[Random] 를 선택해 Random 스윗치를 추가합니다.


그림 12.26 - Random 스윗치가 추가되었습니다.

*19. * Random 스윗치 노드의 프롭퍼티를 변경할 필요가 있습니다. 화면의 좌하로 스크롤 해,[LinkCount] 의 값을 1 에서 3 으로 변경합니다.


그림 12.27 - LinkCount 가 3 으로 설정되었습니다.

*20. * 오른쪽 클릭해 context menu를 열어,[Effect Generator] 카테고리의 [Add Action] 아래에 있는 3 개의 Set Effect Kismet 노드를 추가합니다. 이것은, 실제로는 전에 작성한 SeqAct_SetEffect 입니다. 3 개의 Set Effect Kismet 노드를 추가한 다음에, 그것들을 전술의 순서와 같게 Random 스윗치 Kismet 노드에 잇습니다.


그림 12.28 - Set Effect 액션을 Random 스윗치에 이었습니다.

*21. * 외도 모두와 같이 잇습니다. Set Effect Kismet 노드는 모두 UTEffectsGenerator 에 이어, 효과를 설정하는 UTEffectsGenerator 의 존재를 인식할 수 있도록(듯이) 할 필요가 있습니다. 또, Use Kismet 노드의 Out 를, Random Kismet 노드의 In 에 이어, Use Kismet 노드가 방아쇠 되면(자) Random Kismet 노드를 방아쇠 해, 그 노드가 이번은 3개의 Set Effect Kismet 노드의 어느쪽이든을 방아쇠 하도록(듯이) 합니다.


그림 12.29 - 나머지의 접속이 완성했습니다.

*22. * 레베르뷰포트에 돌아와, 레벨내에 배치한 UTEffects 의 어느쪽이든을 선택해, 상기의 UTEffectsGenerator 로 간 것과 같은 순서로, 이것을 오브젝트로서 Kismet 에 추가합니다. 오른쪽 클릭해 context menu를 열면(자), 선택한 UTEffect 가 context menu내에 나타납니다.


그림 12.30 - UTEffect 오브젝트 변수가 작성되었습니다.

*23. * 다른 2 개의 UTEffects 에 대해서도 상기의 순서를 반복합니다. 3 개(살)의 것의 효과를 모두 Kismet 에디터 윈도우내에 배치하면(자), 다음은 Set Effect Kismet 노드에 그것들을 잇습니다.


그림 12.31 - 3 개의 UTEffect 변수는 모두 Set Effect 액션에 연결되고 있습니다.

*24. * 자주(잘) 할 수 있었습니다. 이것으로 논리는 거의 갖추어졌습니다. 그러나, 최초로 레벨을 로드했을 때에 UTEffectsGenerator 에 아직 UTEffect 를 할당할 수 있지 않기 때문에, 이것을 수정합시다. 오른쪽 클릭해 context menu를 열어, Level Loaded and Visible 이벤트 노드를 작성합니다.


그림 12.32 - Level Loaded and Visble 이벤트를 추가했습니다.

*25. * 이 Level Loaded And Visible Kistmet 노드를, Random Kismet 노드에 이을 필요가 있습니다. 그 이유는, 레벨의 로드시에는 효과를 UTEffectsGenerator 로 설정하는 것만으로 자주(잘), 그 밖에 굳이 필요없기 때문입니다.


그림 12.33 - 새로운 이벤트를 Random 스윗치에 잇습니다.

*26. * Kismet 에 관한 작업은 이것 뿐입니다. 다음에 필요한 것은, 전체를 테스트하는 것입니다. 메인 툴바의 [Build All] 버튼을 눌러, 레벨 전체를 빌드 합니다.

*27. * 레벨이 빌드 되면(자) [PIE] 버튼을 클릭합니다. 레벨을 테스트하기 위한 작은 윈도우가 열립니다.

*28. * 레벨에 배치한 볼륨을 달려 나가 효과의 1 개가 나타나면(자) 성공입니다.


그림 12.34 - 효과의 1 개가 액티브하게 되었습니다.

*29. * UTEffect_Gibbage 과 UTEffect_GrenadeRing 내에는 편집 가능한 변수를 작성했으므로, 그것들은 모두 Unreal 에디터내에 항목으로서 표시됩니다. 레벨 디자이너는 이것을 이용해, 효과의 행동을 변경할 수가 있습니다. (와)과 같이 다른 변수도 공개하는 것으로, 작성한 효과를 프로그래머에 의해 매우 순응성의 높은 것으로 할 수 있습니다. 이 튜토리얼을 거슬러 올라가 이러한 변수를 조정해, 다채로운 효과를 작성해 보세요.


그림 12.35 - Gibbage 와 Grenade 효과의 편집 가능 프롭퍼티

이 튜토리얼에서는, Delegate를 Kismet 와 병용 하는 방법을 검토했습니다. Kismet 는 그 어프로치가 보다 객체 지향이기 (위해)때문에, 이 예에서는 Delegate를 인스턴스내에서를 함수에 바인드 하는 것만으로, 본래의 목적대로 기능시킬 수가 있었습니다. 이 Delegate의 사용법은 매우 소중한 포인트로, 이것에 의해 효과 제네레이터에 의해 생성되는 효과를 레벨 디자이너가 변경 가능할 뿐만 아니라, 사용하기 쉽게 하기 위해서 그러한 효과에 손볼 수도 있도록(듯이) 하고 있습니다. 같은 것을 달성하기 위한 수단은 그 밖에도 있습니다만, Delegate를 이용하면(자), 이 태스크를 한층 간단하게, 한편 매우 유연한 방법으로 실시할 수가 있습니다.

12. 10 - 통계

이 장에서는 Delegate를 깊게 파고 들어 소개했습니다만, 이 장으로부터 무엇인가 가치가 있는 것을 배워 받을 수 있었다고 생각합니다. Delegate는 통상, 코드 실행이 여러가지로 변화하는 경우나, 특히 순응성이 있는 코드를 기술해야 하는 경우에 사용됩니다. UnrealScript 에 대해 Delegate는 편리한 툴이므로, 특정 타입의 태스크의 실행 가능한 수단의 1 개로서 항상 검토되는 것을 강하게 추천합니다. Unreal Tournament 3 에서는, 써드파티에 특정 이벤트의 동작을 변경할 수 있을 기회를 준다고 하는 단순한 이유로써, 주로 GUI 내에서 사용되고 있었습니다만, 이 장의 각 튜토리얼에 나타낸 것처럼, 실은 Delegate는 거의 어디에서라도 이용할 수 있습니다.

유감스럽지만, Delegate를 사용할까 하지 않는가의 결정은 주로 경험에 의지하는 곳(중)입니다. Delegate의 매핑처의 함수를 Unreal Engine 가 결정되지 않으면 안 되기 때문에, 다른 몇개의 방법보다 훨씬 간결합니다만, 처리가 비교적 늦어질 가능성이 있습니다.

추가 파일