void EntityManager::update(float dt) { CCArray *keys = m_pIDToEntitiesMap->allKeys(); if (keys) { // if the dictionary has no objects, keys will be NULL for (int i=0; i<keys->count(); i++) { CCInteger *integer = (CCInteger *)keys->objectAtIndex(i); int key = integer->getValue(); BaseGameEntity *entity = (BaseGameEntity *)m_pIDToEntitiesMap->objectForKey(key); if (entity->getIsActive()) { // Only update the entity if it's active. entity->update(dt); } } } /* // Add new entities. for (int i=0; i<m_pEntitiesToAdd->count(); i++) { BaseGameEntity *newEntity = (BaseGameEntity *)m_pEntitiesToAdd->objectAtIndex(i); m_pIDToEntitiesMap->setObject(newEntity, newEntity->getID()); } m_pEntitiesToAdd->removeAllObjects(); */ // Remove old entities. for (int i=0; i<m_pEntitiesToRemove->count(); i++) { BaseGameEntity *oldEntity = (BaseGameEntity *)m_pEntitiesToRemove->objectAtIndex(i); m_pIDToEntitiesMap->removeObjectForKey(oldEntity->getID()); } m_pEntitiesToRemove->removeAllObjects(); }
//---------------------- DispatchDelayedMessages ------------------------- // // This function dispatches any telegrams with a timestamp that has // expired. Any dispatched telegrams are removed from the queue //------------------------------------------------------------------------ void MessageDispatcher::DispatchDelayedMessages() { //first get current time double CurrentTime = TickCounter->GetCurrentFrame(); //now peek at the queue to see if any telegrams need dispatching. //remove all telegrams from the front of the queue that have gone //past their sell by date while( !PriorityQ.empty() && (PriorityQ.begin()->DispatchTime < CurrentTime) && (PriorityQ.begin()->DispatchTime > 0) ) { //read the telegram from the front of the queue const Telegram& telegram = *PriorityQ.begin(); //find the recipient BaseGameEntity* pReceiver = EntityMgr->GetEntityFromID(telegram.Receiver); #ifdef SHOW_MESSAGING_INFO debug_con << "\nQueued telegram ready for dispatch: Sent to " << pReceiver->ID() << ". Msg is "<< telegram.Msg << ""; #endif //send the telegram to the recipient Discharge(pReceiver, telegram); //remove it from the queue PriorityQ.erase(PriorityQ.begin()); } }
//---------------------- DispatchDelayedMessages ------------------------- // // This function dispatches any telegrams with a timestamp that has // expired. Any dispatched telegrams are removed from the queue //------------------------------------------------------------------------ void MessageDispatcher::DispatchDelayedMessages() { // cout << "\nDispatch Delayed Message"; //first get current time double CurrentTime = Clock->GetCurrentTime(); //cout << "\nCurrent time" << CurrentTime; //now peek at the queue to see if any telegrams need dispatching. //remove all telegrams from the front of the queue that have gone //past their sell by date /*if(!PriorityQ.empty()){ cout << "\nDispatch time" << PriorityQ.begin()->DispatchTime; }*/ while( !PriorityQ.empty() && (PriorityQ.begin()->DispatchTime < CurrentTime) && (PriorityQ.begin()->DispatchTime > 0) ) { //read the telegram from the front of the queue const Telegram& telegram = *PriorityQ.begin(); //find the recipient BaseGameEntity* pReceiver = EntityMgr->GetEntityFromID(telegram.Receiver); cout << "\nQueued telegram ready for dispatch: Sent to " << GetNameOfEntity(pReceiver->ID()) << ". Msg is " << MsgToStr(telegram.Msg); //send the telegram to the recipient Discharge(pReceiver, telegram); //remove it from the queue PriorityQ.erase(PriorityQ.begin()); } }
void StateZombieChase::Execute(Zombie* pZombie, u32 elapsedTime) { Animate(pZombie, elapsedTime); //-------------------------------------------- // // use physics model for executing // //-------------------------------------------- // find target object ZombiePhysics* pPhysicsModel = pZombie->GetPhysicsModel(); pPhysicsModel->ResetTarget(); vector2df me(pZombie->Pos().X,pZombie->Pos().Y); std::vector<BaseGameEntity*> enties = EntityMgr.GetEntityListFromGroupID(ENTITY_TYPE_HUMAN); bool isTarget = false; for (std::vector<BaseGameEntity*>::iterator iter = enties.begin(); iter != enties.end(); iter++) { // find out close human, but now just get first human.... BaseGameEntity* pEntity = *iter; f32 collisiondistance = me.getDistanceFrom(vector2df(pEntity->Pos().X, pEntity->Pos().Y)); if(RANGE_ZOMBIE_TARGET_RECOGNITION >= collisiondistance)//ÀÎ½Ä ¹üÀ§ ¾È¿¡¼ ÀÖ´ÂÁö? { if(RANGE_ZOMBIE_ATTACKMEELE_RECOGNITION >= collisiondistance)//¸Â ´ê¾Æ¼ attack mode·Î º¯°æ { pZombie->GetFSM()->ChangeState(StateZombieAttackBite::Instance()); isTarget = true; break; } else//¾ÆÁ÷ Á»ºñ°¡ °ø°ÝÇÒ Á¤µµ·Î °¡±õÁö ¾ÊÀ½ { pPhysicsModel->SetTarget(b2Vec2(pEntity->Pos().X, pEntity->Pos().Y)); isTarget = true; break; } } } if(!isTarget)//Ÿ°ÙÀ» †õÄ¡¸é ´Ù½Ã roam »óÅ·Π{ //°Ë»ö µÇ¸é ÃßÀû ½ºÅ×ÀÌÆ®·Î º¯½Å pZombie->GetPhysicsModel()->GetBody()->m_maxForwardSpeed = ZOMBIE_ROAMSTATE_PHYSICS_MAX_FORWARDSPEED; pZombie->GetPhysicsModel()->GetBody()->m_maxDriveForce = ZOMBIE_ROAMSTATE_PHYSICS_MAX_FRONTFORCE; //RAN_LOG("Zombie[chase] changestate - Roam"); pZombie->GetFSM()->ChangeState(StateZombieRoam::Instance()); } pPhysicsModel->Update(elapsedTime); //-------------------------------------------- // // apply executed result to object property // //-------------------------------------------- b2Vec2 vec = pZombie->GetPhysicsModel()->GetPosition(); f32 angle = pZombie->GetPhysicsModel()->GetAngle(); pZombie->SetPos(vector3df(vec.x, vec.y, 0)); pZombie->SetRotation(vector3df(0.f, 0.f, ANGLE_TO_RADIAN(angle))); }
//-------------------------------- Cohesion ------------------------------ // // returns a steering force that attempts to move the agent towards the // center of mass of the agents in its immediate area // // USES SPACIAL PARTITIONING //------------------------------------------------------------------------ Vector2D SteeringBehavior::CohesionPlus(const vector<Vehicle*> &neighbors) { //first find the center of mass of all the agents Vector2D CenterOfMass, SteeringForce; int NeighborCount = 0; //iterate through the neighbors and sum up all the position vectors for (BaseGameEntity* pV = m_pVehicle->World()->CellSpace()->begin(); !m_pVehicle->World()->CellSpace()->end(); pV = m_pVehicle->World()->CellSpace()->next()) { //make sure *this* agent isn't included in the calculations and that //the agent being examined is close enough if (pV != m_pVehicle) { CenterOfMass += pV->Pos(); ++NeighborCount; } } if (NeighborCount > 0) { //the center of mass is the average of the sum of positions CenterOfMass /= (double)NeighborCount; //now seek towards that position SteeringForce = Seek(CenterOfMass); } //the magnitude of cohesion is usually much larger than separation or //allignment so it usually helps to normalize it. return Vec2DNormalize(SteeringForce); }
void HeroHurt::enter(Hero *object) { // 面向对你造成伤害者 int entity_id = object->getStateMachine()->userdata().hurt_source; BaseGameEntity *entity = object->getEntityManger()->getEntityByID(entity_id); if (entity != nullptr) { if (entity->getPositionX() < object->getPositionX()) { object->setDirection(BaseGameEntity::kLeftDirection); } else { object->setDirection(BaseGameEntity::kRightDirection); } } system_clock::time_point current_time = system_clock::now(); system_clock::time_point last_hurt_time = object->getStateMachine()->userdata().was_hit_time; system_clock::duration duration = current_time - last_hurt_time; if (duration_cast<milliseconds>(duration).count() < 1000) { ++object->getStateMachine()->userdata().was_hit_count; } else { object->getStateMachine()->userdata().was_hit_count = 1; } if (object->getStateMachine()->userdata().was_hit_count < 3) { Animation *animation = AnimationManger::instance()->getAnimation("hero_hurt"); Animate *animate = Animate::create(animation); animate->setTag(ActionTags::kHeroHurt); object->runAction(animate); object->getStateMachine()->userdata().was_hit_time = system_clock::now(); } else { object->getStateMachine()->change_state(HeroKnockout::instance()); } if (object->hasWeapon()) { auto current_level = object->getEntityManger()->getCurrentLevel(); current_level->dropWeapon(object); } }
void RabbitWanderingState::Execute(Rabbit* rabbit) { Node* current = rabbit->GetPosition(); Node* next = current->GetEdges()[Random::Next(0, current->GetEdges().size() - 1)]->child; if (next->ContainsEntity("Pill")) { BaseGameEntity *pill = next->ContainsEntity("Pill"); next->RemoveEntity(pill); Node *random = rabbit->GetGraph()->GetRandomNode(next); random->AddEntity(pill); pill->SetPosition(random); rabbit->GetFSM()->ChangeState(RabbitSleepingState::Instance()); } rabbit->MoveTo(next); }
void RabbitSearchPillState::Execute(Rabbit* rabbit) { Node* current = rabbit->GetPosition(); Node* next = current->GetEdges()[Random::Next(0, current->GetEdges().size() - 1)]->child; if (next->ContainsEntity("Pill")) { BaseGameEntity *pill = next->ContainsEntity("Pill"); next->RemoveEntity(pill); pill->SetPosition(nullptr); rabbit->Pickup(static_cast<GameItem*>(pill)); printf("Rabbit: picked up pill\n"); rabbit->GetFSM()->ChangeState(RabbitWanderingState::Instance()); } rabbit->MoveTo(next); }
void ChaseGroupState::Execute(ChaserPlayer* pPlayer, u32 elapsedTime) { //sk //충돌 처리를 여기 넣는게 맞나?? - 현재 정의된 어떤 상태이든 총알에 영향을 받기 때문에 //충돌 테스트 - 나중에 독립된 함수로 분리 std::vector<BaseGameEntity*> vec = EntityMgr.GetCollidedEntites(pPlayer); if(vec.size() > 0) { //if there is bullet, chaser state should be changed. std::vector<BaseGameEntity*>::iterator iter; for (iter = vec.begin(); iter != vec.end(); iter++) { BaseGameEntity* pEntity = *iter; if(pEntity->Name() == "Bullet") { pPlayer->GetFSM()->ChangeState(ChaseDeadState::Instance()); return; } } } Animate(pPlayer, elapsedTime); //플레이어를 향해 가도록 설정 //*/ //BaseGameEntity* pTargetEntity = EntityMgr.GetEntityFromID(12); //주인공 케릭터를 얻어오는 방식이 수정되어야 함. 현재 id로 얻어 오는 방식은 ID가 계속 변하기 때문에 의미가 없음. std::vector<BaseGameEntity*> fugivevec = EntityMgr.GetEntityListFromGroupID(100); BaseGameEntity* pTargetEntity = fugivevec[0];// vector3df forwardobject = pTargetEntity->Pos()-pPlayer->Pos(); pPlayer->SetPos(pPlayer->m_myAI.ObjectFlokcing(pPlayer->Pos(),pPlayer->Velocity(), pPlayer->MaxSpeed() , elapsedTime,forwardobject.normalize(),pPlayer->m_uGroupID,pPlayer)); /*/테스트용 patrol pPlayer->SetPos(pPlayer->m_myAI.ObjectFlokcing(pPlayer->Pos(),pPlayer->Velocity(), pPlayer->MaxSpeed() , elapsedTime,pPlayer->Heading(),pPlayer->m_uGroupID,pPlayer)); //*/ //end sk }
void StateZombieAttackBite::Execute(Zombie* pZombie, u32 elapsedTime) { Animate(pZombie, elapsedTime); //-------------------------------------------- // // use physics model for executing // //-------------------------------------------- // find target object ZombiePhysics* pPhysicsModel = pZombie->GetPhysicsModel(); pPhysicsModel->ResetTarget(); vector2df me(pZombie->Pos().X,pZombie->Pos().Y); std::vector<BaseGameEntity*> enties = EntityMgr.GetEntityListFromGroupID(ENTITY_TYPE_HUMAN); bool isTarget = false; for (std::vector<BaseGameEntity*>::iterator iter = enties.begin(); iter != enties.end(); iter++) { // find out close human, BaseGameEntity* pEntity = *iter; f32 collisiondistance = me.getDistanceFrom(vector2df(pEntity->Pos().X, pEntity->Pos().Y)); if(RANGE_ZOMBIE_ATTACKMEELE_RECOGNITION >= collisiondistance)//±ÙÁ¢ °ø°Ý ¹üÀ§ ¾È¿¡¼ ÀÖ´ÂÁö? { pPhysicsModel->SetTarget(b2Vec2(pEntity->Pos().X, pEntity->Pos().Y)); isTarget = true; #ifdef ZOBIE_AILEVEL_INFECTION_SYSTEM int idAttacked = pEntity->ID(); //sendmessage: human À» °¨¿°»óÅ·Π... Dispatcher->DispatchMsg(SEND_MSG_IMMEDIATELY, // time delay pZombie->ID(), // ID of sender idAttacked, // ID of recipient MSG_TYPE_HUMAN_INFECTION, // the message NO_ADDITIONAL_INFO); #endif break; } } if(!isTarget)//Ÿ°ÙÀ» ³õÄ¡¸é ´Ù½Ã roam »óÅ·Π{ pZombie->GetPhysicsModel()->GetBody()->m_maxForwardSpeed = ZOMBIE_ROAMSTATE_PHYSICS_MAX_FORWARDSPEED; pZombie->GetPhysicsModel()->GetBody()->m_maxDriveForce = ZOMBIE_ROAMSTATE_PHYSICS_MAX_FRONTFORCE; pZombie->GetFSM()->ChangeState(StateZombieRoam::Instance()); } pPhysicsModel->Update(elapsedTime); //-------------------------------------------- // // apply executed result to object property // //-------------------------------------------- b2Vec2 vec = pZombie->GetPhysicsModel()->GetPosition(); f32 angle = pZombie->GetPhysicsModel()->GetAngle(); pZombie->SetPos(vector3df(vec.x, vec.y, 0)); pZombie->SetRotation(vector3df(0.f, 0.f, ANGLE_TO_RADIAN(angle))); }
//--------------------- GetPosOfClosestSwitch ----------------------------- // // returns the position of the closest visible switch that triggers the // door of the specified ID //----------------------------------------------------------------------------- Vector2D Raven_Game::GetPosOfClosestSwitch(Vector2D botPos, unsigned int doorID)const { std::vector<unsigned int> SwitchIDs; //first we need to get the ids of the switches attached to this door std::vector<Raven_Door*>::const_iterator curDoor; for (curDoor = m_pMap->GetDoors().begin(); curDoor != m_pMap->GetDoors().end(); ++curDoor) { if ((*curDoor)->ID() == doorID) { SwitchIDs = (*curDoor)->GetSwitchIDs(); break; } } Vector2D closest; double ClosestDist = MaxDouble; //now test to see which one is closest and visible std::vector<unsigned int>::iterator it; for (it = SwitchIDs.begin(); it != SwitchIDs.end(); ++it) { BaseGameEntity* trig = EntityMgr->GetEntityFromID(*it); if (isLOSOkay(botPos, trig->Pos())) { double dist = Vec2DDistanceSq(botPos, trig->Pos()); if ( dist < ClosestDist) { ClosestDist = dist; closest = trig->Pos(); } } } return closest; }
bool Projectile::handleMessage(const Telegram *telegram) { switch (telegram->message) { case kMessageReachPosition: reset(); return true; case kMessageCollide: BaseGameEntity *entity = GameModel::instance()->getEntityForID(telegram->sender); if (arc4random()%10 > 3) { return false; } if (entity->getEntityType() == kFighter && entity->getController() != m_eController) { MessageDispatcher::instance()->dispatchMessage(0, m_uID, entity->getID(), kMessageHit, (void *)&m_iDamage); reset(); return true; } return false; } return false; }
void IdleCamera::Execute(BaseCamera* pCamera, u32 elapsedTime) { // follow target int id = pCamera->GetTargetEntityID(); if (id < 0) { return; } BaseGameEntity* pTargetEntity = EntityMgr.GetEntityFromID(id); vector3df targetPos = pTargetEntity->Pos(); vector3df newPos = vector3df(targetPos.X, targetPos.Y, pCamera->Pos().Z); static EventReceiver* pEventReceiver = &(EventRcv); /*if (pEventReceiver->IsKeyDown(KEY_KEY_W)) { pEventReceiver->SetKeyDown(KEY_KEY_W, false); newPos.Z += 10.0f; if (0 <= newPos.Z) { newPos.Z = -10.f; } } else if (pEventReceiver->IsKeyDown(KEY_KEY_S)) { pEventReceiver->SetKeyDown(KEY_KEY_S, false); newPos.Z -= 10.0f; }*/ //pCamera->SetDestPos(newPos, true); pCamera->SetPos(newPos); pCamera->SetLookAt(vector3df(newPos.X, newPos.Y, targetPos.Z)); }
//---------------------------- Separation -------------------------------- // // this calculates a force repelling from the other neighbors // // USES SPACIAL PARTITIONING //------------------------------------------------------------------------ Vector2D SteeringBehavior::SeparationPlus(const vector<Vehicle*> &neighbors) { Vector2D SteeringForce; //iterate through the neighbors and sum up all the position vectors for (BaseGameEntity* pV = m_pVehicle->World()->CellSpace()->begin(); !m_pVehicle->World()->CellSpace()->end(); pV = m_pVehicle->World()->CellSpace()->next()) { //make sure this agent isn't included in the calculations and that //the agent being examined is close enough if (pV != m_pVehicle) { Vector2D ToAgent = m_pVehicle->Pos() - pV->Pos(); //scale the force inversely proportional to the agents distance //from its neighbor. SteeringForce += Vec2DNormalize(ToAgent) / ToAgent.Length(); } } return SteeringForce; }
//---------------------------- DispatchMessage --------------------------- // // given a message, a receiver, a sender and any time delay , this function // routes the message to the correct agent (if no delay) or stores // in the message queue to be dispatched at the correct time //------------------------------------------------------------------------ void MessageDispatcher::DispatchMessage(double delay, int sender, int receiver, int msg, void* ExtraInfo) { SetTextColor(BACKGROUND_RED|FOREGROUND_RED|FOREGROUND_GREEN|FOREGROUND_BLUE); //get pointers to the sender and receiver BaseGameEntity* pSender = EntityMgr->GetEntityFromID(sender); BaseGameEntity* pReceiver = EntityMgr->GetEntityFromID(receiver); //make sure the receiver is valid if (pReceiver == NULL) { cout << "\nWarning! No Receiver with ID of " << receiver << " found"; return; } //create the telegram Telegram telegram(0, sender, receiver, msg, ExtraInfo); //if there is no delay, route telegram immediately if (delay <= 0.0f) { SetTextColor(BACKGROUND_RED|FOREGROUND_RED|FOREGROUND_GREEN|FOREGROUND_BLUE); cout << "\nInstant telegram dispatched at time: " << Clock->GetCurrentTime() << " by " << GetNameOfEntity(pSender->ID()) << " for " << GetNameOfEntity(pReceiver->ID()) << ". Msg is "<< MsgToStr(msg); //send the telegram to the recipient Discharge(pReceiver, telegram); } //else calculate the time when the telegram should be dispatched else { double CurrentTime = Clock->GetCurrentTime(); telegram.DispatchTime = CurrentTime + delay; //and put it in the queue PriorityQ.insert(telegram); SetTextColor(BACKGROUND_RED|FOREGROUND_RED|FOREGROUND_GREEN|FOREGROUND_BLUE); cout << "\nDelayed telegram from " << GetNameOfEntity(pSender->ID()) << " recorded at time " << Clock->GetCurrentTime() << " for " << GetNameOfEntity(pReceiver->ID()) << ". Msg is "<< MsgToStr(msg); } }
bool Human::Update(u32 elapsedTime) { //-------------------------------------------- // // update entity // //-------------------------------------------- MovingEntity::Update(elapsedTime); #ifdef HUMAN_AILEVEL_STARVATION_SYSTEM //effect which are applied independently of state if(m_fCurrentLifeEnergy>0) m_fCurrentLifeEnergy-= (elapsedTime * HUMAN_ENERGYDECREASE_PER_MILLISECOND); else m_fCurrentLifeEnergy=0; if(m_fCurrentLifeEnergy < HUMAN_THRESHOLD_TO_STARVATION && this-> m_State != HUMAN_STATE_STARVATION && this-> m_State != HUMAN_STATE_DEATH){ m_State = HUMAN_STATE_STARVATION; GetFSM()->ChangeState(StateHumanStarvation::Instance()); } #endif #ifdef HUMAN_AILEVEL_EAT_SYSTEM vector2df me(this->Pos().X,this->Pos().Y); std::vector<BaseGameEntity*> enties = EntityMgr.GetEntityListFromGroupID(ENTITY_TYPE_ITEM_FOOD); //bool isTarget = false; for (std::vector<BaseGameEntity*>::iterator iter = enties.begin(); iter != enties.end(); iter++) { // find out close human, but now just get first human.... BaseGameEntity* pEntity = *iter; f32 collisiondistance = me.getDistanceFrom(vector2df(pEntity->Pos().X, pEntity->Pos().Y)); if(RANGE_HUMAN_EAT_RECOGNITION >= collisiondistance) { //식량 섭취 m_fCurrentLifeEnergy = HUMAN_MAX_LIFE_ENERGY_DEFAULT; HumanPhysics* pPhysicsModel = this->GetPhysicsModel(); pPhysicsModel->ResetTarget(); GetFSM()->ChangeState(StateHumanHide::Instance()); //해당 아이템에 소멸 메세지 전달 int idfood = pEntity->ID(); Dispatcher->DispatchMsg(SEND_MSG_IMMEDIATELY, // time delay ID(), // ID of sender idfood, // ID of recipient MSG_TYPE_FOOD_DISAPPEAR, // the message NO_ADDITIONAL_INFO); //((BaseItem*)pEntity)->GetFSM()->ChangeState(StateBaseItemDisappear::Instance()); break; } } #endif if (m_pStateMachine) { m_pStateMachine->Update(elapsedTime); } //이전 프레임의 위치가 필요하므로 저장한다.(업데이트 되기전의 이전 좌표) m_VecTemporayPos.X = Pos().X; m_VecTemporayPos.Y = Pos().Y; //-------------------------------------------- // // sync property with scene node // //-------------------------------------------- if (m_p2DSprite) { m_p2DSprite->setPosition(Pos()); } return this->IsAlived(); }
void StateZombieRoam::Execute(Zombie* pZombie, u32 elapsedTime) { Animate(pZombie, elapsedTime); //-------------------------------------------- // // use physics model for executing // //-------------------------------------------- // find target object ZombiePhysics* pPhysicsModel = pZombie->GetPhysicsModel(); vector2df me(pZombie->Pos().X,pZombie->Pos().Y); vector2df roamdest(pZombie->m_VecRoamDest.X,pZombie->m_VecRoamDest.Y); //pZombie->CountTimeSamePos(vector2df(pZombie->Pos().X,pZombie->Pos().Y),elapsedTime); pZombie->m_AIAgent.CountTimeSamePos(me, pZombie->m_VecTemporayPos,elapsedTime,pZombie->m_uLockPosTime,TOLERANCE_ZOMBIE_MOVOMENT); if(pZombie->m_AIAgent.IsArriveRoamDest(me,roamdest,TOLERANCE_ZOMBIE_ROAMARRIVE) ) { //¹æÇâ Àç ¼³Á¤ pZombie->m_AIAgent.SetRandDestforRoam(me,pZombie->m_VecRoamDest,RANGE_ZOMBIE_ROAM); pPhysicsModel->ResetTarget(); pPhysicsModel->SetTarget(b2Vec2(pZombie->m_VecRoamDest.X, pZombie->m_VecRoamDest.Y)); pZombie->m_uLockPosTime = 0; //RAN_LOG("dest point %d, %f, %f", (int)pZombie, pZombie->m_VecRoamDest.X, pZombie->m_VecRoamDest.Y); } else if(pZombie->m_AIAgent.IsSamePosLongtime(pZombie->m_uLockPosTime,TIME_ZOMBIE_ROCKPOS))//º®¸é¿¡ ºÎµúÈù °æ¿ì ´Ù½Ã ¼³Á¤ or ÀÏÁ¤ ½Ã°£ ÀÌ»ó ÇÑ ÁÂÇ¥¿¡ ¸Ó¹° °æ¿ì { //¹æÇâ Àç ¼³Á¤ pZombie->m_AIAgent.SetRandDestforRoam(me,pZombie->m_VecRoamDest,RANGE_ZOMBIE_ROAM); pPhysicsModel->ResetTarget(); pPhysicsModel->SetTarget(b2Vec2(pZombie->m_VecRoamDest.X, pZombie->m_VecRoamDest.Y)); pZombie->m_uLockPosTime = 0; } else { std::vector<BaseGameEntity*> enties = EntityMgr.GetEntityListFromGroupID(ENTITY_TYPE_HUMAN); for (std::vector<BaseGameEntity*>::iterator iter = enties.begin(); iter != enties.end(); iter++) { // find out close human BaseGameEntity* pEntity = *iter; if(RANGE_ZOMBIE_RECOGNITION >= me.getDistanceFrom(vector2df(pEntity->Pos().X, pEntity->Pos().Y)))//ÀÎ½Ä ¹üÀ§ ¾È¿¡¼ ÀÖ´ÂÁö? { pPhysicsModel->SetTarget(b2Vec2(pEntity->Pos().X, pEntity->Pos().Y)); //°Ë»ö µÇ¸é ÃßÀû ½ºÅ×ÀÌÆ®·Î º¯½Å pZombie->GetPhysicsModel()->GetBody()->m_maxForwardSpeed = ZOMBIE_CHASESTATE_PHYSICS_MAX_FORWARDSPEED; pZombie->GetPhysicsModel()->GetBody()->m_maxDriveForce = ZOMBIE_CHASESTATE_PHYSICS_MAX_FRONTFORCE; pZombie->GetPhysicsModel()->ApplyLinearImpulse(ZOMBIE_CHASESTATE_PHYSICS_MAX_FORWARDSPEED); pZombie->GetFSM()->ChangeState(StateZombieChase::Instance()); break; } } } //ÀÌÀü ÇÁ·¹ÀÓÀÇ À§Ä¡°¡ ÇÊ¿äÇϹǷΠÀúÀåÇÑ´Ù.(¾÷µ¥ÀÌÆ® µÇ±âÀüÀÇ ÀÌÀü ÁÂÇ¥) pZombie->m_VecTemporayPos.X = pZombie->Pos().X; pZombie->m_VecTemporayPos.Y = pZombie->Pos().Y; pPhysicsModel->Update(elapsedTime); //-------------------------------------------- // // apply executed result to object property // //-------------------------------------------- b2Vec2 vec = pZombie->GetPhysicsModel()->GetPosition(); f32 angle = pZombie->GetPhysicsModel()->GetAngle(); pZombie->SetPos(vector3df(vec.x, vec.y, 0)); pZombie->SetRotation(vector3df(0.f, 0.f, ANGLE_TO_RADIAN(angle))); }
//------------------------------ Render ---------------------------------- //------------------------------------------------------------------------ void GameWorld::Render() { gdi->TransparentText(); //render any walls gdi->BlackPen(); for (unsigned int w = 0; w < m_Walls.size(); ++w) { m_Walls[w].Render(true); //true flag shows normals } //render any obstacles gdi->BlackPen(); for (unsigned int ob = 0; ob < m_Obstacles.size(); ++ob) { gdi->Circle(m_Obstacles[ob]->Pos(), m_Obstacles[ob]->BRadius()); } //render the agents for (unsigned int a = 0; a < m_Vehicles.size(); ++a) { m_Vehicles[a]->Render(); //render cell partitioning stuff if (m_bShowCellSpaceInfo && a == 0) { gdi->HollowBrush(); InvertedAABBox2D box(m_Vehicles[a]->Pos() - Vector2D(Prm.ViewDistance, Prm.ViewDistance), m_Vehicles[a]->Pos() + Vector2D(Prm.ViewDistance, Prm.ViewDistance)); box.Render(); gdi->RedPen(); CellSpace()->CalculateNeighbors(m_Vehicles[a]->Pos(), Prm.ViewDistance); for (BaseGameEntity* pV = CellSpace()->begin(); !CellSpace()->end(); pV = CellSpace()->next()) { gdi->Circle(pV->Pos(), pV->BRadius()); } gdi->GreenPen(); gdi->Circle(m_Vehicles[a]->Pos(), Prm.ViewDistance); } } //#define CROSSHAIR #ifdef CROSSHAIR //and finally the crosshair gdi->RedPen(); gdi->Circle(m_vCrosshair, 4); gdi->Line(m_vCrosshair.x - 8, m_vCrosshair.y, m_vCrosshair.x + 8, m_vCrosshair.y); gdi->Line(m_vCrosshair.x, m_vCrosshair.y - 8, m_vCrosshair.x, m_vCrosshair.y + 8); gdi->TextAtPos(5, cyClient() - 20, "Click to move crosshair"); #endif //gdi->TextAtPos(cxClient() -120, cyClient() - 20, "Press R to reset"); gdi->TextColor(Cgdi::grey); if (RenderPath()) { gdi->TextAtPos((int)(cxClient() / 2.0f - 80), cyClient() - 20, "Press 'U' for random path"); m_pPath->Render(); } if (RenderFPS()) { gdi->TextColor(Cgdi::grey); gdi->TextAtPos(5, cyClient() - 20, ttos(1.0 / m_dAvFrameTime)); } if (m_bShowCellSpaceInfo) { m_pCellSpace->RenderCells(); } }
//---------------------- ObstacleAvoidance ------------------------------- // // Given a vector of CObstacles, this method returns a steering force // that will prevent the agent colliding with the closest obstacle //------------------------------------------------------------------------ Vector2D SteeringBehavior::ObstacleAvoidance() { //the detection box length is proportional to the agent's velocity float realBoxLength = m_dDBoxLength /* + (m_pMovingEntity->Speed()) * m_dDBoxLength */; //this will keep track of the closest intersecting obstacle (CIB) BaseGameEntity* ClosestIntersectingObstacle = NULL; //this will be used to track the distance to the CIB double DistToClosestIP = MaxDouble; //this will record the transformed local coordinates of the CIB Vector2D LocalPosOfClosestObstacle; std::set<Obstacle*>::const_iterator curOb = Obstacle::getAll().begin(), endOb = Obstacle::getAll().end(); while(curOb != endOb) { Obstacle* obst = (*curOb); Vector2D to = obst->Pos() - m_pMovingEntity->Pos(); //the bounding radius of the other is taken into account by adding it //to the range double range = realBoxLength + obst->BRadius(); //if entity within range, tag for further consideration. (working in //distance-squared space to avoid sqrts) if ((to.LengthSq() < range*range)) { //calculate this obstacle's position in local space Vector2D LocalPos = PointToLocalSpace(obst->Pos(), m_pMovingEntity->Heading(), m_pMovingEntity->Pos()); //if the local position has a negative x value then it must lay //behind the agent. (in which case it can be ignored) if (LocalPos.x >= 0) { //if the distance from the x axis to the object's position is less //than its radius + half the width of the detection box then there //is a potential intersection. double ExpandedRadius = obst->BRadius() + m_pMovingEntity->BRadius(); /*if (fabs(LocalPos.y) < ExpandedRadius) {*/ //now to do a line/circle intersection test. The center of the //circle is represented by (cX, cY). The intersection points are //given by the formula x = cX +/-sqrt(r^2-cY^2) for y=0. //We only need to look at the smallest positive value of x because //that will be the closest point of intersection. double cX = LocalPos.x; double cY = LocalPos.y; //we only need to calculate the sqrt part of the above equation once double SqrtPart = sqrt(ExpandedRadius*ExpandedRadius - cY*cY); double ip = cX - SqrtPart; if (ip <= 0.0) { ip = cX + SqrtPart; } //test to see if this is the closest so far. If it is keep a //record of the obstacle and its local coordinates if (ip < DistToClosestIP) { DistToClosestIP = ip; ClosestIntersectingObstacle = obst; LocalPosOfClosestObstacle = LocalPos; } } //} } ++curOb; } //if we have found an intersecting obstacle, calculate a steering //force away from it Vector2D SteeringForce; if (ClosestIntersectingObstacle) { //the closer the agent is to an object, the stronger the //steering force should be float multiplier = 1.0 + (m_dDBoxLength - LocalPosOfClosestObstacle.x) / m_dDBoxLength; //calculate the lateral force SteeringForce.y = (ClosestIntersectingObstacle->BRadius()- LocalPosOfClosestObstacle.y) * multiplier; //apply a braking force proportional to the obstacles distance from //the MovingEntity. const float BrakingWeight = 0.2f; SteeringForce.x = (ClosestIntersectingObstacle->BRadius() - LocalPosOfClosestObstacle.x) * BrakingWeight; } //finally, convert the steering vector from local to world space return VectorToWorldSpace(SteeringForce, m_pMovingEntity->Heading()); }
Vec2 SteeringForce::ObstacleAvoidance(const std::vector<BaseGameEntity *> obstacles) { m_dDBoxLength = m_pVehicle->getVeloctity().length()/m_pVehicle->getMaxSpeed()*40+40; //标记范围内的所有障碍物 GameData::Instance()->tagObstaclesWithinViewRange(m_pVehicle, m_dDBoxLength); //追踪最近相交的障碍物 BaseGameEntity *ClosestIntersectingObstacle = nullptr; //追踪到CIB的距离 double DistToClosestIP = MAXFLOAT; //记录CIB被转化的局部坐标 Vec2 LocalPosOfClosestObstacle; std::vector<BaseGameEntity*>::const_iterator curOb = obstacles.begin(); while (curOb!= obstacles.end()) { if ((*curOb)->isTagged()) { Vec2 LocalPos = m_pVehicle->convertToNodeSpaceAR((*curOb)->getPosition()); //如果举办空间位置有个负的x值,那么它肯定在智能体后面 if (LocalPos.x >=0) { //如果物体到x轴的距离小于它的半径+检查盒宽度的一半 //那么可能相交 double ExpandeRadius = (*curOb)->getContentSize().height/2*(*curOb)->getScale()+m_pVehicle->getContentSize().height/2; if (fabs(LocalPos.y)<ExpandeRadius) { //现在做线/圆周相交厕所吗 圆周圆心是(cx,cy); //相交点的公式是x = cx +(-sqrt( r*r - cY*cY)); //我们只需看x的最小值,因为那是最近的相交点 double cX = LocalPos.x; double cY = LocalPos.y; //我们只需一次计算上面等式的开方 double SqrtPart = sqrt(ExpandeRadius*ExpandeRadius-cY*cY); double ip = SqrtPart; if (ip<=0) { ip = cX+SqrtPart; } if (ip<DistToClosestIP) { DistToClosestIP = ip; ClosestIntersectingObstacle = *curOb; LocalPosOfClosestObstacle = LocalPos; } } } } ++curOb; } Vec2 SteeringForce; if (ClosestIntersectingObstacle) { //智能体越近,操控力越强 double muliplier =1 + (m_dDBoxLength-LocalPosOfClosestObstacle.x)/m_dDBoxLength; //计算侧向力 SteeringForce.y = (ClosestIntersectingObstacle->getContentSize().height/2*ClosestIntersectingObstacle->getScale()-LocalPosOfClosestObstacle.y)*muliplier; if (LocalPosOfClosestObstacle.y>0&&LocalPosOfClosestObstacle.y<ClosestIntersectingObstacle->getContentSize().height/2*ClosestIntersectingObstacle->getScale()) { SteeringForce.y = -SteeringForce.y; } //施加一个制动力,它正比于障碍物到交通工具的距离 const double BrakingWeight = 0.3; SteeringForce.x = (ClosestIntersectingObstacle->getContentSize().height/2*ClosestIntersectingObstacle->getScale()-LocalPosOfClosestObstacle.x)*BrakingWeight; } //最后,把操控向量换成世界坐标 // log("********SteeringForce:%f,%f*********",( m_pVehicle->convertToWorldSpaceAR(SteeringForce)-m_pVehicle->getPosition()).x,( m_pVehicle->convertToWorldSpaceAR(SteeringForce)-m_pVehicle->getPosition()).y); return m_pVehicle->convertToWorldSpaceAR(SteeringForce)-m_pVehicle->getPosition(); }
//---------------------- ObstacleAvoidance ------------------------------- // // Given a vector of CObstacles, this method returns a steering force // that will prevent the agent colliding with the closest obstacle //------------------------------------------------------------------------ Vector2D SteeringBehavior::ObstacleAvoidance(const std::vector<BaseGameEntity*>& obstacles) { //the detection box length is proportional to the agent's velocity m_dDBoxLength = Prm.MinDetectionBoxLength + (m_pVehicle->Speed() / m_pVehicle->MaxSpeed()) * Prm.MinDetectionBoxLength; //tag all obstacles within range of the box for processing m_pVehicle->World()->TagObstaclesWithinViewRange(m_pVehicle, m_dDBoxLength); //this will keep track of the closest intersecting obstacle (CIB) BaseGameEntity* ClosestIntersectingObstacle = NULL; //this will be used to track the distance to the CIB double DistToClosestIP = MaxDouble; //this will record the transformed local coordinates of the CIB Vector2D LocalPosOfClosestObstacle; std::vector<BaseGameEntity*>::const_iterator curOb = obstacles.begin(); while (curOb != obstacles.end()) { //if the obstacle has been tagged within range proceed if ((*curOb)->IsTagged()) { //calculate this obstacle's position in local space Vector2D LocalPos = PointToLocalSpace((*curOb)->Pos(), m_pVehicle->Heading(), m_pVehicle->Side(), m_pVehicle->Pos()); //if the local position has a negative x value then it must lay //behind the agent. (in which case it can be ignored) if (LocalPos.x >= 0) { //if the distance from the x axis to the object's position is less //than its radius + half the width of the detection box then there //is a potential intersection. double ExpandedRadius = (*curOb)->BRadius() + m_pVehicle->BRadius(); if (fabs(LocalPos.y) < ExpandedRadius) { //now to do a line/circle intersection test. The center of the //circle is represented by (cX, cY). The intersection points are //given by the formula x = cX +/-sqrt(r^2-cY^2) for y=0. //We only need to look at the smallest positive value of x because //that will be the closest point of intersection. double cX = LocalPos.x; double cY = LocalPos.y; //we only need to calculate the sqrt part of the above equation once double SqrtPart = sqrt(ExpandedRadius*ExpandedRadius - cY*cY); double ip = cX - SqrtPart; if (ip <= 0.0) { ip = cX + SqrtPart; } //test to see if this is the closest so far. If it is keep a //record of the obstacle and its local coordinates if (ip < DistToClosestIP) { DistToClosestIP = ip; ClosestIntersectingObstacle = *curOb; LocalPosOfClosestObstacle = LocalPos; } } } } ++curOb; } //if we have found an intersecting obstacle, calculate a steering //force away from it Vector2D SteeringForce; if (ClosestIntersectingObstacle) { //the closer the agent is to an object, the stronger the //steering force should be double multiplier = 1.0 + (m_dDBoxLength - LocalPosOfClosestObstacle.x) / m_dDBoxLength; //calculate the lateral force SteeringForce.y = (ClosestIntersectingObstacle->BRadius() - LocalPosOfClosestObstacle.y) * multiplier; //apply a braking force proportional to the obstacles distance from //the vehicle. const double BrakingWeight = 0.2; SteeringForce.x = (ClosestIntersectingObstacle->BRadius() - LocalPosOfClosestObstacle.x) * BrakingWeight; } //finally, convert the steering vector from local to world space return VectorToWorldSpace(SteeringForce, m_pVehicle->Heading(), m_pVehicle->Side()); }
void Human::DrawExtraInfo() { #ifdef AI_TEST_DISPLAY_HUMAN_STATE //--------- //sk test /*/ //좌표 보정전 gui::IGUIFont* font2 = IrrDvc.GetDevice()->getGUIEnvironment()->getBuiltInFont(); u32 time = IrrDvc.GetDevice()->getTimer()->getTime(); core::stringw temp; temp = core::stringw(time).c_str(); //숫자를 stringw로 변환하는 루틴 u32 coordposX = Pos().X; u32 coordposY = Pos().Y; if (font2) font2->draw(temp,core::rect<s32>(coordposX,coordposY,coordposX+50,coordposY+60), video::SColor(255,time % 255,time % 255,255)); /*/ //좌표 보정 후 std::vector<BaseGameEntity*> enties = EntityMgr.GetEntityListFromGroupID(ENTITY_TYPE_VEHICLE); std::vector<BaseGameEntity*>::iterator iter = enties.begin(); // find out close vehicle, but now just get first vehicle.... BaseGameEntity* pTargetEntity = *iter; m_uDifferenceXOrgFugtivePlayer = m_uScreenHalfWidth - pTargetEntity->Pos().X * LOCALCOORD_SCREENCOORD_RATIO;//need optimization. change to once call. m_uDifferenceYOrgFugtivePlayer = m_uScreenHalfHeight + pTargetEntity->Pos().Y * LOCALCOORD_SCREENCOORD_RATIO;//need optimization. change to once call. /* m_uDifferenceXOrgFugtivePlayer = m_uScreenHalfWidth - Pos().X * LOCALCOORD_SCREENCOORD_RATIO;//need optimization. change to once call. m_uDifferenceYOrgFugtivePlayer = m_uScreenHalfHeight + Pos().Y * LOCALCOORD_SCREENCOORD_RATIO;//need optimization. change to once call. */ gui::IGUIFont* font2 = IrrDvc.GetDevice()->getGUIEnvironment()->getBuiltInFont(); u32 time = IrrDvc.GetDevice()->getTimer()->getTime(); core::stringw temp; u32 coordposX = m_uDifferenceXOrgFugtivePlayer + Pos().X * LOCALCOORD_SCREENCOORD_RATIO; u32 coordposY = m_uDifferenceYOrgFugtivePlayer - Pos().Y * LOCALCOORD_SCREENCOORD_RATIO; core::stringw prefix; if (font2) { temp = core::stringw(time).c_str(); //숫자를 stringw로 변환하는 루틴 font2->draw(temp,core::rect<s32>(coordposX,coordposY,coordposX+50,coordposY+60), video::SColor(255,time % 255,time % 255,255)); temp = GetStateName(); prefix = "state:"; font2->draw(prefix+temp,core::rect<s32>(coordposX,coordposY+10,coordposX+50,coordposY+60), video::SColor(255,time % 255,time % 255,255)); temp = core::stringw(m_fCurrentLifeEnergy).c_str(); //숫자를 stringw로 변환하는 루틴 prefix = "E:"; font2->draw(prefix+temp,core::rect<s32>(coordposX,coordposY+20,coordposX+50,coordposY+60), video::SColor(255,time % 255,time % 255,255)); } #endif //AI_TEST_DISPLAY_HUMAN_STATE //*/ //-------- }