Upload
dong-hyeun-lee
View
1.051
Download
1
Embed Size (px)
DESCRIPTION
Citation preview
SMC – State Machine [email protected]아꿈사 . 이동현
FSM?
C++ Code
수 많은 반복 코드와 노가다…통제가 안될 정도로 커진다 .
상태기계를 이용하면 프로그램이 간단하고
이해하기 쉽다 .
좀 더 견고한 방법 . – 상태 기계 언어• 고전적인 의미의 상태 기계와 현실적인 의미의 상태 기계 .• 대부분의 게임 개발자는 느슨한 정의를 이용 .• 상태안의 상태 .• 다중 상태 변수 .• 상태 전이의 임의성 .• 상태 안에서 모든 게임 tick 를 실행하는 코드 .• 기타 생각할 수 있는 모든 것 .
코딩된 상태 기계void RunLogic( int* state ){ switch( *state ) { case 0: // 돌아다님 Wander(); if( SeeEnemy() ) { if( GetRandomChance() < 0.8 ) *state = 1; else *state = 2; } if( Dead() ) *state = 3; break; case 1: // 공격 Attack(); if( Dead() ) *state = 3; break;
case 2: // 도망 RunAway(); if( Dead() ) *state = 3; break;
case 3: // 죽음 SlowlyRot(); break; }}
합법적인 코드 그러나…
• 상태 변화가 잘 규제되지 않는다 .• 상태들이 int 형태이며 , 열거형이라면 더
견고하고 디버그 하기 쉬울 것이다 .• Break 키워드 하나만 지워도 찾기 어려운
버그들을 만들게 된다 .• 중복적인 논리가 다중 상태에 나타난다 .• 어떤 상태에 처음 들어갔는지를 알려줄 수 있는
방법이 없다 .• 상태 기계가 시간에 따라 어떻게 움직여 왔는지를
모티너하거나 기록으로 남길 (log) 방법이 없다 .
상태 기계 언어• C++ 매크로의 활용 .• 언어의 일부분이므로 따로 파서등의 도구가 필요없다 .
• 핵심 키워드• BeginStateMachine• EndStateMachine• State• OnEnter• OnExit• OnUpdate
상태 기계 언어 기본 예제BeginStateMachine
State( STATE_Wander ) OnEnter
// 상태시작점에대한 C 나 C++ 코드 OnUpdate
// 매틱 (tick) 마다실행되는 C 나 C++ 코드 OnExit // 상태의뒷정리를위한 C 나 C++ 코드
State( STATE_Attack ) OnEnter
// 상태시작점에대한 C 나 C++ 코드
EndStateMachine #define BeginStateMachine if(state < 0) { if (0) {#define EndStateMachine return (true); }} else { assert(0);\
return (false); } return (false);#define State(a) return (true);}}else if(a == state){if(0){#define OnEvent(a) return (true);}else if(a == event){#define OnEnter OnEvent(EVENT_Enter)#define OnUpdate OnEvent(EVENT_Update)#define OnExit OnEvent(EVENT_Exit)
실제로 확장 해보면 ..if( state < 0 ){
if( 0 ) {return ( true );
}}else if( STATE_Wander == state ) {
if( 0 ){return ( true );
}else if( EVENT_Enter == state ) {// 상태시작점에대한 C++ 코드return ( true );
}else if(EVENT_Update == state ) {// 매틱 (tick) 마다실행되는 C++ 코드return ( true );
}else if(EVENT_Wander == state ) {// 상태의뒷정리를위한 C++ 코드return ( true );
}}else if( STATE_Attack == state ) {
if( 0 ){return ( true );
}else if( EVENT_Enter == state ) {// 상태시작점에대한 C++ 코드return ( true );
}}else{
assert(0);return( false );
}return false;
BeginStateMachine
State( STATE_Wander )
OnEnter// 상태시작점에대한 C 나 C++ 코드
OnUpdate// 매틱 (tick) 마다실행되는 C 나 C++ 코드
OnExit // 상태의뒷정리를위한 C 나 C++ 코드
State( STATE_Attack ) OnEnter
// 상태시작점에대한 C 나 C++ 코드
EndStateMachine
좀 더 나아가서 ..• AI 디자이너의 생산성 높이기 .• GUI 기반의 모델링 .• C++ 코더로의 변환 용이성 .
CreatureMachine::CreatureMachine(){
// add all variables to the variable listAddVariable("Health",VAR_INTEGER,&m_Health);AddVariable("EnemyLocation",VAR_POSITION,&m_Enemy;
// now add conditions (may reference variables)AddCondition("InRange",LESSTHAN,"EnemyLocation",100);AddCondition("LowHealth",LESSTHAN,"Health", 50);
// now add all the actions (may be referenced by the // states)AddAction("IdleAction");AddAction("FightAction");AddAction("FleeAction");
// now add all the statesAddState("Idle","IdleAction");AddState("Fight","FightAction");AddState("Flee","FleeAction");
// now add all the transitions (may reference states // and variables)// transitions syntax : <condition-name> <start state>// <end state>AddTransition("In Range","Idle","Fight");AddTransition("Low Health","Fight","Flee");
};
다이어 그램의 코드화
SMC – The State Map Compiler• http://smc.sourceforge.net/SmcManual.htm
“Your detailed state diagrams are only pictures. How are you going to translate your drawings into code? A transition matrix is cryptic while switch statements means your state machine logic is scattered all over your code. The state pattern looks like a great solution but that means writing and maintaining a class for each state - too much work.”
SMC
Adding a state machine to your class
1. Download SMC - http://sourceforge.net/projects/smc/files/smc/6_0_0/smc_6_0_0.zip/download
2. Include the SMC class definitions into your appli-cation.
3. Include the state machine's source file.4. Instantiate the state machine's context object.5. If you want to execute the start state's entry ac-
tions call the state machine context's enterStart-State method. This is not needed to set the start state as that is done when the state machine context is instantiated. enterStartState only exe-cutes the start state's entry actions (if any exist).
Make SMC file
// This FSM works for the Task class only and only the Task // class may instantiate it. %class Task %package com.acme.supercron %fsmclass TaskFSM %access package %start TaskFSM::Suspended %map TaskFSM %%
<snip> Running Exit { stopSliceTimer(); }{ Suspend Suspended { suspendTask(); } Block Blocked { blockTask(); } Done Stopped { releaseResources(); } } <snip> } %%
{ Suspend Suspended { suspendTask(); } Block Blocked { blockTask(); } Done Stopped { releaseResources(); } }
Transition End State Action
Transition Guards
// State Idle { // Trans Run // Guard condition [ctxt.isProcessorAvailable() == true && ctxt.getConnection().isOpen() == true] // Next State Running // Actions { StopTimer("Idle"); DoWork(); } Run nil {RejectRequest();} }
Transition Arguments
// State Idle { // Transition Run(msg: const Message&) // Guard condition [ctxt.isProcessorAvailable() == true && msg.isValid() == true] // Next State Running // Actions { StopTimer("Idle"); DoWork(msg); } Run(msg: const Message&) // Next State Actions nil {RejectRequest(msg);} }
Transition Arguments
void MainMap_CLOSED::PassiveOpen(TcpConnectionContext& context, unsigned short port){ TcpConnection& ctxt(context.getOwner());
CLOSED{ PassiveOpen(port: unsigned short) ServiceOpening { openServerSocket(port); }
Default Transitions• What happens if a state receives a transition that
is not defined in that state?Default{ // Valid run request but transition occurred in an invalid // state. Send a reject reply to valid messages. Run(msg: const Message&) [ctxt.isProcessorAvailable() == true && msg.isValid() == true] nil { RejectRequest(msg); }
// Ignore invalid messages are ignored when received in // an invalid state. Run(msg: const Message&) nil {}
Shutdown ShuttingDown { StartShutdown(); }}
Connecting{ // We are now connected to the far-end. Now we can logon. Connected Connected { logon(); }
// Any other transition at this point is an error. // Stop the connecting process and retry later. Default RetryConnection { stopConnecting(); }}
Transition Precedence
1. Guarded transition 2. Unguarded transition 3. The Default state's guarded definition. 4. The Default state's unguarded definition. 5. The current state's guarded Default transition. 6. The current state's unguarded Default transition. 7. The Default state's guarded Default transition. 8. The Default state's unguarded Default transition.
Compiling a .sm• Prepare• Java 1.6.0 or newer is properly installed and the "javac",
"java" and "jar" executables are in your PATH environment variable. The standard Java Development Kit can be obtained for free from http://java.sun.com . • The SMC_HOME environment variable contains the path to
where SMC is installed.
• $ java -jar $SMC_HOME/bin/Smc.jar [-c | -c++ | -csharp | -graph | -groovy | -java | -lua | -objc | -perl | -php | -python | -ruby | -scala | -table | -tcl | -vb] <fsm_source_file>.sm
Behind the Curtain
GOF’s State Pattern SMC Pattern
Ex4
StopMap
State
Stoplight-State
StopMap_EastWestGreen
StopMap_EastWestYellow
StopMap_NorthSouthGreen
StopMap_NorthSouthYellow
StopMap_Default
StoplightCon-text
FSMCon-text
Stop-light
enterStartState