void gkAuxRenderer::AuxRenderSkeleton( const Vec3& from, const Vec3& to, ColorF& color /*= ColorF(1.0,1.0,1.0,1.0)*/, float radius /*= 0.05f*/, bool ignoreZ /*= false */ ) { Vec3 dir = to - from; Vec3 dirInPlane = Vec3::CreateProjection(Vec3(0,0,1), dir.GetNormalized()); if (dirInPlane.IsEquivalent(Vec3(0,0,0))) { dirInPlane = Vec3::CreateProjection(Vec3(1,0,0), dir.GetNormalized()); } float len = dir.GetLength(); dirInPlane.Normalize(); dirInPlane *= radius * len; Vec3 dirInPlane1 = dirInPlane.GetRotated(dir.GetNormalized(), DEG2RAD(120.0f)); Vec3 dirInPlane2 = dirInPlane.GetRotated(dir.GetNormalized(), DEG2RAD(-120.0f)); Vec3 jointPt = from + dir.GetNormalized() * len * 0.8f; AuxRender3DLine(from, jointPt + dirInPlane, color, true); AuxRender3DLine(from, jointPt + dirInPlane1, color, true); AuxRender3DLine(from, jointPt + dirInPlane2, color, true); AuxRender3DLine(to, jointPt + dirInPlane, ColorF(1,0,0,1), true); AuxRender3DLine(to, jointPt + dirInPlane1, ColorF(1,0,0,1), true); AuxRender3DLine(to, jointPt + dirInPlane2, ColorF(1,0,0,1), true); AuxRender3DLine(jointPt + dirInPlane, jointPt + dirInPlane2, ColorF(1,0,0,1), true); AuxRender3DLine(jointPt + dirInPlane1, jointPt + dirInPlane2, ColorF(1,0,0,1), true); AuxRender3DLine(jointPt + dirInPlane, jointPt + dirInPlane1, ColorF(1,0,0,1), true); }
void CIntersectionAssistanceUnit::DebugUpdate() const { if(g_pGameCVars->pl_pickAndThrow.intersectionAssistDebugEnabled) { IEntity* pEntity = gEnv->pEntitySystem->GetEntity(m_subjectEntityId); if(pEntity) { IPhysicalEntity *pPhysical = pEntity->GetPhysics(); if(pPhysical) { const float fFontSize = 1.2f; float drawColor[4] = {1.0f, 1.0f, 1.0f, 1.0f}; string sMsg(string().Format(" Entity ID: [%d]", m_subjectEntityId)); sMsg += string().Format("\n Entity Name: [%s]", pEntity->GetName()); sMsg += string().Format("\n EmbedTimer: [%.3f]", m_embedTimer); sMsg += string().Format("\n EmbedState: [%s]",(m_embedState == eES_None) ? "NONE" : (m_embedState == eES_Evaluating) ? "EVALUATING" : (m_embedState == eES_ReEvaluating) ? "REEVALUATING" : (m_embedState == eES_NotEmbedded) ? "NOT EMBEDDED" : (m_embedState == eES_Embedded) ? "EMBEDDED" : "UNKNOWN"); Vec3 vCurrTrans = m_entityStartingWPos - pEntity->GetWorldPos(); sMsg += string().Format("\n Translation: < %.3f, %.3f, %.3f >", vCurrTrans.x, vCurrTrans.y, vCurrTrans.z ); sMsg += string().Format("\n Trans magnitude: < %.3f >", vCurrTrans.GetLength() ); sMsg += string().Format("\n Trans per sec: < %.3f >", vCurrTrans.GetLength() / g_pGameCVars->pl_pickAndThrow.intersectionAssistTimePeriod ); sMsg += string().Format("\n Collision count: %u", m_collisionCount ); // RENDER Vec3 vDrawPos = pEntity->GetWorldPos() + Vec3(0.0f,0.0f,0.6f); gEnv->pRenderer->DrawLabelEx(vDrawPos, fFontSize, drawColor, true, true, sMsg.c_str()); // Box pe_params_bbox bbox; if(pPhysical->GetParams(&bbox)) { ColorB colDefault = ColorB( 127,127,127 ); ColorB embedded = ColorB(255, 0, 0); ColorB notEmbedded = ColorB(0, 255, 0); gEnv->pRenderer->GetIRenderAuxGeom()->DrawAABB( AABB(bbox.BBox[0],bbox.BBox[1]), Matrix34(IDENTITY), false, (m_embedState == eES_Embedded) ? embedded : (m_embedState == eES_NotEmbedded) ? notEmbedded : colDefault, eBBD_Faceted); } } } } }
Quat QuatFromSourceToTarget( const Vec3& source, const Vec3& target ) { Vec3 s = source.GetNormalized(); Vec3 t = target.GetNormalized(); Vec3 c = s.GetCrossProduct( t ); Real d = s.GetDotProduct( t ); // check if vectors are the same if ( Equals( d, Real( 1 ), REAL_EPSILON * 3 ) ) { // set to no rotation and return return Quat::ZERO; } // check for 180 degree rotation Real clen = c.GetLength(); if ( clen <= REAL_EPSILON ) { // pick an axis to rotate around Vec3 r = Vec3::UNIT_Y.GetCrossProduct( source ); Real rlen = r.GetLength(); if ( rlen <= REAL_EPSILON ) { // bad luck, pick another axis r = Vec3::UNIT_X.GetCrossProduct( source ); rlen = r.GetLength(); } // normalize, set rotation and return r /= rlen; return QuatFromAxisAngle( r, Radian( REAL_PI ) ); } // normalize c c /= clen; // get angle and set quaternion Real a = acos( d ) * Real( 0.5 ); Real sa = sin( a ); return Quat( cos( a ), c.X() * sa, c.Y() * sa, c.Z() * sa ); }
//==================================================================== // DebugDrawArrow //==================================================================== void CAIDebugRenderer::DrawArrow(const Vec3& vPos, const Vec3& vLength, float fWidth, const ColorB& color) { Vec3 points[7]; Vec3 tris[5 * 3]; float len = vLength.GetLength(); if (len < 0.0001f) return; float headLen = fWidth * 2.0f; float headWidth = fWidth * 2.0f; if (headLen > len * 0.8f) headLen = len * 0.8f; Vec3 vDir(vLength/len); Vec3 norm(vLength.y, -vLength.x, 0); norm.NormalizeSafe(); Vec3 end(vPos + vLength); Vec3 start(vPos); unsigned int n = 0; points[n++] = end; points[n++] = end - vDir * headLen - norm * headWidth/2; PREFAST_SUPPRESS_WARNING(6386) points[n++] = end - vDir * headLen - norm * fWidth/2; points[n++] = end - vDir * headLen + norm * fWidth/2; points[n++] = end - vDir * headLen + norm * headWidth/2; points[n++] = start - norm * fWidth/2; points[n++] = start + norm * fWidth/2; n = 0; tris[n++] = points[0]; tris[n++] = points[1]; tris[n++] = points[2]; tris[n++] = points[0]; tris[n++] = points[2]; tris[n++] = points[3]; tris[n++] = points[0]; tris[n++] = points[3]; tris[n++] = points[4]; tris[n++] = points[2]; tris[n++] = points[5]; tris[n++] = points[6]; tris[n++] = points[2]; tris[n++] = points[6]; tris[n++] = points[3]; DrawTriangles(tris, n, color); }
Quat QuatFromExponentialMap( const Vec3& v ) { Radian angle( v.GetLength() ); if ( angle > std::numeric_limits<Real>::epsilon() ) { return QuatFromAxisAngle( v / angle, angle ); } else { return Quat::ZERO; } }
void CIntersectionAssistanceUnit::UpdateCheckingForObjectEmbed(const float dt) { if(IsClientResponsibleForSubjectEntity()) { if(m_embedTimer > 0.0f) { m_embedTimer -= dt; if(m_embedTimer < 0.0f) { IEntity* pEntity = gEnv->pEntitySystem->GetEntity(m_subjectEntityId); if(pEntity) { // Make our decision, is this object stuck? Vec3 translation = m_entityStartingWPos - pEntity->GetWorldPos(); const float transPerSec = translation.GetLength() / g_pGameCVars->pl_pickAndThrow.intersectionAssistTimePeriod; const float countsPerSec = m_collisionCount / g_pGameCVars->pl_pickAndThrow.intersectionAssistTimePeriod; if( countsPerSec >= g_pGameCVars->pl_pickAndThrow.intersectionAssistCollisionsPerSecond && transPerSec <= g_pGameCVars->pl_pickAndThrow.intersectionAssistTranslationThreshold ) { OnDetectObjectEmbedded(); } else { // Are we still suspicious? if(countsPerSec >= g_pGameCVars->pl_pickAndThrow.intersectionAssistCollisionsPerSecond) { // The object moved a fair distance, but its getting an awful lot of high penetration collision events - Test a while longer BeginCheckingForObjectEmbed(); m_embedState = eES_ReEvaluating; } else { m_embedState = eES_NotEmbedded; } } } } } } #ifndef _RELEASE DebugUpdate(); #endif //#ifndef _RELEASE }
void CBoidBug::UpdateBugsBehavior( float dt,SBoidContext &bc ) { if (cry_random(0, 9) == 0) { // Randomally modify heading vector. m_heading.x += Boid::Frand()*0.2f*bc.factorAlignment; // Used as random movement. m_heading.y += Boid::Frand()*0.2f*bc.factorAlignment; m_heading.z += Boid::Frand()*0.1f*bc.factorAlignment; m_heading = m_heading.GetNormalized(); if (bc.behavior == EBUGS_DRAGONFLY) m_speed = bc.MinSpeed + (bc.MaxSpeed - bc.MinSpeed)*Boid::Frand(); } // Avoid player. Vec3 fromPlayerVec = Vec3( m_pos.x-bc.playerPos.x, m_pos.y-bc.playerPos.y, 0 ); if ((fromPlayerVec).GetLengthSquared() < BUGS_SCARE_DISTANCE*BUGS_SCARE_DISTANCE) // 2 meters. { float d = (BUGS_SCARE_DISTANCE - fromPlayerVec.GetLength()); m_accel += 5.0f * fromPlayerVec * d; } // Maintain average speed. float targetSpeed = (bc.MaxSpeed + bc.MinSpeed)/2; m_accel -= m_heading*(m_speed-targetSpeed)*0.5f; //m_accel = (m_targetPos - m_pos)*bc.factorAttractToOrigin; if (m_pos.z < bc.terrainZ+bc.MinHeight) { m_accel.z = (bc.terrainZ+bc.MinHeight-m_pos.z)*bc.factorAttractToOrigin; } else if (m_pos.z > bc.terrainZ+bc.MaxHeight) { m_accel.z = -(m_pos.z-bc.terrainZ+bc.MinHeight)*bc.factorAttractToOrigin; } else { // Always try to accelerate in direction oposite to current in Z axis. m_accel.z += -m_heading.z * 0.2f; } }
//------------------------------------------------------------------------ void CProjectile::SetVelocity(const Vec3 &pos, const Vec3 &dir, const Vec3 &velocity, float speedScale) { if (!m_pPhysicalEntity) return; Vec3 totalVelocity = (dir * m_pAmmoParams->speed * speedScale) + velocity; if (m_pPhysicalEntity->GetType()==PE_PARTICLE) { pe_params_particle particle; particle.heading = totalVelocity.GetNormalized(); particle.velocity = totalVelocity.GetLength(); m_pPhysicalEntity->SetParams(&particle); } else if (m_pPhysicalEntity->GetType()==PE_RIGID) { pe_action_set_velocity vel; vel.v = totalVelocity; m_pPhysicalEntity->Action(&vel); } }
virtual void ProcessEvent( EFlowEvent event,SActivationInfo *pActInfo ) { switch (event) { case eFE_Activate: { // update destination only if dynamic update is enabled. otherwise destination is read on Start/Reset only if (m_bActive && IsPortActive(pActInfo, IN_DEST) && GetPortBool(pActInfo, IN_DYN_DEST) == true) { ReadDestinationPosFromInput( pActInfo ); if (m_valueType==VT_TIME) CalcSpeedFromTimeInput( pActInfo ); } if (m_bActive && IsPortActive(pActInfo, IN_VALUE)) { ReadSpeedFromInput( pActInfo ); } if (IsPortActive(pActInfo, IN_START)) { Start( pActInfo ); } if (IsPortActive(pActInfo, IN_STOP)) { pActInfo->pGraph->SetRegularlyUpdated( pActInfo->myID, false ); if (m_bActive) { ActivateOutput(pActInfo, OUT_DONE, true); m_bActive = false; } ActivateOutput(pActInfo, OUT_STOP, true); } // we dont support dynamic change of those inputs assert( !IsPortActive(pActInfo, IN_COORDSYS) ); assert( !IsPortActive(pActInfo, IN_VALUETYPE) ); break; } case eFE_Initialize: { m_bActive = false; m_position = ZERO; m_coorSys = (ECoordSys)GetPortInt( pActInfo, IN_COORDSYS ); m_valueType = (EValueType)GetPortInt(pActInfo, IN_VALUETYPE); IEntity *pEnt = pActInfo->pEntity; if(pEnt) m_position = pEnt->GetWorldPos(); ActivateOutput(pActInfo, OUT_CURRENT, m_position); // i dont see a sense for this, but lets keep it for now pActInfo->pGraph->SetRegularlyUpdated( pActInfo->myID, false ); break; } case eFE_Update: { IEntity *pEnt = pActInfo->pEntity; if (!pEnt) { pActInfo->pGraph->SetRegularlyUpdated( pActInfo->myID, false ); break; } // Use physics velocity updates, unless the entity is parented in another entity space and not rigid. IPhysicalEntity* pPhysEnt = pEnt->GetPhysics(); if( pPhysEnt && (pEnt->GetParent()!=NULL || pPhysEnt->GetType() == PE_STATIC) ) { pPhysEnt = NULL; } if (m_stopping) { m_stopping = false; pActInfo->pGraph->SetRegularlyUpdated( pActInfo->myID, false ); if( pPhysEnt == NULL ) { SetPos(pActInfo, m_destination); } m_bActive = false; break; } if (!m_bActive) break; float time = gEnv->pTimer->GetFrameStartTime().GetSeconds(); float timeDifference = time - m_lastFrameTime; m_lastFrameTime = time; // note - if there's no physics then this will be the same, but if the platform is moved through physics, then // we have to get back the actual movement - this maybe framerate dependent. m_position = pActInfo->pEntity->GetPos(); // let's compute the movement vector now Vec3 oldPosition = m_position; if(m_bForceFinishAsTooNear || m_position.IsEquivalent(m_destination, 0.01f)) { m_position = m_destination; oldPosition = m_destination; ActivateOutput(pActInfo, OUT_DONE, true); ActivateOutput(pActInfo, OUT_FINISH, true); SetPos(pActInfo, m_position); // for finishing we have to make a manual setpos even if there is physics involved, to make sure the entity will be where it should. if (pPhysEnt) { pe_action_set_velocity setVel; setVel.v = ZERO; pPhysEnt->Action( &setVel ); m_stopping = true; } else { pActInfo->pGraph->SetRegularlyUpdated( pActInfo->myID, false ); m_bActive = false; } } else { Vec3 direction = m_destination - m_position; float distance = direction.GetLength(); Vec3 directionAndSpeed = direction.normalized(); // ease-area calcs float distanceForEaseOutCalc = distance + m_easeOutDistance * EASE_MARGIN_FACTOR; if (distanceForEaseOutCalc < m_easeOutDistance) // takes care of m_easeOutDistance being 0 { directionAndSpeed *= distanceForEaseOutCalc / m_easeOutDistance; } else // init code makes sure both eases dont overlap, when the movement is time defined. when it is speed defined, only ease out is applied if they overlap. { if (m_easeInDistance>0.f) { Vec3 vectorFromStart = m_position - m_startPos; float distanceFromStart = vectorFromStart.GetLength(); float distanceForEaseInCalc = distanceFromStart + m_easeInDistance * EASE_MARGIN_FACTOR; if (distanceForEaseInCalc < m_easeInDistance) { directionAndSpeed *= distanceForEaseInCalc / m_easeInDistance; } } } directionAndSpeed *= (m_topSpeed * timeDifference); if(direction.GetLength() < directionAndSpeed.GetLength()) { m_position = m_destination; m_bForceFinishAsTooNear = true; } else m_position += directionAndSpeed; } ActivateOutput(pActInfo, OUT_CURRENT, m_position); if (pPhysEnt == NULL) { SetPos(pActInfo, m_position); } else { pe_action_set_velocity setVel; float rTimeStep = timeDifference>0.000001f ? 1.f / timeDifference : 0.0f; setVel.v = (m_position - oldPosition) * rTimeStep; pPhysEnt->Action( &setVel ); } break; } }; };
void CPlayerStateUtil::CalculateGroundOrJumpMovement( const CPlayer& player, const SActorFrameMovementParams &movement, const bool bigWeaponRestrict, Vec3 &move ) { const bool isPlayer = player.IsPlayer(); const float totalMovement = fabsf(movement.desiredVelocity.x) + fabsf(movement.desiredVelocity.y); const bool moving = (totalMovement > FLT_EPSILON); if (moving) { Vec3 desiredVelocityClamped = movement.desiredVelocity; const float desiredVelocityMag = desiredVelocityClamped.GetLength(); const float invDesiredVelocityMag = 1.0f / desiredVelocityMag; float strafeMul; if (bigWeaponRestrict) { strafeMul = g_pGameCVars->pl_movement.nonCombat_heavy_weapon_strafe_speed_scale; } else { strafeMul = g_pGameCVars->pl_movement.strafe_SpeedScale; } float backwardMul = 1.0f; desiredVelocityClamped = desiredVelocityClamped * (float)__fsel(-(desiredVelocityMag - 1.0f), 1.0f, invDesiredVelocityMag); //going back? if (isPlayer) //[Mikko] Do not limit backwards movement when controlling AI. { backwardMul = (float)__fsel(desiredVelocityClamped.y, 1.0f, LERP(backwardMul, player.m_params.backwardMultiplier, -desiredVelocityClamped.y)); } NETINPUT_TRACE(player.GetEntityId(), backwardMul); NETINPUT_TRACE(player.GetEntityId(), strafeMul); const Quat oldBaseQuat = player.GetEntity()->GetWorldRotation(); // we cannot use m_baseQuat: that one is already updated to a new orientation while desiredVelocity was relative to the old entity frame move += oldBaseQuat.GetColumn0() * desiredVelocityClamped.x * strafeMul * backwardMul; move += oldBaseQuat.GetColumn1() * desiredVelocityClamped.y * backwardMul; } //ai can set a custom sprint value, so dont cap the movement vector if (movement.sprint<=0.0f) { //cap the movement vector to max 1 float moveModule(move.len()); //[Mikko] Do not limit backwards movement when controlling AI, otherwise it will disable sprinting. if (isPlayer) { move /= (float)__fsel(-(moveModule - 1.0f), 1.0f, moveModule); } NETINPUT_TRACE(player.GetEntityId(), moveModule); } //player movement don't need the m_frameTime, its handled already in the physics float scale = player.GetStanceMaxSpeed(player.GetStance()); move *= scale; NETINPUT_TRACE(player.GetEntityId(), scale); if (isPlayer) { const bool isCrouching = ((player.m_actions & ACTION_CROUCH) != 0); AdjustMovementForEnvironment( player, move, bigWeaponRestrict, isCrouching ); } }
////////////////////////////////////////////////////////////////////////// // NOTE: This function must be thread-safe. Before adding stuff contact MarcoC. void CVehicleMovementTank::ProcessAI(const float deltaTime) { FUNCTION_PROFILER( GetISystem(), PROFILE_GAME ); float dt = max( deltaTime, 0.005f); m_movementAction.brake = false; m_movementAction.rotateYaw = 0.0f; m_movementAction.power = 0.0f; float inputSpeed = 0.0f; { if (m_aiRequest.HasDesiredSpeed()) inputSpeed = m_aiRequest.GetDesiredSpeed(); Limit(inputSpeed, -m_maxSpeed, m_maxSpeed); } Vec3 vMove(ZERO); { if (m_aiRequest.HasMoveTarget()) vMove = ( m_aiRequest.GetMoveTarget() - m_PhysPos.pos ).GetNormalizedSafe(); } //start calculation if ( fabsf( inputSpeed ) < 0.0001f || m_tireBlownTimer > 1.5f ) { // only the case to use a hand break m_movementAction.brake = true; } else { Matrix33 entRotMatInvert( m_PhysPos.q ); entRotMatInvert.Invert(); float currentAngleSpeed = RAD2DEG(-m_PhysDyn.w.z); const static float maxSteer = RAD2DEG(gf_PI/4.f); // fix maxsteer, shouldn't change Vec3 vVel = m_PhysDyn.v; Vec3 vVelR = entRotMatInvert * vVel; float currentSpeed =vVel.GetLength(); vVelR.NormalizeSafe(); if ( vVelR.Dot( FORWARD_DIRECTION ) < 0 ) currentSpeed *= -1.0f; // calculate pedal static float accScale = 0.5f; m_movementAction.power = (inputSpeed - currentSpeed) * accScale; Limit( m_movementAction.power, -1.0f, 1.0f); // calculate angles Vec3 vMoveR = entRotMatInvert * vMove; Vec3 vFwd = FORWARD_DIRECTION; vMoveR.z =0.0f; vMoveR.NormalizeSafe(); if ( inputSpeed < 0.0 ) // when going back { vFwd *= -1.0f; vMoveR *= -1.0f; currentAngleSpeed *=-1.0f; } float cosAngle = vFwd.Dot(vMoveR); float angle = RAD2DEG( acos_tpl(cosAngle)); if ( vMoveR.Dot( Vec3( 1.0f,0.0f,0.0f ) )< 0 ) angle = -angle; // int step =0; m_movementAction.rotateYaw = angle * 1.75f/ maxSteer; // implementation 1. if there is enough angle speed, we don't need to steer more if ( fabsf(currentAngleSpeed) > fabsf(angle) && angle*currentAngleSpeed > 0.0f ) { m_movementAction.rotateYaw = m_currSteer*0.995f; // step =1; } // implementation 2. if we can guess we reach the distination angle soon, start counter steer. float predictDelta = inputSpeed < 0.0f ? 0.1f : 0.07f; float dict = angle + predictDelta * ( angle - m_prevAngle) / dt ; if ( dict*currentAngleSpeed<0.0f ) { if ( fabsf( angle ) < 2.0f ) { m_movementAction.rotateYaw = angle* 1.75f/ maxSteer; // step =3; } else { m_movementAction.rotateYaw = currentAngleSpeed < 0.0f ? 1.0f : -1.0f; // step =2; } } // implementation 3. tank can rotate at a point if ( fabs( angle )> 20.0f ) { m_movementAction.power *=0.1f; // step =4; } // char buf[1024]; // sprintf(buf, "steering %4.2f %4.2f %4.2f %d\n", deltaTime,currentAngleSpeed, angle - m_prevAngle, step); // OutputDebugString( buf ); m_prevAngle = angle; } }
////////////////////////////////////////////////////////////////////////// // NOTE: This function must be thread-safe. Before adding stuff contact MarcoC. void CVehicleMovementVTOL::ProcessAI(const float deltaTime) { FUNCTION_PROFILER( GetISystem(), PROFILE_GAME ); if (!m_isVTOLMovement) { CVehicleMovementHelicopter::ProcessAI(deltaTime); return; } m_velDamp = 0.15f; const float maxDirChange = 15.0f; // it's useless to progress further if the engine has yet to be turned on if (!m_isEnginePowered) return; m_movementAction.Clear(); m_movementAction.isAI = true; ResetActions(); // Our current state const Vec3 worldPos = m_PhysPos.pos; const Matrix33 worldMat( m_PhysPos.q); Ang3 worldAngles = Ang3::GetAnglesXYZ(worldMat); const Vec3 currentVel = m_PhysDyn.v; const Vec3 currentVel2D(currentVel.x, currentVel.y, 0.0f); // +ve direction mean rotation anti-clocwise about the z axis - 0 means along y float currentDir = worldAngles.z; // to avoid singularity const Vec3 vWorldDir = worldMat * FORWARD_DIRECTION; const Vec3 vWorldDir2D = Vec3( vWorldDir.x, vWorldDir.y, 0.0f ).GetNormalizedSafe(); // Our inputs const float desiredSpeed = m_aiRequest.HasDesiredSpeed() ? m_aiRequest.GetDesiredSpeed() : 0.0f; const Vec3 desiredMoveDir = m_aiRequest.HasMoveTarget() ? (m_aiRequest.GetMoveTarget() - worldPos).GetNormalizedSafe() : vWorldDir; const Vec3 desiredMoveDir2D = Vec3(desiredMoveDir.x, desiredMoveDir.y, 0.0f).GetNormalizedSafe(vWorldDir2D); const Vec3 desiredVel = desiredMoveDir * desiredSpeed; const Vec3 desiredVel2D(desiredVel.x, desiredVel.y, 0.0f); const Vec3 desiredLookDir = m_aiRequest.HasLookTarget() ? (m_aiRequest.GetLookTarget() - worldPos).GetNormalizedSafe() : desiredMoveDir; const Vec3 desiredLookDir2D = Vec3(desiredLookDir.x, desiredLookDir.y, 0.0f).GetNormalizedSafe(vWorldDir2D); // Calculate the desired 2D velocity change Vec3 desiredVelChange2D = desiredVel2D - currentVel2D; float velChangeLength = desiredVelChange2D.GetLength2D(); bool isLandingMode = false; if (m_pLandingGears && m_pLandingGears->AreLandingGearsOpen()) isLandingMode = true; bool isHorizontal = (desiredSpeed >= 5.0f) && (desiredMoveDir.GetLength2D() > desiredMoveDir.z); float desiredPitch = 0.0f; float desiredRoll = 0.0f; float desiredDir = atan2f(-desiredLookDir2D.x, desiredLookDir2D.y); while (currentDir < desiredDir - gf_PI) currentDir += 2.0f * gf_PI; while (currentDir > desiredDir + gf_PI) currentDir -= 2.0f * gf_PI; float diffDir = (desiredDir - currentDir); m_actionYaw = diffDir * m_yawInputConst; m_actionYaw += m_yawInputDamping * (currentDir - m_lastDir) / deltaTime; m_lastDir = currentDir; if (isHorizontal && !isLandingMode) { float desiredFwdSpeed = desiredVelChange2D.GetLength(); desiredFwdSpeed *= min(1.0f, diffDir / DEG2RAD(maxDirChange)); if (!iszero(desiredFwdSpeed)) { const Vec3 desiredWorldTiltAxis = Vec3(-desiredVelChange2D.y, desiredVelChange2D.x, 0.0f); const Vec3 desiredLocalTiltAxis = worldMat.GetTransposed() * desiredWorldTiltAxis; m_forwardAction = m_fwdPID.Update(currentVel.y, desiredLocalTiltAxis.GetLength(), -1.0f, 1.0f); float desiredTiltAngle = m_tiltPerVelDifference * desiredVelChange2D.GetLength(); Limit(desiredTiltAngle, -m_maxTiltAngle, m_maxTiltAngle); if (desiredTiltAngle > 0.0001f) { const Vec3 desiredWorldTiltAxis2 = Vec3(-desiredVelChange2D.y, desiredVelChange2D.x, 0.0f).GetNormalizedSafe(); const Vec3 desiredLocalTiltAxis2 = worldMat.GetTransposed() * desiredWorldTiltAxis2; Vec3 vVelLocal = worldMat.GetTransposed() * desiredVel; vVelLocal.NormalizeSafe(); float dotup = vVelLocal.Dot(Vec3( 0.0f,0.0f,1.0f ) ); float currentSpeed = currentVel.GetLength(); desiredPitch = dotup *currentSpeed / 100.0f; desiredRoll = desiredTiltAngle * desiredLocalTiltAxis2.y *currentSpeed/30.0f; } } } else { float desiredTiltAngle = m_tiltPerVelDifference * desiredVelChange2D.GetLength(); Limit(desiredTiltAngle, -m_maxTiltAngle, m_maxTiltAngle); if (desiredTiltAngle > 0.0001f) { const Vec3 desiredWorldTiltAxis = Vec3(-desiredVelChange2D.y, desiredVelChange2D.x, 0.0f).GetNormalizedSafe(); const Vec3 desiredLocalTiltAxis = worldMat.GetTransposed() * desiredWorldTiltAxis; desiredPitch = desiredTiltAngle * desiredLocalTiltAxis.x; desiredRoll = desiredTiltAngle * desiredLocalTiltAxis.y; } } float currentHeight = m_PhysPos.pos.z; if ( m_aiRequest.HasMoveTarget() ) { m_hoveringPower = m_powerPID.Update(currentVel.z, desiredVel.z, -1.0f, 4.0f); //m_hoveringPower = (m_desiredHeight - currentHeight) * m_powerInputConst; //m_hoveringPower += m_powerInputDamping * (currentHeight - m_lastHeight) / deltaTime; if (isHorizontal) { if (desiredMoveDir.z > 0.6f || desiredMoveDir.z < -0.85f) { desiredPitch = max(-0.5f, min(0.5f, desiredMoveDir.z)) * DEG2RAD(35.0f); m_forwardAction += abs(desiredMoveDir.z); } m_liftAction = min(2.0f, max(m_liftAction, m_hoveringPower * 2.0f)); } else { m_liftAction = 0.0f; } } else { // to keep hovering at the same place m_hoveringPower = m_powerPID.Update(currentVel.z, m_desiredHeight - currentHeight, -1.0f, 1.0f); m_liftAction = 0.0f; if (m_pVehicle->GetAltitude() > 10.0f) //TODO: this line is not MTSafe m_liftAction = m_forwardAction; } m_actionPitch += m_pitchActionPerTilt * (desiredPitch - worldAngles.x); m_actionRoll += m_pitchActionPerTilt * (desiredRoll - worldAngles.y); Limit(m_actionPitch, -1.0f, 1.0f); Limit(m_actionRoll, -1.0f, 1.0f); Limit(m_actionYaw, -1.0f, 1.0f); if (m_horizontal > 0.0001f) m_desiredHeight = m_PhysPos.pos.z; Limit(m_forwardAction, -1.0f, 1.0f); }
void CNetLerper::Update(float dt, const Vec3& entityPos, SPrediction& predictionOut, const Vec3& velGround, bool bInAirOrJumping) { if(!m_enabled) { predictionOut.predictedPos = entityPos; predictionOut.lerpVel.zero(); predictionOut.shouldSnap = false; return; } CRY_ASSERT(m_settings); dt = max(dt, 0.001f); IEntity* pGroundEntity = gEnv->pEntitySystem->GetEntity(m_standingOn); m_desired.worldPos = m_desired.pos; if (pGroundEntity) { if (IPhysicalEntity* pGroundPhys = pGroundEntity->GetPhysics()) { pe_status_pos psp; pGroundPhys->GetStatus(&psp); m_desired.worldPos = psp.q * m_desired.pos + psp.pos; } } // Prediction is done a "long" time ahead const float predictTime = min(m_clock + m_settings->lookAhead, m_settings->maxLookAhead); const Vec3 predictedPos = m_desired.worldPos + (m_desired.vel * predictTime); const Vec3 predOffset = predictedPos - entityPos; const float predDist = predOffset.GetLength(); // Errors: m_lerpedError = entityPos - predictedPos; // Error between desired pos (nb: not predicted pos) const Vec3 errorToDesiredPos = entityPos - m_desired.worldPos; const int snapError = GetLerpError(errorToDesiredPos, m_lerpedError); m_clock += dt; const float lerpDist = predDist + (dt*velGround).GetLength(); if (lerpDist<m_settings->minLerpDistance && m_desired.vel.GetLengthSquared() < sqr(m_settings->minLerpSpeed) && !bInAirOrJumping) // Stop lerping { // This block should be entered as few times as possible while on a moving platform. predictionOut.predictedPos = predictedPos; predictionOut.lerpVel.zero(); predictionOut.shouldSnap = false; m_lerpedPos = m_desired.worldPos; m_lerpedError.zero(); if (m_snapType== eSnap_None) { predictionOut.shouldSnap = true; m_snapType = eSnap_Minor; LogSnapError(); } } else if (snapError & k_desiredError) // k_lerpError is ignored because it works improperly during collisions with living entities { predictionOut.predictedPos = m_desired.worldPos; predictionOut.lerpVel.zero(); predictionOut.shouldSnap = true; m_lerpedPos = m_desired.worldPos; m_lerpedError.zero(); if(errorToDesiredPos.GetLengthSquared() > sqr(m_settings->snapDistMarkedMajor)) { m_snapType = eSnap_Major; } else { m_snapType = eSnap_Normal; } LogSnapError(); } else { // Calculate simple lerp velocity Vec3 lerpVel = predOffset * (float)__fres(m_settings->lookAhead); // Clamp it const float maxPredictionDistance = m_settings->maxInterSpeed * m_settings->lookAhead; if (predDist > maxPredictionDistance) lerpVel *= maxPredictionDistance * (float)__fres(predDist); // Output predictionOut.predictedPos = predictedPos; predictionOut.lerpVel = lerpVel; predictionOut.shouldSnap = false; m_snapType = eSnap_None; } // Keep this in local space m_lerpedPos += dt * (predictionOut.lerpVel + velGround); m_lerpedPos += (m_desired.worldPos - m_lerpedPos) * 0.05f; // Keep on top of any drift }
void CFireModePlugin_AutoAim::AdjustFiringDirection( const Vec3& attackerPos, Vec3& firingDirToAdjust, const bool bCurrentlyZoomed, const EntityId ownerId ) const { CPlayer* pAttackingPlayer = static_cast<CPlayer*>(g_pGame->GetIGameFramework()->GetIActorSystem()->GetActor(ownerId)); if (pAttackingPlayer && pAttackingPlayer->IsPlayer()) { const ConeParams& aimConeSettings = GetAimConeSettings(bCurrentlyZoomed); // Don't do any projectile adjusting if the player already has a target for themselves, and is on target (e.g. manually scoping to get a headshot) if( m_targetSelectionParams.m_bDisableAutoAimIfPlayerAlreadyHasTarget && pAttackingPlayer->GetCurrentTargetEntityId() || !aimConeSettings.m_enabled) { #if ALLOW_PROJECTILEHELPER_DEBUGGING m_lastShotAutoAimedStatus.append("FALSE - [Reason]: Player already on target"); #endif //#if #endif //#if ALLOW_PROJECTILEHELPER_DEBUGGING return; } float incomingDirLength = firingDirToAdjust.GetLength(); CRY_ASSERT(incomingDirLength>0.f); Vec3 firingDirToAdjustNorm(firingDirToAdjust*__fres(incomingDirLength)); #if ALLOW_PROJECTILEHELPER_DEBUGGING // DEBUG RENDER if (g_pGameCVars->pl_debug_projectileAimHelper) { // Draw Target acquisition cone float length = aimConeSettings.m_maxDistance; float radius = length * tan(aimConeSettings.m_outerConeRads * 0.5f); SAuxGeomRenderFlags originalFlags = gEnv->pRenderer->GetIRenderAuxGeom()->GetRenderFlags(); SAuxGeomRenderFlags newFlags = originalFlags; newFlags.SetCullMode(e_CullModeNone); newFlags.SetFillMode(e_FillModeWireframe); newFlags.SetAlphaBlendMode(e_AlphaBlended); gEnv->pRenderer->GetIRenderAuxGeom()->SetRenderFlags(newFlags); gEnv->pRenderer->GetIRenderAuxGeom()->DrawCone(attackerPos + (firingDirToAdjustNorm*aimConeSettings.m_maxDistance),-firingDirToAdjustNorm, radius , length , ColorB(132,190,255,120), true ); // Draw projectile adjust cone radius = length * tan(aimConeSettings.m_innerConeRads * 0.5f); gEnv->pRenderer->GetIRenderAuxGeom()->DrawCone(attackerPos + (firingDirToAdjustNorm*aimConeSettings.m_maxDistance),-firingDirToAdjustNorm, radius , length ,ColorB(0,0,127,120), true ); // Restore render flags gEnv->pRenderer->GetIRenderAuxGeom()->SetRenderFlags(originalFlags); } #endif //#if ALLOW_PROJECTILEHELPER_DEBUGGING IEntity* pTargetPlayer = CalculateBestProjectileAutoAimTarget(attackerPos, firingDirToAdjustNorm, bCurrentlyZoomed, ownerId); if(pTargetPlayer) { const SAutoaimTarget* pAutoAimInfo = g_pGame->GetAutoAimManager().GetTargetInfo(pTargetPlayer->GetId()); if(pAutoAimInfo) { Vec3 desiredFiringDir = ( pAutoAimInfo->primaryAimPosition - attackerPos ).GetNormalized(); // Make sure final firing dir still constrained to valid cone float vecDot = firingDirToAdjustNorm.Dot(desiredFiringDir); float maxConeAngle = cos(0.5f * aimConeSettings.m_innerConeRads); if(vecDot >= maxConeAngle) { // within cone firingDirToAdjustNorm = desiredFiringDir; #if ALLOW_PROJECTILEHELPER_DEBUGGING m_lastShotAutoAimedStatus.append("TRUE + desired dir fully WITHIN allowed adjust cone"); #endif //#if ALLOW_PROJECTILEHELPER_DEBUGGING } else { // constrain (generally working with small angles, nLerp should be fine + cheap) const float invConeDot = 1.0f - maxConeAngle; const float invVecDot = 1.0f - vecDot; float zeroToOne = invConeDot / invVecDot; Vec3 finalVec = (zeroToOne * desiredFiringDir) + ((1.0f - zeroToOne) * firingDirToAdjustNorm); finalVec.Normalize(); firingDirToAdjustNorm = finalVec; #if ALLOW_PROJECTILEHELPER_DEBUGGING m_lastShotAutoAimedStatus.Format("TRUE + desired dir CONSTRAINED to allowed cone [desired]: %.3f deg [constrained To]: %.3f deg", RAD2DEG(acos(vecDot)), 0.5f * RAD2DEG(aimConeSettings.m_innerConeRads)); #endif //#if ALLOW_PROJECTILEHELPER_DEBUGGING } } } #if ALLOW_PROJECTILEHELPER_DEBUGGING else { m_lastShotAutoAimedStatus.Format("FALSE - CalculateBestProjectileAutoAimTarget NULL [Last reason]: %s", m_lastTargetRejectionReason.c_str()); } // Draw adjusted vec if (g_pGameCVars->pl_debug_projectileAimHelper) { float length = aimConeSettings.m_maxDistance; gEnv->pRenderer->GetIRenderAuxGeom()->DrawLine(attackerPos,ColorB(255,0,255,0),attackerPos + firingDirToAdjustNorm * length,ColorB(255,0,255,0)); } #endif //#if ALLOW_PROJECTILEHELPER_DEBUGGING firingDirToAdjust = firingDirToAdjustNorm*incomingDirLength; } }
int CFlowConvoyNode::OnPhysicsPostStep(const EventPhys * pEvent) { FUNCTION_PROFILER(GetISystem(), PROFILE_GAME); if(m_bFirstUpdate) return 0; //after QuickLoad OnPhysicsPostStep called before ProcessEvent const EventPhysPostStep *pPhysPostStepEvent = (const EventPhysPostStep *)pEvent; IPhysicalEntity *pEventPhysEnt = pPhysPostStepEvent->pEntity; Vec3 posBack, posFront, posCenter; for (size_t i = 0; i < m_coaches.size(); ++i) { IPhysicalEntity *pPhysEnt = m_coaches[i].m_pEntity->GetPhysics(); if (pEventPhysEnt == pPhysEnt) { if (m_ShiftTime > 0.0f) { m_speed = m_speed * (1.0f - breakValue * pPhysPostStepEvent->dt / m_MaxShiftTime); m_ShiftTime -= pPhysPostStepEvent->dt; } else { m_speed = m_speed + min(1.0f, (pPhysPostStepEvent->dt / 5.0f)) * (m_desiredSpeed - m_speed); } float speed = (m_splitCoachIndex > 0 && (int)i >= m_splitCoachIndex) ? m_splitSpeed : m_speed; float distance = (m_coaches[i].m_distanceOnPath += pPhysPostStepEvent->dt * speed); if(m_splitCoachIndex>0) {//train splitted if(i==m_splitCoachIndex-1) // update m_distanceOnPath for serialization m_distanceOnPath=distance-m_coaches[i].m_coachOffset; else if(i==m_coaches.size()-1) // update m_splitDistanceOnPath for serialization m_splitDistanceOnPath=distance-m_coaches[i].m_coachOffset; } else {//train in one piece if(i==m_coaches.size()-1)// update m_distanceOnPath for serialization m_distanceOnPath=distance-m_coaches[i].m_coachOffset; } posBack = m_path.GetPointAlongPath(distance - m_coaches[i].m_wheelDistance, m_coaches[i].m_backWheelIterator[0]); posFront = m_path.GetPointAlongPath(distance + m_coaches[i].m_wheelDistance, m_coaches[i].m_frontWheelIterator[0]); posCenter = (posBack+posFront)*0.5f; Vec3 posDiff = posFront - posBack; float magnitude = posDiff.GetLength(); if (magnitude > FLT_EPSILON) { posDiff *= 1.0f / magnitude; pe_params_pos ppos; ppos.pos = posCenter; ppos.q = Quat::CreateRotationVDir(posDiff); if (m_bXAxisFwd) ppos.q *= Quat::CreateRotationZ(gf_PI*-0.5f); pPhysEnt->SetParams(&ppos, 0 /* bThreadSafe=0 */); // as we are calling from the physics thread Vec3 futurePositionBack, futurePositionFront; futurePositionBack = m_path.GetPointAlongPath(distance + PATH_DERIVATION_TIME * speed - m_coaches[i].m_wheelDistance, m_coaches[i].m_backWheelIterator[1]); futurePositionFront = m_path.GetPointAlongPath(distance + PATH_DERIVATION_TIME * speed + m_coaches[i].m_wheelDistance, m_coaches[i].m_frontWheelIterator[1]); Vec3 futurePosDiff = futurePositionFront - futurePositionBack; magnitude = futurePosDiff.GetLength(); if (magnitude > FLT_EPSILON) { futurePosDiff *= 1.0f / magnitude; pe_action_set_velocity setVel; setVel.v = ((futurePositionBack+ futurePositionFront)*0.5f - posCenter) * (1.0f/PATH_DERIVATION_TIME); //Vec3 dir=(posFront-posBack).GetNormalized(); //Vec3 future_dir=(futurePositionFront-futurePositionBack).GetNormalized(); Vec3 w=posDiff.Cross(futurePosDiff); float angle=cry_asinf(w.GetLength()); setVel.w=(angle/PATH_DERIVATION_TIME)*w.GetNormalized(); pPhysEnt->Action(&setVel, 0 /* bThreadSafe=0 */); // as we are calling from the physics thread break; } } } } // Done processing once we reach end of path if (m_atEndOfPath) m_processNode = false; return 0; }
void CPlayerRotation::TargetAimAssistance(CWeapon* pWeapon, float& followH, float& followV, float& scale, float& _fZoomAmount, const Vec3 playerView[4]) { FUNCTION_PROFILER(GetISystem(), PROFILE_GAME); CRY_ASSERT(m_player.IsClient()); followH = 0.0f; followV = 0.0f; scale = 1.0f; float bestScale = 1.0f; const Vec3 playerFwd = playerView[1]; const Vec3 playerRgt = playerView[0]; const Vec3 playerUp = playerView[2]; const Vec3 playerPos = playerView[3]; Vec3 follow_target_pos(ZERO); float follow_vote_leader = 0.0f; float snap_vote_leader = 0.0f; Vec3 follow_target_dir(ZERO); Vec3 snap_target_dir(ZERO); EntityId follow_target_id = 0; EntityId snap_target_id = 0; CGameRules * pGameRules = g_pGame->GetGameRules(); float distance_follow_threshold_near = max(0.0f, g_pGameCVars->aim_assistMinDistance); float distance_follow_threshold_far = max(20.0f, g_pGameCVars->aim_assistMaxDistance); int playerTeam = pGameRules->GetTeam(m_player.GetEntity()->GetId()); float cloakedPlayerMultiplier = g_pGameCVars->pl_aim_cloaked_multiplier; const bool multipleTeams = pGameRules->GetTeamCount() > 0; const float fFollowFalloffDist = g_pGameCVars->aim_assistFalloffDistance + FLT_EPSILON*g_pGameCVars->aim_assistFalloffDistance; const bool playerIsScoped = m_player.GetActorStats()->isScoped; float minTurnScale, fAimAssistStrength, fMaxDistMult; if(pWeapon) { const float fZoomAmount = pWeapon->GetZoomTransition(); _fZoomAmount = fZoomAmount; const float fStrength = g_pGameCVars->aim_assistStrength; const float fStrengthIronSight = playerIsScoped ? g_pGameCVars->aim_assistStrength_SniperScope : g_pGameCVars->aim_assistStrength_IronSight; const float fDiff = fStrengthIronSight - fStrength; fAimAssistStrength = fStrength + (fZoomAmount * fDiff); const float fMinTurn = g_pGameCVars->aim_assistMinTurnScale; const float fMinTurnIronSight = playerIsScoped ? g_pGameCVars->aim_assistMinTurnScale_SniperScope : g_pGameCVars->aim_assistMinTurnScale_IronSight; const float fMinTurnDiff = fMinTurnIronSight - fMinTurn; minTurnScale = fMinTurn + (fZoomAmount * fMinTurnDiff); const float fMaxAssistDist = g_pGameCVars->aim_assistMaxDistance; const float fMaxAssistDist_Iron = playerIsScoped ? g_pGameCVars->aim_assistMaxDistance_SniperScope : g_pGameCVars->aim_assistMaxDistance_IronSight; const float fMaxAssistDistDiff = (fMaxAssistDist_Iron - fMaxAssistDist) * fZoomAmount; fMaxDistMult = (fMaxAssistDist + fMaxAssistDistDiff) * __fres(fMaxAssistDist); } else { _fZoomAmount = 0.0f; fMaxDistMult = 1.0f; fAimAssistStrength = g_pGameCVars->aim_assistStrength; minTurnScale = g_pGameCVars->aim_assistMinTurnScale; } const float falloffStartDistance = g_pGameCVars->aim_assistSlowFalloffStartDistance; const float falloffPerMeter = 1.0f / (g_pGameCVars->aim_assistSlowDisableDistance - falloffStartDistance); const TAutoaimTargets& aaTargets = g_pGame->GetAutoAimManager().GetAutoAimTargets(); const int targetCount = aaTargets.size(); float fBestTargetDistance = FLT_MAX; #if DBG_AUTO_AIM SAuxGeomRenderFlags oldFlags = gEnv->pRenderer->GetIRenderAuxGeom()->GetRenderFlags(); SAuxGeomRenderFlags newFlags = e_Def3DPublicRenderflags; newFlags.SetAlphaBlendMode(e_AlphaBlended); newFlags.SetDepthTestFlag(e_DepthTestOff); newFlags.SetCullMode(e_CullModeNone); gEnv->pRenderer->GetIRenderAuxGeom()->SetRenderFlags(newFlags); #endif for (int i = 0; i < targetCount; ++i) { const SAutoaimTarget& target = aaTargets[i]; CRY_ASSERT(target.entityId != m_player.GetEntityId()); //Skip friendly ai if(gEnv->bMultiplayer) { if(multipleTeams && (pGameRules->GetTeam(target.entityId) == playerTeam)) { continue; } } else { if (target.HasFlagSet(eAATF_AIHostile) == false) continue; distance_follow_threshold_far = fMaxDistMult * (target.HasFlagSet(eAATF_AIRadarTagged) ? g_pGameCVars->aim_assistMaxDistanceTagged : g_pGameCVars->aim_assistMaxDistance); } Vec3 targetPos = target.primaryAimPosition; Vec3 targetDistVec = (targetPos - playerPos); float distance = targetDistVec.GetLength(); if (distance <= 0.1f) continue; Vec3 dirToTarget = targetDistVec / distance; // fast reject everything behind player, too far away or too near from line of view // sort rest by angle to crosshair and distance from player float alignment = playerFwd * dirToTarget; if (alignment <= 0.0f) continue; if ((distance < distance_follow_threshold_near) || (distance > distance_follow_threshold_far)) continue; const int kAutoaimVisibilityLatency = 2; CPlayerVisTable::SVisibilityParams visParams(target.entityId); visParams.queryParams = eVQP_IgnoreGlass; if (!g_pGame->GetPlayerVisTable()->CanLocalPlayerSee(visParams, kAutoaimVisibilityLatency)) { // Since both player and target entities are ignored, and the ray still intersected something, there's something in the way. // Need to profile this and see if it's faster to do the below checks before doing the linetest. It's fairly expensive but // linetests generally are as well... - Richard continue; } #if DBG_AUTO_AIM const ColorB green(0,255,0,255); const ColorB darkgreen(0,155,0,225); gEnv->pRenderer->GetIRenderAuxGeom()->DrawLine( playerPos, darkgreen, targetPos, green); #endif const float angleDot = dirToTarget.dot(-playerRgt); const float angle = (RAD2DEG(acos_tpl(angleDot)) - 90.f); const float absAngle = fabsf(angle); const float angleDotV = playerUp.dot(dirToTarget); const float angleToTargetV = (RAD2DEG(acos_tpl(angleDotV)) - 90.f); const float absAngleV = fabsf(angleToTargetV); const float slowModifiedDistance = distance * g_pGameCVars->aim_assistSlowDistanceModifier; const float radius_slow_threshold_inner = 0.5f; const float radius_slow_threshold_outer = g_pGameCVars->aim_assistSlowThresholdOuter; const float angle_slow_threshold_inner = RAD2DEG(atan_tpl(radius_slow_threshold_inner / slowModifiedDistance)); const float angle_slow_threshold_outer = RAD2DEG(atan_tpl(radius_slow_threshold_outer / slowModifiedDistance)); float angle_slow_fractionH = clamp_tpl((absAngle - angle_slow_threshold_inner) / (angle_slow_threshold_outer - angle_slow_threshold_inner), 0.0f, 1.0f); float angle_slow_fractionV = clamp_tpl((absAngleV - angle_slow_threshold_inner) / (angle_slow_threshold_outer - angle_slow_threshold_inner), 0.0f, 1.0f); float angle_slow_fraction = max(angle_slow_fractionH, angle_slow_fractionV); const float distance_follow_fraction = clamp_tpl((distance - fFollowFalloffDist) / (distance_follow_threshold_far - fFollowFalloffDist), 0.0f, 1.0f); const float radius_follow_threshold_inner = target.innerRadius; const float radius_follow_threshold_outer = target.outerRadius; const float radius_snap = target.HasFlagSet(eAATF_AIRadarTagged) ? target.snapRadiusTagged * g_pGameCVars->aim_assistSnapRadiusTaggedScale : target.snapRadius * g_pGameCVars->aim_assistSnapRadiusScale; const float angle_follow_threshold_inner = RAD2DEG(atan_tpl(radius_follow_threshold_inner / distance)); const float angle_follow_threshold_outer = RAD2DEG(atan_tpl(radius_follow_threshold_outer / distance)); const float angle_follow_fraction = clamp_tpl((absAngle - angle_follow_threshold_inner) / (angle_follow_threshold_outer - angle_follow_threshold_inner), 0.0f, 1.0f); const float angle_follow_fractionV = clamp_tpl((absAngleV - angle_follow_threshold_inner) / (angle_follow_threshold_outer - angle_follow_threshold_inner), 0.0f, 1.0f); const float worst_follow_fraction = (float)__fsel(angle_follow_fraction - angle_follow_fractionV, angle_follow_fraction, angle_follow_fractionV); float follow_fraction = ((1.0f - worst_follow_fraction) * (1.0f - distance_follow_fraction)); float follow_vote = follow_fraction; //clamp the lower bound of the distance_slow_modifier so it can't be lower than the angle slow fraction // which prevents close but off-centre targets slowing us too much const float distance_slow_modifier = clamp_tpl( 1.0f - ((distance - falloffStartDistance) * falloffPerMeter), angle_slow_fraction, 1.0f); const float fCombinedModifier = angle_slow_fraction * distance_slow_modifier; fBestTargetDistance = (float)__fsel(fCombinedModifier - bestScale, fBestTargetDistance, distance); bestScale = min(fCombinedModifier, bestScale); if (follow_vote > follow_vote_leader) { follow_vote_leader = follow_vote; //m_follow_target_id only gets set after the loop -> this won't get hit when a target is selected // as a follow target for the first time. This doesn't need to be in the loop. if ( m_follow_target_id == target.entityId) { const Vec3 follow_target_dir_local = m_follow_target_dir; Vec3 target_rgt = playerRgt; Vec3 target_up = target_rgt.cross(follow_target_dir_local); target_rgt = follow_target_dir_local.cross(target_up); target_rgt.Normalize(); target_up.Normalize(); float alignH = dirToTarget * -target_rgt; float alignV = dirToTarget.z - follow_target_dir_local.z; float angleH = min(fabsf(alignH * fAimAssistStrength), fabsf(angleDot)); float angleV = min(fabsf(alignV * fAimAssistStrength), fabsf(angleDotV)); followH = follow_fraction * (float)__fsel(angleDot, angleH, -angleH); followV = follow_fraction * (float)__fsel(angleDotV, angleV, -angleV); follow_vote_leader += 0.05f; // anti oscillation between different targets follow_target_pos = targetPos; } follow_target_id = target.entityId; snap_target_id = target.entityId; follow_target_dir = dirToTarget; snap_target_dir = PickBestSnapDirection(playerPos, playerFwd, target); } else if (!follow_target_id && (radius_snap > 0.0f)) { Lineseg lineSegment; lineSegment.start = playerPos; lineSegment.end = playerPos + (playerFwd * (distance + radius_snap)); Sphere sphere; sphere.center = targetPos; sphere.radius = radius_snap; Vec3 intersectionPoint; if (Intersect::Lineseg_SphereFirst(lineSegment, sphere, intersectionPoint)) { float t = 0.0f; const float snap_fraction = 1.0f - (Distance::Point_Lineseg(targetPos, lineSegment, t) * (float)__fres(radius_snap)); if (snap_fraction > snap_vote_leader) { snap_vote_leader = snap_fraction; snap_target_id = target.entityId; snap_target_dir = PickBestSnapDirection(playerPos, playerFwd, target); } } } } #if DBG_AUTO_AIM if ((!follow_target_pos.IsZeroFast()) && (g_pGameCVars->pl_targeting_debug != 0)) { float radius_inner = 0.30f; float radius_outer = 0.33f; ColorB colorInner(255,255,0,0x40); ColorB colorOuter(255,255,0,0x40); DrawDisc(follow_target_pos, follow_target_dir, radius_inner, radius_outer, colorInner, colorOuter); } gEnv->pRenderer->GetIRenderAuxGeom()->SetRenderFlags(oldFlags); #endif m_follow_target_id = follow_target_id; m_follow_target_dir = follow_target_dir; //IMPORTANT: Apply the minimum-distance scaling of the slowdown _after_ calculating the slowdown for the best target // as we want to help the player aim at the nearest target, and modifying the slowdown multiplier prior to this // could result in a different target being selected const float fSlowDownProximityFadeInBand = (g_pGameCVars->aim_assistSlowStopFadeinDistance - g_pGameCVars->aim_assistSlowStartFadeinDistance) + FLT_EPSILON; float fSlowDownProximityScale = (fBestTargetDistance - g_pGameCVars->aim_assistSlowStartFadeinDistance) / fSlowDownProximityFadeInBand; Limit(fSlowDownProximityScale, 0.0f, 1.0f); float fInvBestScale = (1.0f - bestScale) * fSlowDownProximityScale; bestScale = 1.0f - fInvBestScale; scale = minTurnScale + ((1.0f - minTurnScale) * bestScale); UpdateCurrentSnapTarget(snap_target_id, snap_target_dir); }
static void GetTalosInput(CPlayerRotation * pPlayerRotation, const CPlayer& rPlayer, float& x, float& z, const Vec3 playerView[4], float fFrameTime) { //Do I need to reproject the view to actually get the positioning correct? Shouldn't be. const Vec3 playerFwd = playerView[1]; const Vec3 playerRgt = playerView[0]; const Vec3 playerUp = playerView[2]; const Vec3 playerViewPos = playerView[3]; Vec3 playerPos = playerViewPos; IPhysicalEntity * pPhysicalEntity = rPlayer.GetEntity()->GetPhysics(); if(pPhysicalEntity) { pe_status_dynamics dyn_status; pPhysicalEntity->GetStatus(&dyn_status); playerPos = playerViewPos + (dyn_status.v * fFrameTime * 2.0f); } Vec3 follow_target_dir(ZERO); EntityId follow_target_id = 0; static EntityId s_follow_target_id = 0; CGameRules * pGameRules = g_pGame->GetGameRules(); int playerTeam = pGameRules->GetTeam(rPlayer.GetEntity()->GetId()); float cloakedPlayerMultiplier = g_pGameCVars->pl_aim_cloaked_multiplier; const bool multipleTeams = pGameRules->GetTeamCount() > 0; const TAutoaimTargets& aaTargets = g_pGame->GetAutoAimManager().GetAutoAimTargets(); const int targetCount = aaTargets.size(); float fBestTargetDistance = FLT_MAX; for (int i = 0; i < targetCount; ++i) { const SAutoaimTarget& target = aaTargets[i]; if(multipleTeams && (pGameRules->GetTeam(target.entityId) == playerTeam)) { continue; } Vec3 targetPos = target.secondaryAimPosition; IEntity * pEntity = gEnv->pEntitySystem->GetEntity(target.entityId); if(pEntity) { IPhysicalEntity * pPhysicalEntity2 = pEntity->GetPhysics(); if(pPhysicalEntity2) { pe_status_dynamics dyn_status; pPhysicalEntity2->GetStatus(&dyn_status); targetPos = targetPos + (dyn_status.v * fFrameTime); } } Vec3 targetDistVec = (targetPos - playerPos); float distance = targetDistVec.GetLength(); if (distance <= 0.01f) continue; Vec3 dirToTarget = targetDistVec / distance; // fast reject everything behind player, too far away or too near from line of view // sort rest by angle to crosshair and distance from player const int kAutoaimVisibilityLatency = 1; if (!g_pGame->GetPlayerVisTable()->CanLocalPlayerSee(target.entityId, kAutoaimVisibilityLatency)) { // Since both player and target entities are ignored, and the ray still intersected something, there's something in the way. // Need to profile this and see if it's faster to do the below checks before doing the linetest. It's fairly expensive but // linetests generally are as well... - Richard continue; } const float angleDot = dirToTarget.dot(-playerRgt); const float angle = (RAD2DEG(acos_tpl(angleDot)) - 90.f); const float absAngle = fabsf(angle); const float angleDotV = playerUp.dot(dirToTarget); const float angleToTargetV = (RAD2DEG(acos_tpl(angleDotV)) - 90.f); const float absAngleV = fabsf(angleToTargetV); if ( s_follow_target_id == target.entityId ) { follow_target_id = target.entityId; follow_target_dir = dirToTarget; break; } else if(distance < fBestTargetDistance) { fBestTargetDistance = distance; follow_target_id = target.entityId; follow_target_dir = dirToTarget; } } if(follow_target_id != 0) { //Player up is the normal of the plane that we are rotating around - (Correct? Or do we want to project both the player direction and the target direction onto the X/Y plane?) Vec3 vProjectedTargetHorz = playerUp.cross(follow_target_dir.cross(playerUp)); Vec3 vProjectedTargetVert = playerRgt.cross(follow_target_dir.cross(playerRgt)); float horzDot = vProjectedTargetHorz.GetNormalized().dot(playerFwd); float vertDot = vProjectedTargetVert.GetNormalized().dot(playerFwd); const float directionDotHorz = follow_target_dir.dot(playerRgt); const float directionDotVert = follow_target_dir.dot(playerUp); const float angle = acos_tpl(horzDot); const float angleToTargetV = acos_tpl(vertDot); const float fHorzFinalAngle = (float)__fsel(directionDotHorz, -angle, angle); const float fVertFinalAngle = (float)__fsel(directionDotVert, angleToTargetV, -angleToTargetV); //CryWatch("Angle to target: %.6f", RAD2DEG(angle)); //CryWatch("Final Angle to target: %.6f", RAD2DEG(fHorzFinalAngle)); x = x + fVertFinalAngle; z = z + fHorzFinalAngle; } s_follow_target_id = follow_target_id; return; }
//------------------------------------------------------------------------ void CTornado::Update(SEntityUpdateContext &ctx, int updateSlot) { if (g_pGame->GetIGameFramework()->IsEditing()) return; // wandering Matrix34 m = GetEntity()->GetWorldTM(); Vec3 dir(m.GetColumn(1)); Vec3 pos(GetEntity()->GetWorldPos()); if(!gEnv->bServer) pos = m_currentPos; Vec3 wanderPos(dir * 1.414214f); float wanderStrength(1.0f); float wanderRate(0.6f); Vec3 wanderOffset; wanderOffset.SetRandomDirection(); wanderOffset.z = 0.0f; wanderOffset.NormalizeSafe(Vec3(1,0,0)); m_wanderDir += wanderOffset * wanderRate + (m_wanderDir - wanderPos) * wanderStrength; m_wanderDir = (m_wanderDir - wanderPos).GetNormalized() + wanderPos; Vec3 wanderSteer = (dir + m_wanderDir * gEnv->pTimer->GetFrameTime()); wanderSteer.z = 0; wanderSteer.NormalizeSafe(Vec3(1,0,0)); Vec3 targetSteer(0,0,0); // go to target if (m_pTargetEntity) { Vec3 target = m_pTargetEntity->GetWorldPos() - pos; if (target.GetLength() < 10.0f) { // emit target reached event SEntityEvent event( ENTITY_EVENT_SCRIPT_EVENT ); event.nParam[0] = (INT_PTR)"TargetReached"; event.nParam[1] = IEntityClass::EVT_BOOL; bool bValue = true; event.nParam[2] = (INT_PTR)&bValue; GetEntity()->SendEvent( event ); if (m_pTargetCallback) m_pTargetCallback->Done(); m_pTargetEntity = 0; m_pTargetCallback = 0; } targetSteer = (target - dir); targetSteer.z = 0; targetSteer.NormalizeSafe(Vec3(1,0,0)); } Vec3 steerDir = (0.4f * wanderSteer + 0.6f * targetSteer).GetNormalized(); Matrix34 tm = Matrix34(Matrix33::CreateRotationVDir(steerDir)); pos = pos + steerDir * gEnv->pTimer->GetFrameTime() * m_wanderSpeed; pos.z = gEnv->p3DEngine->GetTerrainElevation(pos.x, pos.y); float waterLevel = gEnv->p3DEngine->GetWaterLevel(&pos); bool prevIsOnWater = m_isOnWater; m_isOnWater = (pos.z < waterLevel); if (m_isOnWater) { pos.z = waterLevel; } // raycast does not work for oceans if (prevIsOnWater != m_isOnWater && m_isOnWater) { m_pGroundEffect->SetParticleEffect("weather.tornado.water"); } else if (!m_isOnWater) { IMaterialEffects *mfx = gEnv->pGame->GetIGameFramework()->GetIMaterialEffects(); Vec3 down = Vec3(0,0,-1.0f); int matID = mfx->GetDefaultSurfaceIndex(); static const int objTypes = ent_all; static const unsigned int flags = rwi_stop_at_pierceable|rwi_colltype_any; ray_hit hit; int col = gEnv->pPhysicalWorld->RayWorldIntersection(pos, (down * 5.0f), objTypes, flags, &hit, 1, GetEntity()->GetPhysics()); if (col) { matID = hit.surface_idx; } if (m_curMatID != matID) { TMFXEffectId effectId = mfx->GetEffectId("tornado", matID); SMFXResourceListPtr pList = mfx->GetResources(effectId); if (pList && pList->m_particleList) { m_pGroundEffect->SetParticleEffect(pList->m_particleList->m_particleParams.name); } m_curMatID = matID; } } if(gEnv->bServer) { tm.SetTranslation(pos); m_currentPos = pos; CHANGED_NETWORK_STATE(this, POSITION_ASPECT); GetEntity()->SetWorldTM(tm); } else { tm.SetTranslation(m_currentPos); GetEntity()->SetWorldTM(tm); } UpdateParticleEmitters(); UpdateTornadoSpline(); UpdateFlow(); }
void CNetLerper::DebugDraw(const SPrediction& prediction, const Vec3& entityPos, bool hadNewData) { #if !defined(_RELEASE) if (m_debug == NULL) m_debug = new Debug; Vec3 desiredVelocity = m_desired.vel; Vec3 lerpVel = prediction.lerpVel; Vec3 desiredPosition = m_desired.worldPos; Vec3 predictedPosition = prediction.predictedPos; if(g_pGameCVars->pl_debugInterpolation > 1) { CryWatch("Cur: (%.2f, %.2f, %.2f) Des: (%.2f, %.2f, %.2f) Pred: (%.2f, %.2f, %.2f) ", entityPos.x, entityPos.y, entityPos.z, desiredPosition.x, desiredPosition.y, desiredPosition.z, predictedPosition.x, predictedPosition.y, predictedPosition.z); CryWatch("LerpErrorXY: (%.2f)", m_lerpedError.GetLength2D()); CryWatch("InputSpeed: (%.2f, %.2f, %.2f) lerpVel: (%.2f, %.2f, %.2f) lerpSpeed: %.2f", desiredVelocity.x, desiredVelocity.y, desiredVelocity.z, lerpVel.x, lerpVel.y, lerpVel.z, lerpVel.GetLength()); } if (hadNewData) { m_debug->AddDesired(m_desired.worldPos, m_desired.vel); } m_debug->AddCurrent(prediction.shouldSnap ? prediction.predictedPos : entityPos, prediction.lerpVel, m_lerpedError, prediction.shouldSnap); m_debug->Draw(); #endif }
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 CFireModePlugin_Reject::OnShoot() { const SEffectParams& rejectEffect = m_pParams->rejectEffect; CWeapon* pWeapon = m_pOwnerFiremode->GetWeapon(); const int slot = pWeapon->GetStats().fp ? 0 : 1; const bool doRejectEffect = (g_pGameCVars->i_rejecteffects != 0) && (!rejectEffect.effect[slot].empty()); if (doRejectEffect) { //First check if we can skip/cull the effect (not for the local player) if (!pWeapon->IsOwnerClient()) { const CCamera& camera = gEnv->p3DEngine->GetRenderingCamera(); const Vec3 cameraPos = camera.GetPosition(); const Vec3 effectPosition = pWeapon->GetWorldPos(); const float fDist2 = (cameraPos-effectPosition).len2(); // Too far, skip if (fDist2 > g_pGameCVars->g_rejectEffectCullDistance) { return; } // Not in the view ? if(g_pGameCVars->g_rejectEffectVisibilityCull) { Sphere emitterSphere(effectPosition, 2.0f); if(camera.IsSphereVisible_F(emitterSphere) == false) { return; } } } IParticleEffect* pParticleEffect = gEnv->pParticleManager->FindEffect(rejectEffect.effect[slot].c_str()); if (m_shellFXSpeed == 0.0f) { if (pParticleEffect) { const ParticleParams& particleParams = pParticleEffect->GetParticleParams(); m_shellFXSpeed = particleParams.fSpeed.GetMaxValue(); } } const Vec3 shellDirection = pWeapon->GetSlotHelperRotation(slot, rejectEffect.helper[slot].c_str(), true).GetColumn1(); const Vec3 shellVelocity = m_shellHelperVelocity + (shellDirection * m_shellFXSpeed); EntityEffects::SEffectSpawnParams spawnParams(ZERO, shellVelocity.GetNormalized(), rejectEffect.scale[slot], shellVelocity.GetLength(), false); EntityEffects::SpawnParticleWithEntity(pWeapon->GetEntity(), slot, pParticleEffect, rejectEffect.helper[slot].c_str(), spawnParams); } }
void CBoidObject::CalcMovement(float dt,SBoidContext &bc,bool banking) { // Calc movement with current velocity. Vec3 prevAccel(0,0,0); if(banking) { if(m_currentAccel.x != 0 && m_currentAccel.y != 0 && m_currentAccel.z != 0) prevAccel = m_currentAccel.GetNormalized(); else banking = false; } m_currentAccel = m_currentAccel*bc.fSmoothFactor + m_accel*(1.0f - bc.fSmoothFactor); Vec3 velocity = m_heading*m_speed; m_pos = m_pos + velocity*dt; velocity = velocity + m_currentAccel*dt; m_speed = velocity.GetLength(); // ClampSpeed(bc,dt); if(fabs(m_speed) > 0.0001f) { Vec3 newHeading = velocity;// * (1.0f/m_speed); // Normalized velocity vector is our heading. newHeading.NormalizeFast(); if(bc.fMaxTurnRatio) { float fHeadingSmothFactor = bc.fMaxTurnRatio * bc.fSmoothFactor; if(fHeadingSmothFactor > 1.0f) fHeadingSmothFactor = 1.0f; m_heading = newHeading*fHeadingSmothFactor + m_heading*(1.0f - fHeadingSmothFactor); } else { m_heading = newHeading; } } /* if (m_speed > bc.MaxSpeed) m_speed = bc.MaxSpeed; if (m_speed < bc.MinSpeed) m_speed = bc.MinSpeed; */ ClampSpeed(bc,dt); if(banking) { Vec3 sideDir = m_heading.Cross(Vec3(0,0,1)); if(sideDir.IsZero()) sideDir = m_heading.Cross(Vec3(0,1,0)); // Vec3 v = m_currentAccel.GetLength(); m_bankingTrg = prevAccel.Dot(sideDir.GetNormalized()); } else m_bankingTrg = 0; // Slowly go into the target banking. float bd = m_bankingTrg - m_banking; m_banking = m_banking + bd*dt*10.0f; /* if (m_pPhysics) { //pe_params_pos ppos; //ppos.pos = Vec3(m_pos); //m_pPhysics->SetParams(&ppos); //pe_action_set_velocity asv; //asv.v = m_heading*m_speed; //m_pPhysics->Action(&asv); } */ }
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()); } } } } } } } }
//------------------------------------------------------------------------ bool CVehicleMovementHelicopter::RequestMovement(CMovementRequest& movementRequest) { FUNCTION_PROFILER( gEnv->pSystem, PROFILE_GAME ); m_movementAction.isAI = true; //StartEngine(0); if (m_HoverAnim && !(m_HoverAnim->GetAnimTime() < 1.0f - FLT_EPSILON)) { m_HoverAnim->StartAnimation(); } CryAutoCriticalSection lk(m_lock); if (movementRequest.HasLookTarget()) m_aiRequest.SetLookTarget(movementRequest.GetLookTarget()); else m_aiRequest.ClearLookTarget(); if (movementRequest.HasBodyTarget()) m_aiRequest.SetBodyTarget(movementRequest.GetBodyTarget()); else m_aiRequest.ClearBodyTarget(); if (movementRequest.HasDesiredBodyDirectionAtTarget()) m_aiRequest.SetDesiredBodyDirectionAtTarget(movementRequest.GetDesiredBodyDirectionAtTarget()); else m_aiRequest.ClearDesiredBodyDirectionAtTarget(); if (movementRequest.HasMoveTarget()) { Vec3 end( movementRequest.GetMoveTarget() ); if(m_bExtendMoveTarget) { Vec3 entityPos = m_pEntity->GetWorldPos(); Vec3 start(entityPos); Vec3 pos = ( end - start ) * 100.0f; pos +=start; m_aiRequest.SetMoveTarget( pos ); } else { m_aiRequest.SetMoveTarget( end ); } if (!m_isEnginePowered) { StartDriving(0); } } else m_aiRequest.ClearMoveTarget(); float fDesiredSpeed = 0.0f; if (movementRequest.HasDesiredSpeed()) fDesiredSpeed = movementRequest.GetDesiredSpeed(); else m_aiRequest.ClearDesiredSpeed(); if (movementRequest.HasForcedNavigation()) { const Vec3 forcedNavigation = movementRequest.GetForcedNavigation(); const Vec3 entityPos = m_pEntity->GetWorldPos(); m_aiRequest.SetForcedNavigation(forcedNavigation); m_aiRequest.SetMoveTarget(entityPos+forcedNavigation.GetNormalizedSafe()*100.0f); if (fabsf(fDesiredSpeed) <= FLT_EPSILON) fDesiredSpeed = forcedNavigation.GetLength(); } else m_aiRequest.ClearForcedNavigation(); m_aiRequest.SetDesiredSpeed(fDesiredSpeed * m_EnginePerformance); m_pVehicle->NeedsUpdate(IVehicle::eVUF_AwakePhysics, false); return true; }
void CBoidBird::Kill( const Vec3 &hitPoint,const Vec3 &force ) { if (m_dead) return; m_status = Bird::DEAD; m_flock->m_bAnyKilled = true; IEntity *pEntity = gEnv->pEntitySystem->GetEntity(m_entity); if (pEntity) { SpawnParams params; params.eAttachForm = GeomForm_Surface; params.eAttachType = GeomType_Render; gEnv->pEntitySystem->GetBreakableManager()->AttachSurfaceEffect( pEntity,0,SURFACE_BREAKAGE_TYPE("destroy"),params,ePEF_Independent ); } if (CFlock::m_e_flocks_hunt == 0) { m_physicsControlled = false; m_dead = true; m_nodraw = true; if (pEntity) { pEntity->Hide(true); } if (!m_dead && m_pPhysics) { if (pEntity) { pEntity->UnphysicalizeSlot(0); } m_pPhysics = 0; } // No physics at all. return; } SBoidContext bc; m_flock->GetBoidSettings(bc); Vec3 impulse = force; if (impulse.GetLength() > 100.0f) { impulse.Normalize(); impulse *= 100.0f; } //if (!m_physicsControlled) { if (!m_object) return; AABB aabb = m_object->GetAABB( ); Vec3 size = ((aabb.max - aabb.min)/2.2f)*m_scale; CreateArticulatedCharacter( bc, size, bc.fBoidMass ); m_physicsControlled = true; // Small impulse. // Apply force on this body. pe_action_impulse theAction; Vec3 someforce; someforce = impulse; //someforce.Normalize(); theAction.impulse = someforce; theAction.ipart = 0; theAction.iApplyTime = 0; if (m_pPhysics) m_pPhysics->Action(&theAction); } if (m_object && !m_dying && !m_dead) { m_object->GetISkeletonAnim()->StopAnimationsAllLayers(); } m_dead = true; }
void CVehiclePartSuspensionPart::Update(const float frameTime) { inherited::Update(frameTime); const Matrix34& parentTm = m_pParentPart->GetLocalTM(false); const Matrix34& targetTm = m_targetPart->GetLocalTM(false); Vec3 pos = parentTm * m_pos0; Vec3 targetPos = (m_ikFlags&k_flagIgnoreTargetRotation) ? (targetTm.GetColumn3() + m_targetOffset) : (targetTm * m_targetOffset); Vec3 dir = targetPos - pos; float length = dir.GetLength(); if (length > 1e-2f) { Matrix33 rot = Matrix33::CreateRotationV0V1(m_direction0, dir*(1.f/length)); Matrix33 partRot = rot*Matrix33(m_initialRot); if (m_mode==k_modeRotate || m_mode==k_modeSnapToEF) { if (m_mode==k_modeSnapToEF) { pos = targetPos - rot * m_direction0; } Matrix34 tm(partRot, pos); SetLocalTM(tm); } else if (m_mode==k_modeStretch) { const float scale = length * m_invLength0; const Vec3 z = m_direction0; const Vec3 sz = m_direction0*(scale-1.f); Matrix33 scaleM; scaleM.m00 = 1.f+sz.x*z.x; scaleM.m01 = sz.y*z.x ; scaleM.m02 = sz.z*z.x; scaleM.m10 = sz.x*z.y ; scaleM.m11 = 1.f+sz.y*z.y; scaleM.m12 = sz.z*z.y; scaleM.m20 = sz.x*z.z ; scaleM.m21 = sz.y*z.z ; scaleM.m22 = 1.f+sz.z*z.z; Matrix34 tm(partRot * scaleM, pos); SetLocalTM(tm); } } #if !defined(_RELEASE) if (VehicleCVars().v_debugSuspensionIK) { IRenderAuxGeom* pAuxGeom = gEnv->pRenderer->GetIRenderAuxGeom(); SAuxGeomRenderFlags flags = pAuxGeom->GetRenderFlags(); SAuxGeomRenderFlags oldFlags = pAuxGeom->GetRenderFlags(); flags.SetDepthWriteFlag(e_DepthWriteOff); flags.SetDepthTestFlag(e_DepthTestOff); pAuxGeom->SetRenderFlags(flags); ColorB colRed(255,0,0,255); ColorB colBlue(0,0,255,255); ColorB colWhite(255,255,255,255); ColorB colGreen(0,255,0,255); pos = m_pVehicle->GetEntity()->GetWorldTM() * pos; targetPos = m_pVehicle->GetEntity()->GetWorldTM() * targetPos; pAuxGeom->DrawSphere(pos, 0.02f, colGreen); pAuxGeom->DrawSphere(targetPos, 0.02f, colBlue); pAuxGeom->DrawLine(pos, colWhite, targetPos, colWhite); } #endif }
////////////////////////////////////////////////////////////////////////// // NOTE: This function must be thread-safe. Before adding stuff contact MarcoC. void CVehicleMovementStdBoat::ProcessAI(const float deltaTime) { FUNCTION_PROFILER( GetISystem(), PROFILE_GAME ); float dt = max( deltaTime, 0.005f); SVehiclePhysicsStatus* physStatus = &m_physStatus[k_physicsThread]; // It is copyed from CVehicleMoventTank::ProcessAI m_movementAction.brake = false; m_movementAction.rotateYaw = 0.0f; m_movementAction.power = 0.0f; float inputSpeed = 0.0f; { if (m_aiRequest.HasDesiredSpeed()) inputSpeed = m_aiRequest.GetDesiredSpeed(); Limit(inputSpeed, -(m_maxSpeed*m_factorMaxSpeed), m_maxSpeed*m_factorMaxSpeed); } Vec3 vMove(ZERO); { if (m_aiRequest.HasMoveTarget()) vMove = ( m_aiRequest.GetMoveTarget() - m_pEntity->GetWorldPos() ).GetNormalizedSafe(); } //start calculation if ( fabsf( inputSpeed ) < 0.0001f ) { m_movementAction.brake = true; if ( physStatus->v.GetLength() > 1.0f ) { m_movementAction.power =-1.0f; } } else { Matrix33 entRotMatInvert( physStatus->q ); entRotMatInvert.Invert(); float currentAngleSpeed = RAD2DEG(-physStatus->w.z); const static float maxSteer = RAD2DEG(gf_PI/4.f); // fix maxsteer, shouldn't change Vec3 vVel = physStatus->v; Vec3 vVelR = entRotMatInvert * vVel; float currentSpeed =vVel.GetLength(); vVelR.NormalizeSafe(); if ( vVelR.Dot( FORWARD_DIRECTION ) < 0 ) currentSpeed *= -1.0f; // calculate pedal static float accScale = 0.5f; m_movementAction.power = (inputSpeed - currentSpeed) * accScale; Limit( m_movementAction.power, -1.0f, 1.0f); // calculate angles Vec3 vMoveR = entRotMatInvert * vMove; Vec3 vFwd = FORWARD_DIRECTION; vMoveR.z =0.0f; vMoveR.NormalizeSafe(); if ( inputSpeed < 0.0f ) // when going back { vFwd *= -1.0f; vMoveR *= -1.0f; currentAngleSpeed *=-1.0f; } float cosAngle = vFwd.Dot(vMoveR); float angle = RAD2DEG(acos_tpl(cosAngle)); if ( vMoveR.Dot( Vec3( 1.0f,0.0f,0.0f ) )< 0 ) angle = -angle; //int step =0; m_movementAction.rotateYaw = angle * 1.75f/ maxSteer; // implementation 1. if there is enough angle speed, we don't need to steer more if ( fabsf(currentAngleSpeed) > fabsf(angle) && angle*currentAngleSpeed > 0.0f ) { m_movementAction.rotateYaw = m_movementAction.rotateYaw*0.995f; //step =1; } // implementation 2. if we can guess we reach the distination angle soon, start counter steer. float predictDelta = inputSpeed < 0.0f ? 0.1f : 0.1f; float dict = angle + predictDelta * ( angle - m_prevAngle) / dt ; if ( dict*currentAngleSpeed<0.0f ) { if ( fabsf( angle ) < 2.0f ) { m_movementAction.rotateYaw = angle* 1.75f/ maxSteer;// ; step =3; } else { m_movementAction.rotateYaw = currentAngleSpeed < 0.0f ? 1.0f : -1.0f;// step =2; } } if ( fabsf( angle ) > 20.0f && currentSpeed > 3.0f ) { m_movementAction.power = 0.1f ; //step =4; } m_prevAngle = angle; //CryLog("steering %4.2f %4.2f %4.2f %4.2f %4.2f %4.2f %d", deltaTime,inputSpeed - currentSpeed,angle,currentAngleSpeed, m_movementAction.rotateYaw,currentAngleSpeed-m_prevAngle,step); } }