http://donggas90.blog.me/100141378528



[UDK] 프로그래밍 초보를 위한 언리얼 스크립트 코드 10선

  

이번 포스트는 프로그래밍을 UDK로 처음 접하시는 분을 위해 적어 볼까 합니다.

 

 

먼저 UDK(언리얼 엔진)는 언리얼 스크립트라는 자신들만의 언어를 사용합니다.

 

 

언리얼 스크립트를 위한 비쥬얼 스튜디오 플러그인 엔프린지와

스크립팅을 시작하는 방법에 대해서는 아래 포스트에서 확인하세요.

http://donggas90.blog.me/100127258591

 

 

그리고 짠 언리얼 스크립트를 어떻게 게임과 에디터에 적용하는 지에 대한 정보는

아래 포스트를 확인하세요.

http://donggas90.blog.me/100134298424

 

 

위 두 포스트의 내용을 숙지하셨다는 가정 하에 시작하겠습니다.

 

 

1. 클래스 오버라이드 - extends

 

  class HUD extends Actor;

 HUD.uc의 일부입니다.

 

class는 앞으로 클래스를 선언할 것임을 나타 냅니다.

 

HUD는 이 클래스의 이름을 나타내며, uc파일과 이름이 같아야 합니다. 

 

extends는 이 클래스가 어느 클래스를 오버라이드하고 있는지 가르킵니다.

 

Actor는 extends가 가르키고 있는 클래스 입니다.

 

;는 여기까지 클래스 선언이 끝났음을 알리고 있습니다. 

 

 

오버라이드란 extends가 가르키는 클래스의 모든 내용을 전부 그대로 복사한다는 뜻입니다.

 

복사'당한' 클래스는 부모 클래스가 되고, 복사'받은' 클래스는 자식 클래스가 됩니다.

 

비록 그 내용이 여기 일일이 적혀 있지는 않지만 적혀져 있는 것으로 간주하는 것입니다.

 

 

그리고 또 다른 의미로 '덮어쓴다'는 의미가 있습니다.

 

부모 클래스에 있는 것을 다시 새로 쓸 때, 오버라이드했다고 합니다.

 

 

언리얼 스크립트 파일들을 하나하나 열어 보시면

 

모든 클래스들이 계속해서 다른 클래스를 오버라이드하고 있음을 알 수 있습니다.

 

그리고 그 가장 위에는 Object클래스가 있고 그 바로 밑에는 Actor가 있습니다.

 

즉, 모든 언리얼 스크립트의 시조는 Object입니다.

 

 

 

2. 변수 선언 - var

 

var string A;

var int B;

var(Variable) float C;

var bool D; 

var는 앞으로 변수를 선언할 것임을 나타냅니다. 

 

이것들은 이 변수가 어떤 타입인지 나타 냅니다. 

 

string이란 문자열을 말합니다. 

 

int란 정수를 말합니다. 

 

float이란 실수 말합니다.

 

bool이란 참, 거짓 논리자입니다. 

 

A는 이 변수의 이름이 A임을 나타냅니다.

 

;는 여기까지 변수의 선언이 끝났음을 나타냅니다. 

 

(Variable)란 언리얼 에디터에서 클래스 프로퍼티 창에

 

Variable이라는 카테고리를 만들고 이 변수를 표시하라는 의미이며 

 

반드시 필요하지는 않습니다. 

 

 

이런 방법으로 변수에 이름을 붙여 줄 수 있습니다. 

 

변수의 종류는 더 많지만 일단 이 정도만 알아도 대부분의 데이터 주무르기가 가능합니다.

 

 

변수에 값을 넣는 방법은 아래와 같습니다.

A = "string";

B = 123;

= 1.f;

이것들은 값을 넣어줄 대상입니다.

 

값을 받을 대상은 항상 왼쪽에 위치합니다.

 

=는 왼쪽에 있는 것에 오른쪽 것을 넣는다는 뜻입니다. 

 

일반적으로 사용하는 의미와는 다릅니다. 

 

넣을 대상과 넣어 줄것의 타입이 일치해야 함을 유의하세요. 

 

"string"은 문자열 string을 나타냅니다. " 가 양쪽으로 사용됐음에 유의하세요.

 

123는 정수 123(백이십삼)을 나타냅니다. 

 

별다른 기호를 사용하지 않아도 됩니다. 

 

1.f는 실수 1(일)을 나타냅니다. 

 

언리얼 스크립트에서는 정수와 실수를 구분하기 위해 

 

실수에는 특수한 표기 방법을 사용합니다. 

 

값의 끝에 f를 붙이는 것이 그것입니다.

 

만약 소수점 자리가 없다면 .(온점)과 함께 f를 붙입니다.

 

;는 여기까지 명령이 끝났음을 알립니다. 

 

 

* 심화

var array<int> A;

 

A[0] = 1;

A[100] = 2;

 

배열은 이름은 같은데 다른 번호를 가진 여러 값의 무리입니다.

 

 

 

 

3. 기본값 - DefaultProperties

 

DefaultProperties
{ 

 A = 123

} 

DefaultProperties{ 는 앞으로 기본값 영역이 시작될 것임을 의미합니다. 

 

A의 기본값이 123임을 의미합니다. 여기서 세미콜론(;)은 선택 사항입니다.

 

} 는 기본값 영역이 끝났음을 의미합니다. 

 

 

이렇게 하면 A는 UDK가 시작되면 항상 123일 것입니다. 

 

이런식으로 기본값이 필요할 경우 정의해 줄 수 있습니다.

 

 

* 심화

런타임이 초기화될 때마다 이 영역의 기본값이 로드됩니다.

 

 

4. 함수 - function

 

함수를 선언하는 방법은 아래와 같습니다.

 

function EXAMPLE()

{

A = 123;

}

function{}는 함수 영역을 나타냅니다. 

 

EXAMPLE는 함수의 이름을 나타냅니다.

 

()는 함수에 사용할 인수(파라미터)의 목록입니다. 

 

자세한 내용은 아래에... 

 

A = 123;는 함수에서 할 것입니다. 

 

 

이 함수가 집행되면  A = 123;을 할 것입니다.

 

하지만 재밌는 점은 이렇게 만들더라도 실질적으로 작동은 되지 않습니다.

 

왜냐면 언리얼 엔진이 이 함수를 호출하지 않기 때문입니다.

 

따라서 이 함수를 작동하게 하려면

 

언리얼 엔진이 호출하는 함수 안에서 이 함수를 호출해야 합니다.

 

simulated event Tick(float DeltaTime)
{
 

 EXAMPLE();

} 

대표적인 예로 Tick이라는 이벤트가 있습니다.

 

이 이벤트는 일정 시간 간격으로 계속 이 영역을 집행합니다.

 

그리고 그 시간 간격은 DeltaTime에 실수 타입으로 저장합니다.

 

 

이벤트는 함수와는 성격이 다른데, 이벤트는 모두 언리얼 엔진이 특정 상황이나 조건에서 호출하는 것입니다.

 

임의로 프로그래머가 호출할 수 없습니다.

 

 

 

function EXAMPLE( int B )

{  

A = 25;

A = B;

} 

 

EXAMPLE( 12 ); 

A는 12 

위 스크립트는 인수 사용의 대표적인 예입니다.

 

인수는 함수를 선언할 당시에는 타입만 지정돼 있습니다.

 

뭔가 값은 없습니다.

 

하지만 다른 곳에서 사용되었을 때 그 값을 지정해 주고

 

함수 내용을 집행하게 됩니다.

 

 

 

 

5. 함수의 변수화 - return

 

앞에서 함수에 대해 알아 봤습니다.

 

그런데 함수에서 뭔가 계산한 뒤 바로 무엇인가 얻고 싶을 경우가 생길 겁니다.

 

따로 변수의 도움 없이 말입니다.

 

function int EXAMPLE()

{

A = 123; 

return A; 

} 

 

B =  EXAMPLE();

B는 123 

int로 이 함수는 정수 결과를 출력할 것임을 나타냅니다. 

 

return A; 로 이 함수의 출력 값은 A값임을 알립니다.

 

이렇게 하면 함수 내에서 계산한 값을 또 다른 변수에 넣어주고

 

다시 받아서 B에 할당하는 번거로운 과정이 생략됩니다. 

 

* 심화

function Ex ( out int A )

{

A = B + C ;

return;

}

값을 직접 받지 않고 간접으로 받을 수도 있습니다.

 

 

6. 부모 함수 집행 - super

 

오버라이드는 덮어쓴다는 개념이 있다고 말씀 드렸습니다.

 

덮어쓰게 되면 이전의 것은 없어지고 새로운 것만 작성되게 됩니다.

 

함수 역시 오버라이드할 수 있습니다.

 

그런데 함수를 통째로 다시 쓰지 않고 나만의 새로운 코드만 추가하고 싶을 때가 있습니다.

 

이럴 때 쓰는 것이 super코드입니다.

function EXAMPLE()

{

super(Actor).Example(); 

A = 123;

}

super.Example();로 가장 가까운 부모에 있는 Example()함수를 집행하도록 합니다. 

 

 (Actor)는 선택 사항인데 어느 클래스에 있는 부모 함수를 집행할지 지정합니다.

 

 부모 엑터 클래스의 함수가 집행된 뒤 A=123; 집행되게 됩니다.

 

게임의 기본 틀을 구성하는 함수여서 마음데로 수정이 어렵거나

 

언리얼 엔진이 호출하는 이벤트에 내용을 덧붙이고 싶을 때 아주 유용합니다.

 

 

 

7. 조건부 - if

 

뭔가 조건을 제시하고 그게 맞다면 실행되게 하고 싶을 때가 많을 겁니다.

 

이럴 때 쓸 수 있는 것이 if 코드 입니다.

if ( A == 1 )

{

 B = 1;

} 

else if ( A == 2 )

{ 

B = 2; 

} 

else 

{ 

B = 3; 

} 

이것들은 한 묶음입니다. if와 else는 처음과 끝에 각각 하나만 올 수 있고 

 

else if 는 원하는 만큼 쓸 수 있습니다. 

 

이것이 참이면 그 아래 영역을 집행합니다. 

 

즉, A가 1이면 B는 1이될 겁니다. 

 

여기에 사용되는 논리 판단 기호에 유의하세요. 

 

==는 서로 같은지 비교합니다. 

 

!=는 서로 다른지 비교합니다.

 

이외에 <, >, <=, >=는 일반적인 수학에서 쓰는 그데로입니다. 

 

if는 조건 부분을 무조건 참인지 거짓인지 판단합니다.

else if 는 if의 조건이 거짓일 경우 참인지 거짓인지 판단합니다.

else 는 if 와 else if 의 조건 모두가 거짓이면 집행합니다.

 

 

위에서 적어드린데로 프로그램이 조건을 검사하게 됩니다.

 

조건을 검사하려면 CPU가 계산을 해야하고

 

그러면 리소스가 소모 됩니다.

 

게임을 최적화하려면 if를 남발하지 말고 적절히 else를 이용해야 합니다.

 

 

조건을 검사할 때, 꼭 한 가지가 아니라 여러 가지의 조건을 쓰는 경우가 있습니다.

 

이럴 때 수학에서는 AND, OR라는 표현을 쓰는데

 

프로그래밍에도 이런 개념이 존재합니다.

if ( A == 1 && B == 3 )

{

B = 1;

}

else if ( A == 2 || B == 1 )

{

B = 2;

}

&&(쉬프트 + 숫자 7)는 AND라는 의미입니다.

 

||(쉬프트 + \)는 OR라는 의미입니다.

 

 

덧붙여 이런 것도 가능합니다.

var bool A;

 

A = true;

B = 0;

 

if ( A )

{

B = 1;

} 

 

B는 1 

조건 부분이 참(true)인지 거짓(false)인지 검사하는 것이기 때문에

 

조건 그 자체가 참인 경우도 집행됩니다.

 

* 심화

switch(A) 

{ 

case(1) : 

//A가 1이면 집행합니다. 

break;//으로 집행의 끝을 알립니다. 

 

default: 

//A와 관계 없이 집행합니다.

break; 

} 

 

 

8. 변수의 무리 - struct

 

변수들을 여럿 선언하고 보면

 

이따금씩 서로 관련이 있는 변수인 경우가 있습니다.

 

예를 들면 게임 케릭터의 능력치입니다.

 

힘 변수를 선언하고 지능 변수를 각각 선언한다면

 

관리하기가 쉽지 않겠죠.

 

왜냐면 케릭터가 하나가 아닐테니까요.

 

그리고 새로운 능력치를 추가하려면 대부분의 코드들을 뜯어 고쳐야할 것입니다.

 

이럴 때 필요한 것이 바로 구조체, struct 코드입니다.

struct CharacterInfo

{

var int Strength;

var int Intelligence;

};

struct로 여기부터 구조체를 선언하겠다고 알립니다. 

 

CharacterInfo는 이 구조체의 이름입니다. 

 

var int Strength; 구조체에 포함된 변수입니다. 

 

; 구조체를 선언한 뒤 붙이는 것을 잊지 마세요. 

 

그런데 이걸 어떻게 사용하는 걸까요.

 

<strong></strong>

var CharacterInfo A;

구조체를 선언하면 마치 변수 타입인 것처럼 사용할 수 있습니다.

 

A라는 이름을 가진 CharacterInfo 구조체를 만들었습니다.

 

그렇다면 구조체에 포함된 변수는 어떻게 쓰는 걸까요.

 

A.Strength = 123;

A.Intelligence = 321;

구조체의 이름 뒤에 온점을 붙여 그 속에 포함된 변수를 부를 수 있습니다.

 

 

다른 이름의 같은 구조체가 있습니다.

 

하나의 값을 다른 하나에 넣어 주기 위해

 

포함된 변수를 하나하나씩 불러 할당하고 있습니다.

 

var CharacterInfo A; 

var CharacterInfo B; 

 

A.Strength = B.Strength;

A.Intelligence = B.Intelligence;

물론 이런 방법을 쓸 수도 있지만 

 

굳이 일일이 값들을 불러오지 않아도 됩니다.

 

var CharacterInfo A;

var CharacterInfo B;

 

A = B;

 

 

 

 

9. 메모 - /* **/

 

프로그래밍 언어는 우리가 쓰는 말과는 전혀 다릅니다.

 

그리고 복잡한 함수나 추상적인 이름의 변수를 사용해야 하는 경우가 자주 발생합니다.

 

이를 설명하기 위해 메모, 주석을 달게 됩니다.

/** 수 두 개를 더하는 함수 */

function int Add( int A, int B )

{

C = A + B;

return C;

}

/** */이 부호가 사용된 문자들은 모두 무시됩니다.

 

비쥬얼 스튜디오와 엔프린지를 사용하는 경우

 

Add에 마우스를 올리면 툴팁이 나오는데

 

두번째 줄에 주석의 내용이 표시됩니다.

 

 

* 심화

/** 수 두 개를 더하는 함수

* @param A 더할 첫번째 값

* @param B 더할 두번째 값 */

<strong></strong>

function int Add( int A, int B )

{

C = A + B;

return C;

} 

파라미터마다 개별적인 주석을 달 수도 있습니다. 

 

 

 

10. 디버깅 - `log 

 

버그는 예상치 못한 곳에서 주로 발생합니다. 

 

버그를 해결하는 작업을 디버깅이라 하는데 

 

디버깅을 위해서 사용되는 코드가 있습니다. 

 

바로 `log코드입니다. 

 

`는 1의 왼쪽에 있는 키입니다.

 

쉬프트를 누르면 ~이 되는 키죠.

`log("test");

이런 식으로 사용합니다.

 

괄호안의 내용은 문자열이므로 쌍따옴표를 사용해야 합니다.

 

그런데 이 글자는 어디서 확인하는 것일까요.

 

UDK에서 게임 태스트를 시작합니다.

 

그리고 커멘드라인에 SHOWLOG를 입력하면

 

윈도우 cmd같은 검은 창이 표시됩니다.

 

만약 로그가 정상적으로 집행됐다면

 

그곳에 하얀색 글씨로 test란 글자가 나타날 겁니다.

 

 

이런 단순 문자열 로그는 특정 함수나 조건부가 제대로 동작하는지

 

파악할 때 유용합니다.

 

 

만약 변수 값이 궁금할 때는 어떻게 할까요.

 

그럴 때는 이렇게 합니다.

var int A;

`log("variable is"@A);

@는 문자열을 공백 하나를 넣고 합칠 때 사용합니다.

 

만약 A가 123이면

 

로그창에는 이렇게 나타날 것입니다.

 

variable is 123

 

로그 코드는 디버깅에 효과적이기는 하지만

 

로그 또한 집행하려면 CPU가 계산을 해야 합니다.

 

따라서 디버깅이 끝나면 로그 코드는 지워 주세요.

 

반응형

+ Recent posts