Upload
hyosung-jeon
View
745
Download
3
Embed Size (px)
Citation preview
목적이 부여된 에이전트 행동
전효성
에이전트의 행동 기술 방법• FSM 기반 아키텍처–에이전트 행동 = 상태 + 상태 전이 조건
• 목적 기반 아키텍처–에이전트의 행동 = 목적 (Goal) 들의 집합
목적• 단일 목적
– 직접 엔티티 요소를 제어– 단일 임무 , 행위 , 행동을 정의– 예 , 위치 찾기 , 무기 재장전
• 복합 목적– 여러 부목적을 순차적 /
선택적으로 수행– 몇 개의 부 목적으로 구성– 예 , 후퇴하여 엄폐물 찾기
목적 기반 계획1. 상위 레벨 추상 목적 선택2. 목적을 추상적으로 분해하여 행동계획 만듬
예 , “ 극장에 간다”라는 복합 목적의 구조
순차적
선택적 목적
Dragon Slayer2 의 사례
구현 – 기본 개념
Composite 디자인 패턴
Stack 을 이용한 Subgoal 관리
Method 역할Activate •초기화 논리 수행
Process •목적의 상태 갱신•상태 ={failed, completed, active, inactive}
Terminate •정리 작업 수행
구현 – 최종 디자인
Goal_Composite::ProcessSubgoals()
template <class entity_type>int Goal_Composite<entity_type>::ProcessSubgoals(){ while (!m_SubGoals.empty() && (m_SubGoals.front()->isComplete() || m_SubGoals.front()->hasFailed())) // 실패한 goal 이나 성공한 goal 제거 { m_SubGoals.front()->Terminate(); delete m_SubGoals.front(); m_SubGoals.pop_front(); }
if (!m_SubGoals.empty()) { int StatusOfSubGoals = m_SubGoals.front()->Process(); // 스택의 top 에 해당하는 goal 을 실행
if (StatusOfSubGoals == completed && m_SubGoals.size() > 1) { return active; } return StatusOfSubGoals; } else { return completed; }}
Goal_Composite:: RemoveAll-Subgoals()
template <class entity_type>void Goal_Composite<entity_type>::RemoveAllSubgoals(){ for (SubgoalList::iterator it = m_SubGoals.begin(); it != m_SubGoals.end(); ++it) { (*it)->Terminate(); delete *it; } m_SubGoals.clear();}
Raven Bot 에서 사용되는 목적들
단일 목적 - Goal_Wandervoid Goal_Wander::Activate(){ m_iStatus = active; m_pOwner->GetSteering()->WanderOn();}
int Goal_Wander::Process(){ //if status is inactive, call Activate() ActivateIfInactive(); return m_iStatus;}
void Goal_Wander::Terminate(){ m_pOwner->GetSteering()->WanderOff();}
단일 목적 - Goal_TraverseEdge(1/2)void Goal_TraverseEdge::Activate(){ m_iStatus = active; //the edge behavior flag may specify a type of movement that necessitates a change in the bot's max possible speed as it follows this edge switch(m_Edge.Behavior()) { case NavGraphEdge::swim: { m_pOwner->SetMaxSpeed(script->GetDouble("Bot_MaxSwimmingSpeed")); } break; case NavGraphEdge::crawl: { m_pOwner->SetMaxSpeed(script->GetDouble("Bot_MaxCrawlingSpeed")); } break; }
//record the time the bot starts this goal m_dStartTime = Clock->GetCurrentTime(); //calculate the expected time required to reach the this waypoint. This value //is used to determine if the bot becomes stuck m_dTimeExpected = m_pOwner->CalculateTimeToReachPosition(m_Edge.Destination()); //factor in a margin of error for any reactive behavior static const double MarginOfError = 2.0; m_dTimeExpected += MarginOfError; //set the steering target m_pOwner->GetSteering()->SetTarget(m_Edge.Destination()); //Set the appropriate steering behavior. If this is the last edge in the path //the bot should arrive at the position it points to, else it should seek if (m_bLastEdgeInPath) { m_pOwner->GetSteering()->ArriveOn(); } else { m_pOwner->GetSteering()->SeekOn(); }
이어서
단일 목적 - Goal_TraverseEdge(2/2)
int Goal_TraverseEdge::Process(){ //if status is inactive, call Activate() ActivateIfInactive(); //if the bot has become stuck return failure if (isStuck()) { m_iStatus = failed; } //if the bot has reached the end of the edge return completed else { if (m_pOwner->isAtPosition(m_Edge.Destination())) { m_iStatus = completed; } } return m_iStatus;}void Goal_TraverseEdge::Terminate(){ //turn off steering behaviors. m_pOwner->GetSteering()->SeekOff(); m_pOwner->GetSteering()->ArriveOff(); //return max speed back to normal m_pOwner->SetMaxSpeed(script->GetDouble("Bot_MaxSpeed"));}
복합 목적 - Goal_FollowPath
• 목적지까지의 에지 경로를 따라간다 .• 에지별로 따라가는 동작을 정의한다 .– Example • AB 로 이동 할 때에는 수영을 한다 .• DF 로 이동 할 때에는 문을 연다 .
복합 목적 - Goal_FollowPathvoid Goal_FollowPath::Activate(){ m_iStatus = active; //get a reference to the next edge PathEdge edge = m_Path.front(); //remove the edge from the path m_Path.pop_front(); switch(edge.Behavior()) { case NavGraphEdge::normal: { AddSubgoal(new Goal_TraverseEdge(m_pOwner, edge, m_Path.empty())); } break; case NavGraphEdge::goes_through_door: { //also add a goal that is able to handle opening the door AddSubgoal(new Goal_NegotiateDoor(m_pOwner, edge, m_Path.empty())); } break; case NavGraphEdge::jump: { //add subgoal to jump along the edge } break; default: throw std::runtime_error("<Goal_FollowPath::Activate>: Unrecognized edge type"); }}
int Goal_FollowPath::Process(){ //if status is inactive, call Activate() ActivateIfInactive(); m_iStatus = ProcessSubgoals(); if (m_iStatus == completed && !m_Path.empty()) { Activate(); } return m_iStatus;}
복합 목적 - Goal_MoveToPositionvoid Goal_MoveToPosition::Activate(){ m_iStatus = active; //make sure the subgoal list is clear. RemoveAllSubgoals(); if (m_pOwner->GetPathPlanner()->RequestPathToPosition(m_vDestination)) { AddSubgoal(new Goal_SeekToPosition(m_pOwner, m_vDestination)); }}int Goal_MoveToPosition::Process(){ //if status is inactive, call Activate() ActivateIfInactive(); //process the subgoals m_iStatus = ProcessSubgoals(); //if any of the subgoals have failed then this goal re-plans ReactivateIfFailed(); return m_iStatus;}
bool Goal_MoveToPosition::HandleMessage(const Tele-gram& msg){ //first, pass the message down the goal hierarchy bool bHandled = ForwardMessageToFrontMostSubgoal(msg); //if the msg was not handled, test to see if this goal can handle it if (bHandled == false) { switch(msg.Msg) { case Msg_PathReady: //clear any existing goals RemoveAllSubgoals(); AddSubgoal(new Goal_FollowPath(m_pOwner, m_pOwner->GetPathPlanner()->GetPath())); return true; //msg handled case Msg_NoPathAvailable: m_iStatus = failed; return true; //msg handled default: return false; } } return true;}
복합 목적 - Goal_AttackTargetvoid Goal_AttackTarget::Activate(){ m_iStatus = active;
RemoveAllSubgoals(); if (!m_pOwner->GetTargetSys()->isTargetPresent()) { m_iStatus = completed; return; } if (m_pOwner->GetTargetSys()->isTargetShootable()) { Vector2D dummy; if (m_pOwner->canStepLeft(dummy) || m_pOwner->canStepRight(dummy)) { AddSubgoal(new Goal_DodgeSideToSide(m_pOwner)); } else { AddSubgoal(new Goal_SeekToPosition(m_pOwner, m_pOwner->GetTargetBot()->Pos())); } } else { AddSubgoal(new Goal_HuntTarget(m_pOwner)); }}
int Goal_AttackTarget::Process(){ ActivateIfInactive(); m_iStatus = ProcessSubgoals(); ReactivateIfFailed(); return m_iStatus;}
목적 중재 (Goal_Think)
• Goal_Think 를 통하여 가장 적절한 전략을 선택
• 선택 가능한 전략들–무기 얻기 - 로켓 발사기–무기 얻기 - 샷건–무기 얻기 - 레일건–목표 공격하기–건강 얻기–탐험하기
전략 평가 구조
Raven_Featurestatic double Health(Raven_Bot* pBot)
static double DistanceToItem(Raven_Bot* pBot, int ItemType)
static double IndividualWeaponStrength(Raven_Bot* pBot, int WeaponType)
static double TotalWeaponStrength(Raven_Bot* pBot)
평가 함수
목적을 어떻게 선택할 것인가 ?
• 전략적 요소의 구현 방법• 다양한 평가 함수 이용–내가 공격 하는 것이 유리한가 ?–후퇴하는 것이 유리한가 ?–목표점으로 이동하는 것이 유리한가 ?
공격 평가 점수0.3
후퇴 평가 점수0.1
이동 평가 점수0.7
가장 적절한 전략
특정 지역에 무기 얻기
HP 아이템 찾기
공격 목표 찾기
맵 탐색하기
전략 평가 함수
0.5
or
전략 평가 소스코드void Goal_Think::Arbitrate(){ double best = 0; Goal_Evaluator* MostDesirable = 0; //iterate through all the evaluators to see which produces the highest score GoalEvaluators::iterator curDes = m_Evaluators.begin(); for (curDes; curDes != m_Evaluators.end(); ++curDes) { double desirabilty = (*curDes)->CalculateDesirability(m_pOwner); if (desirabilty >= best) { best = desirabilty; MostDesirable = *curDes; } } assert(MostDesirable && "<Goal_Think::Arbitrate>: no evaluator selected"); MostDesirable->SetGoal(m_pOwner);}
부산물• 개성의 표현– Goal_Evaluator 의 subclass 에 bias 부여
• 상태 메모리– Stack 구조를 이용해 이전 내용 기억함
• 명령 큐잉– FollowPosition 의 Queue 로 된 경로점 리스트
• 스크립트 행동에 큐 사용하기– List 구조의 Subgoals 를 통하여 절차적인
흐름을 기술 할 수 있다 .