void CCameraFlight::DetectCollisions() { primitives::sphere sph; sph.r = 0.15f; sph.center = m_vTargetFadePos + m_vLookingDirection * RAY_SCAN_DISTANCE; CCameraRayScan *pRayScan = g_pGame->GetCameraManager()->GetCamView()->GetCamRayScan(); if (m_RayId == INVALID_RAY_ID) { m_RayId = pRayScan->ShootRay(sph.center, -m_vLookingDirection * RAY_SCAN_DISTANCE, ent_all & ~(ent_living | ent_independent | ent_rigid), geom_colltype0); } const RayCastResult* pRayRes = pRayScan->GetExternalHit(m_RayId); const ray_hit *pHit = pRayRes->hitCount > 0 ? &pRayRes->hits[0] : NULL; static int iNumHits = 0; if(pHit && pHit->dist > 0.0f) { iNumHits++; if(iNumHits > 2) { bool bIgnore = false; IPhysicalEntity *pPhysEntity = pHit->pCollider; if(pPhysEntity) { int iForeignData = pPhysEntity->GetiForeignData(); if (iForeignData == PHYS_FOREIGN_ID_STATIC) { //check whether the hit rendernode is "vegetation" void *pForeignData = pPhysEntity->GetForeignData(PHYS_FOREIGN_ID_STATIC); IRenderNode * pRN = (IRenderNode*)pForeignData; if(pRN && pRN->GetRenderNodeType() == eERType_Vegetation) bIgnore = true; } else if(iForeignData == PHYS_FOREIGN_ID_ENTITY) { IEntity *pEntity = gEnv->pEntitySystem->GetEntityFromPhysics(pPhysEntity); if(pEntity && (pEntity == m_pRefEnt || pEntity->GetId() == LOCAL_PLAYER_ENTITY_ID)) bIgnore = true; } else if(iForeignData == -1) bIgnore = true; } if(!bIgnore) m_vTargetFadePos = m_vTargetFadePos + m_vLookingDirection * max(0.0f, (RAY_SCAN_DISTANCE - pHit->dist)); else iNumHits = 0; } } else iNumHits = 0; if (pRayRes) { pRayScan->RemoveExternalHit(m_RayId); m_RayId = INVALID_RAY_ID; } }
void CDeflectorShield::ProcessCollision(const EventPhysCollision& pCollision) { int id = 0; IPhysicalEntity* pTarget = pCollision.pEntity[id]; if (pTarget == GetEntity()->GetPhysics()) { id = 1; pTarget = pCollision.pEntity[id]; } IEntity* pTargetEntity = (IEntity*)pTarget->GetForeignData(PHYS_FOREIGN_ID_ENTITY); if (pTargetEntity == 0) return; CProjectile* pProjectile = g_pGame->GetWeaponSystem()->GetProjectile(pTargetEntity->GetId()); if (pProjectile) ProcessProjectile(pProjectile, pCollision.pt, pCollision.n, pCollision.vloc[id].GetNormalized()); }
//------------------------------------------------------------------------ IEntity *CWorkOnTarget::CanWork() { static Vec3 pos,dir; static ICVar* pAimDebug = gEnv->pConsole->GetCVar("g_aimdebug"); CActor *pActor=m_pWeapon->GetOwnerActor(); static IPhysicalEntity* pSkipEntities[10]; int nSkip = CSingle::GetSkipEntities(m_pWeapon, pSkipEntities, 10); IEntity *pEntity=0; float range=m_workparams.range; IMovementController * pMC = pActor ? pActor->GetMovementController() : 0; if (pMC) { SMovementState info; pMC->GetMovementState(info); pos = info.weaponPosition; if (!pActor->IsPlayer()) { dir = range * (info.fireTarget-pos).normalized(); } else { dir = range * info.fireDirection; // marcok: leave this alone if (g_pGameCVars->goc_enable && pActor->IsClient()) { CPlayer *pPlayer = (CPlayer*)pActor; pos = pPlayer->GetViewMatrix().GetTranslation(); } } } else { assert(0); } primitives::sphere sphere; sphere.center = pos; sphere.r = m_workparams.radius; Vec3 end = pos+dir; geom_contact *pContact=0; float dst=gEnv->pPhysicalWorld->PrimitiveWorldIntersection(sphere.type, &sphere, end-sphere.center, ent_all, &pContact, 0, (geom_colltype_player<<rwi_colltype_bit)|rwi_stop_at_pierceable, 0, 0, 0, pSkipEntities, nSkip); if (pContact && dst>=0.0f) { IPhysicalEntity *pCollider = gEnv->pPhysicalWorld->GetPhysicalEntityById(pContact->iPrim[0]); if(pCollider && pCollider->GetiForeignData() == PHYS_FOREIGN_ID_ENTITY) { if (pEntity = static_cast<IEntity *>(pCollider->GetForeignData(PHYS_FOREIGN_ID_ENTITY))) { if (CGameRules *pGameRules=g_pGame->GetGameRules()) { if (IScriptTable *pScriptTable=pGameRules->GetEntity()->GetScriptTable()) { HSCRIPTFUNCTION pfnCanWork=0; if (pScriptTable->GetValueType("CanWork")==svtFunction && pScriptTable->GetValue("CanWork", pfnCanWork)) { bool result=false; Script::CallReturn(gEnv->pScriptSystem, pfnCanWork, pScriptTable, ScriptHandle(pEntity->GetId()), ScriptHandle(m_pWeapon->GetOwnerId()), m_workparams.work_type.c_str(), result); gEnv->pScriptSystem->ReleaseFunc(pfnCanWork); if (result) return pEntity; } } } } } } return 0; }
void Update(float elapsed) { float maxTime = GetPortFloat(&m_actInfo, EIP_Duration); float percent = maxTime > FLT_EPSILON ? elapsed / maxTime : 1.0f; if(percent >= 1.0f) { m_actInfo.pGraph->SetRegularlyUpdated(m_actInfo.myID, false); m_triggered = false; return; } Vec3 N = GetPortVec3(&m_actInfo, EIP_Normal); float rangeMin = GetPortFloat(&m_actInfo, EIP_RangeMin); float rangeMax = GetPortFloat(&m_actInfo, EIP_RangeMax); const float range = rangeMax - rangeMin; Vec3 boxDim(rangeMax, rangeMax, rangeMax); Vec3 ptmin = m_effectCenter - boxDim; Vec3 ptmax = m_effectCenter + boxDim; float speed = GetPortFloat(&m_actInfo, EIP_Speed); float waveFront = elapsed * speed; float decay = GetPortFloat(&m_actInfo, EIP_Decay); if(decay > FLT_EPSILON) decay = 1.0f / decay; float force = GetPortFloat(&m_actInfo, EIP_Force); force = pow_tpl(force * (1-percent), decay); float amplitude = GetPortFloat(&m_actInfo, EIP_Amplitude); amplitude = pow_tpl(amplitude * (1-percent), decay); if (gEnv->bMultiplayer) // Turned off for performance and network issues { return; } IPhysicalEntity** pEntityList = NULL; static const int iObjTypes = ent_rigid | ent_sleeping_rigid | ent_living;// | ent_allocate_list; int numEntities = gEnv->pPhysicalWorld->GetEntitiesInBox(ptmin, ptmax, pEntityList, iObjTypes); AABB bounds; for(int i=0; i<numEntities; ++i) { IPhysicalEntity* pPhysicalEntity = pEntityList[i]; IEntity* pEntity = static_cast<IEntity*>(pPhysicalEntity->GetForeignData(PHYS_FOREIGN_ID_ENTITY)); // Has the entity already been affected? if(pEntity) { bool affected = stl::find(m_entitiesAffected, pEntity->GetId()); if(!affected) { IEntityPhysicalProxy* pPhysicalProxy = static_cast<IEntityPhysicalProxy*>(pEntity->GetProxy(ENTITY_PROXY_PHYSICS)); if(pPhysicalProxy) { pPhysicalProxy->GetWorldBounds(bounds); Vec3 p = bounds.GetCenter(); Vec3 v = p - m_effectCenter; float distFromCenter = v.GetLength() + FLT_EPSILON; if(distFromCenter < rangeMax) { if(waveFront > distFromCenter) // has the wavefront passed the entity? { //pPhysicalEntity->GetStatus(&dyn); // normalize v, cheaper than another sqrt v /= distFromCenter; Vec3 dir = N + v * force; static bool usePos = false; float impulse = 1.0f - (max(0.0f, distFromCenter - rangeMin) / range); impulse = impulse * amplitude;// / dyn.mass; if(impulse > FLT_EPSILON) { pPhysicalProxy->AddImpulse(-1, p, dir * impulse, usePos, 1.0f); m_entitiesAffected.push_back(pEntity->GetId()); } } } } } } } }
//-------------------------------------------------------------------------------------------------- // Name: HandleImpact // Desc: Passes an impact on to the simulation //-------------------------------------------------------------------------------------------------- int CBreakableGlassSystem::HandleImpact(const EventPhys* pPhysEvent) { if (CCryAction* pCryAction = CCryAction::GetCryAction()) { if (CBreakableGlassSystem* pGlassSystem = static_cast<CBreakableGlassSystem*>(pCryAction->GetIBreakableGlassSystem())) { pGlassSystem->AssertUnusedIfDisabled(); if (pGlassSystem->m_enabled) { if (const EventPhysCollision* pCollEvent = static_cast<const EventPhysCollision*>(pPhysEvent)) { // Glass fragments always get destroyed on their first collision const uint physFrag = (pCollEvent->iForeignData[0] == PHYS_FOREIGN_ID_BREAKABLE_GLASS_FRAGMENT) ? 0 : 1; IPhysicalEntity* pPhysEnt = pCollEvent->pEntity[physFrag]; if (pPhysEnt && pCollEvent->iForeignData[physFrag] == PHYS_FOREIGN_ID_BREAKABLE_GLASS_FRAGMENT) { // Fragments only collide with non-glass geometry const int nonFragType = pCollEvent->iForeignData[1-physFrag]; if (nonFragType != PHYS_FOREIGN_ID_BREAKABLE_GLASS && nonFragType != PHYS_FOREIGN_ID_BREAKABLE_GLASS_FRAGMENT && nonFragType != PHYS_FOREIGN_ID_ENTITY) // Only break on floors, walls, etc. { // Verify parent glass node, then allow it to handle impact if (SGlassPhysFragment* pPhysFrag = (SGlassPhysFragment*)pCollEvent->pForeignData[physFrag]) { if (IBreakableGlassRenderNode* pRenderNode = (IBreakableGlassRenderNode*)pPhysFrag->m_pRenderNode) { pRenderNode->DestroyPhysFragment(pPhysFrag); } } } } else if (pCollEvent->iForeignData[PHYSEVENT_COLLIDEE] == PHYS_FOREIGN_ID_BREAKABLE_GLASS) { // Get breakable glass data PodArray<IBreakableGlassRenderNode*>& glassPlanes = pGlassSystem->m_glassPlanes; const int numPlanes = glassPlanes.Count(); // Duplicate event so we can freely manipulate it EventPhysCollision dupeEvent = *pCollEvent; const EventPhysCollision* pDupeEvent = (const EventPhysCollision*)&dupeEvent; // Some actors can force breaks for gameplay reasons IPhysicalEntity* pCollider = dupeEvent.pEntity[PHYSEVENT_COLLIDER]; if (pCollider && pCollider->GetType() == PE_LIVING) { IEntity* pColliderEntity = (IEntity*)pCollider->GetForeignData(PHYS_FOREIGN_ID_ENTITY); IActor* pActor = pColliderEntity ? gEnv->pGame->GetIGameFramework()->GetIActorSystem()->GetActor(pColliderEntity->GetId()) : NULL; if (pActor && pActor->MustBreakGlass()) { pGlassSystem->ModifyEventToForceBreak(&dupeEvent); } } // Verify glass node and pass impact through IBreakableGlassRenderNode* pRenderNode = (IBreakableGlassRenderNode*)pCollEvent->pForeignData[PHYSEVENT_COLLIDEE]; const int targetId = pRenderNode ? pRenderNode->GetId() : numPlanes; if (targetId < numPlanes && pRenderNode == glassPlanes[targetId]) { pGlassSystem->PassImpactToNode(pRenderNode, pDupeEvent); } } } } } } return 1; // Pass event to other handlers even if we processed it }//-------------------------------------------------------------------------------------------------