UDN
Search public documentation:

MasteringUnrealScriptFunctionsKR
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

제 6 장 - 함수

본장에서는, 함수를 사용해 동작을 실행하는 클래스의 기능에 대해 설명합니다. 변수 선언과 그러한 변수에 대한 디폴트 프롭퍼티의 설정 이외는, 사실상 클래스에 속하는 모든 코드는, 함수안에 포함됩니다. 이 때문에, 어떠한 재미있는 일을 실시하는 클래스, 즉 프로그램을 손에 넣기 위해서(때문에)는, 함수를 필요 불가결이 됩니다. 어떤 함수가 있어, 어떻게 동작할까를 확실히 파악하기만 하면, 두근거리는 것 같은 게임 체험을 실현한다, 매우 유용한 클래스를 작성하는 일도 가능하게 되겠지요.

6. 1 개요

그런데, 실제의 곳함수와는 어떠한 것입니까 - 함수는, 클래스내에서 특별한 태스크를 실행하는 커멘드의 부분집합에 대해서 이름을 붙인 컨테이너입니다. 관련하는 코드행을 정리해 이름을 붙인 유니트로 하는 것으로, 프로그램의 정리가 진행되어, 공통에 이용되는 코드의 실행이 용이하게 됩니다. 실행이 필요한 때마다 코드를 써내는 교체에, 그 함수명으로 함수가 불려 가 함수에 관련지을 수 있었던 코드가 실행됩니다. 함수에 대한 코드가 종료하면(자), 프로그램은, 함수 호출을 실시한 장소로부터 계속합니다.

함수를 보다 유연하게 하기 위해서, 함수에는, 파라미터의 형식에서 정보를 거두어 들여 또, 값을 출력하는 기능도 있습니다. 함수에 프로그램의 다른 부분과의 제휴를 허락하면, 게임내의 먼지에서는 지시를 주어 서로 회화를 하는 기능을 가집니다. 어느 클래스내의 데이터는, 다른 클래스의 함수에 의해 처리 가능해져, 처리 결과는 원의 클래스에 돌려줄 수가 있습니다. 이 제휴 기능이 없으면, 함수는 보다 동적이어 없어지기 (위해)때문에, 완전히 사용하기 어려운 것이 되겠지요.

「 제 4 장 : 변수」로 배운 것처럼, 함수내에서 사용하기 위해서, 로컬 변수로 불리는 특별한 변수를 선언할 수 있습니다. 이것으로, 함수는 사용 및 조작이 가능한 데이터를 생성할 수 있습니다. 그러나, 이 데이터는 함수가 실행되고 있는 동안만 존재하고 있습니다. 이 데이터는, 함수 내부 이외의 어디에서도 액세스 하지 못하고, 함수의 실행과 실행의 사이는, 보관 유지되지 않습니다. 함수가 실행을 개시했을 때에, 로컬 변수 선언을 읽어내, 이러한 변수를 생성합니다. 실행중은, 통상의 변수와 같이, 임의의 변경이 실행 가능합니다. 함수가 종료하면(자), 모든 로컬 변수는 파기됩니다.

주기 : 로컬 변수 선언은, 함수내의 다른 모든 실행 코드의 전으로 실시하지 않으면 안됩니다. 만약, 로컬 변수 선언전에, 하등의 실행 코드가 있었을 경우는, 스크립트를 컴파일 할 때에 에러가 일어납니다.

튜토리얼 6.1 앰비언트 크리쳐, 파트 I: 베이스 클래스 선언

본장의 튜토리얼의 코스를 통해서, 플레이어에 대해, 보다 신용할 수 있는 환경을 제공하기 위해서 맵내에 배치할 수 있는, 비교적 단순한 앰비언트 크리쳐를 실장하기 위해서 필요한 클래스를 생성합니다. 물고기의 형1개(살)을 생성하는 것에 초점을 맞힙니다만, 객체 지향을 사용하면, 다른 형태의 물고기 및 다른 형태의 크리쳐의 추가는, 지극히 간단합니다.

일반적인 기능을 포함한 기저 AmbientCreature 클래스의 설정으로부터 시작합시다. 실질적으로, 이 클래스는, 이동처의 위치를 선택해, 그 위치로 향해 크리쳐를 움직이는 설정을 합니다. 크리쳐가 새로운 목적지를 선택 가능한 원래의 위치를 마크 하는 AmbientCreatureNode 클래스도 생성할 생각입니다.


그림 6.1 - AmbientCreatureNode 는, AmbientCreature 의 패스에 대한 locator로서 사용됩니다.

1. ConTEXT 를 오픈해, New from the File 메뉴를 선택하는지, 툴바내의 New File 버튼을 누르는 것에 의해 신규의 파일을 생성해 주세요. UnrealScript 하이 라이터도 이와 같이 잊지 않고 선택해 주세요.


그림 6.2 - 신규 UnrealScript 문서를 생성.

2. 상술한 것처럼, 앰비언트 크리쳐에 대한 base class의 이름은, AmbientCreature 가 됩니다. 이 클래스는, Actor 클래스로부터의 계승을 받습니다. 스크립트의 선두행에, 이하를 입력해 이 클래스를 선언해 주세요 :

class AmbientCreature extends Actor;

3. 이 클래스에는, 더욱 코드가 추가됩니다만, 여기에서는, 단지 스크립트를 보존해, 먼저 진행되어, AmbientCreature 클래스에 대한 클래스 변수를 선언할 때에 필요한 AmbientCreatureNode 클래스를 생성할 수 있습니다.

File 메뉴로부터 Save As 를 선택해, 전회의 튜토리얼로 작성한 MasterinUnrealScript/Classes 디렉토리로 이동해 주세요. 이 장소에, 선언내의 클래스명에 맞추어 AmbientCreature.uc 의 이름으로 파일을 보존해 주세요.


그림 6.3 - AmbientCreature.uc 스크립트를 보존해 주세요.

4. ConTEXT 로, File 메뉴 또는 툴바로부터, 이제(벌써) 1 개(살) 신규 파일을 생성해, UnrealScript 하이 라이터를 선택해 주세요.

5. 새로운 파일의 선두행상에서, AmbientCreatureNode 클래스를 선언해 주세요. AmbientCreature 클래스와는 달라, 이 클래스는, Actor 클래스를 확장하지 않습니다. UnrealEd 내에서 간단하게, 이 클래스의 아이콘을 작성하기 위해서, Info 클래스로부터의 계승을 실시합니다. 아이콘이 없으면, 노드가 배치된 장소를 재빠르게 발견하는 것은 매우 어려워져, 레벨 디자이너의 작업이 매우 곤란하게 됩니다. 클래스를 선언하기 위해서 이하의 코드를 추가해 주세요.

class AmbientCreatureNode extends Info placeable;

6. 이 새로운 클래스에 대해서, 변수 선언을 1 개 추가해 주세요. 이 변수는 Float 로 Radius 라는 이름입니다. 이 값으로는, 크리쳐의 동작에 좀 더 바리에이션을 주기 위해서(때문에) 사용되는, 이 노드 주위의 반경을 디자이너가 지정이 가능합니다.

var Float Radius;

7. Radius 변수는, 편집 가능해 선언되어 있지 않은 것에 기분귀댁도 알려지지 않습니다. DrawSphereComponent 를 사용해, 에디터내에서도 이 반경을 비쥬아라이즈 해, 설정하는 방법을 디자이너에게 줄 예정입니다. 노드 클래스에, DrawSpereComponent 를 추가하기 위해서, 이하의 선언을 추가해 주세요 :

var() Const EditConst DrawSphereComponent RadiusComponent;

8. 이하에 나타내는 defaultproperites 블록을 추가해, 이 Radius 변수에 디폴트치를 설정해 주세요 :

defaultproperties
{
   Radius=128
}

9. defaultproperties 블록내에, DrawSphereComponent 를 작성해, 노드에 아탓치 하기 위해서 이하의 행의 코드를 추가해 주세요.

Begin Object Class=DrawSphereComponent Name=DrawSphere0
SphereColor=(B=255, G=70, R=64, A=255)
SphereRadius=128. 000000
End Object
RadiusComponent=DrawSphere0
Components.Add(DrawSphere0);

10. 마지막 스텝은, 디자이너만이, 에디터내의 DrawSphereCompnent 에 액세스 할 수 있도록(듯이), 실행시의 DrawSphereComponent 의 반경과 동일하게 노드의 Radius 프롭퍼티를 설정하는 것입니다. 이것은, PreBeginPlay() 함수를 오버라이드(override) 해 실시합니다.

function PreBeginPlay()
{
   Radius = RadiusComponent.SphereRadius;
   Super.PreBeginPlay();
}

11. File 메뉴로부터 Save As 를 선택해, 재차 MasteringUnrealScript/Classes 디렉토리로 이동합니다. 선언하고 있는 클래스의 이름에 맞추어 AmbientCreatureNode.uc 라는 이름으로 이 장소에 파일을 보존해 주세요.


그림 6.4 - AmbientCreatureNode.uc 스크립트를 보존해 주세요.

이 약간의 설정이 완료하면(자), 다음의 튜토리얼로부터, 기저 크리쳐 클래스의 작성을 시작할 수가 있습니다.

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

튜토리얼 6.2 안비엔트크리치야, 파트 II: 클래스 변수 선언

많은 변수가 모든 크리쳐에 공통이 되기 (위해)때문에, 기저의 AmbientCreature 클래스에 추가를 실시할 수가 있습니다. 이 튜토리얼에서는, 변수에 대한 모든 선언을 작성해 갈 것입니다.

1. ConTEXT 를 오픈해, 아직 오픈하고 있지 않으면, AmbientCreature.uc 파일을 오픈해 주세요.

2. Enter 키를 2 회 눌러, 클래스 선언으로부터 몇 줄기하로 옮겨 주세요.

3. 크리쳐에 대해서 목적지에 관한 로케이션 마커의 기능을 제공하는 클래스를 전회의 튜토리얼로 설정한 것을 기억이지요. 목적지로서 1 개를 선택하기 위해(때문에), 이것들을 크리쳐 클래스내에 보존할 방법이 필요합니다. 주어진 정황에서는, 얼마나의 수의 노드가 존재하는지 모르기 때문에, 동적 배열을 이 용도로 사용합니다. 이 프롭퍼티에 대한 노드의 추가도 디자이너에 허가하고 싶기 때문에, 임의의 개개의 크리쳐는, 가능성이 있는 목적지로서 이용하기 위해(때문에), 특정의 노드로 주어질지도 모릅니다. 이 크리쳐와 관련하는 AmbientCreatureNodes 를 보관 유지하는 MyNodes 변수를 선언하기 위해(때문에) 이하의 코드를 입력해 주세요.

var() array<AmbientCreatureNode> MyNodes;

4. 크리쳐가, 단지 1 개의 목적지로부터 다음의 목적지로 이동하는 경우, 어떤 시점으로는, 동작이 반복해지고 예측 가능하도록 보이기 시작합니다. 이 발생을 막기 위해서(때문에), 크리쳐가 일정 방향으로 이동하는 시간의 최소치와 최대치를 정할 생각입니다. 이것에 의해, 좀 더 랜덤인 동작 패턴이 됩니다. 이러한 변수에도 float 치를 사용합니다. MoveDistance 변수 선언아래에, 이 코드행을 추가해 주세요 :

var float MinTravelTime, MaxTravelTime;

2 개의 변수를 1 행의 코드행으로 선언하고 있는 것에 기분나무지요. 이러한 변수는 서로 관계가 있기 (위해)때문에, 구성상의 의도로 모아 둡니다.

5. Unreal 는, 크리쳐가 이동할 방향과 속도를 결정하기 위해서(때문에), 크리쳐의 Actor 클래스로부터 계승된 Velocity 변수를 사용합니다. 크리쳐를 희망 대로에 이동시키기 위해서(때문에), 이 Velocity 변수를 설정하는 경우는, 동작의 방향과 속도를 보관 유지할 필요가 있는 것을 의미합니다.

잠시 후에 설명하도록(듯이), 방향은, 크리쳐의 희망하는 회전을 설정하기 위해서 1회만 사용됩니다. 그리고, 물리 엔진은, 목적지로 향한 크리쳐의 회전을 일으킵니다. 언제라도 크리쳐가 향하고 있을 방향을, 동작의 방향으로서 사용해, 거기에 속도를 단지 곱합니다. 방향의 값은, 계산되어 사용되어 폐기되기 (위해)때문에, 로컬 변수에서도 좋은 일을 의미합니다. 그렇지만, 속도는 크리쳐 클래스에서는, 몇번이나 사용할 필요가 있어, 이 값을 보관 유지하는 변수가 필요합니다. 스크립트의 다음의 행에, 이하의 내용을 입력해 주세요 :

var Float Speed;

6. 크리쳐는, 여러가지 사이즈가 되기 때문에, 크리쳐를 모두 같은 사이즈로 하는 것은 배려가 부족합니다. 개개의 타입의 크리쳐로 최소와 최대의 사이즈의 지정을 허가하기 위해서, 이러한 수치에 대한 변수를 선언해, 그것들에 대한 수치를 각각의 아이 클래스로 설정시킵니다. 이러한 수치는 크리쳐의 개개의 인스턴스의 랜덤인 스케일을 계산하기 위해(때문에) 사용됩니다. Speed 의 선언에 계속되는 행에 이하의 선언을 추가해 주세요 :

var Float MinSize, MaxSize;

7. 기저 크리쳐 클래스에 대해서 필요한 변수를 준비할 수 있었습니다. 작업 내용을 잃지 않게 파일을 보존해 주세요.

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

튜토리얼 6.3 앰비언트 크리쳐, 파트 III: 렌더링 및 라이팅 컴퍼넌트

크리쳐 클래스의 주요 기능에 착수하기 전의, 셋업의 최종 부분은, 디폴트 프롭퍼티입니다. 물리, 충돌 설정이 적절한 타입이며, 메쉬의 표시 및 릿트를 적절히 실시하는 수단을 가지고 있을까를 크리쳐로 확인할 필요가 있습니다. 최초로, 렌더링 및 라이팅의 설정에 초점을 맞힙시다.

1. ConTEXT 를 오픈해, 아직 오픈하고 있지 않으면, AmbientCreature.uc 파일을 오픈해 주세요.

2. 최초의 스텝은, defaultproperties 블록을 개시하는 것입니다. 변수 선언아래에 얼마인가의 스페이스를 비우기 (위해)때문에 Enter 키를 몇차례 눌러 주세요. 이하의 코드행을 추가해, defaultproperties 블록을 개시해 주세요 :

default properties
{

3. 이동중의 오브젝트로 있기 (위해)때문에, 동적으로 점등을 실시할 필요가 있습니다. 크리쳐를 라이팅 하는 코스트를 최소에 유지하기 위해서(때문에) DynamicLightEnvironment 를 사용할 생각입니다. 그 때문에(위해), defaultproperties 블록내에 서브 오브젝트를 생성해, 크리쳐의 Components 배열에 추가할 필요가 있습니다. 전의 장으로 본 것처럼, 디폴트 프롭퍼티내의 서브 오브젝트의 생성은, 클래스 및 신규 서브 오브젝트에 대한 이름이 계속되는 Begin Object 구문의 이용이 필요합니다. 서브 오브젝트의 생성을 종료하기 위해서는, End Object 구문을 이용합니다.

직하의 행으로 이동하기 위해서(때문에) Enter 키를 눌러, 이 부분의 코드를 인덴트 하기 위해서 Tab 키를 눌러 주세요. DynamicLightEnvironment 를 작성하기 위해(때문에), 이하의 코드를 입력해 주세요.

Begin Object Class=DynamicLightEnvironmentComponent Name=MyLightEnvironment
End Object

4. DynamicLightEnvironment 를 작성하면(자), Components 배열에 그것을 대입할 필요가 있습니다. 어느 형태의 컴퍼넌트를 이용할 때는 언제라도, 어떠한 효과를 얻기 위해서(때문에) Components 배열에 대입할 필요가 있습니다. DynamicLightEnvironment 를 생성하는 코드아래에 이하의 코드행을 추가해 주세요 :

Components(0) =MyLightEnvironment

단지 이전 작성된 서브 오브젝트의 이름을 사용해, 그것을 Components 배열의 최초의 요소에 대입합니다.

5. 여기에서는, 애니메이션을 취급하지 않기 위해(때문에), 크리쳐용의 표시 메쉬로서 정적 메쉬를 사용할 생각입니다. DynamicLightEnvironment 와 같게, 이것에 대해서도, 서브 오브젝트의 생성과 Components 배열에의 대입이 필요합니다. 스크립트의 다음의 행에, 이하의 코드를 입력해 주세요 :

Begin Object Class=StaticMeshComponent Name=MyStaticMesh

서브 오브젝트의 종료전에, 여기에서는, 1개의 프롭퍼티를 설정할 필요가 있습니다. 이 StaticMeshComponent 에 이전 작성한 DynamicLightEnvironment 를 사용하는 것을 고할 필요도 있습니다. 다음의 행을 인덴트 해, 이하의 행의 코드를 추가해 주세요 :

LightEnvironment=MyLightEnvironment

마지막으로, 서브 오브젝트를 종료해 주세요 :

End Object

6. 그런데, 이 컴퍼넌트도 Components 배열에 추가하지 않으면 안됩니다. 스크립트의 다음의 행에 이하의 코드를 입력해 주세요 :

Components(1) =MyStaticMesh

7. 작업의 결과를 잃지 않게 스크립트를 보존해 주세요.

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

튜토리얼 6.4 앰비언트 크리쳐, 파트 IV: 충돌 및 물리 프롭퍼티

기저 크리쳐 클래스의 디폴트 프롭퍼티에 이어, 여기에서는, 충돌 및 물리에 대한 프롭퍼티의 설정을 실시합시다.

1. ConTEXT 를 오픈해, 아직 오픈하고 있지 않으면 AmbientCreature.uc 파일을 오픈해 주세요.

2. 최초로 실행해야 하는 것은, 충돌 지오메트리로서 무엇을 사용할까를 결정하는 Actor 클래스로부터 계승한 CollisionComponents 프롭퍼티의 설정입니다. 충돌이 일어났는지 어떠했는지를 계산하는 경우에 무엇을 사용할까를 엔진에게 전합니다. 단지, 간략화된 충돌 메쉬의 셋업을 실시하는, 이전에 작성한 StaticMeshComponent 를 사용할 생각입니다. 파일내의 코드의 맨 마지막 줄아래에, 이하의 코드를 추가해 주세요 :

CollisionComponent=MyStaticMesh

3. 충돌을 계산하기 위해서, 어느 지오메트리를 사용할까를 엔진에 알리는 CollisionComponent 설정과 함께, 크리쳐가 충돌해야 할 다른 지오메트리궕 어느 형태인지를 엔진에 통지할 필요가 있습니다. 앰비언트 크리쳐이므로, 다른 먼지와 충돌하거나 블록 하거나는 하고 싶지는 않습니다. (이)라고는 말해도, 이 크리쳐는, 월드와는 충돌을 행하게 하고 싶습니다. 물고기의 크리쳐의 경우, 이것은, 서로는 충돌하지 않는 것을 의미합니다. 그렇지만, 물고기가 수조 또는 연못안에 있는 경우는, 수조 또는 연못을 구성하는 지오메트리로 바운드 합니다. 크리쳐를 월드와 충돌시키기 위해서(때문에)는, 이하의 행의 코드를 추가해 bCollideWorld 를 설정할 필요가 있을 뿐입니다.

bCollideWorld=True

4. 충돌의 프롭퍼티에 대응했습니다만, 더욱, 크리쳐에 대한 물리를 셋업 할 필요가 있습니다. 단지, 간단한 속도와 회전의 설정을 실시하면, 그 외의 부분은 주의가 두루 미치고 있기 (위해)때문에, PHYS_Projectile 물리 타입을 사용합니다. 스크립트의 다음의 행에 이하의 코드행을 추가해 주세요 :

Physics=PHYS_Projectile

5. 설정할 필요가 있는, 마지막 2 개의 프롭퍼티는, 이 먼지가 월드내를 돌아다니는 것을 엔진에 고하기 위한 것입니다. 이것을 실시하기 위해서(때문에) 2 개의 프롭퍼티 bStatic 및 bMovable 를 설정할 필요가 있습니다. 스크립트의 말미에 이하의 코드행을 추가해 주세요 :

bStatic=False
bMovable=True

6. 이 행을 추가하는 것으로, defaultproperties 블록을 닫아 주세요 :

}

이 시점에서의 스크립트는 이하와 같이 됩니다 :

class AmbientCreature extends Actor;

var() array<AmbientCreatureNode> MyNodes;
var float MinTravelTime, MaxTravelTime;
var float Speed;
var float MinSize, MaxSize;

defaultproperties
{
   Begin Object Class=DynamicLightEnvironmentComponent Name=MyLightEnvironment
      End Object
   Components(0) =MyLightEnvironment
   Begin Object Class=StaticMeshComponent Name=MyStaticMesh
             LightEnvironment=MyLightEnvironment
   End Object
      Components(1) =MyStaticMesh
   CollisionComponent=MyStaticMesh;
   bCollideWorld=true
   Physics=PHYS_Projectile
   bStatic=False
   bMovable=True
}

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

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

6. 2 함수 선언

그러면, 함수의 선언은 어떻게 실시하면 좋은 것일까요? 클래스나 변수의 선언이 class 나 var 의 키워드로 컴파일러에 선언으로 있는 것을 고하는 것과 같게, 함수 선언은 function 키워드를 사용합니다. 만약 함수가, 어떠한 데이터를 출력한다면, 함수가 리턴 하는 데이터의 형태가 function 키워드에 계속됩니다. 그 후의 함수명에는, 함수가 가질 가능성이 있는, 임의의 인수, 또는, 입력을 포함한 1조의 외모가 계속됩니다. 함수로 데이터를 받을 필요가 없는 경우는, 외모는 하늘에서도 상관하지 않습니다. 함수 선언의 마지막 부분은, 함수가 불려 갔을 때에 실행되는 코드를 포함한 1조안이나 개입니다. 함수 선언의 간단한 예를 이하에 나타냅니다.

Function Int Clamp(Int Value, Int Min, Int Max)
{
   if( Value < Min)
      Value = Min;
   else if( Value > Max)
      Value = Max;

   return Value;
}

선언이 function 키워드로 시작되어 있어, 이 함수가 정수의 형식의 값을 리턴 하는 것을 나타내는 Int 의 용어가 계속되고 있는 것에 기분나무지요. 이 함수의 이름은 Clamp 로, Value, Min 및 Max 의 3 개의 정수치를 받습니다. 마지막으로, 함수가 불려 갔을 때에 실행되는 코드가, 안이나 이 안으로 보여집니다. 분이나 리카도 알려지지 않습니다만, 이 코드는, 최초의 입력치를, 2 번째와 3 번째의 입력에 의해 결정할 수 있던 범위에 클램프 해, 클램프 된 결과의 값을 리턴 합니다.

튜토리얼 6.5 앰비언트 크리쳐, 파트 V: SETRANDDEST() 함수

지금은, 기저의 크리쳐 클래스의 내용에 발을 디딜 때입니다. 개시하기 전에, 크리쳐로 무엇을 실시할 필요가 있을까를 검토해야 합니다. 이하는, 1 개의 장소로부터 다른 장소로 이동할 때에 실행하지 않으면 안 되는 기본적인 액션의 일람입니다 :

  • 새로운 목적지로서 노드를 선택한다
  • 현재의 장소에서 목적지까지의 이동의 방향을 계산한다
  • 목적지에 크리쳐를 향하기 위해서(때문에) 희망하는 회전을 설정한다
  • 이동의 방향과 크리쳐의 속도에 근거해 속도를 설정한다

본튜토리얼에서는, 이러한 액션을 실행하는 SetRandDest()라는 이름의 함수를 작성할 생각입니다.

1. ConTEXT 를 오픈해, 아직 오픈하고 있지 않으면, AmbientCreature.uc 파일을 오픈해 주세요.

2. 변수 선언과 defaultproperties 블록의 사이에, 몇행인가의 스페이스를 작성해 주세요. 이 부분이 SetRandDest() 함수를 배치하는 장소입니다. 우선, 함수를 선언할 필요가 있습니다. 지금, 배운 것처럼, 이것은, 함수명과 1조의 외모가 계속되는 function 키워드의 사용이 필요합니다. 선언을 개시하기 위해서 이하의 행의 코드를 입력해 주세요 :

function SetRandDest()

여기서, 코드행아래에 이하와 같이 열어 및 닫고 안이나 개를 기술해 주세요 :

{
}

마지막으로, 열림중이나 이 뒤로 커서를 두어, 함수내의 코드를 인덴트 하기 위해서 Enter 키에 이어 Tab 키를 눌러 주세요.

3. 리스트상의 최초의 액션은, 새로운 목적지로서 노드를 선택하는 것이었습니다. 또, 이 노드는, 랜덤에 선택되도록(듯이) 하고 싶습니다. 이 때문에, MyNodes 배열내의 인덱스로서 랜덤인 정수치를 이용할 필요가 있습니다. 최초로, 랜덤 인덱스를 취득해, 로컬 변수내에 보존합니다. 이하의 코드를 입력해 Idx 라는 이름의 로컬의 Integer 변수를 선언해 주세요 :

local Int Idx;

여기서, 모든 클래스가 액세스 하는 Rand() 함수를 사용합시다. 0 으로 함수에게 건네지는 값보다 1 작은 값의 사이의 랜덤인 정수치를 리턴 합니다. 이것은, Rand(5) 라고 입력하면(자), 0 에서 4 까지의 값을 얻는 것을 의미합니다. 이것은, MyNodes 배열내에 격납된 요소의 수를 얻기 위해서(때문에) 동적 배열의 Length 프롭퍼티를 사용할 수 있어 배열의 랜덤인 인덱스를 얻기 위한 Rand() 함수의 입력치에 사용할 수 있기 (위해)때문에, 이 경우의 목적으로 매우 자주(잘) 합치하는 동작입니다

2 번 Enter 키를 눌러, 이하의 코드의 행을 추가해 주세요 :

Idx = Rand(MyNodes.Length);

4. 랜덤인 인덱스를 손에 넣으면(자), MyNodes 배열로부터 노드를 선택하기 위해서 그것을 사용할 수가 있습니다. 결과를 격납하기 위해서, 이제(벌써) 1 개의 로컬 변수가 필요하므로, SetRandDest() 함수내에 이제(벌써) 1 개의 로컬 변수를 선언합니다. Idx 변수에 선언에 계속되는 행에, 이하에 나타내는 행의 코드를 기술해 주세요 :

local AmbientCreatureNode DestNode;

MyNodes 배열에 액세스 해, 선택한 노드를 DestNode 변수에 대입하기 위해서 Idx 변수를 이용할 필요가 있습니다. Idx 변수의 수치를 설정해 있는 행아래에 이하의 코드행을 입력해 주세요 :

DestNode = MyNodes[Idx];

이 시점에서, SetRandDest() 함수는 이하와 같이 될 것입니다 :

function SetRandDest()
{
   local Int Idx;
   local AmbientCreatureNode DestNode;

   Idx = Rand(MyNodes.Length);
   DestNode = MyNodes[Idx];
}

5. 노드의 선택을 실시했으므로, 그 노드에 도달하기 위해서 크리쳐가 이동해야 하는 방향을 계산할 필요가 있습니다. 1 개의 장소로부터, 다른 장소의 방향을 계산하기 위해서는, 단지 다음의 위치로부터, 최초의 위치를 단지 감산할 필요가 있을 뿐입니다. 이 경우는, 목적지로서 선택된 노드의 Location 로부터, 크리쳐의 현재의 Location 를 감산하는 것을 의미합니다.

이 연산을 실시하기 전에, 결과를 격납하기 위한 변수가 필요합니다. 임의의 Actor 의 월드 스페이스내의 현재의 위치를 보관 유지하는 Location 변수는, Vector 입니다. 그 때문에, 이 로컬 변수도 같이 Vector 일 필요가 있습니다. DestNode 변수의 선언의 뒤로, 이하의 선언을 추가해 주세요 :

local Vector MoveDirection;

이 코드에서는, 크리쳐로부터 노드에의 방향을 보관 유지하기 위해서 사용 가능한 MoveDirection 라는 이름의 Vector 변수를 작성합니다.

6. DestNode 변수의 값을 설정해 있는 행아래에서, 이동의 방향을 결정하기 위한 연산을 실행해, MoveDirection 변수에 결과를 대입합니다. 이하의 코드행을 SetRandDest() 함수에 추가해 주세요 :

MoveDirection = DestNode.Location - Location;


그림 6.5 - 새로운 목적지에의 경로가 계산됩니다

7. 크리쳐를 새로운 목적지로 이동하려 하고 있으니까, 이동하려고 하고 있을 방향으로 크리쳐도 회전해 두는 것은, 이치에 필적하고 있습니다. 크리쳐의 DesiredRotation 프롭퍼티를 설정해, 이 처리를 실행할 수 있습니다. 1회 설정되면(자), 물리 엔진은, RotationRate 프롭퍼티로 지정된 회전의 변화율에 따라, 크리쳐를 새로운 회전 방향을 향해 매끄럽게 회전합니다. 이 시점에서 고려할 필요가 있는 유일한 부분은, DesiredRotation 프롭퍼티를 설정하는 것입니다.

이것은, 곧바로, 알지 않을지도 모릅니다만, 이미, 이 프롭퍼티를 설정하기 위해서 필요한 정보는 모두 손에 넣고 있습니다. 크리쳐를 향하고 싶은 방향을 나타내는 벡터인 MoveDirection 벡터가 있기 때문에, DesiredRotation 프롭퍼티에 대입하는 값으로 변환하기 (위해)때문에, 단지 Vector 를 Rotator 에 캐스트 할 수 있습니다. 스크립트의 다음의 행에, 이하의 코드행을 추가해 주세요 :

DesiredRotation = Rotator(MoveDirection);


그림 6.6 - 크리쳐는, 새로운 목적지로 향하기 위해서(때문에) 회전합니다

8. 여기에서는, 크리쳐로 이동하는 것을 고하기 (위해)때문에, Velocity 변수를 설정할 필요가 있습니다. 이 변수는, 그 길이가 실제의 속도를 결정하는 Vector 입니다. 자기의 Speed 변수를 사용한 속도의 제어를 가능하게 하고 싶기 때문에, 이동의 방향을 결정하는 길이 1 의 벡터가 필요했습니다. 이 방법에서는, Speed 변수로 지정된 속도로 노드로 향해 크리쳐를 이동시키기 (위해)때문에, Speed 변수로 곱셈한 결과를 Velocity 변수에 대입할 수 있습니다.

다음의 행상에서, Velocity 프롭퍼티를 설정하기 위해서 이하의 코드를 추가해 주세요 :

Velocity = Normal(MoveDirection) * Speed;

곧 위의 코드내에서 Normal()로 불리는 함수를 사용했던 것에 기분나무지요. 본함수는, 벡터를 취득해, 같은 방향의 단위 벡터 즉 길이 1 의 벡터를 출력합니다. 이것은, MoveDirection 변수에서는, 임의의 크기 정보는 아니고, 방향의 정보만이 필요해서, 중요하게 됩니다.

SetRandDest() 함수는, 이하와 같이 되어 있을 것입니다 :

function SetRandDest()
{
   local Int Idx;
   local AmbientCreatureNode DestNode;
   local Vector MoveDirection;

   Idx = Rand(MyNodes.Length);
   DestNode = MyNodes[Idx];
   MoveDirection= DestNode.Location - Location;
   DesiredRotation = Rotator(MoveDirection);
   Velocity = Normal(MoveDirection * Speed);
}

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

지금은, SetRandDest() 함수는 완성되었으므로, 랜덤에 새로운 목적지를 선택해, 그 목적지로 향해 이동하도록(듯이) 설정하는 것으로, 언제라도 호출하는 것이 가능합니다.

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

6. 3 함수 지정자

Classes 및 Variables 에는, 그 조작해야 할 방법을 컴파일러에 고하기 (위해)때문에, 선언중에서 사용되는 키워드의 조가 있습니다만, 똑같이, 함수도 독자적인 지정자를 가집니다. 이하의 설명으로 그 밖에 지정을 실시하지 않으면, 이러한 지정자는 함수 선언의 function 키워드에 선행합니다.

Static

이 지정자는, 글로벌 함수와 같이, 함수를 포함한 클래스의 오브젝트 참조 변수의 필요 없이 임의의 다른 클래스로부터 호출해 가능한 함수의 생성을 실시할 때에 사용됩니다. 함수를 포함한 클래스의 인스턴스가 존재하는 것에는 무슨 보증도 없기 때문에, non-static(비정적) 함수에의 호출은 static(정적) 함수중에서 하행 그림, 함수를 포함한 클래스로부터의 변수를 인수로 할 수 없습니다. 이러한 함수는 서브 클래스내에서의 오버라이드(override)가 가능합니다.

Native

이 지정자는, 함수가 native(네이티브) 코드(C++)로 정의되고 있지만, UnrealScript 내로부터의 소환을 허가하는 것을 선언합니다. 본서는, UnrealScript 를 취급하고 있기 때문에, 이 키워드를 사용하는 국면은 없습니다만, 스크립트를 상세하게 조사하고 있을 때는, 자주 볼 수 있는 것입니다.

Final

이 지정자는, 아이 클래스에서의 함수의 오버라이드(override)의 기능을 무효로 합니다. 함수를 Final 로서 선언하면(자), 약간의 퍼포먼스 향상이 됩니다만, 그 함수의 오버라이드(override)의 필요가 전혀 없는 일이 확실한 경우에만 사용되어야 합니다. 이 지정자는, 함수 선언내에서 function 키워드의 직전에 두지 않으면 안됩니다. 함수의 오버라이드(override)에 대한보다 자세한 정보에 대해서는, 6.6 함수 오버라이드(override)를 참조해 주세요.

Singular

이 지정자는, 함수의 재귀적인 소환을 허가하지 않습니다, 즉, 그 함수내로부터 같은 함수의 호출을 할 수 없는 것을 의미합니다.

NoExport

이 지정자는, native(네이티브) 함수용의 C++ 선언의 생성을 실시할 수 없게 합니다.

Exec

이 지정자는, 함수명과 임의의 지정 인수를 콘솔로부터 직접 키보드 입력해, 게임중의 소환을 가능하게 하는 것 같은 함수를 선언합니다. Exec 함수는, 특정의 클래스내에서만 사용 가능합니다.

Latent

이 지정자는, 게임이 진행중에 백그라운드에서 그 함수가 동작할 가능성이 있는 것을 나타냅니다. latent 함수는, 「 제 11 장 : 상태」로 상세하게 설명되는 상태 코드내로부터 마셔 불려 갑니다. 이 지정자는, native(네이티브) 함수와 함께 사용되었을 때 마셔 유효합니다.

Iterator

이 지정자는, 먼지의 리스트를 차례로 반복하기 위한 Foreach 커멘드와 함께 사용 가능합니다.

Simulated

이 지정자는, 이 함수가 클라이언트측에서 실행될지도 모르는 것을 나타냅니다만, 이 함수를 가지는 먼지가, 시뮬레이트 된 프록시 또는 자율적인 프록시때만 실행됩니다.

Server

이 지정자는, 실행하기 위해(때문에), 서버에 함수를 보냅니다.

Client

이 지정자는, 실행하기 위해(때문에), 클라이언트에 함수를 보냅니다. Client 지정자를 사용하면(자), 그 함수로 Simulated 도 같이 지정되고 있게 됩니다.

Reliable

이 지정자는, 네트워크상의 복사를 취급해, Server 또는 Client 지정자와 조합해 사용됩니다. Reliable 함수는, 먼지내에서 다른 복사된 항목에 대해, 차례로 복사되는 것을 보증합니다.

Unreliable

이 지정자는, 네트워크상의 복사를 취급해, Server 또는 Client 지정자와 조합해 사용됩니다. Unreliable 함수는, Actor 내에서 다른 복사된 항목에 대해, 차례로 복사되는 것을 보증하지 않고, 네트워크상의 밴드폭이 불충분한 경우는 전혀 복사를 실시하지 않을 가능성도 있습니다.

Private

이 지정자는, 함수가 선언된 클래스내로부터 마셔 액세스 가능하게 합니다. 서브 클래스는, 기술적으로는 이 함수를 포함하고 있습니다만, 직접 이 지정자를 사용할 수 없습니다. 그렇지만, 서브 클래스가, private (프라이빗) 함수를 차례차례 호출하는 것 같은, 몇개의 친클래스판의 non-private(비-프라이빗) 함수를 호출하는 경우에는, 간접적으로 호출이 가능합니다. 프라이빗 함수를, 다른 클래스로부터 오브젝트 참조 변수를 사용한 호출할 수 없습니다.

Protected

이 지정자는, 함수를, 선언된 클래스 또는 그 서브 클래스만으로부터 액세스 가능하게 합니다. 서브 클래스는, protected(프로 텍 테드) 함수를 포함해, 직접 호출을 실시할 수 있습니다만, 다른 클래스로부터의 오브젝트 참조 변수를 이용한 호출은 할 수 없습니다.

Event

이 지정자는, native(네이티브) 코드로부터도 호출하는 것이 가능한 UnrealScript 내의 함수를 작성하기 위해(때문에), 함수의 선언시에 function 키워드 대신에 사용됩니다. native(네이티브) 코드에 관련하기 위해(때문에), 본서의 적용 범위를 넘고 있습니다. 그렇지만, Unreal 의 스크립트를 보고 있으면(자), 큰 일 자주 눈에 띄는 것입니다.

Const

이 지정자는, native(네이티브) 함수와 함께 마셔 사용되어 자동 생성된 C++ 헤더내에서 const 로 정의된 함수가 됩니다. 이 지정자에게는, 함수 선언내의 인수 리스트가 계속됩니다.

6. 4 리턴치

함수로 값이 출력 가능하다 (일)것은, 몇번인가 말해 왔습니다. 이것은, 함수가 원래 불려 간 장소에 요구하고 싶은 값이 돌려주어지기 (위해)때문에, 리턴치로 불립니다. 그러면, 어느 값을 리턴 할까를 함수는 어떻게 아는 것일까요? Return 키워드는, 실행을 멈추어 키워드에 계속되는 어떠한 것을 리턴 해야 할것을, 함수에 알립니다. 이것은, 간단한 값, 변수 또는 식의 형태를 취할 수가 있습니다. 값이 변수의 형식의 경우는, 그 변수의 현재의 값이 리턴 됩니다. 식의 경우는, 식을 평가한 결과가 리턴 되는 값이 됩니다.

주기 : Return 키워드는, 그것 자신으로서는, 값을 리턴 하지 않는 함수의 실행을 정지하기 위해서 사용할 수 있습니다. 이것은, 함수의 실행을 바라지 않는다고 하는 것 같은, 어느 특정의 상황에서는, 편리할지도 모릅니다.

매우 간단한 예를 사용해, 이것이 어떻게 동작할까를 간단하게 볼 수가 있습니다. 이하의 함수는, 1 의 값을 리턴 할 뿐(만큼)의 것입니다.

function Int ReturnOne()
{
   return 1;
}

본함수는, 이하와 같이 Int 변수의 값을 설정하기 위해서 사용 가능합니다.

var Int MyInt;
…
MyInt = ReturnOne();

이 코드행을 실행한 후에, ReturnOne()의 소환으로 1 의 값을 리턴 했기 때문에, MyInt 의 값은, 1 으로 동일해집니다. 결국은, 함수 실행 후의 코드행은, 이하와 같이 됩니다 :

MyInt = 1;

함수 소환이 최초로 실행되고 나서, 코드행의 나머지의 부분이 평가됩니다. 이 예는, 매우 간단합니다만, 리턴치는, 보다 복잡한 상황으로, 매우 편리하게 될 가능성이 있습니다. 때로는, 함수 호출은, 실제로, 이하와 같은 닷 표기의 캐릭터 라인안으로 지정되는 일도 있습니다 :

OnlineSub.GameInterface.GetGameSettings(). bUsesArbitration

이 코드행으로 보고 있는 변수가 무엇을 나타내고 있을까는, 실제는 중요하지는 않습니다. 이 코드행에서는, 함수 호출이, 본질적으로, 변수와 같게 사용되고 있는 점을 눈치채는 것이 중요합니다. 부분마다 분해하면, 무엇을 하고 있을지가 보다 확실하겠지요.

OnlineSub.GameInterface.GetGameSettings()

GetGameSettings() 함수가 리턴 하기 위한(해), 이 닷 표기의 캐릭터 라인의 최초의 부분에서는, OnlineGameSettings 오브젝트를 평가합니다. 그 때문에, 이 코드가 실시하고 있는 것은, "OnlineSub 오브젝트에 속하는 GameInterface 오브젝트에 속하는 OnlineGameSetting 오브젝트를 리턴 하는" 입니다. 이 부분을 평가한 후는, 이 행의 논리는, 간단하게 읽을 수 있게 됩니다 :

OnlineGameSettings.bUsesArbitration

그런데, 여기에서는, 개념화를 보다 용이하게 하기 위한(해), OnlineGameSettings 오브젝트에 속하는 bUsesAbritration 변수를 단순하게 참조하고 있습니다. 어째서 시작해에 OnlineGameSettings 를 직접 참조하는 만큼 해, 함수 호출을 회피하지 않는 것인지와 의문으로 생각할지도 모릅니다. 부적절하게 변수를 변경하면(자) 중대한 부작용이 될 가능성이 있으므로, 변수의 제공 또는, 특정의 변수에의 직접 액세스 허가는 항상 좋은 생각이다고는 말할 수 없는 것이 그 이유입니다. 모든 것을 계속 순조롭게 실행하기 (위해)때문에 , 그러한 오브젝트에의 참조를 리턴 하기 위해서, 이 함수는 작성되었습니다.

6. 5 함수의 인수

함수에는, 불려 갔을 때에, 값을 인도하는 또는, 정보를 함수에 보내는 능력이 있습니다. 이러한 값은, 임의의 형태로 자주(잘), 함수의 내부에서의 사용이 가능하게 됩니다. 자주, 함수에 인도해지는 값은 변수의 형식이 되고 있습니다. 그 밖에 지정이 없으면, 인수로서 함수에 변수가 건네받았을 때에, 변수의 카피가 작성되어, 함수내에서 변수의 변경이 발생해도 카피만이 영향을 받습니다. 어떻게 함수에 인도하는 인수가 동작할까를 알기 위해서(때문에), 다음의 예를 봅시다.

이하의 함수는, 1 개의 값을 다른 2 개의 값의 사이에 클램프 하기 위해서 사용되겠지요. 동일한 함수는 이미 Unreal 내에 존재하고 있습니다만, 이것은, 인수의 데모를 이해하는 도움이 됩니다.

Function Int Clamp(Int Value, Int Min, Int Max)
{
   if( Value < Min)
      Value = Min;
   else if( Value > Max)
      Value = Max;

   return Value;
}

여기서, 먼지의 Health 를 0 으로 100 의 값의 사이에 클램프 하고 싶다고 합시다. 위의 함수를 이하와 같은 방법으로 사용하는 것이 가능합니다.

Health = Clamp(Health, 0, 100);

이 커멘드는, 클램프 한 값을 리턴 하는 Clamp 함수를 실행해, Health 변수를 대입합니다. 함수에서는 Health 변수의 카피를 대상으로 작업하고 있는 것만으로, 직접 수정을 실시하지 않기 때문에, 값의 대입이 필요했습니다. 다음의 섹션으로 참조하도록(듯이), 파라미터로서 건네받은 변수의 직접 조작을 함수에 강제할 수가 있습니다.

함수 인수 지정자

함수 인수 지정자는, 함수 인수에만 관련하는 변수 지정자의 특별한 세트입니다.

Out

인수가 Out 지정자를 사용해 선언되었을 때는, 작업용의 카피를 작성하는 대신에, 함수에게 건네진 변수가 직접 함수에 의해 수정됩니다. 이것은, 기본적으로는 함수에 1 개 이상의 값의 리턴을 허가합니다. Out 지정자를 사용했을 때의 차이를 나타내기 위해서(때문에), 전회의 Clamp() 함수의 예를 사용합시다, 이번 만은 Out 지정자를 사용하기 위해(때문에), 함수는 값을 리턴 하지 않습니다.

Function Clamp(Out Int Value, Int Min, Int Max)
{
   if( Value < Min)
      Value = Min;
   else if( Value > Max)
      Value = Max;
}

또, 먼지의 Health 를 0 으로 100 의 사이에 클램프 하고 싶은 경우는, 위의 함수는, 다음과 같이 사용됩니다.

Clamp(Health, 0, 100);

전회의 예와는 달라, 실행해야 하는 것은, 적절한 파라미터와 함께 함수를 호출할 뿐입니다. 함수로 Health 에의 올바른 값의 대입을 취급하기 (위해)때문에, 리턴치는 불필요합니다.

Optional

인수가 Optional 지정자를 사용해 선언되었을 때는, 함수의 인수에 값을 건네주지 않고 호출할 수가 있습니다. Optional 인수는, 만약 함수에 값이 건네받지 않는 경우에 사용되는 디폴트치를 가질 수가 있습니다. 디폴트치가 지정되지 않고, 값이 건네받지 않으면, 제로를 나타내는 값 (파라미터의 형태에 의존해 0, 0.0, False, “”, None, 그 외)이 사용됩니다.

optional 파라미터에 대한 디폴트치의 정의는, 이하와 같은 방법으로 행해집니다.

Function Clamp(Out Int Value, Optional Int Min = 0, Optional Int Max = 1)
{
   if( Value < Min)
      Value = Min;
   else if( Value > Max)
      Value = Max;
}

본선언은, 호출시에, 함수의 인수에 값이 건네받지 않는 경우에, Min 를 0 에, Max 를 1 으로 하도록(듯이) 정의합니다. 이전과 같은 상황으로 사용하면(자), 이하의 인수로 함수를 호출하는 것으로 0 및 100 의 사이로, 플레이어의 Health 를 클램프 할 수 있습니다.

Clamp(Health, , 100);

디폴트치가 사용하고 싶은 값과 같기 때문에, 2 번째의 인수는, 지정되어 있지 않은 것에 주목해 주세요. 3 번째의 인수에 대해서는, 디폴트치가 1 이며, 희망하는 값으로 없기 때문에, 100 을 건네주지 않으면 안됩니다. 마지막 인수는 아닌 optional 인수로 값을 지정하지 않을 때는, 함수로 다음에 값을 건네주는 인수가 어떤 것인지를 알기 (위해)때문에, 그 인수의 위치에, 공백을 남겨 두지 않으면 안됩니다. optional 인수가 마지막 인수이면, 공백을 남겨 둘 필요는 없고, 모두 생략 할 수 있습니다.

Coerce

인수가 Coerce 지정자를 사용해 선언되었을 때는, 함수에 대해서 인수용으로 건네받은 값은, UnrealScript 가 통상에 변환을 실행할지 어떨지에 관계없이, 인수의 형태에 변환됩니다. 이것은, `log() 함수를 실행하는 Coerce 지정자의, 가장 일반적인 사용예로, String 인수로 가장 자주 이용되고 있습니다.

`log( coerce string Msg, optional bool bCondition=true, optional name LogTag='ScriptLog' );

Msg 인수로서 건네받는 데이터에 임의의 형태를 허가하는 Coerce 지정자를 사용해, 캐릭터 라인에 강제적으로 변환합니다. 이것은, 스크립트의 디버그를 실시하려면 매우 유용이 됩니다. 특정의 오브젝트를 보관 유지해야 할 오브젝트 참조 변수를 가지는 것이 가능합니다. 이 케이스에 해당될지 어떨지를 결정하기 위해서(때문에), `log() 함수에 변수를 건네주면(자), 오브젝트의 캐릭터 라인 표현, 이 경우는 이름을 로그 파일에 출력합니다.

튜토리얼 6.6 앰비언트 크리쳐, 파트 VI: SETDEST() 함수

본튜토리얼에서는, MoveDirection 를 계산해 DesiredRotation 을 설정해, SetRandDest() 함수로부터 Velocity 를 설정하는 기능을 꺼내, 다른 함수내에 설치합니다. 이 기능을 분리하는 것으로, 목적지를 랜덤에 선택할 뿐만 아니라, 필요에 따라서 특정의 목적지를 설정할 수도 있는 능력을 추가했습니다. 이것에 의해, 클래스는 보다 유연하게 되어, 이후의 장에서도 사용하기 쉽게 됩니다.

1. ConTEXT 를 오픈해, 아직 오픈하고 있지 않으면, AmbientCreature.uc 파일을 오픈해 주세요.

2. SetRandDest() 함수로부터 코드의 부분을 집적해 새로운 함수를 선언할 필요가 있습니다. SetRandDest()의 몇 줄기하에 이하에 나타내는 코드행을 추가해 주세요 :

function SetDest(AmbientCreatureNode inNode)
{
}

기분 다음 같게, SetDest() 함수는, AmbientCreatureNode 를 취득합니다. 여기에서는, 랜덤인 노드 선택도, 특정의 노드 선택도 허가되고 있습니다만, 그 다음에, 이 함수에 인도해집니다.

3. 초에, 필요한 로컬 변수 선언을 SetRandDest() 함수로부터, SetDest() 함수에 이동합니다. 3 개의 선언 가운데, 관계하는 것은 MoveDirection 선언만입니다.

SetRandDest() 함수내의 이하에 나타내는 행의 코드를 선택해, Ctrl+X 를 눌러 절취를 실시해 주세요.

local Vector MoveDirection;

4. SetDest() 함수의 열림중이나 일 닫고 안이나 이전으로, Ctrl+V 를 눌러 변수 선언을 붙여 주세요. 여기서 SetDest() 함수는, 이하와 같이 됩니다 :

function SetDest(AmbientCreatureNode inNode)
{
   local Vector MoveDirection;
}

5. 다음에, SetRandDest()로부터 MoveDirection, DesiredRotation 및 Velocity 변수를 설정할 책임을 지는 코드행을 선택해, Ctrl+X 를 눌러 절취를 실시해 주세요 :

MoveDirection= DestNode.Location - Location;
DesiredRotation = Rotator(MoveDirection);
Velocity = Normal(MoveDirection * Speed);

6. SetDest() 함수의 변수 선언의 뒤로, Ctrl+V 를 눌러 코드행을 붙여 주세요. DestNode 의 인스턴스를 1 개, 함수의 인수의 이름에 맞도록(듯이) inNode 로 변경해 주세요. SetDest 함수는 이하와 같이 되었습니다 :

function SetDest(AmbientCreatureNode inNode)
{
   local Vector MoveDirection;

   MoveDirection= inNode.Location - Location;
   DesiredRotation = Rotator(MoveDirection);
   Velocity = Normal(MoveDirection * Speed);
}

7. 목적지에 대해서, 어떤 종류의 치우침도 추가하고 싶다고 생각합니다, 즉 크리쳐는, 항상, 노드의 위치에 직접 이동하는 것 만이 아니고, 노드의 주위의 반경내에 이동할 수도 있게 됩니다. 처음에, 현재의 로컬 변수 선언을 이하와 같이 변경해, MoveOffset 라는 이름의, 이제(벌써) 1 개의 로컬 Vector 를 추가해 주세요 :

local Vector moveDirection, MoveOffset;

8. 이 MoveOffset 변수는, 처음에 랜덤 Vector 를 얻어, 그리고, 거기에 목적으로 노드의 Radius 변수로 지정된 기호의 반경을 곱하는 것으로 계산됩니다. 이 계산을 실행하기 위해(때문에) SetDest() 함수내의 다른 코드의 전에, 이하에 나타내는 행을 추가해 주세요 :

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

9. 그리고, 새로운 MoveOffest 치를 이용하기 위해서, MoveDirection 를 설정하는 행을 이하와 같이 변경해 주세요 :

MoveDirection = (inNode.Location + MoveOffset) - Location;


그림 6.7 - 목적지는, 노드의 반경내가 되고 있다.

10. 그런데, SetRandDest() 함수에 돌아와, 이하의 코드행을 추가해 주세요 :

SetDest(DestNode);

완성한 SetRandDest() 함수는, 현재로서는, 이하의 코드로 구성되어 있을 것입니다 :

function SetRandDest()
{
   local Int Idx;
   local AmbientCreatureNode DestNode;

   Idx = Rand(MyNodes.Length);
   DestNode = MyNodes[Idx];
   SetDest(DestNode);
}

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

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

6. 6 함수 오버 라이딩

클래스를 편리하게 하기 위해서, 클래스내에 함수를 만드는 방법을 이해했습니다. 또, 클래스를 확장하는 것에 의해, 클래스내에 포함된 함수는, 서브 클래스에게 건네지는 것을 알았습니다. 서브 클래스판의 함수에 얼마인가 기능을 추가하거나 완전히 다른 어떠한 동작을 시키고 싶을 때로는, 어떻게 하면 좋은 것일까요 - UnrealScript 는, 서브 클래스에 대해, 함수의 부모의 판을 오버라이드(override) 하는 기능을 제공하고 있다. 이것은, 서브 클래스에서는, 친클래스의 함수와 같은 인수와 리턴치로 같은 이름의 함수로 다른 동작이 가능한 일을 나타냅니다.

이 기능은, 계승의 이점도 향수하면서, 필요에 따라서 친클래스와 서브 클래스에 다른 동작을 시킨다고 하는 유연성을 갖게할 수가 있다고 하는 점으로써 매우 효과가 있습니다. 더욱, 실장도 매우 간단합니다. 함수의 부모의 버젼을 서브 클래스에 카피해, 함수내에 포함되는 코드에 대해서, 임의의 희망하는 변경을 실시할 필요가 있을 뿐입니다. 이것에 의해, 부모의 버젼 대신에, 이 함수의 새로운 판이 사용되는 것을 컴파일러에 고합니다.


그림 6.8 - 개개의 아이 클래스의 Draw() 함수는, 부모의 함수와는 다른 동작을 실시합니다.

서브 클래스내의 함수를 오바라이드 하는 Unreal Tournament 3 에서는, 일반적이어, 매우 간단한 예를 봅시다. 이 예에서는, Touch() 함수는, 잘 동작할 것입니다. 이 함수는, Actor 클래스에서 정의되고 있습니다만, 기능의 제공은 실시하지 않습니다. 이것은, 기본적으로, 어떠한 동작으로 오버라이드(override) 되도록(듯이) 대기하고 있는 하늘의 함수입니다. Actor 클래스를 확장해, Touch() 함수를 오바라이드 하는 것으로, 이 먼지에 터치하는 임의의 먼지의 이름을 Log 파일에 출력한다라고 하는, 어떠한 동작을 실행하는 기능을 확장하고 있는 Actor 클래스내의 모든 기능을 이용할 수가 있습니다.

class Toucher extends Actor placeable;

event Touch(Actor Other, PrimitiveComponent OtherComp, vector HitLocation, vector HitNormal)
{
   `log(Other);
}

계승이나, 함수의 오버라이드(override)의 효율성은, 이 예로부터 곧바로 알겠지요. 완전히 새롭고 완전하게 기능하는 클래스를 작성하기 위해서, 아주 조금의 코드행을 기술할 필요가 있는 것만으로 했다. Actor 클래스는 3000 행 이상의 길이의 코드입니다만, 이 클래스는, 그저 몇 줄기의 코드만으로, 모든 기능과 추가 기능을 손에 넣을 수 있습니다.

6. 7 SUPER 키워드

서브 클래스내에서 함수를 오버라이드(override) 하는 것으로, 계승된 함수에 의해 실행되는 동작을 변경 가능합니다. 새로운 기능을 얻기 위해서(때문에) 함수를 오바라이드 하는 능력을 이용했을 경우에, 부모의 함수의 기능을 보관 유지하고 싶을 때에는 무엇이 일어나겠지요? 함수의 서브 클래스판에, 함수의 친클래스판으로부터의 코드를 단순하게 포함하면 좋다고 추측할지도 모릅니다만, 그것이, 제일 효율적인 해결법으로 없는 것은 확실합니다. UnrealScript 에서는, 함수의 부모의 판을 호출하려면 , 서브 클래스에서 Super 키워드를 사용합니다. 이와 같이 하면(자), 서브 클래스에서는, 계층내에서 위가 되는 개개의 클래스의 모든 기능을 보관 유지하면서 기능을 추가할 수가 있습니다. 친클래스의 Touch() 함수를 호출하기 위해서(때문에) Super 키워드를 사용할 때의 구문은, 이하와 같은 것입니다.

Super.Touch();


그림 6.9 - Rifle 클래스는, Weapon 클래스의 Touch() 함수를 호출합니다.

더욱, 클래스명은, 계층내 위의 특정의 클래스로부터 함수를 호출하는 것을 서브 클래스에 허가하기 위해서 Super 키워드를 지정 가능합니다. 여기에 Actor(먼지), Weapon(무기) 및 Rifle(라이플)의 3 개의 클래스가 있어, Weapon 가 Actor 로부터 확장되어 Rifle 가 Weapon 로부터 확장되고 있는 계층 구조를 만들고 있다고 합시다. 개개의 서브 클래스, 즉 Weapon 및 Rifle 는, 대응하는 친클래스로부터의 Touch() 함수를 오버라이드(override) 가능합니다. 만약, Rifle 클래스가 Actor 클래스의 판의 Touch() 함수를 호출하고 싶은 경우는, 이하와 같은 방법으로 실행할 수 있습니다.

Super(Actor). Touch();

이 지정에서는, 비록 Rifle 의 부모가 Weapon 에서도, 그 클래스의 버젼의 함수를 스킵 해, Actor 클래스판의 Touch() 함수를 실행합니다.


그림 6.10 - Rifle 클래스는, Actor 클래스의 Touch() 함수를 호출한다.

주기 : 상기의 함수 호출을 간단하게 하기 위해서, 인수는 방치되어 있습니다.

튜토리얼 6.7 앰비언트 크리쳐, 파트 VII: POSTBEGINPLAY() 함수

여기까지로, 랜덤인 목적지를 선택해, 크리쳐를 목적지로 이동하기 위해(때문에), 베이스 크리쳐 클래스에 함수를 추가했습니다. 이 전체의 동작을 설정하는 메소드를 아직 실장하고 있지 않는 것에 기분귀댁도 알려지지 않습니다. 추가한지 얼마 안된 기능을 사용하기 위해(때문에), 레벨이 시작될 때에, SetRandDest() 함수를 호출하는 수단이 필요합니다. 이것이, 확실히 본튜토리얼로 실시하고 싶은 것입니다. 동시에, Speed(속도)와 RotationRate(회전 속도)의 다소의 변화의 설정과 같이, 개개의 크리쳐에 대해서 랜덤인 사이즈를 설정하는 기능을 실장합니다.

1. ConTEXT 를 오픈해, 아직 오픈하고 있지 않으면, AmbientCreature.uc 파일을 오픈해 주세요.

2. 레벨 개시 후에, 개개의 Actor 상의 엔진에 의해 불려 가는 PostBeginPlay() 함수를 사용할 예정입니다. 이 함수를 오바라이드 해, 크리쳐의 동작의 초기화와 동시에 크리쳐에 대한 사이즈, 속도 및 회전 속도를 설정하는 이상적인 장소를 제공합니다.

클래스내의 함수의 위치는 중요하지는 않습니다만, 클래스 변수 선언의 곧 뒤로 PostBeginPlay() 함수를 두기로 합시다. 이것으로, 클래스내의 함수가 실행순서에 줄서게 됩니다.

클래스 변수의 선언과 SetRandDest() 함수의 사이에, 몇행인가의 공백을 작성해, 이하와 같이, PostBeginPlay() 함수에 대한 선언을 추가해 주세요.

function PostBeginPlay()
{
}

3. 최초로, 이 함수를 오버라이드(override) 할 때에 실시하고 싶은 것은, Super 키워드를 사용해 부모의 버젼의 함수가 실행되는 것의 확인입니다. 이것에 의해, 추가할 예정의 기능 외에, 몇개의 일반적인 설정 동작의 실시를 확실히 실시합니다. 안이나 이 내부에, 이하의 행을 추가해 PostBeginPlay() 함수의 친버젼을 호출해 주세요.

Super.PostBeginPlay();

4. 클래스 변수를 선언했을 때에, 개개의 크리체의 사이즈에 대한 최소치 및 최대치로서 사용되는 변수를 2 개 선언했습니다. 랜덤인 값을 취득하기 위해서 RandRange()라는 이름의 함수와 함께 이러한 값을 사용하고 싶다고 생각합니다. 크리쳐의 사이즈를 설정하기 위해서 SetDrawScale()로 불리는 함수로 이러한 값을 사용할 예정입니다. PostBeginPlay() 함수의 다음의 행에, 이하의 코드행을 추가해 주세요 :

SetDrawScale(RandRange(MinSize, MaxSize));

이 처리 모든 것이, 1 행만으로 기술 가능한 것으로 기분나무지요. 이것은, RandRange() 함수가 Float 치를 리턴 해, 한편, SetDrawScale() 함수가, 인수로서 Float 치를 수중에 넣고 있기 때문입니다. 즉, 하나의 함수 호출을, 다른 함수 호출의 인수로서 사용할 수가 있어 추가의 로컬 변수를 필요로 하지 않고 , 모든 것이 완전하게 동작합니다.


그림 6.11 - 개개의 크리쳐의 사이즈는, 사이즈의 범위로부터 랜덤으로 선택됩니다.

5. 1 개의 크리쳐와 다음의 크리쳐와의 사이에 Speed 및 RotationRate 프롭퍼티에 다소의 변화를 주고 싶다고 생각합니다. 그렇지만, 이것들 2 개의 프롭퍼티는, 서로 관련하고 있습니다. 보다 빠른 속도의 크리쳐는, 동시에보다 빠른 회전 속도가 필요한 것을 의미합니다. 이전의 스텝에서 사용한 것과 같은 randRange() 함수를 사용해, 이 조작을 실시하고 싶다고 생각합니다만, 이번은, 같은 랜덤치로, Speed 및 RatationRate 의 쌍방의 적산을 할 수 있도록(듯이), 로컬 변수내에 값을 보존합니다.

기존의 PostBeginPlay() 함수내의 코드행을, 몇 줄기하로 이동하고 나서, 이하의 코드를 추가해 RandVal 라는 이름의 Float 변수를 선언해 주세요 :

local Float RandVal;

여기서, 0.5 로 1.5 의 사이의 랜덤치를 선택하는 것에 의해 RandVal 함수의 값을 설정합니다. 기본적으로, 이 처리로, Speed 및 RotationRate 변수의 디폴트치로부터 0.5 의 편차를 얻습니다. PostbeginPlay() 함수의 마지막 행의 뒤로, 이하의 코드행을 추가해 주세요 :

RandVal = RandRange(0.5, 1.5);

6. 여기에서는, 단지 RandVal 변수로, Speed 및 RotationRate 변수를 적산할 필요가 있을 뿐입니다. Speed 및 RotationRate 변수에 대해서 변화를 주기 위해서(때문에), PostBeginPlay() 함수에, 이러한 2 행의 코드를 추가해 주세요 :

RotationRate *= RandVal;
Speed *= RandVal;


그림 6.12 - 좌측의 크리쳐는, 낮은 Speed 및 RotationRate 을 가져, 한편, 우측의 것은, 높은 Speed 및 RotationRate 를 가집니다.

7. 이 시점에서, 실행 해야 할것은, 크리쳐를 움직이기 시작하기 위해서(때문에) SetRandDest() 함수를 호출할 뿐입니다. PostBeginPlay() 함수의 말미에 이하의 코드를 추가해 주세요.

SetRandDest();

PostBeginPlay() 함수는 이하와 같이 될 것입니다 :

function PostBeginPlay()
{
   local Float RandVal;

   Super.PostBeginPlay();
   SetDrawScale(RandRange(ScaleMin, ScaleMax));
   RandVal = RandRange(0.5, 1.5);
   RotationRate *= RandVal;
   Speed *= RandVal;
   SetRandDest();
}

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

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

튜토리얼 6.8 앰비언트 크리쳐, 파트 VIII: TICK() 함수

현재의 셋업에서는, 크리쳐는, 목적지에 향하도록(듯이) 회전하면서, 목적의 노드로 향해 움직이기 시작합니다. 이것은, 시각적인 견지로부터 보면(자) 비현실적인 결과가 됩니다. 이것을 바로잡기 위해서(때문에), 크리쳐가 향하고 있을 방향으로 항상 크리쳐의 속도를 주도록(듯이) 합니다. 이 방법으로, 다음의 목적지에 얼굴을 향하여 있는 동안, 크리쳐의 이동 경로는, 곡선이 됩니다.

1. ConTEXT 를 오픈해, 아직 오픈하고 있지 않으면, AmbientCreature.uc 파일을 오픈해 주세요.

2. 크리쳐의 Velocity 가, 항상, 현재 향하고 있을 방향으로 크리쳐를 움직이는 것을 확실히 하기 위해서, Tick() 함수를 사용합니다. 이 함수는, 엔진에 의해, 자동적으로 프레임마다 불려 가므로, 목적으로는, 자주(잘) 합치하고 있습니다. SetGoal() 함수의 뒤로, 이하의 Tick() 함수의 선언을 추가해 주세요 :

function Tick(Float Delta)
{
}

3. PostBeginPlay() 함수와 함께, 이 함수의 부모의 버젼이 실행되는 것을 확실히 하고 싶기 때문에, 안이나 이전에, 이하의 코드를 추가해 Super 키워드를 사용하는 함수 호출을 기술합니다.

Super.Tick(Delta);

여기서, 부모의 함수에 Delta 인수를 건네주고 있는 것에 유의해 주세요.

4. 여기서, SetDest() 함수내에서 Velocity 를 설정해 있는 코드를 선택해, 그 자리소로부터 잘라냅니다. 이하와 같이 표시된 코드행을 찾아내 선택해 주세요. 그리고, 코드행을 잘라내기 위해서(때문에) Ctrl+X 를 눌러 주세요.

Velocity = Normal(MoveDirection) * Speed;

5. Tick() 함수의 다음의 행으로, 이 코드행을 붙이기 위해서(때문에) Ctrl+V 를 눌러 주세요.

6. MoveDirection 변수를 크리쳐가 향하고 있을 방향을 나타내는 식에서 옮겨놓을 필요가 있습니다. 크리쳐의 Rotation 프롭퍼티를 Vector 에 캐스트 하면(자), 그 결과는 크리쳐가 향하고 있을 방향의 벡터가 됩니다. 코드행의 MoveDirection 의 존재하는 부분을, 이하에 나타내는 식에서 옮겨놓아 주세요 :

Vector(Rotation)

Tick() 함수는, 현재, 이하와 같이 되어 있을 것입니다 :

function Tick(Float Delta)
{
   Super.Tick(Delta);
   Velocity = Normal(Vector(Rotation)) * Speed;
}


그림 6.13 - 크리쳐는, 일정 위치에서 방향을 바꾸는 대신에, 곡선을 더듬어 방향을 바꾸게 되었습니다.

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

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

6. 8 TIMER 함수

개개의 Actor 내에 존재하고 있는 Timer() 함수에서는, 특정의 시간이 경과한 후에, Actor 를 실행할 수 있는 특별한 기능을 이용할 수 있습니다. 이것은, 한 번 한계의 이벤트일지도 모르고, 어느 특정의 시간이 경과한 후에, 반복 발생한 것일까도 알려지지 않습니다. Timer 함수의 이용에 대한 적절한 설명을 실시하는, 몇개의 동작이 좋은 예는, 픽업의 re-spawning(재스폰)지요. 아이템이 플레이어에 의해 취득되면(자), 게임중에 아이템을 한번 더 플레이어에게 이용 가능하게 하기 위해서, 픽업 클래스는, 특정의 시간 경과후에 아이템을 re-spawn(재스폰) 하는 타이머를 기동합니다.


그림 6.14 - 좌측은, 루프 하지 않는 타이머이며, 우측은, 루프 하는 타이머입니다.

Unreal Engine 3 에서는, 현재, 클래스내에 복수의 타이머 함수를 가지는 것이 가능하고, 그러한 중 임의의 함수가 동시에 동작 가능합니다. 이전에는, 한 번 한계의 동작만이 가능했어에 대해서, 현재는, 클래스내에서 필요한 개개의 시한의 동작에 대해서 다른 함수의 지정이 가능하게 되었습니다. 모두 동시에 동작시키는 일도 가능한 복수의 타이머를 이용하면(자), 보다 복잡한 행동을 할 수 있게 되어, 플레이어는, 보다 흥미롭게 게임의 플레이가 생기게 됩니다. 이하에 나타내도록(듯이), 인수 없음의 함수로서 선언된 임의의 함수가, 타이머 함수로서 이용할 수 있습니다 :

function NewTimer()
{
   // 여기서, 어떠한 처리를 실시합니다
}

SetTimer

타이머 함수를 기동하기 위해서는, 다른 함수를 사용하지 않으면 안됩니다. SetTimer() 함수는 Actor 클래스에 짜넣어지고 있어 타이머 함수의 파라미터를 셋업 해, 타이머를 기동하기 위해서 사용됩니다. SetTimer() 함수는, 몇개의 인수를 가지고 있기 때문에, 여기서 간단하게 봅시다.

float inRate

본인수는, 타이머 함수내의 동작을 실행하기 전에 대기하는 시간량을 지정합니다.

optional bool inbLoop

본인수는, 타이머가 지정 시간 후에 1회만 기동되는지, 지정한 시간 간격이 경과하면(자) 매회 기동을 계속하는지를 지정하기 위해서 사용됩니다. 이 파라미터는, 옵션지정입니다. SetTimer() 함수의 호출시에 생략 되고 있으면(자), 타이머 함수내의 동작은, 1회만 실행됩니다.

optional Name inTimerFunc

본인수는, 타이머 함수로서 함수명의 사용을 허가합니다. 이것은, 복수의 타이머를 사용하기 위한 기능입니다. 본인수는, Timer 의 디폴트치를 가져, 옵션지정입니다. 이것은, SetTimer() 함수가 불려 갔을 때에 생략 되고 있으면(자), 편입의 Timer() 함수가 사용되는 것을 의미합니다.

optional Object inObj

본인수는, 비-Actor 상속 클래스에 대해서 타이머 기능의 추가를 할 수 있도록(듯이) 합니다. 여기서, Object 가 지정되었을 경우는, 통상 SetTimer() 함수를 호출하는 Actor 상은 아니고, Object상에서 inTimerFunc 인수에 의해 지정된 함수가 불려 갑니다. 또, inTimerFunc 인수에 의해 지정된 함수는, SetTimer() 함수를 호출한 Actor 내는 아니고, 여기서 지정된 Object 의 클래스내에 포함되지 않으면 안됩니다.

ClearTimer

ClearTimer() 함수는 타이머의 실행을 정지하기 위해서 사용 가능합니다. 이것은, 주로, 타이머 함수가 이전에 계속적으로 기동하도록(듯이) 설정되어 있어, 이미 불필요하게 되어 있는 것 같은 때에 편리합니다. 이러한 경우는, ClearTimer() 함수를 호출해, 타이머 함수의 기동을 실시하게 한 없게 합니다. 이 함수는, 2 개의 인수를 가집니다.

주기 : SetTimer() 함수의 inRate 인수를 0.0 의 값으로 호출하면, ClearTimer() 함수의 호출과 같게 됩니다.

optional Name inTimerFunc

본인수는 클리어 되어야 할 타이머 함수의 이름을 지정하기 위해서 이용됩니다. 본인수는 옵션지정이며, Timer 의 디폴트치를 가집니다. 이것은, ClearTimer() 호출시에 미지정의 경우는, 편입의 Timer() 함수가 클리어 되는 것을 의미합니다.

optional Object inObj

Object 가 지정되고 있으면(자), 본인수는, ClearTimer() 함수를 호출하는 Actor 대신에, 지정한 Object 에 대한 타이머가 클리어 됩니다.

IsTimerActive

본함수는, 특정의 타이머가 현재 실행중인지를 나타내는 Boolean 치를 리턴 합니다.

optional Name inTimerFunc

본인수는, 상태를 리턴 하는 타이머 함수의 이름을 지정하기 위해서 사용됩니다. 본인수는, 옵션지정이며, Timer 의 디폴트치를 가집니다. 이것은, IsTimerActive() 호출시에 미지정의 경우는, 편입의 Timer 함수 상태를 리턴 하는 것을 의미합니다.

optional Object inObj

Object 가 지정되었을 경우는, 본인수는, IsTimerActive() 함수를 호출하는 Actor 대신에, 지정한 Object 에 대한 타이머 상태를 리턴 합니다.

GetTimerCount

본함수는, SetTimer() 함수로 개시되고 나서, 또는, 루프 하고 있는 타이머의 경우는 마지막에 기동되고 나서 타이머가 실행된 시간을 나타내는 float 치를 리턴 합니다.

optional Name inTimerFunc

본인수는, 실행 시간을 리턴 해야 할 타이머 함수의 이름을 지정하기 위해서 사용됩니다. 본인수는, 옵션지정이며, Timer 의 디폴트치를 가집니다. 이것은, GetTimerCount() 호출시에 미지정의 경우는, 편입의 Timer() 함수가 그 실행 시간을 리턴 하는 것을 의미합니다.

optional Object inObj

Object 가 지정되었을 경우는, 본인수는, GetTimerCount() 함수를 Actor 대신에, 지정한 Object 에 대한 타이머의 실행 시간을 리턴 합니다.

GetTimerRate

본함수는, SetTimer() 함수의 inRate 인수로 지정된 타이머의 지속 시간을 float 치로 리턴 합니다.

optional Name TimerFuncName

본인수는, 그 지속 시간을 리턴 해야 할 타이머 함수의 이름을 지정하기 위해서 사용됩니다. 본인수는, 옵션지정이며, Timer 의 디폴트치를 가집니다. 이것은, GetTimerRate() 호출시에 미지정의 경우는, 편입의 Timer() 함수가 그 지속 시간을 리턴 하는 것을 의미합니다.

optional Object inObj

Object 가 지정되고 있었을 때는, 본인수는, GetTimerRate() 함수를 Actor 대신에, 지정한 Object 에 대한 타이머의 지속 시간을 리턴 합니다.

튜토리얼 6.9 앰비언트 크리쳐, 파트 IX: SETRANDDEST 타이머

현재, 크리쳐 클래스를 준비할 수 있었으므로, 크리쳐는, 목적지를 선택해, 거기를 목표로 해 이동합니다만, 그 방향으로 단순하게 언제까지나, 또는, 무언가에 충돌할 때까지 계속 이동합니다. 크리쳐에 새로운 목적지의 선택을 계속적으로 실시하게 할 방법이 필요합니다. 본튜토리얼에서는, 이 용도로 타이머를 이용합니다.

1. ConTEXT 를 오픈해, 아직 오픈하고 있지 않으면, AmbientCreature.uc 파일을 오픈해 주세요.

2. SetRandDest() 함수내에서 SetDest() 함수를 호출했을 때는 언제라도, 특정의 시간 경과후에 재차 SetRandDest() 함수를 실행하는 타이머를 개시하고 싶습니다. 그 시간 경과는, MinTravelTime 및 MaxTravelTime 의 사이의 랜덤인 값이 됩니다만, 크리쳐의 속도로 목적지에 도달할 때까지의 시간을 넘지 않게도 제한을 받은 값이 됩니다.

처음은, 크리쳐가 목적지에 도달하기 위해서 필요로 하는 시간에 초점을 맞힙니다. 이 값을 계산하기 위해서, 목적지까지의 거리를 알 필요가 있습니다. 그리고 거리를 Speed 로 제산해 요구하고 싶은 값을 결과적으로 얻습니다. 그렇다고는 해도, 이 값을 보존하는 로컬 변수가 필요합니다. SetRandDest() 함수내의 DestNode 변수 선언에 이어, 이하에 나타내도록(듯이) MoveInterval 변수용의 선언을 추가해 주세요.

local Float MoveInterval;

3. 여기에서는, MoveInterval 변수의 값을 설정합시다. 목적지에의 거리는, 크리쳐의 현재의 Location 로부터, 목적지의 노드의 Location 의 벡터의 길이를 입수해 계산됩니다. UnrealScript 의 식으로 변환하면(자), 이하와 같이 됩니다 :

VSize(DestNode.Location - Location)

SetDest() 함수에의 호출해 후에, MoveInterval 변수를 설정하기 위해서 이하에 나타내는 코드행을 추가해 주세요.

MoveInterval = VSize(DestNode.Location - Location) / Speed;

4. 목적지까지의 시간을 계산하면(자), 타이머의 설정을 실시합시다. 자신의 타이머의 설정은, 많은 경우 꽤 간단한 것입니다. 거기에는, SetTimer() 함수를, 타이머를 반복할지 어떨지의 지속 시간 및 타이머 함수의 이름과 함께 호출합니다. 지속 시간에는 랜덤인 값이 필요해, 목적지까지의 시간도 제한하고 싶다고 생각하고 있기 (위해)때문에, SetTimer()의 호출은, 약간 복잡하게 됩니다. 함수 호출안의, 함수 호출안의 함수 호출로 종료할 예정입니다. 이 이유로부터, 무엇을 하고 있을까를 명확하게 하기 위해서, 보다 작은 파츠로 나누어 봅시다.

시작해에, 목적지까지의 시간을, 이동 시간의 최대 시간에 제한하는 모습을 봅시다. 보다 간단하게, 이 값을 얻기 위해서(때문에), MaxTravelTime 및 MoveInterval 의 2 개의 값의 작은 (분)편의 값을 요구합니다. 이것들은, 모두 Float 치이므로, Unreal 내의 모든 클래스에 대해서 FMin() 함수의 이용을 할 수 있습니다. FMin() 함수에 2 개의 값을 건네주는 것만으로, 2 개의 값의 쳐 작은 값을 리턴 합니다. 이하의 식이 이것을 나타내고 있습니다 :

FMin(MaxTravelTime, MoveInterval);

5. 타이머 설정의 다음의 부분에서는, 랜덤인 값의 선택이 필요합니다. 이미 RandRange() 함수는 몇차례 봐 왔으므로, 어떻게 동작할까는 친숙한은 두입니다. 이 함수에는 2 개의 값을 건네줄 필요가 있습니다. 이러한 값중 1 번째는 MinTravelTime 변수의 값이며, 2 번째의 값은, 위의 식의 결과입니다. SetTimer() 함수에 건네주는 지속 시간을 나타내는 식은 이하와 같습니다 :

RandRange(MinTravelTime, FMin(MaxTravelTime, MoveInterval))

6. 여기에서는, 최종적으로 SetTimer() 함수를 호출할 필요가 있습니다. SetRandDest() 함수의 다음의 행에, 이하에 나타내는 함수 호출을 추가해 주세요 :

SetTimer(RandRange(MinTravelTime, FMin(MaxTravelTime, MoveInterval)), false,'SetRandDest');

SetRandDest() 함수를 실행하기 위해서 타이머를 설정했던 것이 분 빌리고지요, 그러나, 그것을 루프 설정해 있습니다. 타이머가 호출하고 있는 함수로부터 타이머를 설정하므로, 실질적으로 루프가 되고 있습니다. 이 방법은, 매회 타이머의 새로운 지속 시간을 취득할 수 있는 것이 이점입니다.

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

이것으로, AmbientCreature 클래스는 완료입니다. 이후의 몇개의 튜토리얼로, 맵내에 배치 가능한 fish(물고기)를 작성하기 위해서 이 클래스를 확장합니다.

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

튜토리얼 6.10 앰비언트 피쉬, 파트 I: 클래스의 설정

AmbientCreature 클래스의 일반적인 기능을 기본으로 해 구축하는 클래스의 작성을 실시합니다. 본클래스는, fish(물고기)의 크리쳐를 작성 위해(때문에) 고유의 모든 코드를 포함하고 있습니다. MinTravelTime, MaxTraveltime, Speed, MinSize, MaxSize 및 RotationRate 프롭퍼티의 디폴트치의 설정과 같게, 랜덤인 burst in speed(급가속), 표시 용도의 메쉬의 할당등의, 몇개의 고유의 동작을 특히 추가합니다.

1. 아직 오픈하고 있지 않으면 ConTEXT 를 오픈해, File 메뉴 또는 툴바로부터 신규 파일을 생성해 주세요. 그리고, UnrealScript 하이 라이터를 선택해 주세요.

2. 스크립트의 선두행으로, 신규 클래스의 선언을 실시할 필요가 있습니다. 본클래스는, AmbientCreature_Fish 라고 명명되어 AmbientCreature 클래스로부터 확장됩니다. 또, 본클래스는 placeable(배치 가능)입니다. 클래스를 선언하기 위해서 이하에 나타내는 코드행을 추가해 주세요.

class AmbientCreature_Fish extends AmbientCreature placeable;

3. 본클래스는, 이전에 말한 급가속을 실행하기 위해서, 몇개의 클래스 변수를 사용합니다. 이러한 프롭퍼티의 제 1 의 것은, 급가속이 일어난 것을 지정하는 Bool 변수로, 물고기의 속도를 원의 속도로 감속을 개시할 필요가 있습니다. bFalloff 변수에 대해, 이하에 나타내는 선언을 추가해 주세요.

var Bool bFalloff;

4. 급가속을 실시할 계획이 있기 때문에, 급가속전의 원의 속도와 같게 급가속시의 속도를 보관 유지하는 변수가 필요합니다. 이하에 나타내는 변수 선언을 추가해 주세요.

var Float BurstSpeed, OrigSpeed;

5. 속도와 회전 속도의 프롭퍼티에 직접적으로 관련이 있는 것을 기억일지도 모릅니다. 이것은, 속도가 급가속 했을 때에는, RotationRate 를 늘릴 필요가 있는 것을 의미하기 위해(때문에), 급가속시의 회전 속도와 원의 회전 속도에 대한 변수가 필요하게 됩니다. 이하의 변수 선언을 추가해 주세요 :

var Rotator BurstRotRate, OrigRotRate;

6. 마지막에 추가하는 변수는, 새로운 목적지를 선택할 때마다 발생하는 급가속의 가능성 또는 퍼센트를 나타내는 것입니다. 스크립트에 대해서 이하에 나타내도록(듯이), 변수 선언을 마지막으로 추가해 주세요.

var Int BurstPercent;

7. 클래스명과 합해 AmbientCreature_Fish.uc 라는 이름으로 MasteringUnrealScript/Classes 디렉토리에 파일을 보존해 주세요.

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

튜토리얼 6.11 앰비언트 피쉬, 파트 II: DEFAULTPROPERTIES

본튜토리얼에서는, AmbientCreautre_Fish 클래스에 대한 defaultproperties 블록의 설정을 실시합니다.

1. ConTEXT 를 오픈해, 아직 오픈하고 있지 않으면, AmbientCreature_Fish.uc 파일을 오픈해 주세요.

2. 변수 선언의 뒤로 몇개의 공백을 두어, defaultproperties 블록을 작성하기 위해서, 이하의 코드행을 추가해 주세요.

defaultproperties
{
}

3. 여기에서는, 기저 AmbientCreature 클래스로부터 계승된 변수에 대해서 몇개의 디폴트치를 설정할 필요가 있습니다. 이러한 프롭퍼티 가운데로, 최초의 것은 Speed 변수입니다. 70 의 디폴트치를 이 변수에게 줍니다만, 그 후 PostBeginPlay() 함수내에서 계산되는 랜덤인 변화로, 35 에서 105 까지의 속도가 됩니다. 이 값을 설정하기 위해서, defaultproperties 블록에 대해서 이하의 코드를 추가해 주세요.

Speed=70

4. 다음에, MinSize 및 MaxSize 의 값을 설정합니다. 이러한 값은, 사용된 메쉬의 사이즈를 기본으로 한 어느 정도의 시행 착오에 의존합니다. 이 케이스에서는, 0.0625 및 0.25 의 값을 선택했습니다. 이러한 값을 설정하기 위해서 이하의 행의 코드를 추가해 주세요.

MinSize=0. 0625
MaxSize=0. 25

5. 계승되는 마지막 변수는, MinTravelTime 및 MaxTravelTime 프롭퍼티입니다. 이러한 값은, 작성되는 크리쳐의 형태에 의존합니다. 의도를 달성하기 위해서, 이러한 값에 대해서는 0.25 및 4.0 을 선택했습니다. 이하의 코드를 추가해, 이러한 디폴트치를 설정해 주세요.

MinTraveltime=0. 25
MaxTravelTime=4. 0

6. 디폴트로 Pitch, Yaw 및 Roll 의 값으로 0 을 디폴트로 하면(자) 크리쳐가 회전하지 않으므로, RotationRate 프롭퍼티에 대해서도 디폴트치를 설정할 필요가 있습니다. 1 초간에 1 회전의 것 1/4 에 동일한 16384 의 값을 Pitch, Yaw 및 Roll 로 선택했습니다. RotationRate 프롭퍼티의 디폴트치를 설정하기 위해서 이하의 코드를 추가해 주세요 :

RotationRate=(Pitch=16384, Yaw=16384, Roll=16384)

7. AmbientCreature_Fish 클래스에는, 같은 디폴트치가 필요한 BurstPercent 변수를 추가합니다. 이 프롭퍼티의 값은, 물고기에 어느 정도 급가속 시키고 싶은가 의존한 것이 됩니다. 너무 높으면, 물고기는 너무 날아 뛰어 보입니다만, 너무 낮으면 점프 동작은 기본적으로 깨닫지 못하는 정도가 됩니다. 여기서의 값은, 10 을 이용하기 때문에, 물고기의 급가속의 가능성은 10 % 가 됩니다. 이하의 코드를 추가해 이 값을 설정해 주세요 :

BurstPercent=10

8. 이러한 물고기의 크리쳐에 대해서 사용되는 메쉬는, 설정해야 하는 마지막 디폴트치입니다. AmbientCreature 클래스의 defaultproperties 내에 StaticMeshComponent 서브 오브젝트를 작성한 것을 기억일지도 모릅니다만, 어느 메쉬를 사용할까는 고하고 있지 않았습니다. 본클래스에 대해서, 적절한 메쉬를 설정하기 위해(때문에) 서브 오브젝트에 액세스 할 수 있습니다. 이것에 대한 구문은, Class= 섹션을 생략 해야 하는 점을 제외하면, 서브 오브젝트의 생성과 거의 같습니다. 이하의 코드는, MyStaticMesh 서브 오브젝트의 메쉬를 설정하기 위한의 것입니다. 클래스에 이러한 코드행을 추가해 주세요.

Begin Object Name=MyStaticMesh
StaticMesh=StaticMesh'Chapter_06_Functions.ClownFish'
End Object

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

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

튜토리얼 6.12 앰비언트 피쉬, 파트 III: POSTBEGINPLAY() 함수

레벨의 개시시에 즉시 설정할 필요가 있는 신규의 변수가 있기 (위해)때문에, 한번 더 PostBeginPlay() 함수를 오버라이드(override) 합니다. 전회는, 함수의 친클래스의 버젼을 호출하고 나서, 필요한 기능을 추가했습니다. 이 경우는, 친클래스의 기능을 포함하는 것을 희망하는 방법이란, 약간 달라, 친클래스의 코드안에 추가의 코드를 삽입할 필요가 있습니다. 기본적으로, Speed 및 RotationRate 의 값을 설정한 후에, 신규의 속도 및 회전 속도의 값을 설정을 실시하고 싶습니다만, SetRandDest()의 호출전으로 설정할 필요가 있습니다. 이것을 취급하려면 , PostBeginPlay() 함수를 모두, 친클래스로부터 카피해, 신규 기능을 추가해, 친버젼을 스킵 해 체인의 다음의 함수의 버젼을 호출합니다.

1. 아직 오픈하고 있지 않으면, ConTEXT 와 동시에 AmbientCreature.uc 및 AmbientCreature_Fish.uc 파일을 오픈해 주세요.

2. AmbientCreature 클래스로부터 PostBeginPlay() 함수 전체를 선택해, 그것을 카피하기 위해서 Ctrl+C 를 눌러 주세요.

3. AmbientCreature_Fish 클래스의 변수 선언의 뒤에, Ctrl+V 를 누르는 것으로 이 함수를 붙여 주세요.

4. 설정을 실시하는, 신규의 회전 속도 프롭퍼티는 2 개 있습니다. OrigRotRate 는, 단지 RotationRate 변수의 값과 동일하게 설정됩니다. 급가속은 속도와 회전 속도를 4 배로 늘릴 예정입니다. 그 때문에, BurstRotRate 변수는, RotationRate 프롭퍼티의 값에 4 를 곱한 것이 됩니다. AmbientCreature_Fish 클래스의 PostBeginPlay() 함수내에서 Speed 변수를 설정해 있는 행의 뒤로, 회전 속도 변수를 설정하기 위해서 이하의 행을 추가해 주세요 :

OrigRotRate = RotationRate;
BurstRotRate = RotationRate * 4;

5. 신규의 2 개의 속도의 프롭퍼티도 회전 속도의 변수와 같은 논리에 따릅니다. OrigSpeed 변수는, Speed 변수의 값과 동일하게 설정되어 또, BurstSpeed 변수는 Speed 변수에 4 를 곱한 값과 동일하게 설정됩니다. 이전의 스텝에서 추가한 행의 직하에 이하에 나타내는 행을 추가해 주세요.

OrigSpeed = Speed;
BurstSpeed = Speed * 4;

6. PostBeginPlay() 함수의 친버젼을 스킵 해, 계승의 다음의 클래스의 버젼을 호출할 필요가 있는 것을 말한 것을 생각해 내 주세요.

이것을 실시하기 위해서(때문에), 다음의 내용을

Super.PostBeginPlay();

이하와 같이 바꾸어 주세요

Super(Actor). PostBeginPlay();

최종적인 PostBeginPlay() 함수는 이하와 같이 될 것입니다 :

function PostBeginPlay()
{
   local float RandVal;

   Super(Actor). PostBeginPlay();
   SetDrawScale(RandRange(ScaleMin, ScaleMax));
   RandVal = RandRange(0.5, 1.5);
   RotationRate *= RandVal;
   Speed *= RandVal;
   OrigRotRate = RotationRate;
   BurstRotRate = RotationRate * 4;
   OrigSpeed = Speed;
   BurstSpeed = Speed * 4;
   SetRandDest();
}

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

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

튜토리얼 6.13 앰비언트 피쉬, 파트 IV: SETRANDDEST() 함수

물고기에 급가속을 실시하게 하기 위해서(때문에), 급가속을 실행할지 어떨지를 결정하는 BurstPercent 변수를 이용하는 SetRandDest() 함수내에 있는 종 상태를 설정할 필요가 있습니다. 물론, 이것은, SetRandDest() 함수를 오바라이드 할 필요가 있는 것을 의미합니다. 지금까지의 개개의 경우에서는, 새로운 기능을 추가하기 전에 함수의 친클래스의 버젼을 호출했습니다. 이 상황에서는, 실제는, 신규 기능을 추가하고 나서 친버젼을 호출하고 싶습니다.

1. ConTEXT 와 동시에 AmbientCreature.uc 및 AmbientCreature_Fish.uc 파일을 오픈해 주세요.

2. 초에, AmbientCreature_Fish 클래스내에 SetRandDest() 함수의 선언이 필요합니다. 이것을 실시하는 간편한 방법은, 친클래스내의 함수를 선택해, 카피해, 그리고, 새로운 클래스에 붙이고 나서 함수내의 코드를 삭제하는 것입니다. 이러한 스텝을 실행해 주세요. 그 결과 PostBeginPlay() 함수의 곧 아래에, 이하의 코드가 추가됩니다.

function SetRandDest()
{
}

3. 상술한 것처럼, 이 함수의 친버젼을 호출하기 전에 새로운 기능을 추가하고 싶습니다. 또, 이것도 이미 말하고 있습니다만, 급가속을 실행해야할 것인가 제발을 결정하기 위해서(때문에) 조건을 사용할 생각입니다. 이 조건은, If 문의 형식을 취합니다. 공식으로는 If 문의 설명을 하고 있지 않습니다만, 이전부터 보이고 있는 것입니다. 이 형태의 문장에서는, 문내에서 동작을 실행하기 위해서 true 가 아니면 안되는 1 개의 조건 또는 편성 조건을 지정할 수 있습니다. 이 경우는, 합치 해 주었으면 하는 조건은 이하의 것입니다 :

  • bFalloff 의 값은, 현재 False
  • 0 에서 99 의 범위에서 랜덤에 선택된 값은, BurstPercent 의 값보다 작다

이것에 가세해 계산식의 형태로, 상술한 상태의 쌍방이 합치하지 않으면 안됩니다, 이러한 상태는 이하의 형태를 취합니다 :

! bFalloff && Rand(100) < BurstPercent

상술의 식을 조건으로서 사용하는 If 문을 작성하는 것이 가능합니다. SetRandDest() 함수의 내부에, 이하의 코드를 추가해 주세요 :

If(! bFalloff && Rand(100) < BurstPercent)
{
}

4. If 문의 내부에, 급가속을 행하기 위한 동작을 추가할 필요가 있습니다. 이러한 동작은, 이하와 같습니다 :

  • Speed 의 값을 BurstSpeed 와 동일하게 설정합니다
  • RotationRate 의 값을 BurstRotRate 와 동일하게 설정합니다
  • bFalloff 의 값을 True 로 설정합니다

If 문에 이하에 나타내는 코드행을 추가해 이러한 액션을 실행해 주세요.

Speed = BurstSpeed;
RotationRate = BurstRotRate;
bFalloff = True;


그림 6.15 - 물고기의 크리쳐는, 랜덤인 시간 간격으로 급가속을 실시합니다.

5. 닫고 안이나 와에 의해 나타난 If 문의 마지막 뒤로, 이하의 코드행을 추가해, 친클래스의 SetRandDest() 함수에의 소환을 추가해 주세요 :

Super.SetRandDest();

최종적인 SetRandDest() 함수는, 이하와 같이 될 것입니다 :

function SetRandDest()
{
   if(! bFalloff && Rand(100) < BurstPercent)
   {
      Speed = BurstSpeed;
      RotationRate = BurstRotRate;
      bFalloff = true;
   }

   Super.SetRandDest();
}

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

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

튜토리얼 6.14 앰비언트 피쉬, 파트 V: TICK() 함수

이 물고기는 속도에 관해서는, 급가속이 생기게 되었습니다만, 이 늘어난 속도를, 원의 스피드에 매끄럽게 감속시키는 것 같은 어떠한 방법이 필요합니다. 이미 Velocity 를 설정하기 위해서 Tick() 함수를 사용하고 있어, 이 함수는, 프레임마다 불려 가기 때문에, 본기능을 취급하기 위해서(때문에)는 가장 당연하게 이루어진 장소와 같이 보입니다.

1. 아직 오픈하고 있지 않으면, ConTEXT 와 AmbientCreature_Fish.uc 파일을 오픈해 주세요.

2. AmbientCreature_Fish 클래스의 Tick() 함수를 오버라이드(override) 하기 위해서, 그 클래스내에도 함수를 선언할 필요가 있습니다. Tick() 함수를 선언하기 위해서, 이하의 코드를 추가해 주세요.

function Tick(Float Delta)
{
}

3. 함수의 친클래스의 버젼내에, Speed 변수의 값을 기본으로 한 Velocity 프롭퍼티의 값과 크리쳐가 향하고 있을 방향을 설정하는 1 행의 코드가 있던 것을 기억이지요. 이것은, 함수의 친버젼을 호출하기 전에 Speed 변수의 값을 갱신할 필요가 있는 것을 의미하므로, Super.Tick()를 호출하기 전에 새로운 기능을 추가합니다.

이 Speed 변수에 대한 수정은, 급가속을 했을 경우에게만 행해질 것입니다. 이전의 명령은, 세심의 주위를 기울이면, 조건인 것처럼 보일지도 모릅니다. 이것은, 아직 If 명령이 필요한 것을 의미합니다. 급가속을 했는지 어떠했는지를 고하는 변수는 이미 있으므로, 감속을 실시할지 어떨지를 결정하기 위해서(때문에) bFalloff 변수의 값이 True 일지 어떨지를 확인할 필요가 있을 뿐입니다. 이하에 나타내는 코드를 추가해, If 문을 설정해 주세요 :

If(bFalloff)
{
}

4. Speed 변수의 값을 완만하게 줄이기 위해서(때문에), Tick() 함수가 실행될 때에 BurstSpeed 가 있는 비율을 감산해 갈 것입니다. 이 비율은, 함수의 Delta 파라미터로 결정됩니다. 이 값은, 전회 함수가 실행되고 있기 (위해)때문에, 비교적 작은 수가 되고 있을 것이므로, 매회 건네받는 시간량이 됩니다. If 명령의 내부에, 틱 마다 Speed 변수를 줄이기 위해서(때문에) 이하의 코드행을 추가해 주세요.

Speed -= BurstSpeed * Delta;

5. Speed 와 RotationRate 는, 제휴해 수정하지 않으면 안됩니다, RotationRate 프롭퍼티의 값도 줄일 필요가 있습니다. 논리는 직전의 스텝을 같습니다만, 속도의 변수를 회전 속도의 변수로 옮겨놓고 있습니다. 이하의 코드행을 추가해 주세요 :

RotationRate -= BurstRotRate * Delta;

6. 만약, 이 함수를 이대로 해 두면(자), 이러한 프롭퍼티의 값은, 계속 영원히 감소하겠지요. 급가속이 종료했을 때를 결정하기 위한 확인을 실시할 필요가 있습니다. 여기가, OrigSpeed 및 OrigRotRate 변수가 플레이에 출현하는 장소가 됩니다. Speed 변수의 현재의 값이, Speed 변수의 원의 값보다 작은, 또는, 동일한가를 확인하기 위해(때문에), 현재의 If 문안에 이제(벌써) 1 개의 If 문을 사용합니다. 그 If 문은, 이하의 코드를 추가해 작성합니다 :

If(Speed <= OrigSpeed)
{
}

7. 조건에 합치했을 경우는, 이하의 동작을 실시합니다 :

  • Speed 및 RotationRate 변수의 값을 원래의 값으로 다시 설정합니다
  • bFalloff 의 값을 False 로 설정합니다
  • 현재의 타이머를 클리어 합니다
  • 새로운 목적지를 선택하기 위해서 SetRandDest()를 호출합니다

이하의 코드는 이러한 동작을 실시합니다. If 문의 내부에 추가해 주세요.

Speed = OrigSpeed;
RotationRate = OrigRotRate;
bFalloff = False;
ClearTimer(‘SetRandDest');
SetRandDest();


그림 6.16 - 물고기는, 급가속 해 시간의 경과와 함께 감속하게 되었습니다.

8. 이 함수에 추가하는 마지막 항목은, 함수의 친클래스의 버젼의 호출입니다. 호출을 실시하기 위해서(때문에) If 문의 뒤로 코드를 추가해 주세요.

Super.Tick();

최종적인 Tick() 함수는 이하와 같은 코드가 될 것입니다 :

function Tick(Float Delta)
{
   if(bFalloff)
   {
      Speed -= (BurstSpeed * Delta);
      RotationRate -= (BurstRotRate * Delta);

      if(Speed <= OrigSpeed)
      {
         Speed = OrigSpeed;
         RotationRate = OrigRotRate;
         bFalloff = false;
         ClearTimer('SetRandDest');
         SetRandDest();
      }
   }

   Super.Tick(Delta);
}

9. 작업 결과를 잃지 않게 파일을 보존해 주세요. 스크립트를 컴파일 해, 에러가 있으면 수정해 주세요.

10. Open UnrealEd 를 오픈해, 또 본장을 위한 파일과 함께 제공된 DM-Chapter_06_FishPool 맵을 오픈해 주세요.


그림 6.17 - DM-Chapter_06_FishPool 맵.

11. 맵의 중앙의 풀의 어디엔가 AmbientCreatureNode 먼지를 배치해, RadiusComponent 의 SphereRadius 프롭퍼티를 설정해 주세요.


그림 6.18 - AmbientCreatureNodes 는, 맵에 추가됩니다.

12. Actor Browser(먼지 브라우저) 내에 AmbientCreature_Fish 클래스를 두어, 선택해 주세요.

13. 뷰포트내에서 오른쪽 클릭을 해, 몇개의 AmbientCreature_Fish 먼지를 추가하기 위해(때문에), "Add AmbientCreature_Fish Here(여기에 AmibentCreature_Fish 를 추가)" 를 선택해 주세요.


그림 6.19 - 맵내에 배치된 AmbientCreature_Fish 먼지.

배열내에 슬롯을 작성하기 위해서 CreatureNodes 배열의 "Add Item(아이템을 추가)" 버튼을 클릭해 주세요. 그리고, Properties Window(프롭퍼티 윈도우)의 좌상의 "Lock To Selected Actor(선택한 먼지에 락)" 버튼을 클릭해, 개개의 AmbientCreatureNode 를 선택해, 배열내의 개개의 요소의 "Use CurrentSelection In Browser(현재의 선택을 브라우저로 사용)" 버튼을 누르는 것으로, CreatureNodes 배열에 AmbientCreatureNodes 를 추가해 주세요. 마지막에 다른 프롭퍼티를 희망하는 임의의 값으로 설정해 주세요.

14. 크리쳐가 동작을 관찰하기 위해(때문에) 맵을 실제로 확인해 주세요. 기호의 외관이나 동작을 물고기에 시키기 (위해)때문에, 부담없이 전의 스텝에 돌아와, 값의 조절이나 미조정을 실시해 주세요.


그림 6.20 - 동작중의 물고기.

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

6. 9 편입 함수

Object 클래스는 UnrealScript 로 작업을 실시하는 경우에, 많은 상황으로 편리하게 사용할 수 있는 몇개의 함수를 가지고 있습니다. Unreal 내의 다른 모든 클래스는, 어떤 시점의 Object 클래스로부터 계승되고 있기 (위해)때문에, 이러한 함수는, 임의의 클래스내에서 액세스 가능합니다. 이하에, 이러한 함수로 가장 일반적으로 사용되는 것을 몇개인가, 제공하는 기능의 설명과 함께 들고 있습니다.

MATH(수치 연산)

Rand(Int Max) /FRand()

난수의 함수는, 어떠한 일견 랜덤인 변화를 만들어 내려고 할 때에는, 매우 편리합니다. Rand() 함수는, 0 으로부터 Max 인수로서 함수에게 건네진 값보다 1 작은까지로 랜덤인 정수치를 리턴 합니다. FRand() 함수는, 0.0 에서 1.0 까지의 랜덤인 float 치를 리턴 합니다.

Min(Int A, Int B) /FMin(Float A, Float B)

minimum(최소) 함수는, 인수로서 건네받은 2 개의 값의 쳐 작은 (분)편을 리턴 합니다. Min() 함수는 정수치로 동작하는데 대해, FMin() 함수는 float 치로 동작합니다.

Max(Int A, Int B) /FMax(Float A, FloatB)

maximum(최대) 함수는, 인수로서 건네받은 2 개의 값의 쳐 큰 (분)편을 리턴 합니다. Max() 함수는 정수치로 동작하는데 대해, FMax() 함수는 float 치로 동작합니다.

Clamp(Int V, Int A, Int B) /FClamp(Float V, Float A, Float B)

clamp(클램프) 함수는, 함수에게 건네진 최초의 값을, 함수에게 건네진 다음의 2 개의 값으로 지정된 범위에 제한합니다. Clamp() 함수는 정수치로 동작하는데 대해, FClamp() 함수는 float 치로 동작합니다.

RandRange(Float InMin, Float InMax)

RandRange() 함수는, 함수에게 건네진 2 개의 값으로 지정된 범위내의 랜덤인 float 치를 리턴 합니다.

VSize(Vector A)

VSize() 함수는, float 로서 함수에게 건네진 벡터의 크기, 또는 길이를 리턴 합니다.


그림 6.21 - VSize()는, 벡터의 길이를 계산합니다.

Normal(Vector A)

Normal() 함수는, 그 인수로서 함수에게 건네진 벡터와 같은 방향을 가지는 단위 벡터를 리턴 합니다.


그림 6.22 - 법선 벡터는, 원의 벡터와 같은 방향으로, 길이는 1 입니다.

MirrorVectorByNormal(Vector InVect, Vector InNormal)

MirrorVctorByNormal() 함수는, 주어진 법선을 가지는 표면에서의 벡터의 반사를 계산해, 반사한 벡터를 리턴 합니다. 이 함수는, 충돌 후의 기동을 결정하기 위해서(때문에), 발사물과 함께 자주 사용됩니다.


그림 6.23 - 벡터가 표면으로 반사하고 있습니다.

FloatToByte(Float inputFloat, Optional Bool bSigned)

FloatToByte() 함수는, float 치를 byte 치로 변환해, 결과의 byte 치를 리턴 합니다. 옵션의 bSign 인수로서 True 치가 건네받지 않으면, float 치의 유효 범위는, 0.0 및 1.0 의 사이가 됩니다. True 치가 건네받았을 경우는, float 치의 유효 범위는, -1. 0 에서 1.0 이 됩니다. 이 값은, 유효 범위외의 float 치에 대해서 클램프를 실시해, 0 에서 255 의 범위의 바이트치에 변환됩니다.

ByteToFloat(Byte inputByte, Optional Bool bSigned)

ByteToFloat() 함수는, function converts a byte value from 0 에서 255 의 바이트치를 0.0 에서 1.0 의 범위의 float 치에 변환해, 결과의 float 치를 리턴 합니다. 옵션의 bSigned 인수로서 True 치가 건네받았을 경우는, 결과의 float 치는 -1. 0 에서 1.0 의 범위가 됩니다.

STRING(캐릭터 라인)

Len(Coerce String S)

Len() 함수는, 공백도 포함한 캐릭터 라인내에 포함되는 문자의 수를 리턴 합니다. 리턴치는, Int 의 형식이 됩니다.

InStr(Coerce String S, Coerce String T)

InStr() 함수는, 최초의 캐릭터 라인으로 제 2 의 캐릭터 라인의 최초의 출현을 검색해, 만약 발견되었을 경우는, 출현 위치를 리턴 합니다. 출현이 발견되지 않았던 경우는, -1 의 값이 리턴 합니다.

Mid(Coerce String S, Int i, Optional Int j)

Mid() 함수는, 함수에게 건네진 캐릭터 라인의 선두로부터 i 문자눈으로부터 부분 캐릭터 라인을 j 문자분 리턴 합니다. 리턴 하는 문자수가 지정되어 있지 않으면, 캐릭터 라인의 나머지의 문자가 리턴 됩니다.

Left(Coerce String S, Int i)

Left() 함수는, 함수에게 건네진 캐릭터 라인의 선두 i 문자를 리턴 합니다.

Right(Coerce String S, Int i)

Right() 함수는, 함수에게 건네진 캐릭터 라인의 말미 i 문자를 리턴 합니다.

Divide(Coerce String Src, String Divider, Out String LeftPart, Out String RightPart)

Divide() 함수는, 지정한 캐릭터 라인의 최초의 출현의 왼쪽과 오른쪽에서 부분 캐릭터 라인을 작성합니다. 이 함수는, 분할을 했을 때는 true 를, 분할 캐릭터 라인이 발견되지 않았던 경우는 false 를 리턴 합니다.

Split(Coerce String Src, String Divider, Out Array Parts)

Split() 함수는, 분할 대상의 캐릭터 라인의 출현마다 캐릭터 라인을 분할해, 결과의 부분 캐릭터 라인을 캐릭터 라인 배열에 집적합니다. 본함수는, 작성한 부분 캐릭터 라인의 수를 리턴 합니다.

Repl(Coerce String Src, Coerce String Match, Coerce String With, Optional Bool bCaseSensitive)

Repl() 함수는, 캐릭터 라인으로부터 Match 캐릭터 라인의 모든 출현을 검색해, 각각을 With 캐릭터 라인으로 옮겨놓습니다. 이 함수는, 치환을 실시한 후의 결과의 캐릭터 라인을 리턴 합니다.

MISCELLANEOUS(그 외)

IsA(Name ClassName)

IsA() 함수는, 오브젝트의 클래스가 ClassName 와 합치하고 있다, 또는, 그 서브 클래스의 경우는, true 를 리턴 합니다. 이 함수는, typecast 를 실행해 결과를 확인하지 않고 , 어느 형태의 오브젝트가 조작될까를 결정하려면 매우 도움이 됩니다.

MakeColor(Byte R, Byte G, Byte B, Optional Byte A)

MakeColor() 함수는, 함수에게 건네진 R, G, B 및 A 의 값이나 칼라를 작성해, 결과의 칼라를 리턴 합니다. 이 함수는, 바이트 기저의 칼라를 작성하기 위한의 것입니다.

MakeLinearColor(Float R, Float G, Float B, Float A)

MakeLinearColor() 함수는, 함수에게 건네진 R, G, B 및 A 의 값으로부터 리니어 칼라를 작성해, 결과의 리니어 칼라를 리턴 합니다. 이 함수는, float 기저의 칼라를 작성하기 위한의 것입니다.

ColorToLinearColor(Color OldColor)

ColorToLinearColor() 함수는, 바이트 기저의 칼라를 float 기저의 리니어 칼라로 변환해, 결과의 리니어 칼라를 리턴 합니다.

6. 10 요약

본장에서는, 함수는, 객체 지향 환경내에서 여러가지 일을 실행하는 요소로 있는 것을 학습했습니다. 자신으로 동작을 실행하기 위해(때문에), 또, 다른 오브젝트와 제휴하기 위해서, 어떻게 오브젝트가 함수를 사용할 수 있을까를 봐 왔습니다. 취득해, 출력하는 데이터에 유연성을 제공해, 함수에 서브 클래스에서의 오바라이드를 허가하는 것으로, UnrealScript 는, 보다 효율성이 요구되는 기능으로 작성된 클래스를 만듭니다. 약간의 창의를 조합해, 이러한 특징을, 최대한으로 활용하는 방법을 학습하면, 최종적으로는, 독자적인 흥미로운 게임 플레이를 작성할 수 있게 됩니다.

추가 파일