Post List

[실용적 예제로 본 게임 인공지능 프로그램하기] 6. 목적이 부여된 에이전트의 행동(Goal-Driven)

[실용적 예제로 본 게임 인공지능 프로그램하기] 6. 목적이 부여된 에이전트의 행동


지금까지 유한상태기계 기반의 아키텍처를 이용하는 에이전트를 시험해 보았는데, 이 장에서는 약간 다른 접근 방법을 소개합니다. 상태 대신에, 어떤 에이전트의 행동은 계층적인 목적의 모음으로 정의됩니다.

목적은 본질적으로 단일이거나 복합적 입니다. 단일목적은 위치찾기나 무기재장전과 같은 단일 임무,행위 및 행동을 정의합니다. 반면 복합적 목적은 몇개의 부목적으로 구성되고 이것은 다시 단일이나 복합적 목적이 될 수 있으므로 중첩된 계층을 정의합니다.

두 타입의 목적은 모두 그들의 상태를 모니터할 수 있고 실패하면 다시 계획을 짤 수 있는 능력이 있다는 것 입니다.

이러한 AI 디자인 방법은 프로그래머에게 에이전트의 행동을 정의하기 위한 직관적인 메커니즘을 제공하는데 이는 사람의 사고방식과 유사한 방식을 띠기 때문입니다.

사용 예

인공지능 에이전트 A가 방금 게임 세계에 들어왔습니다. A는 프로그래머에 의해 예정된 대로 곧 몬스터가 자신의 세계로 공격해올 것임을 알고 있습니다. 하지만 A는 자신의 신체 외에는 아무것도 가지고있지 않습니다(돈도 무기도 아무것도요!). 
우선 A는 [검 구입하기]를 하기로 마음먹습니다. 검을 구입하려면 어떻게 해야할까요? 돈이 없는 A는 우선 금광으로 가서 금을 얻은 후, 대장간에 가서 대장장이에게 검을 구입해야 할 것입니다. 이는 [검 구입하기] 목적의 부목적으로 [금 얻기] 와 [대장간으로 가기] 가 될 것입니다.
[금 얻기]를 먼저 한 후 [대장간으로 가기]가 수행되어야 합니다. 이때 도표는 다음과 같습니다.


[금 얻기] 부목적을 수행하려면 [금광으로 가기(경로계획)] , [경로 따라가기], [금덩이 집기] 부목적이 또 필요합니다. 도표는 다음과 같습니다.


이렇게 계층별로 나누는 것이 계층적인 목적 입니다.
목적을 나누고 완수하는 이 과정들은 전체 계층이 경유될 때까지 계속되고 마지막에는 A의 손에는 빛나는 검이 손에 쥐여져 있을 것입니다.

알고리즘 개요

Goal-Driven 방식의 아키텍처는 목적별로 스크립트를 작성하는것이 그 시작입니다. 
크게 복합목적과 단일목적으로 나뉩니다. 여러개의 단일목적이 합쳐져 복합목적을 이루게 되므로 단일목적을 우선 구현해야 합니다.
단일목적들이 구현이 된다면, 복합목적을 구현해야 하는데, 이때 구현해둔 단일목적들을 복합목적에 삽입해야 합니다. 이것은 복합목적의 스크립트를 작성할 때 어떤 단일목적들을 수합해야 하는지 염두에 두고 삽입을 합니다. 기본적으로는 스택 자료구조를 이용하여 먼저 처리되어야 하는 단일목적을 맨 마지막에 넣지만, 큐로 구현되는 경우도 있습니다.

복합목적들까지 완료가 되었다면 최상위 목적인 Think 클래스를 작성할 차례 입니다. Think클래스에는 각각의 복합목적들이 있고, 시시각각 변화하는 게임 세계에서 적합한 Goal을 선정하기 위해 Desirablity를 검사합니다. 이 적합도에 따라 인공지능 에이전트는 매 순간 적절한 복합목적을 선정하고, 그 복합목적의 단일목적을 수행할 것입니다. 
이를 목적중재 라고 합니다.

우선 단일목적의 대략적인 코드 입니다.


복합목적의 대략적인 코드는 단일목적의 그것과 같습니다. 이때 Activate()에 단일목적 리스트를 넣고 Process에서 해당 단일목적이 완수되면 다음 단일목적을 불러오고 Activate() 합니다.

Think에서 적합도에따라 최선의 목적을 선택하는 목적중재 

중재함수 Arbitrate()는 현 상황에서 목적들 중 가장 큰 적합도를 가진 목적을 선택한 후 반환합니다.  소스코드는 다음과 같습니다.



적합도는 각 상황별로 다를 수 있습니다. 
예를들면 힐팩의 위치를 찾는 바람직함을 계산하는 방법(수식)은 다음과 같습니다.

Desirable = k * (1 - health) / DistanceToHealPack

일반적으로 힐팩의 위치를 찾는 바람직함은 에이전트의 현재 건강레벨에 비례하고( 1-health) 가장 가까운 힐팩에서 떨어진 거리에 반비례합니다.
여기서 k는 결과를 미세조정하기 위해 사용되는 상수 입니다.
상수 k를 변형시킴으로써 다양한 개성을 가지는 에이전트를 만들수 있는데, 만약 상대를 공격하는데에는 덜 관심을 기울이고 자신의 생존이 우선인 에이전트를 설계하고 싶다면 위 수식에서 k값을 보통의 에이전트보다 높게 설정하면 힐팩의 위치를 찾으려는 적합도가 높으므로 많은경우에서 힐팩의 위치를 찾으려고 할 것입니다.

각 복합목적에 맞는 적합도를 설계하는 것도 AI 프로그래머의 일이며 수치를 조절하는 것은 게임 디자이너의 일이겠죠. 이를 위해 변수와 메소드, 심지어 클래스까지 스크립트를 사용해서 외부로 노출시켜야 합니다. 단순 수치만 바뀌었는데 게임 전체를 빌드하는것은 낭비일테니까요.
이 책에서는 LUA를 사용한 스크립팅을 사용하였고, 따로 포스팅은 하지 않겠지만 https://ospace.tistory.com/71 링크에 루아 스크립팅에 대한 포스트가 있습니다. 참고하시면 많은 도움 될것입니다.


정리하자면, 에이전트의 상태를 나타내는것은 FSM과 이번 주제인 Goal-Driven이 있습니다. 두개의 장단점을 취합하여 더 나은 아키텍쳐를 설계하는것이 AI 프로그래머의 일 이라고 합니다. 이상으로 포스팅을 마치겠습니다.





댓글