> 커뮤니티 > 정보마당 > 기획
정보마당

인테리어와 관련된 다양한 지식,정보들을 공유하는 게시판입니다.

퍼지이론 4. 퍼지 이론을 이용한 게임 캐릭터의 조종

4. 퍼지 이론을 이용한 게임 캐릭터의 조종

목 록

1. 서론

2. 퍼지 이론의 탄생과 발전

3. 퍼지 집합과 퍼지 논리

4. 퍼지 이론을 이용한 게임 캐릭터의 조종


퍼지이론을 이용한 응용 분야는 여러가지가 있습니다.

퍼지 추론이니 퍼지 제어니 하는 여러가지가 있는데, 이러한 분야에서 모든 것이 동일한 방법으로 적용되지는 않습니다.

나름의 상황에 맞는 방법들을 사용하기 때문입니다.

저도 본격적으로 퍼지이론을 공부한 처지도 아니고, 나름대로 게임에 응용하는 방법을 알뿐입니다. 

더 깊이 아시고 싶은 분은 나름대로 공부하시기 바랍니다.

그러면 더 좋은 방법을 여러분이 직접 찾을 수 있을 겁니다.

그러면 간단한 것 부터 살펴보죠.

예컨데 우리가 자동차를 운전한다고 합시다. 

자동차의 경우는 비교적 조작이 쉬운 편인데, 우리가 운전을 배운다는 것은 어떤 일련의 규칙을 배워서 몸에 익히는 것입니다.

이를테면 오른쪽으로 가고 싶으면 핸들을 오른쪽으로 돌리고, 멈추고 싶으면 브레이크를 밟고, 속도를 내고 싶으면 가속 패달을 밟습니다.

우리는 자동차가 실제로 어떻게 동력이 전달되며 여러가지 장치들이 어떻게 작동하는지의 구체적인 메카니즘을 모르더라도 저러한 규칙들을 몸에 익히므로서 자동차를 운전할 수 있습니다.

퍼지제어도 마찬가지로 복잡한 메카니즘이 필요없이 자동차 운전의 예와 같이 사람처럼 비교적 간단한 몇가지 규칙을 이용해서 제어를 하게 됩니다.

이러한 규칙들을 나열한 것을 rulebase 라고 합니다. 

제어해야할 대상이 복잡하다면 더 많은 규칙이 필요하겠지만, 간단한 경우 이차원 행렬 형식으로 규칙을 표시하게 됩니다.

가장 간단한 경우가 입력이 하나이고 출력이 하나인 경우입니다.

우리 주위에서 많이 볼수 있죠.

온도를 조절하거나 속도를 조절하는 경우.

퍼지 밥통 같은 것이죠.

즉 입력으로 주어지는 밥의 온도에 따라 전열기를 조절하게 됩니다.

기존의 밥통들은 대개가 온도차에 따른 열 팽창률이 다른 두 가지 금속을 붙여놓은 일종의 스위치(바이메탈)가 있어서 온도가 올라가면 스위치의 접점이 떨어지고, 내려가면 붙는 방식으로 전열기를 켰다 껐다 합니다.

상당히 원시적이죠.

말하자면 ' on ' ' off ', '1' 아니면 '0' 이라는 식의 2치 논리로 작동하죠.

그렇지만 퍼지제어를 할 경우는 더 자세하게 제어 할 수 있습니다.

rulebase 를 한번 보죠.

낮은온도

기준온도

높은온도

온도 상승

조금가열

가열중지

가열중지

온도 고정

가열

조금가열

가열중지

온도 하강

세게가열

가열

조금가열

기존의 ON OFF 방식의 경우는 가열 중에 계속 열을 빼았기므로 해서 생기는 열손실을 보충할 수가 없기 때문에 온도 변화 폭이 커지게 됩니다.

그러나 퍼지 제어의 경우는 상황 변화에 따라 좀더 자세한 제어를 할 수가 있으므로 좀더 양호한 상태로 밥의 온도를 유지할 수가 있습니다. (즉 밥 맛이 좋다 !)

제 설명이 부실하기는 하지만 이제 어느정도 감을 잡으신 분들도 계실 겁니다.

그러니까 저러한 'rule base'를 컴퓨터에 다차원 배열로 저장해두면 우리가 어떤 대상을 제어하는데 이용할 수가 있겠죠.

------------------------------------------------------------

여러분이 가장 기대하시는 강좌의 핵심 부분을 말씀드리죠.

밥통의 예를 통해서 간단한 퍼지제어의 예를 살펴 보았습니다.

퍼지제어의 특징은 무엇보다도 애매성에 있습니다.

우리가 흔히 알고 있기로 기계란 것은 정확한 수치로 작동해야 합니다.

밥통의 예에서 보면 정확하게 몇 도 이상이면 바이메탈의 접점이 붙고 아니면 떨어지고, 물론 실제로는 오차를 보이겠지만요.

그렇지만 퍼지제어는 우리 일상 대화에서 사용하는 대충의 어림수를 그대로 제어에 이용할 수가 있습니다. 

그러니까 낮은 온도, 중간 온도, 높은 온도, 이런 식이죠.

꼭 분명하게 몇 도에서는 어떻게, 몇 도에서는 어떻게 하는 식으로 딱 부러지게 정해 주지 않아도 된다는 겁니다. 

마치 전기 밥통이 없었던 우리의 옛날에 어머니들이 온도계 같은 것 전혀 없이도 맛있는 밥을 지으시던 것과 같죠.

그런데 인간이 사물을 판정하는 어림수는 신기하게도 7 가지를 넘지 않는다는 것이 심리학자들의 실험 결과 입니다.

그래서 이것을 일컬어서 매직 세븐이라고 부릅니다.

아래의 기호는 그 어림수를 표현하는 기호입니다.

'NL' ---------- NEGATIVE LARGE 

'NM' ---------- NEGATIVE MEDIUM 

'NS' ---------- NEGATIVE SMALL 

'Z' ------------ ZERO 

'PS' ----------- POSITIVE SMALL

'PM' ----------- POSITIVE MEDIUM

'PL' ----------- POSITIVE LARGE

요컨데 인지하는 대상의 어떤 변화를 일곱가지 어림수 중에 하나로 나타내면 됩니다.

물론 대상이 단순하다면 일곱가지 수를 다 사용하지 않고 다섯개나 세개를 사용해도 되겠죠.

그러면 제어지시는 어떻게 내리느냐 ?

여기서도 마찬가지로 어림수를 이용해서 내리게 됩니다. 

자동차운전을 예로 든다면 길이 왼쪽으로 중간 정도 휘어있으면 핸들을 중간 정도 왼쪽으로 돌려라 뭐 이런 식이죠.

누구도 정확하게 핸들을 몇도를 돌려야 되는지 몰라도 되죠.

----------------------------------------------------------------

그러면 실제로 제가 슈팅 게임에 사용한 적 캐릭터의 움직임을 제어하는 룰베이스를 한번보죠.  

#define PURSUIT 0 // 추적 모드 

#define ATTACK 1 // 공격 모드 

#define RUN 2 // 회피 모드

char rule_base_x[3][3][5] = // ML SL 0 SR MR 

{

  -3, -3, -2, 0, 2, // LEFT

  -3, -2, 0, 2, 3, // 0 

  -2, 0, 2, 3, 3, // RIGHT

  -3, -3, -4, 3, 2,

  -4, -2, 0, 2, 4,

  -2, -3, 4, 3, 3,

  0, 2, 3, -3, -2,

  0, 3, 4, -3, 0,

  2, 3, -3, -2, 0

};

char rule_base_y[3][3][5] = // MU SU 0 SD MD 

{

  -4, -3, -2, 0, 2, // UP

  -3, -2, -2, 0, 2, // 0

  -3, -2, -2, 3, 2, // DOWN

  -4, -3, -4, 0, 0,

  -3, -2, -4, 0, 2,

  -3, -3, -4, 0, 2,

  2, 2, 3, -3, 0, 

  0, 3, -4, -3, 0,

  0, 3, -3, -2, -2

};  

< 하나는 X, 하나는 Y 에 대한 rule base 입니다. >

위에서 각각의 인덱스의 의미는 다음과 같습니다.

첫째 : 동작 모드 선택 

둘째 : 플레이어 캐릭터의 움직임 

세째 : 적 캐릭터에서 본 플레이어 캐릭터의 떨어진 거리

< 주석으로 표기된 어림수 기호의 의미는 예컨데 SL 이라면 왼쪽으로 조금 떨어졌다는 것입니다. >  

각 캐릭터의 위치는 프로그램 상에서

X = X + DX ;

Y = Y + DY ;

라는 식으로 갱신 되므로, 각 각의 배열 요소의 값은 적캐릭터의 DX 와 DY 값이 됩니다.

그러니까 시시 각각 변화하는 플레이어의 동작을 적절한 인덱스 값으로 바꾸어서, 그 인덱스에 해당하는 rule base 값을 적 캐릭터의 DX 와 DY 값으로 이용하면 되는 겁니다.

동작모드의 경우는 여러개를 준비해 두고 게임의 적절한 상황에 맞게 인덱스를 지정해 주면 다양한 적의 움직임을 만들수 있습니다.

그러면 실제로 rule base 는 어떻게 정해 주어야 할까요?

두 가지 방법이 있습니다. 

하나는 경험적인 방법이고, 하나는 시행착오법입니다. 

제가 위에서 사용한 룰베이스의 값들은 제가 게임 중에 캐릭터를 어떻게 조작하는지를 모방해서 만든 것입니다. 

그러니까 룰베이스의 데이타를 제공하는 사람의 경험능력에 달려 있는 경험적인 방법이죠. 

저 같이 게임을 제대로 못하는 사람이 만들면 잘 해야 만든 사람 정도 실력 밖에 구현이 안되죠. 

반면에 시행착오법은 최적의 룰베이스를 시행착오를 통해서 컴퓨터가 스스로 찾도록 하는 것입니다. 

요즈음 신경망 인공지능을 이용해서 퍼지 룰 베이스를 찾아내는 연구가 활발하게 이루어지고 있는 것으로 알고 있습니다.

---------------------------------------------------------------

그러면 실제로 적 캐릭터를 움직이는 함수입니다.

void type_move(void)

{

  byte b, i, j, k ; 

  int delta_x, delta_y, bm = 0 ;

  delta_x = character[thunder].x - character[type01].x ;

  delta_y = character[thunder].y - character[type01].y ;

  if ( delta_x > 45 )

    torp_fire(character[type02].x, character[type02].y) ;

  for (b = 0 ; b < MAXNO ; b++) 

  { 

    if(beam[b].energy==0)

      continue ; 

    bm++ ;

  }

  if ( character[type01].energy >= character[thunder].energy )

    i = ATTACK ;

  else if ( bm && abs( delta_x ) < 60 )

    i = RUN ;

    else i = PURSUIT ;

  if (abs(delta_x) < 20)

    bullet_fire(character[type01].x, character[type01].y+5) ;

  switch(character[thunder].dx)

  {

    case -3 :

        j=0 ;

        break ;

    case 0 :

        j=1 ;

        break ;

    case 3 :

        j=2 ;

        break ; 

  }

  if ( abs(delta_x) < 5 )

    k = 2 ;

  else if ((delta_x) <= -5 && (delta_x) > -30) 

    k = 1 ;

  else if (delta_x <= -30) 

    k = 0 ;

  else if ((delta_x) >= 5 && (delta_x) < 30) 

    k = 3 ;

  else if (delta_x >= 30)

    k = 4 ;

character[type01].dx = rule_base_x[i][j][k] ; 

character[type01].x+ = character[type01].dx ;

  switch(character[thunder].dy)

  {

    case -3 :

        j = 0 ;

        break ;

    case 0 :

        j = 1 ;

        break ;

    case 3 :

        j = 2 ;

        break ;

  }

  if ( abs(delta_y) < 15 )

    k = 2 ;

  else if ((delta_y) <= -15 && (delta_y) > -60)

    k = 1 ;

  else if (delta_y <= -60) 

    k = 0 ;

  else if ((delta_y) >= 15 && (delta_y) < 60)

    k = 3 ;

  else if (delta_y >= 60) 

    k = 4 ;

  if ( random(5)==0 ) 

  {

    character[type01].dy = rule_base_y[i][j][k] ;

    character[type01].y+ = character[type01].dy ;

  }

}  

세세 하게 설명 하지 않아도 차근히 살펴 보시면 이해 하 실 수 있을겁니다. 

의외로 간단하죠. 

마지막에 if ( random(5)==0 ) 으로 한 건 100% 적용하면 제가 도저히 이길 수가 없으므로 y에 대해서는 1/5 만 적용되도록 한 겁니다.

어디 게시판에 보니까 '로드 런너'라는 애플시절의 게임을 아이비엠 용으로 만드는데, 게임의 상황에 따라서 미묘하게 변화하는 적 캐릭터의 동작 속도를 구현하기 어렵다고 하는데, 퍼지를 이용하면 간단하게 될 것 같네요.

0 Comments
제목