void CEnvironmentSim::Simulate(double dTimeDelta) { if(dTimeDelta<=0) return; CSceneObject* pScene = CGlobals::GetScene(); if((pScene == NULL) || pScene->IsScenePaused() || (!(pScene->IsSceneEnabled())) ) return; // physics engine frame move. CGlobals::GetPhysicsWorld()->StepSimulation(dTimeDelta); /** advance the game time */ g_gameTime.FrameMoveDelta((float)dTimeDelta); // advance time of day pScene->GetSunLight().AdvanceTimeOfDay((float)dTimeDelta); /** Check load physics around the current player and the camera position * this is very game specific. It only ensures that physics object around the current player and camera is loaded. */ CBipedObject* pPlayer = pScene->GetCurrentPlayer(); int nPointCount = 0; CShapeSphere points[2]; if(pPlayer) { points[nPointCount].Set(pPlayer->GetPosition(), pPlayer->GetPhysicsRadius()*2.f); nPointCount++; } if(pScene->GetCurrentCamera()) { points[nPointCount].Set(pScene->GetCurrentCamera()->GetEyePosition(), pScene->GetCurrentCamera()->GetNearPlane()*2); nPointCount++; } CheckLoadPhysics(points, nPointCount); UpdateGameObjects(dTimeDelta); { PERF1("EnvSim::Frame Move Sentient Objects"); for (auto itCur = pScene->GetSentientObjects().begin(); itCur != pScene->GetSentientObjects().end();) { IGameObject* pObj = (*itCur); if (!pObj) { itCur = pScene->GetSentientObjects().erase(itCur); OUTPUT_LOG("warn: invalid weak ref found in pScene->GetSentientObjects()\n"); continue; } else { itCur++; } if(pObj->GetSimTag() != SIM_TAG_FINISHED) { pScene->SetCurrentActor((CBaseObject*)pObj); if(pObj->GetSimTag() == SIM_TAG_START) { // generate way points pObj->PathFinding(dTimeDelta); // move the biped according to way point commands pObj->AnimateBiped(dTimeDelta); } // apply AI controller if(pObj->GetAIModule()) pObj->GetAIModule()->FrameMove((float)dTimeDelta); if(!pObj->GetPerceiveList().empty()) pObj->On_Perception(); // call the frame move script if any. pObj->On_FrameMove(); pObj->SetSimTag(SIM_TAG_FINISHED); if(pObj->HasReferences()) { RefList::iterator itCur, itEnd = pObj->GetRefList().end(); for (itCur = pObj->GetRefList().begin(); itCur!=itEnd; ++itCur) { if(itCur->m_tag == 0) { IGameObject* pRefObj = ((CBaseObject*)((*itCur).m_object))->QueryIGameObject(); if(pRefObj!=0 && !pRefObj->IsSentient() && pRefObj->IsGlobal() && (pRefObj->GetSimTag() == SIM_TAG_START)) { ////////////////////////////////////////////////////////////////////////// // update reference object in the terrain tile according to its current position Vector3 vPos = pRefObj->GetPosition(); CTerrainTile * pTile = pScene->GetRootTile()->GetTileByPoint(vPos.x, vPos.z); if(pTile != NULL) { pRefObj->SetTileContainer(pTile); } ////////////////////////////////////////////////////////////////////////// // basic simulation: path finding, etc. pScene->SetCurrentActor((CBaseObject*)pRefObj); // generate way points pRefObj->PathFinding(dTimeDelta); // move the biped according to way point commands pRefObj->AnimateBiped(dTimeDelta); pRefObj->SetSimTag(SIM_TAG_BASIC); } } } } } } if(CGlobals::WillGenReport()) { CGlobals::GetReport()->SetValue("sentient objects", (int)pScene->GetSentientObjects().size()); } } /// frame move each unexploded missile objects. { for (auto pMissile : pScene->GetMissiles()) { if( !pMissile->IsExploded() ) { pMissile->Animate(dTimeDelta); } } } }
// 2007.8.27: logic changes: the current player is always sentient to all other objects and all other objects are sentient to the current player. void CEnvironmentSim::UpdateGameObjects(double dTimeDelta) { PERF1("EnvSim::UpdateGameObjects"); CSceneObject* pScene = CGlobals::GetScene(); CTerrainTile* duplicateTiles[9]; for (int i = 0;i < (int)pScene->GetSentientObjects().size(); ) { // for each sentient game objects (sentientObj) in the scene IGameObject* sentientObj = pScene->GetSentientObjects()[i]; if (!sentientObj) { pScene->GetSentientObjects().erase(i); OUTPUT_LOG("warn: invalid weak ref found in pScene->GetSentientObjects()\n"); continue; } sentientObj->SetSentientObjCount(0); sentientObj->GetPerceiveList().clear(); Vector3 vPos = sentientObj->GetPosition(); Vector2 vec2Pos(vPos.x, vPos.z); // update itself in the terrain tile according to its current position: CTerrainTile * pTile = pScene->GetRootTile()->GetTileByPoint(vPos.x, vPos.z); if(pTile != NULL) { sentientObj->SetTileContainer(pTile); for(int k=0;k<9;++k) duplicateTiles[k]=NULL; //for each valid terrain tiles(9 or more) in the neighborhood of sentientObj for (int i=0; i<9;++i) { CTerrainTile* pTileAdjacent = pScene->GetRootTile()->GetAdjacentTile(vPos, (CTerrainTileRoot::DIRECTION)i); if(pTileAdjacent!=NULL) { // check if pTile is a new tile that has not been processed by the current sentient object. bool bNewAdjacentTile = true; if((pTileAdjacent==sentientObj->GetTileContainer()) || pTileAdjacent->m_fRadius != sentientObj->GetTileContainer()->m_fRadius) { for(int k=0;k<9 && (duplicateTiles[k]!=NULL);++k) { if(duplicateTiles[k] == pTileAdjacent){ bNewAdjacentTile = false; break; } } } if(bNewAdjacentTile) { { VisitorList_type::iterator itCurCP, itEndCP = pTileAdjacent->m_listVisitors.end(); for( itCurCP = pTileAdjacent->m_listVisitors.begin(); itCurCP != itEndCP;) { IGameObject* AnotherObj = (*itCurCP); if (AnotherObj != nullptr) { if (AnotherObj != sentientObj) { Vector3 vPosAnother = AnotherObj->GetPosition(); Vector2 vec2PosAnother(vPosAnother.x, vPosAnother.z); float fDistSq = (vec2PosAnother - vec2Pos).squaredLength(); if (!AnotherObj->IsSentient()) { //if sentientObj falls inside the sentient area of AnotherObj if ((AnotherObj->IsSentientWith(sentientObj)) && fDistSq <= AnotherObj->GetSentientRadius()*AnotherObj->GetSentientRadius()){ pScene->AddSentientObject(AnotherObj); } } //if AnotherObj falls inside the sentient area of sentientObj if ((sentientObj->IsSentientWith(AnotherObj)) && fDistSq <= sentientObj->GetSentientRadius()*sentientObj->GetSentientRadius()) { sentientObj->SetSentientObjCount(sentientObj->GetSentientObjCount() + 1); // if AnotherObj falls inside the perceptive area of sentientObj if (fDistSq <= sentientObj->GetPerceptiveRadius()*sentientObj->GetPerceptiveRadius()) { sentientObj->GetPerceiveList().push_back(AnotherObj->GetIdentifier()); } } } ++itCurCP; } else itCurCP = pTileAdjacent->m_listVisitors.erase(itCurCP); } } // skip solid object on the root tile, since they are all global objects, not static objects. if(pTileAdjacent!=pScene->GetRootTile()) { // check collision with other static solid objects. for (auto pObject : pTileAdjacent->m_listSolidObj) { IGameObject* AnotherObj = pObject->QueryIGameObject(); if(AnotherObj!=NULL && AnotherObj!=sentientObj && sentientObj->IsSentientWith(AnotherObj) ) { Vector3 vPosAnother = AnotherObj->GetPosition(); Vector2 vec2PosAnother(vPosAnother.x, vPosAnother.z); float fDistSq = (vec2PosAnother-vec2Pos).squaredLength(); //if AnotherObj falls inside the sentient area of sentientObj if(fDistSq<= sentientObj->GetSentientRadius()*sentientObj->GetSentientRadius()) { sentientObj->SetSentientObjCount(sentientObj->GetSentientObjCount()+1); // if AnotherObj falls inside the perceptive area of sentientObj if(fDistSq<= sentientObj->GetPerceptiveRadius()*sentientObj->GetPerceptiveRadius()) { sentientObj->GetPerceiveList().push_back(AnotherObj->GetIdentifier()); } } } } } for(int k=0;k<9;++k) { if(duplicateTiles[k]==NULL) { duplicateTiles[k] = pTileAdjacent; break; } } }//if(bNewAdjacentTile) } } } if(sentientObj->GetSentientObjCount()>0 || sentientObj->IsAlwaysSentient()) { ++i; { // set the simulation tag of all sentient objects and their referenced objects to SIM_TAG_START state. sentientObj->SetSimTag(SIM_TAG_START); if(sentientObj->HasReferences()) { RefList::iterator itCur, itEnd = sentientObj->GetRefList().end(); for (itCur = sentientObj->GetRefList().begin(); itCur!=itEnd; ++itCur) { if(itCur->m_tag == 0) { IGameObject* pRefObj = ((CBaseObject*)((*itCur).m_object))->QueryIGameObject(); if(pRefObj!=0) { pRefObj->SetSimTag(SIM_TAG_START); } } } } } // call on perceived now or in the next pass. } else { sentientObj->On_LeaveSentientArea(); pScene->GetSentientObjects().erase(i); } } }