//------------------------------------------------------------------------ void CDebugGun::Shoot(bool bPrimary) { CWeapon::StartFire(); // console cmd string cmd; cmd = (bPrimary) ? g_pGameCVars->i_debuggun_1->GetString() : g_pGameCVars->i_debuggun_2->GetString(); cmd += " "; unsigned int flags = rwi_stop_at_pierceable|rwi_colltype_any; if (m_fireModes[m_fireMode].first == "pierceability") { flags = (unsigned int)m_fireModes[m_fireMode].second & rwi_pierceability_mask; } IPhysicalWorld* pWorld = gEnv->pPhysicalWorld; IPhysicalEntity *pSkip = GetOwnerActor()->GetEntity()->GetPhysics(); ray_hit rayhit; CCamera& cam = GetISystem()->GetViewCamera(); Vec3 pos = cam.GetPosition()+cam.GetViewdir(); Vec3 dir = cam.GetViewdir() * HIT_RANGE; IEntity* pEntity = 0; if (pWorld->RayWorldIntersection(pos, dir, ent_all, flags, &rayhit, 1, &pSkip, 1)) { pEntity = (IEntity*)rayhit.pCollider->GetForeignData(PHYS_FOREIGN_ID_ENTITY); } cmd.append(pEntity ? pEntity->GetName() : "0"); // if we execute an AI command take care of ai_debugdraw if (cmd.substr(0, 3) == "ai_") { if (pEntity && m_pAIDebugDraw->GetIVal() == 0) m_pAIDebugDraw->Set(1); else if(!pEntity && m_aiDebugDrawPrev == 0 && m_pAIDebugDraw->GetIVal() == 1) m_pAIDebugDraw->Set(0); } gEnv->pConsole->ExecuteString(cmd.c_str()); // if 2nd button hits a vehicle, enable movement profiling if (!bPrimary) { static IVehicleSystem* pVehicleSystem = g_pGame->GetIGameFramework()->GetIVehicleSystem(); string vehicleCmd = "v_debugVehicle "; vehicleCmd.append((pEntity && pVehicleSystem->GetVehicle(pEntity->GetId())) ? pEntity->GetName() : "0"); gEnv->pConsole->ExecuteString(vehicleCmd.c_str()); } OnShoot(GetOwnerId(), 0, 0, pos, dir, Vec3(ZERO)); }
void OnUpdate( SActivationInfo* pActInfo ) { const Vec3 positionOffsetLocal = GetPortVec3( pActInfo, PORT_IN_POSITION_OFFSET_LOCAL ); const float maxDistance = max( 0.f, GetPortFloat( pActInfo, PORT_IN_MAX_LENGTH ) ); const CCamera& camera = GetISystem()->GetViewCamera(); const Vec3 cameraDirection = camera.GetViewdir(); const Vec3 cameraPositionWorld = camera.GetPosition(); const Matrix33 cameraOrientation = Matrix33::CreateRotationVDir( cameraDirection ); const Vec3 positionOffsetWorld = cameraOrientation * positionOffsetLocal; const Vec3 rayOriginWorld = cameraPositionWorld + positionOffsetWorld; const Vec3 raySegment = cameraDirection * maxDistance; IPhysicalWorld* pWorld = gEnv->pPhysicalWorld; const int objectTypes = ent_all; const unsigned int raycastFlags = rwi_stop_at_pierceable | rwi_colltype_any; ray_hit hit; const int hitCount = pWorld->RayWorldIntersection( rayOriginWorld, raySegment, objectTypes, raycastFlags, &hit, 1 ); float hitDistance = maxDistance; if ( 0 < hitCount ) { hitDistance = hit.dist; } const float timeDelta = 0.1f; const float smoothTime = max( 0.f, GetPortFloat( pActInfo, PORT_IN_SMOOTH_TIME ) ); SmoothCD( m_smoothedHitDistance, m_hitDistanceChangeRate, timeDelta, hitDistance, smoothTime ); ActivateOutput( pActInfo, PORT_OUT_FOCUS_DISTANCE, m_smoothedHitDistance ); const float focusRangeFactor = max( 0.f, GetPortFloat( pActInfo, PORT_IN_FOCUS_RANGE_FACTOR ) ); const float focusRange = focusRangeFactor * m_smoothedHitDistance; ActivateOutput( pActInfo, PORT_OUT_FOCUS_RANGE, focusRange ); const bool drawDebugInfo = GetPortBool( pActInfo, PORT_IN_DEBUG_ENABLED ); if ( ! drawDebugInfo ) { return; } IRenderer* pRenderer = gEnv->pRenderer; IRenderAuxGeom* pRenderAuxGeom = pRenderer->GetIRenderAuxGeom(); ColorB rayColor = ( 0 < hitCount ) ? ColorB( 255, 255, 0 ) : ColorB( 255, 0, 0 ); pRenderAuxGeom->DrawSphere( hit.pt, 0.1f, rayColor ); pRenderAuxGeom->DrawLine( rayOriginWorld, rayColor, hit.pt, rayColor ); }
int CScriptBind_Physics::SamplePhysEnvironment(IFunctionHandler *pH) { int nEnts,i,nHits=0,objtypes = ent_static|ent_rigid|ent_sleeping_rigid|ent_sort_by_mass; pe_status_nparts snp; pe_status_pos sp; IPhysicalEntity **pEnts; geom_world_data gwd; IGeometry *pSphere; primitives::sphere sph; intersection_params ip; geom_contact *pcontacts; IPhysicalWorld *pWorld = m_pSystem->GetIPhysicalWorld(); IEntity *pEntity; SmartScriptTable pObj(m_pSS); ip.bStopAtFirstTri=ip.bNoBorder=ip.bNoAreaContacts = true; ip.bThreadSafe = true; if (!pH->GetParams(sph.center,sph.r)) return pH->EndFunction(); if (pH->GetParamCount()>2) pH->GetParam(3,objtypes); pSphere = pWorld->GetGeomManager()->CreatePrimitive(primitives::sphere::type,&sph); nEnts = pWorld->GetEntitiesInBox(sph.center-Vec3(sph.r),sph.center+Vec3(sph.r),pEnts,objtypes); for(i=0;i<nEnts;i++) for(sp.ipart=pEnts[i]->GetStatus(&snp)-1;sp.ipart>=0;sp.ipart--) { sp.partid=-1; pEnts[i]->GetStatus(&sp); gwd.offset=sp.pos; gwd.R=Matrix33(sp.q); gwd.scale=sp.scale; WriteLockCond lock; if ((sp.flagsOR & (geom_colltype0|geom_no_coll_response))==geom_colltype0 && sp.pGeomProxy->IntersectLocked(pSphere,&gwd,0,&ip,pcontacts,lock)) { ++nHits; if (pEntity = (IEntity*)pEnts[i]->GetForeignData(PHYS_FOREIGN_ID_ENTITY)) pObj->SetAt(nHits*3-2, pEntity->GetScriptTable()); else pObj->SetNullAt(nHits*3-2); pObj->SetAt(nHits*3-1, sp.partid); pObj->SetAt(nHits*3, pWorld->GetPhysicalEntityId(pEnts[i])); if (pEnts[i]->GetType()!=PE_ARTICULATED) break; } } pSphere->Release(); return pH->EndFunction(*pObj); }
virtual void OnIterStart(SActivationInfo *pActInfo) { const int type = GetPortInt(pActInfo, EIP_Type); const Vec3& min(GetPortVec3(pActInfo, EIP_Min)); const Vec3& max(GetPortVec3(pActInfo, EIP_Max)); IPhysicalWorld *pWorld = gEnv->pPhysicalWorld; IPhysicalEntity **ppList = NULL; int numEnts = pWorld->GetEntitiesInBox(min,max,ppList,ent_all); for (int i = 0; i < numEnts; ++i) { const EntityId id = pWorld->GetPhysicalEntityId(ppList[i]); const EEntityType entityType = GetEntityType(id); if (IsValidType(type, entityType)) { AddEntity(id); } } }
int CParachute::AddCel(IPhysicalEntity* pPhysics, int _iID,SWing *_pCel) { IPhysicalWorld *pPhysicalWorld = gEnv->pPhysicalWorld; primitives::box geomBox; geomBox.Basis = Matrix33::CreateRotationXYZ(Ang3(DEG2RAD(_pCel->fAngleX),DEG2RAD(_pCel->fAngleY),0.0f)); geomBox.bOriented = 1; geomBox.center.Set(0.0f,0.0f,0.0f); geomBox.size = _pCel->vSize; IGeometry *pGeom = pPhysicalWorld->GetGeomManager()->CreatePrimitive(primitives::box::type,&geomBox); phys_geometry *physGeom = pPhysicalWorld->GetGeomManager()->RegisterGeometry(pGeom); pGeom->Release(); pe_geomparams partpos; partpos.pos = _pCel->vPos; partpos.mass = _pCel->fMass; int id = pPhysics->AddGeometry(physGeom,&partpos); pPhysicalWorld->GetGeomManager()->UnregisterGeometry(physGeom); return id; }
virtual void OnIterStart(SActivationInfo *pActInfo) { const int type = GetPortInt(pActInfo, EIP_Type); const Vec3& center(GetPortVec3(pActInfo, EIP_Pos)); const float range = GetPortFloat(pActInfo, EIP_Range); const float rangeSq = range * range; const Vec3 min(center.x-range, center.y-range, center.z-range); const Vec3 max(center.x+range, center.y+range, center.z+range); IPhysicalWorld *pWorld = gEnv->pPhysicalWorld; IPhysicalEntity **ppList = NULL; int numEnts = pWorld->GetEntitiesInBox(min,max,ppList,ent_all); for (int i = 0; i < numEnts; ++i) { const EntityId id = pWorld->GetPhysicalEntityId(ppList[i]); const EEntityType entityType = GetEntityType(id); if (IsValidType(type, entityType)) { AddEntity(id); } } }
virtual void ProcessEvent( EFlowEvent event, SActivationInfo *pActInfo ) { if (event == eFE_Activate && IsPortActive(pActInfo, GO)) { IEntity * pEntity = pActInfo->pEntity; if (pEntity) { ray_hit hit; IPhysicalEntity *pSkip = pEntity->GetPhysics(); Vec3 direction = GetPortVec3(pActInfo, DIR).GetNormalized(); if(GetPortBool(pActInfo, TRANSFORM_DIRECTION)) direction = pEntity->GetWorldTM().TransformVector( GetPortVec3(pActInfo, DIR).GetNormalized() ); IPhysicalWorld * pWorld = gEnv->pPhysicalWorld; int numHits = pWorld->RayWorldIntersection( pEntity->GetPos() + GetPortVec3(pActInfo, POS), direction * GetPortFloat(pActInfo, MAXLENGTH), ent_all, rwi_stop_at_pierceable|rwi_colltype_any, &hit, 1, &pSkip, 1 ); if (numHits) { pEntity = (IEntity*)hit.pCollider->GetForeignData(PHYS_FOREIGN_ID_ENTITY); ActivateOutput( pActInfo, HIT,(bool)true ); ActivateOutput( pActInfo, DIROUT, direction ); ActivateOutput( pActInfo, DISTANCE, hit.dist ); ActivateOutput( pActInfo, HITPOINT, hit.pt ); ActivateOutput( pActInfo, NORMAL, hit.n ); ActivateOutput( pActInfo, SURFTYPE, (int)hit.surface_idx ); ActivateOutput( pActInfo, HIT_ENTITY, pEntity ? pEntity->GetId() : 0); } else ActivateOutput( pActInfo, NOHIT, false); } } }
virtual void ProcessEvent( EFlowEvent event, SActivationInfo *pActInfo ) { if (event == eFE_Activate && IsPortActive(pActInfo, GO)) { IEntity * pEntity = pActInfo->pEntity; // if (pEntity) { ray_hit hit; CCamera& cam = GetISystem()->GetViewCamera(); Vec3 pos = cam.GetPosition()+cam.GetViewdir(); Vec3 direction = cam.GetViewdir(); IPhysicalWorld * pWorld = gEnv->pPhysicalWorld; // IPhysicalEntity *pSkip = 0; // pEntity->GetPhysics(); int numHits = pWorld->RayWorldIntersection( pos + GetPortVec3(pActInfo, POS), direction * GetPortFloat(pActInfo, MAXLENGTH), ent_all, rwi_stop_at_pierceable|rwi_colltype_any, &hit, 1 /* ,&pSkip, 1 */ ); if (numHits) { pEntity = (IEntity*)hit.pCollider->GetForeignData(PHYS_FOREIGN_ID_ENTITY); ActivateOutput( pActInfo, HIT,(bool)true ); ActivateOutput( pActInfo, DIROUT, direction ); ActivateOutput( pActInfo, DISTANCE, hit.dist ); ActivateOutput( pActInfo, HITPOINT, hit.pt ); ActivateOutput( pActInfo, NORMAL, hit.n ); ActivateOutput( pActInfo, SURFTYPE, (int)hit.surface_idx ); ActivateOutput( pActInfo, HIT_ENTITY, pEntity ? pEntity->GetId() : 0); } else ActivateOutput( pActInfo, NOHIT, false ); } } }
void CFrogBoid::Think( float dt,SBoidContext &bc ) { Vec3 flockHeading(0,0,0); m_accel(0,0,0); bool bScaredJump = false; ////////////////////////////////////////////////////////////////////////// // Scare points also scare chicken off. ////////////////////////////////////////////////////////////////////////// if (bc.scareRatio > 0) { float sqrScareDist = m_pos.GetSquaredDistance(bc.scarePoint); if (sqrScareDist < bc.scareRadius*bc.scareRadius) { bScaredJump = true; } } ////////////////////////////////////////////////////////////////////////// m_fTimeToNextJump -= dt; if (m_onGround) { float fScareDist = MAX_FROG_SCARE_DISTANCE; float sqrPlayerDist = m_pos.GetSquaredDistance(bc.playerPos); if (m_fTimeToNextJump <= 0 || sqrPlayerDist < fScareDist*fScareDist || bScaredJump) { PlaySound(FROG_SOUND_JUMP); PlayAnimationId( FROG_JUMP_ANIM,false,0 ); m_fTimeToNextJump = 2.0f + cry_frand()*5.0f; // about every 5-6 second. //m_fTimeToNextJump = 0; // Scared by player or random jump. m_onGround = false; m_heading = m_pos - bc.playerPos; if (bScaredJump) { // Jump from scare point. m_heading = Vec3(m_pos - bc.scarePoint).GetNormalized(); } else if (sqrPlayerDist < fScareDist*fScareDist) { // Jump from player. m_heading = Vec3(m_pos - bc.playerPos).GetNormalized(); } else { if (m_heading != Vec3(0,0,0)) { m_heading = m_heading.GetNormalized(); } else m_heading = Vec3(Boid::Frand(),Boid::Frand(),Boid::Frand()).GetNormalized(); if (m_pos.GetSquaredDistance(bc.flockPos) > bc.fSpawnRadius) { // If we are too far from spawn radius, jump back. Vec3 jumpToOrigin = Vec3( bc.flockPos.x+Boid::Frand()*bc.fSpawnRadius,bc.flockPos.y+Boid::Frand()*bc.fSpawnRadius,bc.flockPos.z+Boid::Frand()*bc.fSpawnRadius ); m_heading = Vec3(jumpToOrigin-m_pos).GetNormalized(); } } m_heading += Vec3(Boid::Frand()*0.4f,Boid::Frand()*0.4f,0 ); m_heading.Normalize(); m_heading.z = 0.5f + (Boid::Frand()+1.0f)*0.3f; m_heading.Normalize(); if (bc.avoidObstacles) { int retries = 4; bool bCollision; do { bCollision = false; // Avoid obstacles & terrain. IPhysicalWorld *physWorld = bc.physics; Vec3 vPos = m_pos + Vec3(0,0,bc.fBoidRadius*0.5f); Vec3 vDir = m_heading*(bc.fBoidRadius*5) + Vec3(0,0,bc.fBoidRadius*1.0f); int objTypes = ent_all|ent_no_ondemand_activation; int flags = rwi_stop_at_pierceable|rwi_ignore_terrain_holes; ray_hit hit; int col = physWorld->RayWorldIntersection( vPos,vDir,objTypes,flags,&hit,1 ); if (col != 0 && hit.dist > 0) { bCollision = true; m_heading = Vec3(Boid::Frand(),Boid::Frand(),0 ); // Pick some random jump vector. m_heading.Normalize(); m_heading.z = 0.5f + (Boid::Frand()+1.0f)*0.3f; m_heading.Normalize(); } } while (!bCollision && retries-- > 0); } m_speed = bc.MinSpeed + cry_frand()*(bc.MaxSpeed-bc.MinSpeed); } } bc.terrainZ = bc.engine->GetTerrainElevation(m_pos.x,m_pos.y) + bc.fBoidRadius*0.5f; float range = bc.MaxAttractDistance; Vec3 origin = bc.flockPos; if (bc.followPlayer) { origin = bc.playerPos; } // Keep in range. if (bc.followPlayer) { bool bChanged = false; if (m_pos.x < origin.x - range) { m_pos.x = origin.x + range; bChanged = true; } if (m_pos.y < origin.y - range) { m_pos.y = origin.y + range; bChanged = true; } if (m_pos.x > origin.x + range) { m_pos.x = origin.x - range; bChanged = true; } if (m_pos.y > origin.y + range) { m_pos.y = origin.y - range; bChanged = true; } if (bChanged) m_pos.z = bc.terrainZ = bc.engine->GetTerrainElevation(m_pos.x,m_pos.y) + bc.fBoidRadius*0.5f; } else { } if (!m_onGround) { m_accel.Set( 0,0,-10 ); } if (m_pos.z < bc.terrainZ+0.001f) { // Land. m_pos.z = bc.terrainZ+0.001f; if (!m_onGround) { m_heading.z = 0; m_onGround = true; m_speed = 0; PlayAnimationId( FROG_IDLE_ANIM,true ); } } // Do random idle sounds. if ((cry_rand()&0xFF) == 0) PlaySound(FROG_SOUND_IDLE); }
void CBoidFish::Update( float dt,SBoidContext &bc ) { if (m_dead) return; if (m_physicsControlled) { if (m_pPhysics) { // If fish is dead, get it position from physics. pe_status_pos ppos; m_pPhysics->GetStatus(&ppos); m_pos = ppos.pos; { m_dyingTime += Boid::Frand()*0.2f; // Apply force on this body. pe_action_impulse theAction; theAction.impulse = Vec3(sinf(m_dyingTime*0.1f),cosf(m_dyingTime*0.13f),cosf(m_dyingTime*0.171f)*2.8f) * 0.01f; theAction.point = m_pos + Vec3(Boid::Frand(),Boid::Frand(),Boid::Frand())*0.1f; theAction.iApplyTime = 0; theAction.ipart = 0; m_pPhysics->Action(&theAction); pe_simulation_params sym; sym.density = 950.0f + 200.0f*sinf(m_dyingTime); if (sym.density < FISH_PHYSICS_DENSITY) sym.density = FISH_PHYSICS_DENSITY; m_pPhysics->SetParams( &sym ); } } } if (m_dying) { // If fish is dying it floats up to the water surface, and die there. //UpdateDying(dt,bc); m_dyingTime += dt; if (m_dyingTime > 60) { m_dead = true; m_dying = false; if (m_object) m_object->GetISkeletonAnim()->StopAnimationsAllLayers(); } return; } ////////////////////////////////////////////////////////////////////////// if (bc.followPlayer) { if (m_pos.GetSquaredDistance(bc.playerPos) > MAX_FISH_DISTANCE*MAX_FISH_DISTANCE) { float z = bc.MinHeight + (Boid::Frand()+1)/2.0f*(bc.MaxHeight - bc.MinHeight); m_pos = bc.playerPos + Vec3(Boid::Frand()*MAX_FISH_DISTANCE,Boid::Frand()*MAX_FISH_DISTANCE,z ); m_speed = bc.MinSpeed + ((Boid::Frand()+1)/2.0f) / (bc.MaxSpeed - bc.MinSpeed); m_heading = Vec3(Boid::Frand(),Boid::Frand(),0).GetNormalized(); } } float height = m_pos.z - bc.terrainZ; m_accel.Set(0,0,0); m_accel = bc.factorRandomAccel*Vec3(Boid::Frand(),Boid::Frand(),Boid::Frand()); // Continue accelerating in same dir until target speed reached. // Try to maintain average speed of (maxspeed+minspeed)/2 float targetSpeed = (bc.MaxSpeed + bc.MinSpeed)/2; m_accel -= m_heading*(m_speed-targetSpeed)*0.2f; if (bc.factorAlignment != 0) { Vec3 alignmentAccel; Vec3 cohesionAccel; Vec3 separationAccel; CalcFlockBehavior(bc,alignmentAccel,cohesionAccel,separationAccel); m_accel += alignmentAccel*bc.factorAlignment; m_accel += cohesionAccel*bc.factorCohesion; m_accel += separationAccel; } // Avoid water. if (m_pos.z > bc.waterLevel-1) { float h = bc.waterLevel - m_pos.z; float v = (1.0f - h); float vv = v*v; m_accel.z += (-vv)*bc.factorAvoidLand; //gEnv->pRenderer->GetIRenderAuxGeom()->DrawLine( m_pos,ColorB(0,0,255,255),m_pos+m_accel,ColorB(0,0,255,255) ); } // Avoid land. if (height < bc.MinHeight) { float v = (1.0f - height/(bc.MinHeight+0.01f)); float vv = v*v; m_accel.z += vv*bc.factorAvoidLand; // Slow down fast. m_accel -= m_heading*(m_speed-0.1f)*vv*bc.factorAvoidLand; // Go to origin. m_accel += (bc.flockPos - m_pos) * vv * bc.factorAvoidLand; //gEnv->pRenderer->GetIRenderAuxGeom()->DrawLine( m_pos,ColorB(255,0,0,255),Vec3(m_pos.x,m_pos.y,bc.terrainZ),ColorB(255,0,0,255) ); } if (fabs(m_heading.z) > 0.5f) { // Always try to accelerate in direction opposite to the current in Z axis. m_accel.z += -m_heading.z * 0.8f; } // Attract to the origin point. if (bc.followPlayer) { m_accel += (bc.playerPos - m_pos) * bc.factorAttractToOrigin; } else { m_accel += (bc.randomFlockCenter - m_pos) * bc.factorAttractToOrigin; } bool bAvoidObstacles = bc.avoidObstacles; ////////////////////////////////////////////////////////////////////////// // High Terrain avoidance. ////////////////////////////////////////////////////////////////////////// Vec3 fwd_pos = m_pos + m_heading*1.0f; // Look ahead 1 meter. float fwd_z = bc.engine->GetTerrainElevation(fwd_pos.x,fwd_pos.y); if (fwd_z >= m_pos.z-bc.fBoidRadius) { // If terrain in front of the fish is high, enable obstacle avoidance. bAvoidObstacles = true; } ////////////////////////////////////////////////////////////////////////// // Avoid collision with Terrain and Static objects. float fCollisionAvoidanceWeight = 10.0f; float fCollisionDistance = 2.0f; if (bAvoidObstacles) { // Avoid obstacles & terrain. IPhysicalWorld *physWorld = bc.physics; Vec3 vPos = m_pos; Vec3 vDir = m_heading*fCollisionDistance; // Add some random variation in probe ray. vDir.x += Boid::Frand()*0.8f; vDir.y += Boid::Frand()*0.8f; int objTypes = ent_all|ent_no_ondemand_activation; int flags = rwi_stop_at_pierceable|rwi_ignore_terrain_holes; ray_hit hit; //gEnv->pRenderer->GetIRenderAuxGeom()->DrawLine( vPos,ColorB(0,0,255,255),vPos+vDir,ColorB(0,0,255,255) ); int col = physWorld->RayWorldIntersection( vPos,vDir,objTypes,flags,&hit,1 ); if (col != 0 && hit.dist > 0) { // Turn from collided surface. Vec3 normal = hit.n; //normal.z = 0; // Only turn left/right. float w = (1.0f - hit.dist/fCollisionDistance); Vec3 R = m_heading - (2.0f*m_heading.Dot(normal))*normal; Boid::Normalize_fast(R); R += normal; R.z = R.z*0.2f; m_accel += R*(w*w)*bc.factorAvoidLand * fCollisionAvoidanceWeight; //gEnv->pRenderer->GetIRenderAuxGeom()->DrawLine( m_pos,ColorB(0,0,255,255),hit.pt,ColorB(0,0,255,255) ); //gEnv->pRenderer->GetIRenderAuxGeom()->DrawLine( hit.pt,ColorB(255,0,0,255),hit.pt+R*2,ColorB(255,0,0,255) ); //gEnv->pRenderer->GetIRenderAuxGeom()->DrawLine( m_pos,ColorB(255,0,0,255),m_pos+R*2,ColorB(255,0,0,255) ); } } /* if (rand()%80 == 1) { if (m_pos.GetSquaredDistance(bc.playerPos) < 10.0f*10.0f) { // Spawn bubble. SpawnParticleEffect( m_pos,bc,SPAWN_BUBBLE ); } } */ ////////////////////////////////////////////////////////////////////////// // Player must scare fishes off. ////////////////////////////////////////////////////////////////////////// float sqrPlayerDist = m_pos.GetSquaredDistance(bc.playerPos); if (sqrPlayerDist < SCARE_DISTANCE*SCARE_DISTANCE) { Vec3 retreatDir = m_pos - bc.playerPos; Boid::Normalize_fast(retreatDir); float scareFactor = (1.0f - sqrPlayerDist/(SCARE_DISTANCE*SCARE_DISTANCE)); m_accel.x += retreatDir.x*scareFactor*bc.factorAvoidLand; m_accel.y += retreatDir.y*scareFactor*bc.factorAvoidLand; } ////////////////////////////////////////////////////////////////////////// // Calc movement. CalcMovement( dt,bc,false ); m_accel.Set(0,0,0); // Limits fishes to under water and above terrain. if (m_pos.z > bc.waterLevel-0.2f) { m_pos.z = bc.waterLevel-0.2f; if (rand()%40 == 1) { if (m_pos.GetSquaredDistance(bc.playerPos) < 10.0f*10.0f) { // Spawn splash. SpawnParticleEffect( m_pos,bc,SPAWN_SPLASH ); } } } else if (m_pos.z < bc.terrainZ+0.2f && bc.terrainZ < bc.waterLevel) { m_pos.z = bc.terrainZ+0.2f; } }
void CChickenBoid::Think( float dt,SBoidContext &bc ) { Vec3 flockHeading(0,0,0); m_accel(0,0,0); // float height = m_pos.z - bc.terrainZ; if (m_bThrown) { m_accel.Set(0,0,-10.0f); //float z = bc.engine->GetTerrainElevation(m_pos.x,m_pos.y) + bc.fBoidRadius*0.5f; m_pos.z = bc.engine->GetTerrainElevation(m_pos.x,m_pos.y) + bc.fBoidRadius*0.5f; //pe_status_pos ppos; //m_pPhysics->GetStatus(&ppos); //if (m_pos.z < z) { m_physicsControlled = false; m_bThrown = false; m_heading.z = 0; if (m_heading.IsZero()) m_heading = Vec3(1,0,0); m_heading.Normalize(); m_accel.Set(0,0,0); m_speed = bc.MinSpeed; m_heading.z = 0; } return; } // Free will. // Continue accelerating in same dir untill target speed reached. // Try to maintain average speed of (maxspeed+minspeed)/2 float targetSpeed = bc.MinSpeed; m_accel -= m_heading*(m_speed-targetSpeed)*0.4f; // Gaussian weight. m_accel.z = 0; m_bScared = false; if (bc.factorAlignment != 0) { //CalcCohesion(); Vec3 alignmentAccel; Vec3 cohesionAccel; Vec3 separationAccel; CalcFlockBehavior(bc,alignmentAccel,cohesionAccel,separationAccel); //! Adjust for allignment, //m_accel += alignmentAccel.Normalized()*ALIGNMENT_FACTOR; m_accel += alignmentAccel*bc.factorAlignment; m_accel += cohesionAccel*bc.factorCohesion; m_accel += separationAccel; } /* // Avoid land. if (height < bc.MinHeight && !m_landing) { float v = (1.0f - height/bc.MinHeight); m_accel += Vec3(0,0,v*v)*bc.factorAvoidLand; } else if (height > bc.MaxHeight) // Avoid max height. { float v = (height - bc.MaxHeight)*0.1f; m_accel += Vec3(0,0,-v); } else { // Always try to accelerate in direction oposite to current in Z axis. m_accel.z = -(m_heading.z*m_heading.z*m_heading.z * 100.0f); } */ // Attract to origin point. if (bc.followPlayer) { m_accel += (bc.playerPos - m_pos) * bc.factorAttractToOrigin; } else { //m_accel += (m_birdOriginPos - m_pos) * bc.factorAttractToOrigin; if ((cry_rand()&31) == 1) { m_birdOriginPos = Vec3( bc.flockPos.x+frand()*bc.fSpawnRadius,bc.flockPos.y+frand()*bc.fSpawnRadius,bc.flockPos.z+frand()*bc.fSpawnRadius ); if (m_birdOriginPos.z - bc.terrainZ < bc.MinHeight) { m_birdOriginPos.z = bc.terrainZ + bc.MinHeight; } } /* if (m_pos.x < bc.flockPos.x-bc.fSpawnRadius || m_pos.x > bc.flockPos.x+bc.fSpawnRadius || m_pos.y < bc.flockPos.y-bc.fSpawnRadius || m_pos.y > bc.flockPos.y+bc.fSpawnRadius || m_pos.z < bc.flockPos.z-bc.fSpawnRadius || m_pos.z > bc.flockPos.z+bc.fSpawnRadius) */ { m_accel += (m_birdOriginPos - m_pos) * bc.factorAttractToOrigin; } } // Avoid collision with Terrain and Static objects. float fCollisionAvoidanceWeight = 10.0f; // Do walk sounds. if ((cry_rand()&0xFF) == 0) PlaySound(CHICKEN_SOUND_CLUCK); ////////////////////////////////////////////////////////////////////////// // Player must scare chickens off. ////////////////////////////////////////////////////////////////////////// float fScareDist = 5.0f; float sqrPlayerDist = m_pos.GetSquaredDistance(bc.playerPos); if (sqrPlayerDist < fScareDist*fScareDist) { Vec3 retreatDir = (m_pos - bc.playerPos) + Vec3(frand()*2.0f,frand()*2.0f,0); retreatDir.NormalizeFast(); float scareFactor = (1.0f - sqrPlayerDist/(fScareDist*fScareDist)); m_accel.x += retreatDir.x*scareFactor*bc.factorAvoidLand; m_accel.y += retreatDir.y*scareFactor*bc.factorAvoidLand; m_bScared = true; if (m_landing) m_flightTime = m_maxIdleTime+1.0f; // Stop idle. // Do walk sounds. if ((cry_rand()&0xFF) == 0) PlaySound(CHICKEN_SOUND_SCARED); } ////////////////////////////////////////////////////////////////////////// // Scare points also scare chicken off. ////////////////////////////////////////////////////////////////////////// if (bc.scareRatio > 0) { float sqrScareDist = m_pos.GetSquaredDistance(bc.scarePoint); if (sqrScareDist < bc.scareRadius*bc.scareRadius) { float fScareMultiplier = 10.0f; Vec3 retreatDir = m_pos - bc.scarePoint; retreatDir.NormalizeFast(); float scareFactor = (1.0f - sqrScareDist/(bc.scareRadius*bc.scareRadius)); m_accel.x += retreatDir.x*scareFactor*fScareMultiplier; m_accel.y += retreatDir.y*scareFactor*fScareMultiplier; if (m_landing) m_flightTime = m_maxIdleTime+1.0f; // Stop idle. m_bScared = true; // Do walk sounds. if ((cry_rand()&0xF) == 0) PlaySound(CHICKEN_SOUND_CLUCK); } } ////////////////////////////////////////////////////////////////////////// if (bc.avoidObstacles) { // Avoid obstacles & terrain. IPhysicalWorld *physWorld = bc.physics; Vec3 vDir0 = m_heading*bc.fBoidRadius*0.5f; Vec3 vPos = m_pos + Vec3(0,0,bc.fBoidRadius*0.5f) + vDir0; Vec3 vDir = m_heading*(bc.fBoidRadius*2) + Vec3(0,0,bc.fBoidRadius*0.5f); // Add some random variation in probe ray. vDir.x += frand()*0.5f; vDir.y += frand()*0.5f; int objTypes = ent_all|ent_no_ondemand_activation; int flags = rwi_stop_at_pierceable|rwi_ignore_terrain_holes; ray_hit hit; int col = physWorld->RayWorldIntersection( vPos,vDir,objTypes,flags,&hit,1 ); if (col != 0 && hit.dist > 0) { // Turn from collided surface. Vec3 normal = hit.n; float rayLen = vDir.GetLength(); float w = (1.0f - hit.dist/rayLen); Vec3 R = m_heading - (2.0f*m_heading.Dot(normal))*normal; R.NormalizeFast(); R += normal; //m_accel += R*(w*w)*bc.factorAvoidLand * fCollisionAvoidanceWeight; Vec3 accel = R*w*bc.factorAvoidLand * fCollisionAvoidanceWeight; m_avoidanceAccel = m_avoidanceAccel*bc.fSmoothFactor + accel*(1.0f-bc.fSmoothFactor); } } m_accel += m_avoidanceAccel; m_avoidanceAccel = m_avoidanceAccel*bc.fSmoothFactor; if (!m_landing) { m_flightTime += dt; if (m_flightTime > m_maxNonIdleTime && (m_pos.z > bc.waterLevel && bc.bAvoidWater)) { // Play idle. PlayAnimationId( CHICKEN_IDLE_ANIM + (cry_rand()%CHICKEN_IDLE_ANIM_NUM),true ); m_maxIdleTime = 2.0f + cry_frand()*MAX_REST_TIME; m_landing = true; m_flightTime = 0; m_accel.Set(0,0,0); m_speed = 0; } } else { m_accel = m_heading; m_speed = 0.1f; m_flightTime += dt; if (m_flightTime > m_maxIdleTime) { m_maxNonIdleTime = cry_frand()*MAX_WALK_TIME; PlayAnimationId( CHICKEN_WALK_ANIM,true ); m_landing = false; m_flightTime = 0; } } // Limits birds to above water and land. m_pos.z = bc.engine->GetTerrainElevation(m_pos.x,m_pos.y) + bc.fBoidRadius*0.5f; m_accel.z = 0; ////////////////////////////////////////////////////////////////////////// // Avoid water ocean.. if (m_pos.z < bc.waterLevel && bc.bAvoidWater) { if (m_landing) m_flightTime = m_maxIdleTime; Vec3 nextpos = m_pos + m_heading; float farz = bc.engine->GetTerrainElevation(nextpos.x,nextpos.y) + bc.fBoidRadius*0.5f; if (farz > m_pos.z) m_accel += m_heading*bc.factorAvoidLand; else m_accel += -m_heading*bc.factorAvoidLand; m_accel.z = 0; } ////////////////////////////////////////////////////////////////////////// }
void CVehicleDamageBehaviorBlowTire::DamagePlayers() { // check for the nasty case when the player is shooting at the vehicle tires while prone // under or behind the car, In that case the player should get killed by the vehicle, // otherwise he gets stuck forever. Note that he should only get killed when the tier // is actually destroyed and not by collision resulting by the impulse added by just // shooting at the tiers. Unfortunately using physics for doing this check is not reliable // enough so we have to check it explicitly IEntityPhysicalProxy *pPhysicsProxy = (IEntityPhysicalProxy*)m_pVehicle->GetEntity()->GetProxy(ENTITY_PROXY_PHYSICS); if (!pPhysicsProxy) return; AABB bbox; pPhysicsProxy->GetWorldBounds( bbox ); IPhysicalWorld *pWorld = gEnv->pSystem->GetIPhysicalWorld(); IPhysicalEntity **ppColliders; // check entities in collision with the car int cnt = pWorld->GetEntitiesInBox( bbox.min,bbox.max, ppColliders,ent_living); for (int i = 0; i < cnt; i++) { IEntity *pEntity = gEnv->pEntitySystem->GetEntityFromPhysics( ppColliders[i] ); if (!pEntity) continue; // skip the vehicle itself if (pEntity==m_pVehicle->GetEntity()) continue; IPhysicalEntity *pPhysEnt = pEntity->GetPhysics(); if (!pPhysEnt) continue; IActor* pActor = gEnv->pGame->GetIGameFramework()->GetIActorSystem()->GetActor(pEntity->GetId()); if(!pActor) continue; //Jan M.: the player is killed when he entered the vehicle while prone although he is still passenger! if(m_pVehicle == pActor->GetLinkedVehicle()) continue; //the player must be prone under the vehicle IAnimatedCharacter * animatedCharacter=pActor->GetAnimatedCharacter(); if (!animatedCharacter) continue; int stance = animatedCharacter->GetCurrentStance(); if (stance!=STANCE_PRONE) continue; pe_player_dimensions dim; if (!pPhysEnt->GetParams(&dim)) continue; // position returned is at entity's feet, add head position from physics Vec3 vPos1=pEntity->GetPos(); vPos1.z = vPos1.z + dim.heightHead; float fZ=bbox.GetCenter().z; if (vPos1.z>fZ) continue; // not under the vehicle // at this point we have a collision with the car moving down and the guy prone under the car, it is safe // to assume he has been squished so let's kill him. if (gEnv->bServer && pActor->GetHealth()>0) { // adding a server hit to make it working in MP IGameRules *pGameRules = gEnv->pGame->GetIGameFramework()->GetIGameRulesSystem()->GetCurrentGameRules(); if (pGameRules) { HitInfo hit; EntityId shooterId=m_pVehicle->GetEntityId(); if (m_pVehicle->GetDriver()) shooterId=m_pVehicle->GetDriver()->GetEntityId(); hit.targetId = pEntity->GetId(); hit.shooterId = shooterId; hit.weaponId = m_pVehicle->GetEntityId(); hit.damage = 1000.f; hit.type = 0; hit.pos = pActor->GetEntity()->GetWorldPos(); pGameRules->ServerHit(hit); } } } //i }
virtual void OnIterStart(SActivationInfo *pActInfo) { const int type = GetPortInt(pActInfo, EIP_Type); const char* area = GetPortString(pActInfo, EIP_Area); // Find the entity IEntitySystem *pEntitySystem = gEnv->pEntitySystem; if (pEntitySystem) { IEntity *pArea = pEntitySystem->FindEntityByName(area); if (pArea) { IEntityAreaProxy *pAreaProxy = (IEntityAreaProxy*)pArea->GetProxy(ENTITY_PROXY_AREA); if (pAreaProxy) { Vec3 min, max, worldPos(pArea->GetWorldPos()); min.Set(0.f,0.f,0.f); max.Set(0.f,0.f,0.f); EEntityAreaType areaType = pAreaProxy->GetAreaType(); // Construct bounding space around area switch (areaType) { case ENTITY_AREA_TYPE_BOX: { pAreaProxy->GetBox(min, max); min += worldPos; max += worldPos; } break; case ENTITY_AREA_TYPE_SPHERE: { Vec3 center; float radius = 0.f; pAreaProxy->GetSphere(center, radius); min.Set(center.x-radius, center.y-radius, center.z-radius); max.Set(center.x+radius, center.y+radius, center.z+radius); } break; case ENTITY_AREA_TYPE_SHAPE: { const Vec3 *points = pAreaProxy->GetPoints(); const int count = pAreaProxy->GetPointsCount(); if (count > 0) { Vec3 p = worldPos + points[0]; min = p; max = p; for (int i = 1; i < count; ++i) { p = worldPos + points[i]; if (p.x < min.x) min.x = p.x; if (p.y < min.y) min.y = p.y; if (p.z < min.z) min.z = p.z; if (p.x > max.x) max.x = p.x; if (p.y > max.y) max.y = p.y; if (p.z > max.z) max.z = p.z; } } } break; } IPhysicalWorld *pWorld = gEnv->pPhysicalWorld; IPhysicalEntity **ppList = NULL; int numEnts = pWorld->GetEntitiesInBox(min,max,ppList,ent_all); for (int i = 0; i < numEnts; ++i) { const EntityId id = pWorld->GetPhysicalEntityId(ppList[i]); const EEntityType entityType = GetEntityType(id); if (IsValidType(type, entityType)) { // Sanity check - Test entity's position IEntity *pEntity = pEntitySystem->GetEntity(id); if (pEntity && pAreaProxy->CalcPointWithin(id, pEntity->GetWorldPos(), pAreaProxy->GetHeight()==0)) { AddEntity(id); } } } } } } }
void CTornado::UpdateFlow() { IVehicleSystem* pVehicleSystem = g_pGame->GetIGameFramework()->GetIVehicleSystem(); assert(pVehicleSystem); float frameTime(gEnv->pTimer->GetFrameTime()); IPhysicalWorld *ppWorld = gEnv->pPhysicalWorld; Vec3 pos(GetEntity()->GetWorldPos()); //first, check the entities in range m_nextEntitiesCheck -= frameTime; if (m_nextEntitiesCheck<0.0f) { m_nextEntitiesCheck = 1.0f; Vec3 radiusVec(m_radius,m_radius,0); IPhysicalEntity **ppList = NULL; int numEnts = ppWorld->GetEntitiesInBox(pos-radiusVec,pos+radiusVec+Vec3(0,0,m_cloudHeight*0.5f),ppList,ent_sleeping_rigid|ent_rigid|ent_living); m_spinningEnts.clear(); for (int i=0;i<numEnts;++i) { // add check for spectating players... EntityId id = ppWorld->GetPhysicalEntityId(ppList[i]); CActor* pActor = static_cast<CActor*>(g_pGame->GetIGameFramework()->GetIActorSystem()->GetActor(id)); if(!pActor || !pActor->GetSpectatorMode()) { m_spinningEnts.push_back(id); } } //OutputDistance(); } //mess entities around for (size_t i=0;i<m_spinningEnts.size();++i) { IPhysicalEntity *ppEnt = ppWorld->GetPhysicalEntityById(m_spinningEnts[i]); if (ppEnt) { pe_status_pos spos; pe_status_dynamics sdyn; if (!ppEnt->GetStatus(&spos) || !ppEnt->GetStatus(&sdyn)) continue; //gEnv->pRenderer->GetIRenderAuxGeom()->DrawSphere(spos.pos,2.0f,ColorB(255,0,255,255)); Vec3 delta(pos - spos.pos); delta.z = 0.0f; float dLen(delta.len()); float forceMult(max(0.0f,(m_radius-dLen)/m_radius)); if (dLen>0.001f) delta /= dLen; else delta.zero(); Vec3 upVector(0,0,1); float spinImpulse(m_spinImpulse); float attractionImpulse(m_attractionImpulse); float upImpulse(m_upImpulse); if (ppEnt->GetType() == PE_LIVING) { upImpulse *= 0.75f; attractionImpulse *= 0.35f; spinImpulse *= 1.5f; } if (IVehicle* pVehicle = pVehicleSystem->GetVehicle(m_spinningEnts[i])) { IVehicleMovement* pMovement = pVehicle->GetMovement(); if (pMovement && pMovement->GetMovementType() == IVehicleMovement::eVMT_Air) { SVehicleMovementEventParams params; params.fValue = forceMult; pMovement->OnEvent(IVehicleMovement::eVME_Turbulence, params); } } Vec3 spinForce( (delta % upVector) * spinImpulse ); Vec3 attractionForce(delta * attractionImpulse); Vec3 upForce(0,0,upImpulse); pe_action_impulse aimpulse; aimpulse.impulse = (spinForce + attractionForce + upForce) * (forceMult * sdyn.mass * frameTime); aimpulse.angImpulse = (upVector + (delta % upVector)) * (gf_PI * 0.33f * forceMult * sdyn.mass * frameTime); aimpulse.iApplyTime = 0; ppEnt->Action(&aimpulse); //gEnv->pRenderer->GetIRenderAuxGeom()->DrawLine(spos.pos,ColorB(255,0,255,255),spos.pos+aimpulse.impulse.GetNormalizedSafe(ZERO),ColorB(255,0,255,255)); } } }
//----------------------------------------------------------------------------- void CHomingMissile::UpdateControlledMissile(float frameTime) { bool isServer = gEnv->bServer; bool isClient = gEnv->bClient; CActor *pClientActor=0; if (gEnv->bClient) pClientActor=static_cast<CActor *>(g_pGame->GetIGameFramework()->GetClientActor()); bool isOwner = ((!m_ownerId && isServer) || (isClient && pClientActor && (pClientActor->GetEntityId() == m_ownerId) && pClientActor->IsPlayer())); IRenderer* pRenderer = gEnv->pRenderer; IRenderAuxGeom* pGeom = pRenderer->GetIRenderAuxGeom(); float color[4] = {1,1,1,1}; const static float step = 15.f; float y = 20.f; bool bDebug = g_pGameCVars->i_debug_projectiles > 0; if (isOwner || isServer) { //If there's a target, follow the target if(isServer) { if (m_targetId) { if (m_lockedTimer>0.0f) m_lockedTimer=m_lockedTimer-frameTime; else { // If we are here, there's a target IEntity* pTarget = gEnv->pEntitySystem->GetEntity(m_targetId); if (pTarget) { AABB box; pTarget->GetWorldBounds(box); Vec3 finalDes = box.GetCenter(); SetDestination(finalDes); //SetDestination( box.GetCenter() ); if (bDebug) pRenderer->Draw2dLabel(5.0f, y+=step, 1.5f, color, false, "Target Entity: %s", pTarget->GetName()); } m_lockedTimer+=0.05f; } } else if(m_autoControlled) return; } if (m_controlled && !m_autoControlled && isOwner && !m_targetId) { //Check if the weapon is still selected CWeapon *pWeapon = GetWeapon(); if(!pWeapon || !pWeapon->IsSelected()) return; if (m_controlledTimer>0.0f) m_controlledTimer=m_controlledTimer-frameTime; else if (pClientActor && pClientActor->IsPlayer()) //Follow the crosshair { if (IMovementController *pMC=pClientActor->GetMovementController()) { Vec3 eyePos(ZERO); Vec3 eyeDir(ZERO); IVehicle* pVehicle = pClientActor->GetLinkedVehicle(); if(!pVehicle) { SMovementState state; pMC->GetMovementState(state); eyePos = state.eyePosition; eyeDir = state.eyeDirection; } else { SViewParams viewParams; pVehicle->UpdateView(viewParams, pClientActor->GetEntityId()); eyePos = viewParams.position; eyeDir = viewParams.rotation * Vec3(0,1,0); //eyeDir = (viewParams.targetPos - viewParams.position).GetNormalizedSafe(); } int pierceability=7; if (IPhysicalEntity *pPE=GetEntity()->GetPhysics()) { if (pPE->GetType()==PE_PARTICLE) { pe_params_particle pp; if (pPE->GetParams(&pp)) pierceability=pp.iPierceability; } } static const int objTypes = ent_all; static const int flags = (geom_colltype_ray << rwi_colltype_bit) | rwi_colltype_any | (pierceability & rwi_pierceability_mask) | (geom_colltype14 << rwi_colltype_bit); IPhysicalWorld* pWorld = gEnv->pPhysicalWorld; static IPhysicalEntity* pSkipEnts[10]; int numSkip = CSingle::GetSkipEntities(pWeapon, pSkipEnts, 10); ray_hit hit; int hits = 0; float range=m_maxTargetDistance; hits = pWorld->RayWorldIntersection(eyePos + 1.5f*eyeDir, eyeDir*range, objTypes, flags, &hit, 1, pSkipEnts, numSkip); while (hits) { if (gEnv->p3DEngine->RefineRayHit(&hit, eyeDir*range)) break; eyePos = hit.pt+eyeDir*0.003f; range -= hit.dist+0.003f; hits = pWorld->RayWorldIntersection(eyePos, eyeDir*range, objTypes, flags, &hit, 1, pSkipEnts, numSkip); } DestinationParams params; if(hits) params.pt=hit.pt; else params.pt=(eyePos+m_maxTargetDistance*eyeDir); //Some point in the sky... GetGameObject()->InvokeRMI(SvRequestDestination(), params, eRMI_ToServer); if (bDebug) { pRenderer->Draw2dLabel(5.0f, y+=step, 1.5f, color, false, "PlayerView eye direction: %.3f %.3f %.3f", eyeDir.x, eyeDir.y, eyeDir.z); pRenderer->Draw2dLabel(5.0f, y+=step, 1.5f, color, false, "PlayerView Target: %.3f %.3f %.3f", hit.pt.x, hit.pt.y, hit.pt.z); pRenderer->GetIRenderAuxGeom()->DrawCone(m_destination, Vec3(0,0,-1), 2.5f, 7.f, ColorB(255,0,0,255)); } } m_controlledTimer+=0.0f; } } } //This code is shared by both modes above (auto and controlled) if(!m_destination.IsZero()) { pe_status_dynamics status; if (!GetEntity()->GetPhysics()->GetStatus(&status)) { CryLogAlways("couldn't get physics status!"); return; } pe_status_pos pos; if (!GetEntity()->GetPhysics()->GetStatus(&pos)) { CryLogAlways("couldn't get physics pos!"); return; } float currentSpeed = status.v.len(); if (currentSpeed>0.001f) { Vec3 currentVel = status.v; Vec3 currentPos = pos.pos; Vec3 goalDir(ZERO); assert(!_isnan(currentSpeed)); assert(!_isnan(currentVel.x) && !_isnan(currentVel.y) && !_isnan(currentVel.z)); //Just a security check if((currentPos-m_destination).len2()<(m_detonationRadius*m_detonationRadius)) { Explode(true, true, m_destination, -currentVel.normalized(), currentVel, m_targetId); return; } goalDir = m_destination - currentPos; goalDir.Normalize(); //Turn more slowly... currentVel.Normalize(); if(bDebug) { pRenderer->Draw2dLabel(50,55,2.0f,color,false, " Destination: %.3f, %.3f, %.3f",m_destination.x,m_destination.y,m_destination.z); pRenderer->Draw2dLabel(50,80,2.0f,color,false, " Current Dir: %.3f, %.3f, %.3f",currentVel.x,currentVel.y,currentVel.z); pRenderer->Draw2dLabel(50,105,2.0f,color,false," Goal Dir: %.3f, %.3f, %.3f",goalDir.x,goalDir.y,goalDir.z); } float cosine = currentVel.Dot(goalDir); cosine = CLAMP(cosine,-1.0f,1.0f); float totalAngle = RAD2DEG(cry_acosf(cosine)); assert(totalAngle>=0); if (cosine<0.99) { float maxAngle = m_turnSpeed*frameTime; if (maxAngle>totalAngle) maxAngle=totalAngle; float t=(maxAngle/totalAngle)*m_lazyness; assert(t>=0.0 && t<=1.0); goalDir = Vec3::CreateSlerp(currentVel, goalDir, t); goalDir.Normalize(); } if(bDebug) pRenderer->Draw2dLabel(50,180,2.0f,color,false,"Corrected Dir: %.3f, %.3f, %.3f",goalDir.x,goalDir.y,goalDir.z); pe_action_set_velocity action; action.v = goalDir * currentSpeed; GetEntity()->GetPhysics()->Action(&action); } } }