UDN
Search public documentation:

MasteringUnrealScriptPreProcessorKR
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

제 9 장 - UNREALSCRIPT 프리프로세서

Unreal Engine 3 에 새롭게 추가된 기능의 1 개에 UnrealScript 프리프로세서가 있습니다. C++ 의 프리프로세서에 익숙해 있다면, UnrealScript 의 새로운 프리프로세서는, 매우 쾌적하겠지요. 프리프로세서가 어떠한 것인가를 모르는 경우에서도, 걱정은 필요 없습니다 ; 간략한가입니다만, 여기에서는 세세한 곳까지 모두 설명해 갈 것입니다..

9. 1 개요

가장 간단한 형식에서는, 프리프로세서는 텍스트를 변경하는 외관만의 변환 툴에 지나지 않습니다. 프리프로세서는, 매크로로서 참조된 텍스트를, 원시 파일내의 다른 텍스트와 치환하기 위해서 사용됩니다. 또, 특정의 컴파일러 명령을 기본으로 한 파일내가 있는 종의 코드를 인클루드 하기 위해서 사용됩니다 ; 이것은, 조건 컴파일로서 알려져 복수 플랫폼에서 다른 코드를 기술해야 하는 때에는 매우 편리합니다.

스크립트의 컴파일이 실행되기 전에 프리프로세서가 기동되는 것은, 소중해서 기억해 둬 주세요.

9. 2 매크로의 기본

스크립트내에서 매크로를 사용하기 위해서는, 몇개인가 매크로를 정의하지 않으면 안됩니다, 그것을 실시하기 (위해)때문에, 편입 매크로 정의를 사용합니다. 빌트인 매크로에 대해서는, 가까운 시일내에보다 상세하게 설명합니다만, 매크로의 기본적인 정의는 이와 같이 됩니다 :

`define    MyFirstMacro    “This is really my first macro. ”

이것을 보면(자), 매크로는 ` (엑센트 기호)으로 시작되어, 뒤로 몇개의 공백 (탭 문자, 공백 문자, 또는 그러한 문자의 임의의 편성)이 도착해 있는 것을 압니다. 다음은 매크로의 이름입니다. 이것은, 후에 스크립트내에서 참조할 때에 사용합니다. 매크로의 이름에는, 공백을 포함해서는 안 되는 것에 유의해 주세요. 최후는, 매크로 본체의 정의가 됩니다. 이 본체의 정의는 옵션입니다. 본체가 없는 매크로도 정의할 수 있습니다. 그러한 매크로는, 특정의 환경하에서의 치환 용도로 사용됩니다만, 프리프로세서의 If 문내에서 이용할 때에는 매우 편리가 될 가능성이 있습니다.

주기 : 매크로의 본체의 정의를 제외한 것은, 인클루드 파일의 문맥에 문제를 발생시킬지도 모릅니다. 이것에 대해서는, 본장의 이 이후에 좀 더 자세하게 설명합니다.

매크로를 이용할 때에는, 같은 룰에 따릅니다. 위에서 작성한 매크로를 원시 파일내에서 사용하고 싶을 때로는, 이하와 같이 입력합니다 :

`MyFirstMacro

이것은, `MyFirstMacro 를 전개해, 인용부호도 포함해“This is really my first macro. ”(이)라고 옮겨놓습니다.

다른 방법으로서 이하와 같이 써도 매크로를 전개할 수 있습니다 :

`{MyFirstMacro}

능숙한 상태에 배치된 공백을 포함하지 않은 어떠한 텍스트의 본체내에서 매크로를 전개하고 싶을 때에 편리합니다. 그 외때로는, 엑센트 기호가 간단하게 간과해지기 (위해)때문에, 스크립트내에서의 매크로 제공을 명확하게 하기 위한(해), 이 형식을 사용합니다.

some`{MyFirstMacro}code

프리프로세서는, 위의 코드를 다음과 같이 변경합니다 :

some“This is really my first macro. ”code

프리프로세서가, 매크로를 전개했을 때, 결과의 매크로를 전개해야할 것인가 제발을 확인하기 위해서 전개 끝난 텍스트를 재스캔 합니다. 이것은, 매크로 전개의 무한 재귀 루프의 결과가 될 가능성이 있기 (위해)때문에, 이 기능의 사용에는 세심의 주위를 기울여야 합니다. 이하의 예에 유의해 주세요 :

`define  hello  This macro will infinitely recurse because of the `hello usage.
`hello

튜토리얼 9.1 - 최초의 매크로

본튜토리얼에서는, 매크로의 기본적인 치환 동작을 나타내기 (위해)때문에, 기존 클래스내에서 사용되는 간단한 매크로를 정의합니다. 구체적으로, 매크로는, 그 본체에 1 개 이상의 클래스 지정자를 포함한 클래스 선언보다 전에 정의됩니다. 이 매크로는, 그 후, 매크로내에서 정의한 지정자를 선언에 추가하기 위해서 클래스 선언 중(안)에서 사용됩니다.

*1. * ConTEXT 및 AmbientCreature.uc 스크립트를 오픈해 주세요.

*2. * 스크립트의 선두에 커서를 두어, 클래스의 전체의 내용을 몇행이나 아래에 움직이기 (위해)때문에 Enter 키를 몇회인가 눌러 주세요.

*3. * 스크립트의 선두행에 돌아와, ClassSpecs 라는 이름의 신규 매크로를 정의해 주세요.

`define ClassSpecs

ClassSpecs 라는 이름의 매크로가 생겼습니다만, 이 시점에서는 본체를 가지지 않습니다.

*4. * ClassSpecs 의 뒤에 공백을 두어, Placeable 클래스 지정자를 추가해 주세요. 그 결과, 최종적인 정의 내용은, 이하와 같이 됩니다 :

`define ClassSpecs placeable

여기에서는, 매크로가 사용된 임의의 장소에 placeable 라고 하는 말이 삽입됩니다.

*5. * 클래스 선언의 내부 Actor 라고 하는 말의 뒤, ; 종단자의 앞에, 공백을 추가하고 나서, 선언으로 지정자를 추가하기 위해서 ClassSpecs 매크로를 배치해 주세요.

class AmbientCreature extends Actor `{ClassSpecs};

안이나 개는, 매크로의 주위에서 관계하는 공백의 확인용으로 사용되는 것에 유의해 주세요. 아주 없으면, 이하와 같은 선언이 되어 버릴 가능성이 있습니다 :

class AmbientCreature extends Actorplaceable;

*6. * 스크립트를 컴파일 하고 나서, UnrealEd 를 오픈해 주세요. 배치 가능한 클래스로서 Actor Browser 내에 리스트 표시된 AmbientCreature 클래스를 볼 뿐만 아니라, AmbientCreature 클래스로부터 placeable 지정자를 계승하는 AmbientCreature_Fish 클래스의 일람도 봐야 합니다. UnrealEd 를 클로우즈 해 주세요.


그림 9.1 - AmbientCreature 및 AmbientCreature_Fish 의 쌍방의 클래스가 배치 가능합니다.

*7. * 여기서, ClassSpecs 매크로의 정의 중(안)에서, placeable 지정자의 곧 전에 abstract 지정자를 추가해 주세요. 정의는 이하와 같이 됩니다 :

`define ClassSpecs abstract placeable

*8. * 재차 스크립트를 컴파일 해, 한번 더 UnrealEd 를 오픈해 주세요. Actor Browser 중에는, 여전히, 양쪽 모두의 클래스가 표시되고 있습니다만, 이번은, AmbientCreature 클래스는, abstract 로서 선언되었기 때문에, 배치 가능한 클래스에서 없는 일을 나타내기 위해서(때문에) 그레이 아웃 되고 있을 것입니다. 어떠한 코드가 매크로의 본체안에 놓여졌다고 해도, 그것은, 클래스 선언의 매크로의 위치에 삽입되는 것을 알겠지요.


그림 9.2 - AmbientCreature_Fish 클래스만이 배치 가능해졌습니다.

*9. * 다음의 튜토리얼로 사용하므로, 새로운 매크로와 함께 파일을 보존해 주세요.

<<<< 튜토리얼의 종료 >>>>

9. 3 파라미터 첨부 매크로

입력으로서 파레메이타를 받는 매크로 정의를 작성하는 일도 가능합니다. 이것은, 기본적으로, 많은 점으로써 함수와 닮아 있습니다만, 평가되는 대신에 전개됩니다. 이것에 의해, 어떤 종류의 매크로는, 함수로 같은 것을 실시하면, 보다 성능이 향상할 가능성이 있습니다.

형식적으로는, 매크로의 정의는 이하와 같이 됩니다 :

`define <macro_name>[(<param1>[,<param2>...])] [macro_definition]

정의가 무섭게 보일지도 모릅니다만, 문제는 없습니다. 몇개인가예를 보고 갑시다.

례 : 수를 세제곱 하는 매크로의 작성

이 매크로의 정의는 이하와 같이 됩니다 :

`define Cube(x) `x * `x * `x

이것은, x 라는 이름의 1 개의 파라미터를 받는 Cube 라는 이름의 매크로를 작성하는 것을 나타냅니다. 전개식에서는, 무엇이 건네받아도 x 로 옮겨놓아 x * x * x 에 전개합니다. 파라미터의 이름을 참조하려면 , ` (엑센트 기호)를 앞에 두고 부가해야 하는 것에 유의해 주세요

이 매크로를 사용할 때는, 이러한 기분이 듭니다 :

var int myVal = `Cube(3);

매크로의 호출시에, ( (열림이나 개)를, 매크로의 이름의 곧 뒤로 기술하는 것은, 매우 중요합니다 ; 공백을 두어서는 안됩니다.

예 : 2 개의 수를 가산해 제곱하기 위한 매크로

이 매크로는 2 개의 수를 더하고 나서, 그 결과를 제곱 합니다.

`define SumSquare(x, y) (`x + `y) * (`x + `y)

이 매크로의 사용은, 이하와 같이 실시합니다 :

var int myVal = `SumSquare(5, 3);

함수와 같게, 파라미터를 나누기 위해서(때문에), 칸마가 사용됩니다. 그렇지만, 함수와는 달라, 매크로의 파라미터는 완전하게 안전한 형태를 제공하지 않습니다. 예를 들어, 만약, 다음과 같이 기술하면(자), 매크로가 이렇게 있어야 하는 것이라고 생각하도록(듯이) 전개를 행하겠지요 :

var int badValue = `SumSquare(p1, p2);

전개는 이하와 같이 행해지겠지요 :

var int badValue = (p1+ p2) * (p1+ p2);

여기서, 만약, p1 및 p2 가 실제로 integer 의 변수로서 정의되고 있으면, 이것은, 예기 한 대로 동작하겠지요. 그렇지만, 프리프로세서는, 이 형태의 유효성 체크를 실시하지 않으므로, 컴파일조차 할 수 없는 코드가 될 가능성도 있습니다.

Unreal 프리프로세서는, 매크로 평가동안의 공백 문자를 생략 하는 경향에 있으므로, 유의해 주세요. 만약, 다음과 같은 출력을 실시하고 싶은 경우는 (p1 의 뒤의 공백에 유의) :

var int badValue = (p1 + p2) * (p1 + p2);

이하와 같이 정의시에 매크로를 {}(안이나 개)로 둘러쌀 필요가 있습니다 :

`define SumSquare(x, y) (`{x} + `{y}) * (`{x} + `{y})

이 예의 경우는, 어디라도 상관없습니다만, 문제가 될 가능성이 있는 부분이므로, 이러한 사실이 있는 것은 제대로 기억해 둬 주세요.

튜토리얼 9.2 - 매크로 파라미터

본튜토리얼에서는, 전회의 튜토리얼로 얻은 지식을 보다 넓혀 파라미터를 사용하는 신규 매크로를 작성합니다. 이 매크로는, 기본적으로는 함수로서 동작해, 새로운 변수의 선언도 할 수 있게 됩니다.

*1. * ConTEXT 및 전회의 튜토리얼에서의 변경을 포함한 AmbientCreature.uf 스크립트를 오픈해 주세요.

*2. * ClassSpecs 매크로의 정의아래에, 이하에 나타내는 파라미터를 가지는 NewEditVar 라는 이름의 신규 매크로를 정의해 주세요 :

`define NewEditVar(varCat, varType, varName)

*3. * 여기서, 매크로의 본체를 추가합니다. 이 매크로의 목적은 새롭게 편집 가능한 변수를 선언하는 것이므로, 매크로 본체는, 매크로의 파라미터를 사용한 변수 선언의 형식을 취합니다. 여기로 보여지도록(듯이) 본체를 추가해 주세요 :

var(`varCat) `{varitype} `{varName}

매크로 정의의 전체는 이하와 같이 됩니다 :

`define NewEditVar(varCat, varType, varName) var(`varCat) `{varitype} `{varName}

여기에서도, 공백의 정합성을 유지하기 위해서(때문에) 중이나 개를 사용했습니다.

*4. * 이것으로, AmbientCreature 클래스안으로, 신규의 편집 가능한 변수를 선언하기 위해서, 이 매크로를 사용할 수 있습니다. 클래스 선언의 후에, 이하의 코드를 추가해 Macro 카테고리내에 놓여지는 bMacro 라는 이름의 신규 bool 변수를 선언해 주세요 :

`NewEditVar(Macro, Bool, bMacro)

*5. * 스크립트를 컴파일 해, UnrealEd 를 오픈해 주세요. AmbientCreature_Fish 클래스는, 전회의 튜토리얼로 간 변경에 근거해 아직도 배치 가능 (placeable)이 되고 있을 것입니다. Actor Browser 내에서 이 클래스를 선택해, 뷰포트내에서 오른쪽 클릭해, Add AmbientCreature_Fish Here 를 선택하는 것으로, 맵에 이 클래스의 인스턴스를 추가해 주세요.


그림 9.3 - 신규 AmbientCreature_Fish 먼지는, 맵내에 배치됩니다.

*6. * 프롭퍼티 윈도우를 오픈하기 위해서 신규 먼지를 더블 클릭 해 주세요. Macro 카테고리가 존재할 것입니다. 이 카테고리를 전개하면, bMacro 프롭퍼티가 리스트 표시되고 있을 것입니다. 이 매크로는, 신규 변수를 선언하기 위해서 적절한 코드를 삽입하기 위해서 사용되었습니다.


그림 9.4 - bMacro 프롭퍼티는 매크로를 사용해 추가되었습니다.

이 경우, 매크로 코드는, 수작업으로 선언을 입력하는 것보다 현격히 효율적이라고 하는 것은 아닙니다만, mod 의 개발시에는, 이러한 형태의 매크로의 이용에 의해, 반복 작업의 실시가 매우 효율화되는 것 같은 상황이 될지도 모릅니다.

*7. * 미사용의 신규 매크로 및 변수의 선언과 함께 파일을 보존해 주세요. 이것들은, 다음의 튜토리얼로 사용됩니다.

<<<< 튜토리얼의 종료 >>>>

9. 4 편입 매크로

UnrealScript 프리프로세서는, 이미 정의되고 있는 몇개의 편입 매크로를 가집니다. 이 설명에서는, 그러한 매크로를 채택해 그 사용법의 예를 제시합니다.

DEFINE

이 매크로는, 사용하고 싶은 다른 매크로를 정의하기 위해서 사용됩니다. 명명된 매크로는, 주어진 정의에 따라 전개되겠지요 ; 만약, 아무것도 정의가 제공되어 있지 않으면, 하늘의 캐릭터 라인에 전개됩니다.

정의의 형식은 이하대로입니다 :

`define <macro_name>[(<param1>[,<param2>...])] [macro_definition]

파라미터와 함께 명명된 매크로를 사용할 때는, ( (열림이나 개)를 매크로의 이름의 직후로 지정하지 않으면 안되어, 매크로와 그 모든 파라미터는, 형지를 무늬를 박아서 염색한 것 되지 않고 , 칸마로 나눌 수 있었던 리스트로 지정되는 것을 생각이 미쳐 주세요.

define 에 대해서는, 특수한 매크로가 있습니다 : `# 입니다. 이 매크로는, 지정된 파라미터의 수를 나타내, 매크로의 정의의 내부에서만 사용 가능합니다. 예를 들면 :

`define MyMacro(p1, p2, p3, p4) “This macro contains `# parameters. ”

var string myString = `MyMacro(1, 2, 3, 4);

위의 MyMacro 의 이용을 전개하면(자) 이하와 같이 됩니다 :

var string myString = “This macro contains 4 parameters. ”;

IF/ELSE/ENDIF

if, else 및 endif 매크로는 조건 컴파일을 서포트하기 위해서 사용됩니다 ; 그것들은, 컴파일시에, 어느 코드의 블록을 대상으로 하거나 대상외로 하거나 합니다. 이것은, 특정의 플랫폼에 대해서 고유의 실장을 제공할 필요가 있을 때에 매우 유용합니다.

정의의 형식은 이하와 같습니다 :

`if(<value>)
`else
`endif

만약 공백 이외의 캐릭터 라인에 전개되면(자), if-문중의 값은 true 라고 평가됩니다만, 그렇지 않으면, false 로 간주해집니다. 이 값이 true 라고 평가되었을 때에는, if 및 else 매크로의 사이의 텍스트의 모든 것이, 파일내에 놓여집니다. 그렇지 않으면, else 및 endif 매크로의 사이의 텍스트가 사용됩니다.

else 매크로는, 이 구조에서는 생략 가능한 부분인 것은, 알아 두면 좋을 것입니다 ; 즉, if 및 endif 매크로만으로 만들어진 블록도 유효가 됩니다.

예 : IF/ELSE/ENDIF 의 사용법

이 예에서는, 매크로를 정의해, 매크로가 공백 캐릭터 라인으로서 평가되는지 아닌지에 근거해 코드의 블록을 인클루드 합니다.

`define MyIfCheck “Yes”

var int myValue;

`if(`MyIfCheck)
myValue = 10;
`else
myValue = 20;
`endif

물론, 이 예는, 만약 MyIfCheck 가 항상 “Yes”라고 평가되지 않았던 경우는, 좀 더 편리하게 되겠지만, 그방법은, 잠시 후에 커멘드 라인 옵션으로 학습합시다.

예 : IF/ELSE/ENDIF 매크로의 상자

1 개(살) 이상 상태를 체크 가능하게 하고 싶은 경우가 가끔 있습니다. 이것을 실시하기 위해서(때문에) 2 종류의 방법이 있는 ; 어느 쪽이 기호인가는 스스로 결정해 주세요.

2 개의 방식으로는 비공백 캐릭터 라인 (PC, XBOX360 또는 PS3)에 대해서 이하의 매크로 가운데 1개를 정의한다고 합니다.

방식 1:

`if(`PC)
// PC 에 대해서 실행되는 코드는 여기입니다
`else `if(`XBOX360)
// Xbox 360 에 대해서 실행되는 코드는 여기입니다
`else `if(`PS3)
// PS3 에 대해서 실행되는 코드는 여기입니다
`endif

방식 2:

`if(`PC)
// PC 에 대해서 실행되는 코드는 여기입니다
`endif
`if(`XBOX360)
// Xbox 360 에 대해서 실행되는 코드는 여기입니다
`endif
`if(`PS3)
// PS3 에 대해서 실행되는 코드는 여기입니다
`endif

위에서 사용된 어느쪽식에서도, 실행하는 플랫폼에 의존해 특정의 코드의 블록만의 실행을 확실히 합니다만, 한편은, 한편보다 약간 간결하게 되어 있습니다.

INCLUDE

include 매크로는 현재의 장소에 다른 파일의 내용을 인클루드 하기 위해서 사용됩니다. include 매크로는 이와 같이 됩니다 :

`include(<filename>)

디폴트에서는, 파일명은, 게임의 INI 파일의 Editor.EditorEngine 섹션내로 설정된 EditPackagesInPath 로 지정된 디렉토리로부터의 상대 패스로 간주해집니다. 파일명이 디렉토리 패스를 포함하지 않을 때는, 컴파일러는, 우선 UTGame/Src 디렉토리를 파일 검색하고 나서, 현재 컴파일 하고 있는 패키지에 대한 기저 디렉토리내를 찾습니다.

인클루드 파일은, 통상의 . uc UnrealScript 파일이 포함할 수가 있는 임의의 코드를 격납할 수 있습니다. 파일내의 코드는, 그것을 인클루드 하는 임의의 스크립트내에 삽입됩니다. 임의의 파일 타입이 지정 가능합니다만, (UC Include 를 의미한다) . uci 가 꽤 일반적으로 사용되고 있습니다. 이 파일 타입은, 본서를 통해서 모든 인클루드 파일에 대해 사용됩니다.

주의하지 않으면 안 되는 중요한 문제의 1 개는, 인클루드 파일 내부에서 본체가 없는 매크로를 정의하면(자), 특히 만약, 이 정의가 파일의 맨 마지막 줄이었을 경우에, compile error를 일으킬 가능성이 있는 것입니다. 단순한 코멘트에서도 좋기 때문에, 그러한 정의의 뒤로 어떠한 코드를 기술해, 이 문제를 해소해야 합니다.

ISDEFINED/NOTDEFINED

isdefined 매크로는, 지정된 매크로가 정의되고 있는 것을 확인하기 위해서 사용됩니다 ; 매크로가 정의되고 있었을 경우는, 이 매크로는 "1" 으로 평가합니다. isdefined 매크로는 이와 같이 됩니다 :

`isdefined(<macro_name>)

notdefined 매크로는 isdefined 매크로와 같습니다만, 지정된 매크로가 정의되어 있지 않은 것을 확인하기 위해서 사용되기도 하고 ; 매크로가 정의되어 있지 않았던 경우에는, 이 매크로는 "1" 으로 평가합니다. notdefined 매크로는 이와 같이 됩니다 :

`notdefined(<macro_name>)

이것들 쌍방의 매크로는, 주로 조건 컴파일의 문맥으로 사용됩니다.

예 : IF/ELSE/ENDIF 및 ISDEFINED/NOTDEFINED 의 편성

플랫폼 고유의 매크로 정의를 확인하기 직전의 예에서는, 매크로는 항상 어떠한 공백에서 없는 캐릭터 라인에 평가되도록(듯이) 보였습니다. 그렇지만, 실제는 항상 그렇지는 않아요로, 이러한 조건을 확인하기 위해서는, 보다 확실한 방법이 바람직합니다. 여기에서는, isdefined 및 notdefined 매크로가 정말로 유용하게 보입니다.

`define MyCode

`if(`isdefined(MyCode))
// MyCode 가 정의되고 있기 (위해)때문에, 이 블록은 인클루드 됩니다
`endif

`if(`notdefined(MyCodeNotDefined))
// MyCodeNotDefined 가 정의되어 있지 않기 때문에, 이 블록도 인클루드 됩니다
`endif

위의 예는, 이전의 if/else/endif 매크로의 예에 자주(잘) 비슷한 것처럼 보일지도 모릅니다만, if 매크로는, 공백에서 없는 캐릭터 라인에 대해서 true 의 평가를 실시할 뿐(만큼)이었던 일을 생각해 내 주세요. 만약, 위의 예의 MyCode 가 공백 캐릭터 라인에 대해서 평가되고, 또, isdefined 매크로도 사용하지 않았으면, if 매크로는 false 라고 평가되어, 블록은 인클루드 되지 않을 것입니다.

UNDEFINE

undefine 매크로는, 지정된 이름의 매크로의 현재의 정의를 삭제하기 위해서 사용됩니다. 이와 같이 됩니다 :

`undefine(<macro_name>)

`# (와)과 같은 파라미터명의 정의의 삭제는 할 수 없기 때문에, 중요한 점으로서 유의해 주세요.

LOG/WARN

log 및 warn 매크로는, 어느쪽이나 Object.uc 내에서 선언된 LogInternal 및 WarnInternal 함수에 대한 래퍼로, 스크립트의 디버그에는 매우 유용합니다. 매크로의 정의는 이하와 같습니다.

`log(string OutputString, optional bool bRequiredCondition, optional name LogTag);
`warn(string OutputString, optional bool bRequiredCondition);

bRequiredCondition 가 지정되고 있으면(자), 조건은, 메세지를 로그 출력하는지 아닌지를 결정하기 위한 스크립트의 실행중에 평가됩니다.

스크립트가, ? final_release 스윗치 첨부로 컴파일 되었을 경우는, 이러한 매크로는 어느쪽이나 무효가 됩니다.

LOGD

logd 매크로는, log 매크로와 완전히 같습니다만, 스크립트가 디버그 모드로 컴파일 되는 때만 평가됩니다.

`logd(string OutputString, optional bool bRequiredCondition, optional name LogTag);

본매크로는, 스크립트가 ? final_release 스윗치 첨부로 컴파일 되었을 경우는 무효가 됩니다.

ASSERT

본매크로는, Assert 편성식에 대한 래퍼입니다. 이것은, 특히 디버그시에, 특정의 조건에 합치했는지를 아서트, 또는 평가하기 위해서 사용됩니다.

아서트마크로는 이하와 같이 정의됩니다 :

`assert(bool bCondition);

본매크로는, 스크립트가 ? final_release 스윗치와 함께 컴파일 되었을 때에는 무효가 되는 것에 유의해 주세요.

예 : 조건의 평가

이 예는, 2 개의 수를 가산해, 합계의 아서트 확인을 실행합니다.

var int x = 1;
var int y = 4;
var int sum = x + y;
`assert(sum == 4);

튜토리얼 9.3 - 인클루드 파일을 사용한다

본튜토리얼에서는, 인클루드 파일의 사용법을 소개합니다. 전회의 튜토리얼내에서 정의된 NewEditVar 매크로는, 별파일에 이동되어 include 매크로의 사용을 통해 AmbientCreature 클래스에서 이용 가능해집니다.

*1. * ConTEXT 와 같게 AmbientCreature.uc 파일을 오픈해 주세요.

*2. * 신규 파일을 작성해, 희망에 응해, UnrealScript 하이 라이터를 설정해 주세요.

*3. * AmbientCreature.uc 파일내의 NewEditVar 매크로 정의를 선택해, Ctrl+X 를 눌러 절취를 실시해 주세요. 신규 파일내에 매크로 정의를 붙이기 (위해)때문에, 여기서 Ctrl+V 를 눌러 주세요.

*4. * 이 시점에서 AmbientCreature.uc 파일을 보존해, 스크립트를 컴파일 하면(자), NewEditVar 매크로가 여전히 사용되고 있습니다만, 스크립트내에서는 정의되어 있지 않기 때문에, 에러가 되겠지요. 실제로 시도해, 스스로 확인해 보세요. 컴파일러는, 매크로가 존재하지 않는다고 하는 에러를 출력할 것입니다.

*5. * File 메뉴로부터 Save As 를 선택해, 매크로 정의를 모두 포함한 신규 파일을 보존해 주세요. 1 개(살)상의 디렉토리 MasteringUnrealScript 폴더로 이동해, 파일명으로서 AmbientCreature_Debug.uci 를 입력해 주세요. ConTEXT 는, UnrealScript 하이 라이터의 사용에 근거해 . uc 파일 타입으로 보존을 실시하려고 하기 위한(해), 파일 타입은 메뉴얼로 입력하지 않으면 안됩니다.

*6. * 여기서, AmbientCreature.uc 파일내에서 NewEditVar 매크로를 정의한 장소에, 신규 파일을 인클루드 하기 위한(해), 이 스크립트내에 이하의 문장을 추가해 주세요.

`include(AmbientCreature_Debug.uci)

*7. * AmbientCreature.uc 파일을 보존해, 재차 스크립트를 컴파일 해 주세요. 이번은, 매크로에 관한 에러는 없을 것입니다.

*8. * UnrealEd 를 오픈해, 맵내에 AmbientCreature_Fish 먼지를 배치해 주세요. 그 프롭퍼티를 오픈해, Macro 카테고리 및 bMacro 프롭퍼티의 쌍방이 존재하는 것을 확인하기 위해서 체크해 주세요. AmbientCreature_Debug.uci 파일로부터의 코드는, include 문을 사용해 AmbientCreature.uc 파일내에 올바르게 삽입됩니다. 이 경우는, 인클루드 된 파일내에는, 프리프로세서문만을 인클루드 했습니다만, 임의의 UnrealScript 코드가 이 파일안에는 배치 가능하고, 다른 임의의 파일내에 인클루드 가능합니다. 이것은, 서로 계승을 실시하는 것 같은 사치가 용서되지 않은 몇개의 클래스내에서 사용하기 위해서 필요한 함수를 가지는 경우에는, 매우 편리합니다. 한 번, 함수를 기술하면, 그것을 포함한 파일을 인클루드 하는 것만으로 어디에서라도 사용할 수가 있습니다.


그림 9.5 - AmbientCreature_Fish 먼지는, 맵내에 배치되고 있습니다.

*9. * 그 프롭퍼티를 오픈해, 아직, Macro 카테고리와 bMacro 프롭퍼티의 쌍방이 존재하고 있는 것을 확인해 주세요.


그림 9.6 - bMacro 프롭퍼티는 여전히 Property 윈도우내에 표시되고 있습니다.

AmbientCreature_Debug.uci 파일로부터의 코드는, include 문을 사용해 AmbientCreature.uc 파일에 올바르게 삽입됩니다. 이 경우는, 인클루드 된 파일내에는, 프리프로세서문만을 인클루드 했습니다만, 임의의 UnrealScript 코드가 이 파일안에는 배치 가능하고, 다른 임의의 파일내에 인클루드 가능합니다. 이것은, 서로 계승을 실시하는 것 같은 사치가 용서되지 않은 몇개의 클래스내에서 사용하기 위해서 필요한 함수를 가지는 경우에는, 매우 편리합니다. 한 번, 함수를 기술하면, 그것을 포함한 파일을 인클루드 하는 것만으로 어디에서라도 사용할 수가 있습니다.

*10. * 다음에 진행되기 전에, 데모의 목적으로 AmbientCreature 클래스에 더해진 추가는, 이미 필요없기 때문에 삭제합시다. 이러한 추가는 이하를 포함합니다 :

  • ClassSpecs 매크로의 정의
  • 클래스 선언내의 ClassSpecs 매크로의 이용
  • AmbientCreature.uci 파일에 대한 인클루드
  • bMacro 변수를 선언하기 위한 NewEditVar 매크로의 이용

*11. * 모든 것이 삭제되면(자), AmbientCreature.uc 파일을 보존해 주세요.

<<<< 튜토리얼의 종료 >>>>

9. 5 커멘드 라인 스윗치

스크립트를 컴파일 할 때에, 커멘드 라인 스윗치가 지정 가능합니다. 이러한 스윗치는, 프리프로세서의 동작 방법을 변경하기 위해서 사용됩니다.

DEBUG

이 스윗치로 스크립트가 컴파일 되었을 때에는, 디버그 매크로가 정의됩니다. 이것은, 스크립트내의, 디버그 정보와 같은, 특정의 기능을 인클루드 하고 싶을 때로는, 특히 편리합니다만. 개발의 테스트 스테이지를 통해서 마셔 필요합니다.

사용법 : ut3.exe make ? debug

FINAL_RELEASE

본스윗치는, 스크립트가 최종 릴리스로서 컴파일 되는 것을 알리기 위한 것입니다. 이것은, final_release 매크로를 정의해, (log, logd, warn, assert 등의) 래퍼 매크로를 이용 불가로 합니다.

사용법 : ut3.exe make ? final_release

NOPREPROCESS

이것은, 모든 매크로 및 코멘트의 프리프로세스 처리를 무효로 합니다 ; 즉, 스크립트의 컴파일중에 매크로는 평가되지 않습니다. 이것은, 매우 편리한 커멘드 라인 스윗치라고 하는 것은 아닙니다만, 매크로를 유도하는 문자 (엑센트 기호)를 사용하는 파일이 있으면, 이 커멘드 라인 스윗치를 사용할 수 있을지도 모릅니다.

사용법 : ut3.exe make ? nopreprocess

INTERMEDIATE

이 스윗치는, 중간적인 프리프로세스가 끝난 파일을 제공하기 위해서 사용됩니다. 이것은, 원인을 더듬는 것이 어려운 프리프로세서의 문제를 추적할 때에 매우 유용합니다. 시간이 걸려, 여분의 디스크 공간도 사용합니다만, 경우에 따라서는, 가치가 있을 가능성이 있습니다.

이러한 파일은, 여기에 격납됩니다 : ..\UTGame\PreProcessedFiles\

..\UTGame 는, mod 를 보존하는 장소의 루트에서도 있는 것에 유의해 주세요.

사용법 : ut3.exe make ? intermediate

튜토리얼 9.4 - 비주얼 디버그 모드, 파트 I: INCLUDE 파일의 설정

이 일련의 튜토리얼을 통해, -debug 스윗치가 사용되는 때인 만큼, 스크립트중에 컴파일 되는 앰비언트 크리쳐에 대한 비주얼 디버그 시스템을 작성합니다. 이 시스템은, 크리쳐의 동작과 같이, 개개의 크리쳐의 위치를 나타내는 박스와 같은 다른 비주얼 인디케이터(indicator)를 나타내는 경로를 그리는 능력을 제공합니다. 이러한 종류의 피드백은, 신규 클래스를 설계할 때에는, 매우 유용이 될 가능성이 있습니다만, 먼지를 맵내로 설정했을 때에는, 디자이너에 있어서는, 그만큼 유용하지는 않습니다. 이러한 사실에 가세해, 사용되는 메소드는 몹시 성능을 해치므로, 스크립트 컴파일시의 -debug 스윗치 사용을, 이 조건으로서 선택하고 있는 이유는 납득할 수 있을지도 모릅니다. 프로그래머로서는, -debug 모드에서의 컴파일에 의해 즉석에서 명쾌한 피드백을 얻는 능력을 가져, 동시에, 디자이너가 셋업 처리를 가능한 한 간단하게 정리할 수 있도록(듯이) 불필요한 것은 컴파일 대상에서 제외할 수가 있습니다.

이 제 1 의 튜토리얼에서는, AmbientCreature 및 AmbientCreatureInfo 클래스의 쌍방에서 사용되는 새로운 구조체의 선언을 포함한 인클루드 파일의 설정에 초점을 맞힙시다. AmbientCreatureInfo 클래스에서는, 각각의 CreatureInfo 가 이 구조체의 자기 자신의 인스턴스를 가지기 때문에, 비주얼 피드백도 개별적으로 설정할 수 있습니다. AmbientCreature 클래스는, AmbientCreatureInfo 로부터 건네받은 프롭퍼티를 보관 유지하기 위해서 구조체의 인스턴스를 가집니다.

*1. * ConTEXT 및 AmbientCreature_Debug.uci 파일을 오픈해 주세요.

*2. * AmbienCreature_Debug.uci 파일은, 현재는 NewEditVar 매크로의 정의를 포함하고 있습니다. 파일내의 이 정의를 그대로 해 두어도 전혀 문제 없습니다만, 자신의 방식과 다른 경우에, 삭제하는 것은 자유롭습니다. 그것은, 이 장에서는 이제 사용되지 않습니다.

이하의 행을 스크립트에 추가해, DebuggingInfo 라는 이름의 신규 구조체의 선언을 설정하는 것으로부터 시작합시다 :

struct DebuggingInfo
{
};

*3. * 구조체를 선언하기 위해서, 이 구조체에 어떠한 변수가 포함될까를 알 필요가 있습니다. 대부분은, 구조 체내의 변수는 Bool 변수로, 특정의 비주얼 인디케이터(indicator)를 묘화 할지 어떨지를 결정합니다. 이러한 변수는 이하와 같습니다 :

  • bShowDebug - 모든 비주얼 인디케이터(indicator)에 대한 글로벌 타글
  • bShowFollowPaths - 무리의 크리쳐의 경로의 묘화에 대한 타글


그림 9.7 - 무리의 각각의 크리쳐의 경로가 묘화 됩니다.

  • bShowLeaderPaths - 무리를 리드하는 크리쳐의 경로의 묘화의 타글


그림 9.8 - 무리를 인솔하는 크리쳐의 경로가 묘화 됩니다.

  • bShowFlockPaths - 무리 안의 크리쳐로부터 리더에게로의 링크를 묘화하기 위한 타글


그림 9.9 - 무리 안의 개개의 크리쳐로부터 리더에게로의 경로가 묘화 됩니다.

  • bShowFlockBoxes - 무리 안의 크리쳐의 장소에 박스를 묘화하기 위한 타글


그림 9.10 - 무리 안의 개개의 크리쳐의 위치에 박스가 묘화 됩니다.

  • bShowLeaderBoxes - 무리를 인솔하는 크리쳐의 위치에 박스를 묘화하기 위한 타글


그림 9.11 - 만약 그것이 크리쳐였다면, 리더의 위치에 박스가 그려집니다.

  • bShowMesh - 크리쳐의 비지비리티를 위한 타글


그림 9.12 - 좌측에서는, bShowMesh 는 True 로, 우측에서는 False 입니다.

여기에서는, 단지, 이하에 나타내는 것 같은 구조체 정의 중(안)에서, 이러한 변수 각각 대해 선언을 추가할 수가 있을 뿐입니다. 이러한 개개의 변수는, 편집 가능으로서 선언 해야 할것에 유의해 주세요.

var() Bool bShowDebug;
var() Bool bShowFollowPaths;
var() Bool bShowFlockPaths;
var() Bool bShowLeaderPaths;
var() Bool bShowFlockBoxes;
var() Bool bShowLeaderBoxes;
var() Bool bShowMesh;

*4. * 다음에 진행되기 전에, 한층 더 필요한 변수가, 2 개(살) 있습니다. 무리 안의 크리쳐는, 리더 패스를 정의하는 일련의 위치 정보를 보존합니다. 크리쳐가 향하고 있는 현재의 위치에의 경로만의 묘화를 선택하는지, 또는, 그 위치의 모든 것을 사용한 경로를 묘화 할 수 있습니다. 그렇지만, 좀 더 유연한 해결책은, 경로를 묘화 할 때에, 에디터의 내부의 프롭퍼티를 사용해, 사용하는 경로의 길이와 위치의 수를 허가하겠지요. FollowPathSegments 라고 이름 붙인 Int 변수가, 이 값을 결정하기 위해서(때문에) 사용됩니다. 여기서, 이 변수에 대한 선언을 추가해 주세요.

var() Int FollowPathSegments;


그림 9.13 - FollowPathSegments 프롭퍼티에 의해, 여러가지 값으로 경로가 묘화 됩니다.

*5. * 이러한 패스를 묘화 할 때도 이와 같이 색을 지정하지 않으면 안됩니다. 동시에, 1 살의 장면내에 복수의 무리를 가지는 것이 가능하므로, 경로의 모든 것을 같은 색으로 그렸다고 하면(자), 얼마나 혼란할까는 상상할 수 있겠지요. 각각의 크리쳐의 무리로, 그 무리에 속하는 크리쳐의 경로마다 개별적으로 커스텀 설정색을 가질 수가 있도록(듯이) FollowPathColor 라는 이름의 Color 변수를 추가할 수 있습니다.

var() Color FollowPathColor;

*6. * 구조체 정의의 마지막 부분에서는, 선언을 실시한 마지막 2 개의 변수에 대한 디폴트치를 설정합니다. FollowPathSegments 프롭퍼티에 대해서는 6 의 초기치가 좋을 것입니다. 또, 디폴트의 티르색을 사용해 경로를 묘화 합니다. 이하와 같은 디폴트치를 지정해 structdefaultproperties 블록을 추가해 주세요 :

structdefaultproperties
{
   FollowPathSegments=6
   FollowPathColor=(R=0, G=255, B=255)
}

*7. * AmbientCreature_Debug.uci 파일을 보존해 주세요.

<<<< 튜토리얼의 종료 >>>>

튜토리얼 9.5 - 비주얼 디버그 모드, 파트 II: 조건 INCLUDE 문

본튜토리얼에서는, 전회의 튜토리얼로 설정한 파일이, 컴파일시에 -debug 스윗치가 사용되었는지 어떠했는지에 근거해 AmbientCreature 및 AmbientCreatureInfo 클래스내에 인클루드 됩니다. 또, 개개의 클래스에서는, DebuggingInfo 구조체의 인스턴스도 선언합니다.

*1. * ConTEXT 와 같이, AmbientCreature.uc 및 AmbientCreatureInfo.uc 파일을 오픈해 주세요.

*2. * 클래스 선언의 뒤의 AmbientCreature 클래스에 있어, 기본적으로 클래스내에서 DebuggingInfo 구조체를 선언하는 AmbientCreature_Debug.uci 파일을 인클루드 가능합니다. 초에, 컴파일 처리중에 -debug 스윗치가 사용되었을 때에게만 인클루드를 하는 것을 확인할 필요가 있습니다. 본장으로 지금까지 배워 온 것처럼, -debug 스윗치가 사용되었을 때는, 디버그 매크로가 정의됩니다. 디버그 매크로가 정의되고 있는 것을 확인하기 위해서 `isdefined 매크로와 함께 `if 매크로를 사용 가능하므로, if 문의 내부에 include 문을 배치합니다.

이하와 같이 ? debug 스윗치를 확인하기 위한 `if 문을 설정해 주세요 :

`if(`isdefined(debug))
`endif

여기서, `if 행의 뒤, `endif 행의 전에, include 문을 기술해 주세요 :

`include(AmbientCreature_Debug.uci)

코드의 최종 섹션은, 이하와 같이 됩니다 :

`if(`isdefined(debug))
`include(AmbientCreature_Debug.uci)
`endif

*3. * DebugInfo 라고 이름 붙인 DebuggingInfo 구조체의 인스턴스도 선언할 필요가 있습니다. 이것도 조건이므로, 같은 `if 문의 내부에 선언을 실시할 수가 있습니다. 여기서, 선언을 추가해 주세요.

var DebuggingInfo DebugInfo;

여기서 `if 문은 이하와 같이 됩니다 :

`if(`isdefined(debug))
`include(AmbientCreature_Debug.uci)
var DebuggingInfo DebugInfo;
`endif

*4. * Ctrl+C 를 눌러, 이 블록의 코드를 카피해 주세요.

*5. * AmbientCreatureInfo 클래스내의 클래스 선언의 뒤에, Ctrl+V 를 눌러, 이 블록의 코드를 붙여 주세요.

*6. * AmbientCreatureInfo 클래스내의 DebuggerInfo 의 인스턴스가, CreatureInfo 구조체의 내부에 놓여지는 일은, 이전에 말했습니다만, 그 결과적으로, 크리쳐의 개개의 그룹은 그것 자신의 인스턴스를 가집니다. DebugInfo 변수의 선언을 선택해, Ctrl+X 를 눌러 절취를 실시해 주세요.

*7. * CreatureInfo 구조체의 정의안의 마지막 변수 선언 (아마 FlockInfo)의 뒤로, DebugInfo 선언을 붙여 include 문에 대해서 사용된 것과 같이 `if 문으로 둘러싸 주세요. 이 DebugInfo 변수도 확실히 편집 가능하게 해 주세요. 새로운 코드의 블록은 이하와 같이 됩니다 :

`if(`isdefined(debug))
var() DebuggingInfo DebugInfo;
`endif

CreatureInfo 는, 이하와 같은 것이 됩니다 :

struct CreatureInfo
{
   var array<AmbientCreature> MyCreatures;
   var() class<AmbientCreature> CreatureClass;
   var() array<AmbientCreatureNode> CreatureNodes;
   var() Int NumCreatures;
   var() Float MinTravelTime, MaxTravelTime;
   var() Float Speed;
   var() DisplayInfo DisplayInfo;
   var() FlockInfo FlockInfo;
   `if(`isdefined(debug))
   var() DebuggingInfo DebugInfo;
   `endif

   structdefaultproperties
   {
      MinTravelTime=0. 25
      MaxTravelTime=4. 0
      Speed=70
      NumCreatures=1
   }
};

*8. * 양쪽 모두의 파일을 보존해 주세요. 신규 코드가 적절히 동작할지 어떨지를 확인하기 위해서, 스크립트를 컴파일 할 필요가 있습니다. 그러나, 결과를 보다 간단하게 보기 위해서(때문에), 컴파일시에, 분명하게 필요한 ? debug 스윗치에 가세해 ? intermediate 스윗치의 이용이 가능합니다. 이러한 스윗치를 사용하기 위해서, 스윗치의 설정을 허가하는 컴파일 방식을 사용하지 않으면 안됩니다. 이러한 방식은 이하와 같은 것을 포함합니다 :

  • 커멘드 라인을 사용한다
  • 커스텀 Target 로 쇼트 컷을 사용한다
  • ConTEXT 내에서 Exec 키를 설정한다

어느 방식의 사용을 선택해도, ? debug 및 ? intermediate 의 양쪽 모두의 스윗치를 추가하지 않으면 안됩니다. 이것은, 다음과 같이 보일지도 모릅니다 :

C:\Program Files\Unreal Tournament 3\Binaries> UT3.exe make ? debug -intermediate

*9. * 스크립트의 컴파일이 끝나면(자), ..\My Games\Unreal Tournament 3\UTGame 디렉토리내에 존재하는 PreProcessedFiles 디렉토리로 이동해 주세요. 이 폴더안에, 스크립트의 중간 버젼이 있습니다. AmbientCreature.UC 및 AmbientCreatureInfo.UC 파일을 오픈해 주세요. DebuggingInfo 구조체 정의 및 DebugInfo 변수 선언은, 예기 한 것처럼 동작하는 프로세스를 나타내기 위해서(때문에) 스크립트내로 보여질 것입니다.

*10. * 단지 확인을 위해서(때문에), 이번은, ? debug 스윗치 없음으로, 한번 더 스크립트를 컴파일 해 주세요. 중간 파일을 한번 더 오픈해, DebuggingInfo 정의 및 DebugInfo 선언이 이번은 존재하지 않는 것에 유의해 주세요.

<<<< 튜토리얼의 종료 >>>>

튜토리얼 9.6 - 비주얼 디버그 모드, 파트 III: 글로벌 BSHOWDEBUG 및 크리쳐 변수의 초기화

*1. * ConTEXT 및 AmbientCreatureInfo.uc 파일을 오픈해 주세요.

*2. * MyCreatureInfos 배열이 선언되고 있는 행을 검색해 주세요. 이 행의 직전에, MyCreatureInfos 배열내의 모든 CreatureInfos 에 대한 비주얼 인디케이터(indicator) 모두에 대한 글로벌 타글로서 작용하는 bShowDebug 라는 이름의 Bool 변수를 선언합니다. 이전과 같이, 이것은, -debug 스윗치가 사용되었는지 어떠했는지의 조건에 의존합니다. 이하와 같이 변수를 선언해 주세요 :

`if(`isdefined(debug))
var() Bool bShowDebug;
`endif

*3. * 여기서, CreatureInfo 내로 설정된 값에 근거해 크리쳐의 변수의 값의 초기화를 개시할 수 있습니다. FollowType 스윗치문의 뒤에, 이 코드를 -debugswitch 가 사용된 조건으로 생성하기 위해서 `if 문을 설정해 주세요.

`if(`isdefined(debug))
`endif

*4. * 변수의 초기화는, 글로벌 bShowDebug 변수가 true 로 설정되어 있는 경우에게만 행해집니다. 이 변수의 값을 확인하고 있는 프리프로세서의 `if 문안에 If 문을 작성해 주세요.

if(bShowDebug)
{
}

*5. * 이 If 문 중(안)에서는, 이하에 나타내는 것 같은 크리쳐의 변수의 값을 설정해 주세요.

MyCreatureInfos[i]. MyCreatures[j]. DebugInfo.bShowDebug=MyCreatureInfos[i]. DebugInfo.bShowDebug;
MyCreatureInfos[i]. MyCreatures[j]. DebugInfo.bShowFollowPaths=MyCreatureInfos[i]. DebugInfo.bShowFollowPaths;
MyCreatureInfos[i]. MyCreatures[j]. DebugInfo.bShowFlockPaths=MyCreatureInfos[i]. DebugInfo.bShowFlockPaths;
MyCreatureInfos[i]. MyCreatures[j]. DebugInfo.bShowLeaderPaths=MyCreatureInfos[i]. DebugInfo.bShowLeaderPaths;
MyCreatureInfos[i]. MyCreatures[j]. DebugInfo.bShowFlockBoxes=MyCreatureInfos[i]. DebugInfo.bShowFlockBoxes;
MyCreatureInfos[i]. MyCreatures[j]. DebugInfo.bShowLeaderPaths=MyCreatureInfos[i]. DebugInfo.bShowLeaderPaths;
MyCreatureInfos[i]. MyCreatures[j]. DebugInfo.bShowMesh=MyCreatureInfos[i]. DebugInfo.bShowMesh;
MyCreatureInfos[i]. MyCreatures[j]. DebugInfo.FollowPathSegments=MyCreatureInfos[i]. DebugInfo.FollowPathSegments;;
MyCreatureInfos[i]. MyCreatures[j]. DebugInfo.FollowPathColor=MyCreatureInfos[i]. DebugInfo.FollowPathColor;

완성한 코드의 블록은 이하와 같이 됩니다 :

`if(`isdefined(debug))
if(bShowDebug)
{
   MyCreatureInfos[i]. MyCreatures[j]. DebugInfo.bShowDebug=MyCreatureInfos[i]. DebugInfo.bShowDebug;
   MyCreatureInfos[i]. MyCreatures[j]. DebugInfo.bShowFollowPaths=MyCreatureInfos[i]. DebugInfo.bShowFollowPaths;
   MyCreatureInfos[i]. MyCreatures[j]. DebugInfo.bShowFlockPaths=MyCreatureInfos[i]. DebugInfo.bShowFlockPaths;
   MyCreatureInfos[i]. MyCreatures[j]. DebugInfo.bShowLeaderPaths=MyCreatureInfos[i]. DebugInfo.bShowLeaderPaths;
   MyCreatureInfos[i]. MyCreatures[j]. DebugInfo.bShowFlockBoxes=MyCreatureInfos[i]. DebugInfo.bShowFlockBoxes;
   MyCreatureInfos[i]. MyCreatures[j]. DebugInfo.bShowLeaderPaths=MyCreatureInfos[i]. DebugInfo.bShowLeaderPaths;
   MyCreatureInfos[i]. MyCreatures[j]. DebugInfo.bShowMesh=MyCreatureInfos[i]. DebugInfo.bShowMesh;
   MyCreatureInfos[i]. MyCreatures[j]. DebugInfo.FollowPathSegments=MyCreatureInfos[i]. DebugInfo.FollowPathSegments;;
   MyCreatureInfos[i]. MyCreatures[j]. DebugInfo.FollowPathColor=MyCreatureInfos[i]. DebugInfo.FollowPathColor;
}
`endif

*6. * 작업 결과를 잃지 않게 파일을 보존해 주세요.

<<<< 튜토리얼의 종료 >>>>

튜토리얼 9.7 - 비주얼 디버그 모드, 파트 IV: 메쉬의 은닉

*1. * ConTEXT 와 같게 AmbientCreature.uc 및 AmbientCreature_Fish.uc 파일을 오픈해 주세요.

*2. * AmbientCreature 클래스의 Initialize() 함수의 마지막으로, -debug 스윗치를 체크하는 표준의 `if 문을 추가해 주세요.

`if(`isdefined(debug))
`endif

*3. * 이 문장의 내부에서, 크리쳐의 bShowDebug 의 값이 True 이며, bShowMesh 의 값이 false 이며, 메쉬를 숨겨야 하는 것인 것을 확인할 필요가 있습니다. 이 확인을 실시하는 If 문을 작성해 주세요.

if(DebugInfo.bShowDebug && ! DebugInfo.bShowMesh)
{
}

*4. * 이하의 함수 소환을 추가해 If 문의 내부에서 숨겨야 할 크리쳐를 설정해 주세요 :

SetHidden(true);

bHidden 변수는 직접 설정할 수 없기 때문에, 이 함수 호출이 사용됩니다.

최종적인 코드의 블록은, 이와 같이 됩니다 :

`if(`isdefined(debug))
if(DebugInfo.bShowDebug && ! DebugInfo.bShowMesh)
{
   SetHidden(true);
}
`endif

*5. * 필요에 따라서 숨기는 메쉬를 설정합니다만, 이것은 기저의 AmbientCreature 클래스에게만 적용됩니다. 이 코드의 블록도 같이 AmbientCreature_Fish 클래스에 카피할 필요가 있습니다. 코드의 블록을 선택해, Ctrl+C 를 눌러 카피해 주세요.

*6. * AmbientCreature_Fish 클래스의 Initialize() 함수 중(안)에서, Ctrl+V 를 눌러, 함수의 말미에 코드의 블록을 붙여 주세요.

*7. * 작업 결과를 잃지 않게, 파일을 보존해 주세요.

<<<< 튜토리얼의 종료 >>>>

튜토리얼 9.8 - 비주얼 디버그 모드, 파트 V: 리더 인디케이터(indicator)의 묘화

*1. * ConTEXT 및 AmbientCreature.uc 파일을 오픈해 주세요.

*2. * Velocity 를 설정한 후의 Tick() 함수의 메인의 If 블록의 내부에서, -debug 스윗치에 대한 `if 문과 같이, 크리쳐의 bShowDebug 의 값이 True 인 것을 확인하는 If 문을 추가해 주세요.

`if(`isdefined(debug))
if(DebugInfo.bShowDebug)
{
}
`endif

*3. * 무리를 인솔하는 크리쳐에 대한 경로를 그리기 위해서(때문에)는, 우선, bShowLeaderPaths 변수가 True 로 설정되어 있는 것을 확인하는 것이 필요합니다.

if(DebugInfo.bShowLeaderPaths)

이것을 실행하면, 크리쳐의 현재의 경로를 나타내는 선을 그리기 (위해)때문에, Actor 클래스내에서 볼 수 있는 몇개의 디버그 묘화 함수의 1 개인 DrawDebugLine() 함수를 사용할 수 있습니다. 이 함수에서는, 다음의 정보가 필요합니다 : 개시점, 종료점, 색, 및 선을 영속적으로 해야 하는가, 현재의 프레임인 만큼 해야 하는가의 정보입니다. 이하와 같이 함수 소환을 추가해 주세요 :


 그림 9.14 - DrawDebugLine() 함수를 사용해 당긴 결과의 선.

이하에 나타내도록(듯이) 함수 소환을 추가해 주세요 :

DrawDebugLine(Location, MoveLocation, 0,255,0, false);

완성한 코드의 블록은, 이하와 같이 됩니다 :

`if(`isdefined(debug))
if(DebugInfo.bShowDebug)
{
   if(DebugInfo.bShowLeaderPaths)
      DrawDebugLine(Location, MoveLocation, 0,255,0, false);
}
`endif

*4. * 이제 기분귀댁도 알려지지 않습니다만, AmbientCreature 클래스내에, 현재 MoveLocation 는, 존재하지 않습니다. 그것들은, 무리를 이루는 동작을 실시하지 않을 때로는, 크리쳐의 현재의 목적지를 보관 유지하는 변수가 없기 때문입니다. 이 정보를 이용 가능하게 하기 위한(해), 클래스 자신에게 작은 변경을 더할 필요가 있습니다. 클래스 변수 선언에, 이하의 선언을 더해 클래스에 MoveLocation 라는 이름의 Vector 변수를 추가해 주세요.

var Vector MoveLocation;

*5. * 여기에서는, SetDest() 함수중에서, 이하의 행을 찾아 주세요 :

MoveOffset = Normal(VRand()) * inNode.Radius;

이 행의 뒤에, MoveLocation 변수를 설정하기 위해서 이하의 행을 추가해 주세요 :

MoveLocation = inNode.Location + MoveOffset;

*6. * 여기서, Tick() 함수에 돌아와, 크리쳐의 위치를 나타내는 박스를 그립니다. 추가된 마지막 If 문의 다음에, 이하와 같이, bShowLeaderBoxes 의 값을 확인하는 If 문을 새롭게 작성해 주세요 :

if(DebugInfo.bShowLeaderBoxes)

*7. * 이번은, 비주얼 인디케이터(indicator)를 그리기 위해서(때문에), 이제(벌써) 1 개의 함수, DrawDebugBox()를 사용합니다. 이 함수에서는, 오리진, extent, 색 및 박스가 영속적인가 어떤가의 정보가 필요합니다. 바란다면, 오리진과 extent에 대해서는, 하드 코드화한 값을 설정 가능합니다만, StaticMeshComponent 에서는, Bounds 변수내에, 이미 그러한 값을 포함하고 있어 그것들을 사용하면, 사이즈나 회전을 신경쓰지 않고 정확하게 크리쳐를 표시합니다. 이하에 나타내는 함수 소환을 추가해 주세요 :


그림 9.15 - DrawDebugBox() 함수에 의해 묘화 된 와이어 프레임 박스.

바란다면, 오리진과 extent에 대해서는, 하드 코드화한 값을 설정 가능합니다만, StaticMeshComponent 에서는, Bounds 변수내에, 이미 그러한 값을 포함하고 있어 그것들을 사용하면, 사이즈나 회전을 신경쓰지 않고 정확하게 크리쳐를 표시할 수 있습니다. 이하에 나타내는 함수 소환을 추가해 주세요 :

DrawDebugBox(DisplayMesh.Bounds.Origin, DisplayMesh.Bounds.BoxExtent, 255,0,0, false);

리더의 비주얼 인디케이터(indicator)를 묘화 하는 코드 블록 전체는, 이하와 같이 됩니다 :

`if(`isdefined(debug))
if(DebugInfo.bShowDebug)
{
   if(DebugInfo.bShowLeaderPaths)
      DrawDebugLine(Location, MoveLocation, 0,255,0, false);

   if(DebugInfo.bShowLeaderBoxes)
      DrawDebugBox(DisplayMesh.Bounds.Origin, DisplayMesh.Bounds.BoxExtent, 255,0,0, false);
}
`endif

*8. * 작업 결과를 잃지 않게 파일을 보존해 주세요.

<<<< 튜토리얼의 종료 >>>>

튜토리얼 9.9 - 비주얼 디버그 모드, 파트 VI: 무리의 비주얼 인디케이터(indicator)

*1. * ConTEXT 및 AmbientCreature.uc 파일을 오픈해 주세요.

*2. * Tick() 함수의 메인의 else 블록의 내부에서, 블록내의 다른 어느 코드보다 전에, ? debug 스윗치에 관해서 확인하는 `if 문과 같게, 크리쳐의 bShowDebug 치가 True 인 것을 확인하는 If 문을 추가해 주세요.

`if(`isdefined(debug))
if(DebugInfo.bShowDebug)
{
}
`endif

*3. * 복수의 세그먼트(segment)가 될 가능성이 있기 (위해)때문에, 보충 패스를 그리는 것은, 리더 패스보다 약간 복잡합니다. 이 처리는 2 개의 부분으로 나누어 실행합니다. 최초의 부분은, 크리쳐로부터 LastLocation 배열내의 최초의 위치에 선을 묘화 합니다. 2 번째의 부분은, 루프내에서 나머지의 세그먼트(segment)를 묘화 합니다.

bShowFollowPaths 변수가 true 로 설정되어 있는 것을 확인하기 위해(때문에), If 문의 체크를 작성해 주세요.

if(DebugInfo.bShowFollowPaths)
{
}

*4. * If 문의 내부에서, 이하의 코드를 추가해 보충 패스의 최초의 세그먼트(segment)를 묘화 해 주세요 :

DrawDebugLine(Location,
      LastLocation[0] + DistOffset,
      DebugInfo.FollowPathColor.R,
      DebugInfo.FollowPathColor.G,
      DebugInfo.FollowPathColor.B,
      false);

*5. * 여기서, LastLocation 배열을 대상으로 루프를 실시해, 배열내에 격납된 위치동안의 세그먼트(segment)를 묘화 합니다만, FollowPathSegments 변수에 의해 지정된 세그먼트(segment)의 양에 그것을 한정합니다. 여기서, 이하의 루프를 추가해 주세요 :

for(i=1;i<Min(LastLocation.Length,DebugInfo.FollowPathSegments);i++)
{
   DrawDebugLine(LastLocation[i-1] + DistOffset,
         LastLocation[i] + DistOffset,
         DebugInfo.FollowPathColor.R,
         DebugInfo.FollowPathColor.G,
         DebugInfo.FollowPathColor.B,
         false);
}

*6. * 변수 i 를 사용하고 있습니다만, 현재, 이것은 존재하고 있습니다. Tick() 함수의 초의 ? debug 스윗치에 대한 확인을 실시하는 `if 문내에, 이 변수에 대한 로컬 변수 선언을 이하와 같이 추가해 주세요 :

`if(`isdefined(debug))
local int i;
`endif

*7. * 여기에서는, bShowFlockPaths 변수가 True 일지 어떨지를 확인해, 크리쳐의 위치로부터 리더의 위치로 선을 묘화 해 주세요.

if(DebugInfo.bShowFlockPaths)
   DrawDebugLine(Location, Leader.Location, 0,0,0, false);

*8. * 마지막으로, bShowFlockBoxes 변수가 True 일지 어떨지를 확인해, 크리쳐의 위치에 박스를 그려 주세요.

if(DebugInfo.bShowFlockBoxes)
{
   DrawDebugBox(DisplayMesh.Bounds.Origin,
         DisplayMesh.Bounds.BoxExtent,
         255,
         160,
         0,
         false);
}

*9. * 무리의 비주얼 인디케이터(indicator)를 그리고 있는 마지막 코드의 블록은, 이하와 같이 됩니다 :

`if(`isdefined(debug))
if(DebugInfo.bShowDebug)
{
   if(DebugInfo.bShowFollowPaths)
   {
      DrawDebugLine(Location,
            LastLocation[0] + DistOffset,
            DebugInfo.FollowPathColor.R,
            DebugInfo.FollowPathColor.G,
            DebugInfo.FollowPathColor.B,
            false);
      for(i=1;i<Min(LastLocation.Length,DebugInfo.FollowPathSegments);i++)
      {
         DrawDebugLine(LastLocation[i-1] + DistOffset,
               LastLocation[i] + DistOffset,
               DebugInfo.FollowPathColor.R,
               DebugInfo.FollowPathColor.G,
               DebugInfo.FollowPathColor.B,
               false);
      }
   }

   if(DebugInfo.bShowFlockPaths)
      DrawDebugLine(Location,Leader.Location,0,0,0,false);

   if(DebugInfo.bShowFlockBoxes)
   {
      DrawDebugBox(DisplayMesh.Bounds.Origin,
            DisplayMesh.Bounds.BoxExtent,
            255,
            160,
            0,
            false);
   }
}
`endif

*10. * 작업 결과를 잃지 않게 파일을 보존해 주세요.

<<<< 튜토리얼의 종료 >>>>

튜토리얼 9.10 - 비주얼 디버그 모드, 파트 VII: 테스트 실시

*1. * -debug 스윗치를 사용하고 있는 스크립트를 컴파일 해 주세요.

*2. * UnrealEd 를 오픈해, DM-CH_09_Debug.ut3 맵을 오픈해 주세요.


그림 9.16 - DM-CH_09_Debug.ut3 맵.

*3. * AmbientCreatureInfo 먼지를 맵에 추가하고 나서, 적어도 1 개의 항목을 MyCreatureInfos 배열에 추가해 주세요.


그림 9.17 - 신규의 AmbientCreatureInfo 먼지가 추가되었습니다.

*4. * 기호에 맞추어 크리쳐를 설정해 주세요. 그 후, 글로벌 bShowDebug 변수 및 배열내의 개개의 항목의 DebugInfo 섹션내의 bShowDebug 변수에 True 를 설정해 주세요.


그림 9.18 - 쌍방의 bShowDebug 프롭퍼티는 True 로 설정됩니다.

*5. * DebugInfo 섹션내의 여러가지 설정으로 플레이 하고 나서, 그 결과를 확인하기 위해서 에디터내에서 맵을 플레이 해 주세요. 이 장을 통해 작성한 비주얼 인디케이터(indicator)를 확인할 수 있을 것입니다.


그림 9.19 - 본장으로 추가한 인디케이터(indicator)를 표시하는 무리의 예.

이번 같은 시스템에 관한 초기 코딩을 실시할 때에, 이것들이, 매우 도움이 되는 것이 될 가능성이 있는 것은 명백하겠지요. (와)과 같이 Log 파일에의 데이터의 로그 출력도 매우 유익합니다만, 실제로 무엇을 하고 있을까를 보려면 , 가끔 , 시각적인 피드백이 필요합니다.

<<<< 튜토리얼의 종료 >>>>

9. 5 요약

UnrealScript 내에서 프리프로세서 커멘드를 사용하는 능력은, 언어의 기능 중(안)에서 넓게 사용되는 것은 아닐지도 모릅니다만, 특정의 상황에 있어 매우 편리한 가능성이 있는 새로운 추가 기능을 제공하고 있습니다. 게임을 구축하는 라이센시에 대해서는, 그러한 이용은 많은 부분, 예를 들면, 게임이 지금 현재 컴파일 되고 있는 플랫폼이나 릴리스의 타입 (즉, 디버그, 최종 릴리스등 )의 조건에 의해 코드를 인클루드 하는 기능과 같은 부분에서 제한되고 있습니다. 이것은, 본장으로 봐 온 것처럼, mod 의 세계에서, 이 기능을 사용할 수 없다고 하는 것을 의미하는 것이 아닙니다. 매크로를 정의 가능하게 해, 파일을 인클루드 하면, 반복의 태스크를 보다 용이하게, 효율적으로 실시할 수가 있습니다.

추가 파일