// FSM의 입력 void CAIMonster2::SendAIMsg( DWORD dwMessage, DWORD dwParam1, DWORD dwParam2 ) { if( dwMessage == AIMSG_DAMAGE ) m_idLastAttacker = dwParam1; if( IsControllable() == FALSE ) return; int nInput, nOutput; nInput = (int)dwMessage; BOOL bResult = GetFSM( m_dwFsmType )->GetTransition( m_nState, nInput, nOutput ); if( bResult == FALSE ) // 전이가 발생하지 않았나? return; ProcessAIMsg( nInput, nOutput, dwParam1, dwParam2 ); }
void CAIMonster2::RouteMessage() { if( IsControllable() == FALSE ) return; DWORD dwCurTick = ::GetTickCount(); CFSMstate* pState = GetFSM( m_dwFsmType )->GetState( m_nState ); if( pState == NULL ) return; // 해당 상태에 대한 주기적 검사가 없다. for( int i=0; i<pState->GetPolling(); ++i ) { FSM_STATE* p = pState->GetEntry( i ); BOOL bHandle = Check( p->nInput, dwCurTick, p->dwExtra ); if( bHandle ) { ProcessAIMsg( p->nInput, p->nOutput, 0, 0 ); // 3rd, 4th data is default break; } } }
//현재 Path.front에 저장되어 있는 타일 인덱스로 이동한다. 만약 Path가 비어있으면 false를 반환한다. bool Unit::MoveToPathFront(int CurrentPacket) { //해당 유닛의 패스를 가져온다. auto& Path = GetPathPlanner()->GetPath(); auto pMap = m_pGameWorld->GetMap(); auto& Graph = pMap->GetNavGraph(); LogMgr->Log("Path Size : %d",Path.size()); if(Path.empty()) { LogMgr->Log("취소"); m_pFSM->ChangeState(State_Idle::Instance()); return false; } //움직일 다음 칸 인덱스를 가져온다. int MoveIndex = Path.front(); Path.pop_front(); //MoveIndex의 타일이 비어있는지 확인한다. //비어 있지 않으면 새로 AStar알고리즘을 실행하여 움직인다. //TODO : 나중에 최적화 할 것 if(!Graph.GetNode(MoveIndex).IsEmpty()) { m_pPathPlanner->CreatePathToPosition(m_pPathPlanner->GetDestination()); if(Path.empty()) { GetFSM()->ChangeState(State_Idle::Instance()); return false; } MoveIndex = Path.front(); Path.pop_front(); } //이동시킨다. int PrevIndex = GetTileIndex(); SetTileIndex(MoveIndex); Vec2 MyPosition = m_pGameWorld->GetMap()->GetNavGraph().GetNode(PrevIndex).getPosition(); Vec2 PathFrontPosition = m_pGameWorld->GetMap()->GetNavGraph().GetNode(MoveIndex).getPosition(); //Heading 설정 SetHeading(PathFrontPosition - getPosition()); //Move 액션 생성 과정 : 타일 간의 거리와 유닛의 이동속도를 고려하여 만든다. //다음 AutoTask를 먼저 등록한다. //본래 속도보다 TweakPacket 정도 더 빠르게 실행시킨다. float Distance = Vec2Distance(PathFrontPosition, MyPosition) / (DIVIDE_NODE ? 32.0f : 64.0f); float Duration = Distance / GetSpeed(); int TweakPacket = 1; int NextPacket = (int)(NETWORK_FPS * Duration) - TweakPacket; printf("NextPacket : %d\n",NextPacket); //만일 NextPacket이 0보다 작거나 같다면 다음 타일을 가져온다. if(NextPacket <= 0) { printf("AAaaaaaaaaaaaa\n"); return MoveToPathFront(CurrentPacket); } NetMgr->PushAutoTask(new AutoTaskMove(CurrentPacket + NextPacket, m_iID)); SetAutoTaskPacket(CurrentPacket+NextPacket); auto pMove = MoveTo::create(Duration,PathFrontPosition); //액션을 실행한다. stopAllActions(); runAction(pMove); return true; }
BOOL ReadAIScriptHelper( FILE* fp ) { READ_TYPE type; char szTokens[3][64]; string strState; int nAI, nState; int nBlock = 0; CFSMstate* pState = NULL; for( ;; ) { type = ReadAILine( fp, szTokens ); switch( type ) { case READ_TYPE_FILE_EOF: return TRUE; case READ_TYPE_FILE_ERROR: return FALSE; case READ_TOKEN0: case READ_COMMENT: continue; case READ_TOKEN1: if( szTokens[0][0] == '{' ) ++nBlock; else if( szTokens[0][0] == '}' ) --nBlock; break; case READ_TOKEN2: if( nBlock == 0 ) { if( memcmp( "TYPE", szTokens[0], 4 ) == 0 ) { nAI = atoi( szTokens[1] ); //printf("type:%d\n", nAI); } } else if( nBlock == 1 ) { nState = GetAIConst( szTokens[0] ); pState = new CFSMstate( nState ); int nPolling = atoi( szTokens[1] ); pState->SetPolling( nPolling ); CFSM* pFSM = GetFSM( nAI ); // nAI = FSM_TYPE_0 pFSM->AddState( pState ); //printf("state:%s(%d)\n", szTokens[0], nState ); } break; case READ_TOKEN3: if( nBlock == 2 ) { // AIMSG_TIMEOUT 1000 AI2_SEARCH pState->AddTransition( GetAIConst( szTokens[0] ), GetAIConst( szTokens[2] ), atoi( szTokens[1] ) ); } break; } } return TRUE; }