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 ); }
//------------------------------------------------------------------------ void CDebugGun::Update( SEntityUpdateContext& ctx, int update) { if (!IsSelected()) return; static float drawColor[4] = {1,1,1,1}; static const int dx = 5; static const int dy = 15; static const float font = 1.2f; static const float fontLarge = 1.4f; IRenderer* pRenderer = gEnv->pRenderer; IRenderAuxGeom* pAuxGeom = pRenderer->GetIRenderAuxGeom(); pAuxGeom->SetRenderFlags(e_Def3DPublicRenderflags); pRenderer->Draw2dLabel(pRenderer->GetWidth()/5.f, pRenderer->GetHeight()-35, fontLarge, drawColor, false, "Firemode: %s (%.1f)", m_fireModes[m_fireMode].first.c_str(), m_fireModes[m_fireMode].second); ray_hit rayhit; int hits = 0; 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; } // use cam, no need for firing pos/dir CCamera& cam = GetISystem()->GetViewCamera(); if (hits = gEnv->pPhysicalWorld->RayWorldIntersection(cam.GetPosition()+cam.GetViewdir(), cam.GetViewdir()*HIT_RANGE, ent_all, flags, &rayhit, 1)) { IMaterialManager* pMatMan = gEnv->p3DEngine->GetMaterialManager(); IActorSystem* pActorSystem = g_pGame->GetIGameFramework()->GetIActorSystem(); IVehicleSystem* pVehicleSystem = g_pGame->GetIGameFramework()->GetIVehicleSystem(); int x = (int)(pRenderer->GetWidth() *0.5f) + dx; int y = (int)(pRenderer->GetHeight()*0.5f) + dx - dy; // draw normal ColorB colNormal(200,0,0,128); Vec3 end = rayhit.pt + 0.75f*rayhit.n; pAuxGeom->DrawLine(rayhit.pt, colNormal, end, colNormal); pAuxGeom->DrawCone(end, rayhit.n, 0.1f, 0.2f, colNormal); IEntity * pEntity = (IEntity*)rayhit.pCollider->GetForeignData(PHYS_FOREIGN_ID_ENTITY); if(pEntity) { pRenderer->Draw2dLabel(x, y+=dy, fontLarge, drawColor, false, pEntity->GetName()); } // material const char* matName = pMatMan->GetSurfaceType(rayhit.surface_idx)->GetName(); if (matName[0]) pRenderer->Draw2dLabel(x, y+=dy, font, drawColor, false, "%s (%i)", matName, rayhit.surface_idx); pRenderer->Draw2dLabel(x, y+=dy, font, drawColor, false, "%.1f m", rayhit.dist); if (pEntity) { IScriptTable* pScriptTable = pEntity->GetScriptTable(); // physics if (IPhysicalEntity* pPhysEnt = pEntity->GetPhysics()) { pe_status_dynamics status; if (pPhysEnt->GetStatus(&status)) { if (status.mass > 0.f) pRenderer->Draw2dLabel(x, y+=dy, font, drawColor, false, "%.1f kg", status.mass); pRenderer->Draw2dLabel(x, y+=dy, font, drawColor, false, "pe_type: %i", pPhysEnt->GetType()); if (status.submergedFraction > 0.f) pRenderer->Draw2dLabel(x, y+=dy, font, drawColor, false, "%.2f submerged", status.submergedFraction); if (status.v.len2() > 0.0001f) pRenderer->Draw2dLabel(x, y+=dy, font, drawColor, false, "%.2f m/s", status.v.len()); } } if (pScriptTable) { HSCRIPTFUNCTION func = 0; if (pScriptTable->GetValue("GetFrozenAmount", func) && func) { float frozen = 0.f; Script::CallReturn(gEnv->pScriptSystem, func, pScriptTable, frozen); gEnv->pScriptSystem->ReleaseFunc(func); if (frozen > 0.f) pRenderer->Draw2dLabel(x, y+=dy, font, drawColor, false, "Frozen: %.2f", frozen); } } // class-specific stuff if (IActor* pActor = pActorSystem->GetActor(pEntity->GetId())) { pRenderer->Draw2dLabel(x, y+=dy, font, drawColor, false, "%i health", pActor->GetHealth()); } else if (IVehicle* pVehicle = pVehicleSystem->GetVehicle(pEntity->GetId())) { const SVehicleStatus& status = pVehicle->GetStatus(); pRenderer->Draw2dLabel(x, y+=dy, font, drawColor, false, "%.0f%% health", 100.f*status.health); pRenderer->Draw2dLabel(x, y+=dy, font, drawColor, false, "%i passengers", status.passengerCount); if (pVehicle->GetMovement() && pVehicle->GetMovement()->IsPowered()) { pRenderer->Draw2dLabel(x, y+=dy, font, drawColor, false, "Running"); } } else { if (pScriptTable) { HSCRIPTFUNCTION func = 0; if (pScriptTable->GetValue("GetHealth", func) && func) { float health = 0.f; if (Script::CallReturn(gEnv->pScriptSystem, func, pScriptTable, health)) { pRenderer->Draw2dLabel(x, y+=dy, font, drawColor, false, "%.0f health", health); } gEnv->pScriptSystem->ReleaseFunc(func); } } } } } }
//---------------------------------------------------------------------------- void CHomingMissile::UpdateCruiseMissile(float frameTime) { 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 (m_targetId) { IEntity* pTarget = gEnv->pEntitySystem->GetEntity(m_targetId); if (pTarget) { AABB box; pTarget->GetWorldBounds(box); SetDestination( box.GetCenter() ); //if (bDebug) //pRenderer->Draw2dLabel(5.0f, y+=step, 1.5f, color, false, "Target Entity: %s", pTarget->GetName()); } } else { // update destination pos from weapon static IItemSystem* pItemSystem = g_pGame->GetIGameFramework()->GetIItemSystem(); IItem* pItem = pItemSystem->GetItem(m_weaponId); if (pItem && pItem->GetIWeapon()) { const Vec3& dest = pItem->GetIWeapon()->GetDestination(); SetDestination( dest ); //if (bDebug) //pRenderer->Draw2dLabel(5.0f, y+=step, 1.5f, color, false, "Weapon Destination: (%.1f %.1f %.1f)", dest.x, dest.y, dest.z); } } pe_status_dynamics status; if (!GetEntity()->GetPhysics()->GetStatus(&status)) return; float currentSpeed = status.v.len(); Vec3 currentPos = GetEntity()->GetWorldPos(); Vec3 goalDir(ZERO); if (!m_destination.IsZero()) { if((currentPos-m_destination).len2()<(m_detonationRadius*m_detonationRadius)) { Explode(true, true, m_destination, -status.v.normalized(), status.v, m_targetId); return; } if (bDebug) pGeom->DrawCone(m_destination, Vec3(0,0,-1), 2.5f, 7.f, ColorB(255,0,0,255)); float heightDiff = (m_cruiseAltitude-m_alignAltitude) - currentPos.z; if (!m_isCruising && heightDiff * sgn(status.v.z) > 0.f) { // if heading towards align altitude (but not yet reached) accelerate to max speed if (bDebug) pRenderer->Draw2dLabel(5.0f, y+=step, 1.5f, color, false, "[HomingMissile] accelerating (%.1f / %.1f)", currentSpeed, m_maxSpeed); } else if (!m_isCruising && heightDiff * sgnnz(status.v.z) < 0.f && (status.v.z<0 || status.v.z>0.25f)) { // align to cruise if (currentSpeed != 0) { goalDir = status.v; goalDir.z = 0; goalDir.normalize(); } if (bDebug) pRenderer->Draw2dLabel(5.0f, y+=step, 1.5f, color, false, "[HomingMissile] aligning"); } else { if (bDebug) pRenderer->Draw2dLabel(5.0f, y+=step, 1.5f, color, false, "[HomingMissile] cruising..."); // cruise m_isCruising = true; if (!m_destination.IsZero()) { float groundDistSq = m_destination.GetSquaredDistance2D(currentPos); float distSq = m_destination.GetSquaredDistance(currentPos); float descendDistSq = sqr(m_descendDistance); if (m_isDescending || groundDistSq <= descendDistSq) { if (bDebug) pRenderer->Draw2dLabel(5.0f, y+=step, 1.5f, color, false, "[HomingMissile] descending!"); if (distSq != 0) goalDir = (m_destination - currentPos).normalized(); else goalDir.zero(); m_isDescending = true; } else { Vec3 airPos = m_destination; airPos.z = currentPos.z; goalDir = airPos - currentPos; if (goalDir.len2() != 0) goalDir.Normalize(); } } } } float desiredSpeed = currentSpeed; if (currentSpeed < m_maxSpeed-0.1f) { desiredSpeed = min(m_maxSpeed, desiredSpeed + m_accel*frameTime); } Vec3 currentDir = status.v.GetNormalizedSafe(FORWARD_DIRECTION); Vec3 dir = currentDir; if (!goalDir.IsZero()) { float cosine = max(min(currentDir.Dot(goalDir), 0.999f), -0.999f); float goalAngle = RAD2DEG(acos_tpl(cosine)); float maxAngle = m_turnSpeed * frameTime; if (bDebug) { pGeom->DrawCone( currentPos, goalDir, 0.4f, 12.f, ColorB(255,0,0,255) ); pRenderer->Draw2dLabel(5.0f, y+=step, 1.5f, color, false, "[HomingMissile] goalAngle: %.2f", goalAngle); } if (goalAngle > maxAngle+0.05f) dir = (Vec3::CreateSlerp(currentDir, goalDir, maxAngle/goalAngle)).normalize(); else //if (goalAngle < 0.005f) dir = goalDir; } pe_action_set_velocity action; action.v = dir * desiredSpeed; GetEntity()->GetPhysics()->Action(&action); if (bDebug) { pGeom->DrawCone( currentPos, dir, 0.4f, 12.f, ColorB(128,128,0,255) ); pRenderer->Draw2dLabel(5.0f, y+=step, 1.5f, color, false, "[HomingMissile] currentSpeed: %.1f (max: %.1f)", currentSpeed, m_maxSpeed); } }
//------------------------------------------------------------------------ void CVehicleMovementStdBoat::Update(const float deltaTime) { CVehicleMovementBase::Update(deltaTime); SetAnimationSpeed(eVMA_Engine, abs(m_rpmScaleSgn)); if (m_inWater) { SetSoundParam(eSID_Run, "slip", 0.2f*abs(m_localSpeed.x)); } #if ENABLE_VEHICLE_DEBUG if (IsProfilingMovement() && g_pGameCVars->v_profileMovement != 2) { IEntity* pEntity = m_pVehicle->GetEntity(); const Matrix34& wTM = pEntity->GetWorldTM(); Matrix34 wTMInv = wTM.GetInvertedFast(); const SVehiclePhysicsStatus* physStatus = &m_physStatus[k_mainThread]; Vec3 localW = physStatus->q * physStatus->w; float speed = physStatus->v.len2() > 0.001f ? physStatus->v.len() : 0.f; float speedRatio = min(1.f, speed/(m_maxSpeed*m_factorMaxSpeed)); float absPedal = abs(m_movementAction.power); float absSteer = abs(m_movementAction.rotateYaw); static const float fSubmergedMin = 0.01f; static const float fWaterLevelMaxDiff = 0.15f; // max allowed height difference between propeller center and water level Vec3 worldPropPos = wTM * m_pushOffset; float waterLevelWorld = gEnv->p3DEngine->GetWaterLevel( &worldPropPos ); float fWaterLevelDiff = worldPropPos.z - waterLevelWorld; // wave stuff float waveFreq = 1.f; waveFreq += 3.f*speedRatio; float kx = m_waveIdleStrength.x*(m_waveRandomMult+0.3f) * (1.f-speedRatio + m_waveSpeedMult*speedRatio); float ky = m_waveIdleStrength.y * (1.f - 0.5f*absPedal - 0.5f*absSteer); Vec3 waveLoc = m_massOffset; waveLoc.y += speedRatio*min(0.f, m_pushOffset.y-m_massOffset.y); waveLoc = wTM * waveLoc; IRenderer* pRenderer = gEnv->pRenderer; static float color[4] = {1,1,1,1}; float colorRed[4] = {1,0,0,1}; float colorGreen[4] = {0,1,0,1}; float y=50.f, step1=15.f, step2=20.f, size1=1.3f, size2=1.5f; pRenderer->Draw2dLabel(5.0f, y, size2, color, false, "Boat movement"); pRenderer->Draw2dLabel(5.0f, y+=step2, size1, color, false, "Speed: %.1f (%.1f km/h)", speed, speed*3.6f); pRenderer->Draw2dLabel(5.0f, y+=step1, size1, color, false, "LocalW.z norm: %.2f", abs(localW.z)/m_turnRateMax); if (m_velLift > 0.f) { pRenderer->Draw2dLabel(5.0f, y+=step2, size1, m_lifted ? colorGreen : color, false, m_lifted ? "Lifted" : "not lifted"); //pRenderer->Draw2dLabel(5.0f, y+=step2, size1, color, false, "Impulse lift: %.0f", liftImp.impulse.len()); } pRenderer->Draw2dLabel(5.0f, y+=step1, size1, physStatus->submergedFraction > fSubmergedMin ? color : colorRed, false, "Submerged: %.2f", physStatus->submergedFraction); pRenderer->Draw2dLabel(5.0f, y+=step1, size1, fWaterLevelDiff < fWaterLevelMaxDiff ? color : colorRed, false, "WaterLevel: %.2f (max: %.2f)", fWaterLevelDiff, fWaterLevelMaxDiff); pRenderer->Draw2dLabel(5.0f, y+=step2, size2, color, false, "Driver input"); pRenderer->Draw2dLabel(5.0f, y+=step2, size1, color, false, "power: %.2f", m_movementAction.power); pRenderer->Draw2dLabel(5.0f, y+=step1, size1, color, false, "steer: %.2f", m_movementAction.rotateYaw); pRenderer->Draw2dLabel(5.0f, y+=step2, size2, color, false, "Propelling"); //pRenderer->Draw2dLabel(5.0f, y+=step2, size1, color, false, "turnAccel (norm/real): %.2f / %.2f", turnAccelNorm, turnAccel); //pRenderer->Draw2dLabel(5.0f, y+=step1, size1, color, false, "Impulse acc: %.0f", linearImp.impulse.len()); //pRenderer->Draw2dLabel(5.0f, y+=step1, size1, color, false, "Impulse steer/damp: %.0f", angularImp.angImpulse.len()); //pRenderer->Draw2dLabel(5.0f, y+=step1, size1, color, false, "Impulse corner: %.0f", dampImp.impulse.len()); pRenderer->Draw2dLabel(5.0f, y+=step2, size2, color, false, "Waves"); pRenderer->Draw2dLabel(5.0f, y+=step2, size1, color, false, "timer: %.1f", m_waveTimer); pRenderer->Draw2dLabel(5.0f, y+=step1, size1, color, false, "frequency: %.2f", waveFreq); pRenderer->Draw2dLabel(5.0f, y+=step1, size1, color, false, "random: %.2f", m_waveRandomMult); pRenderer->Draw2dLabel(5.0f, y+=step1, size1, color, false, "kX: %.2f", kx); pRenderer->Draw2dLabel(5.0f, y+=step1, size1, color, false, "kY: %.2f", ky); if (Boosting()) pRenderer->Draw2dLabel(5.0f, y+=step1, size1, color, false, "Boost: %.2f", m_boostCounter); IRenderAuxGeom* pGeom = pRenderer->GetIRenderAuxGeom(); ColorB colorB(0,255,0,255); pRenderer->DrawLabel(worldPropPos, 1.3f, "WL: %.2f", waterLevelWorld); pGeom->DrawSphere(worldPropPos, 0.15f, colorB); pGeom->DrawSphere(waveLoc, 0.25f, colorB); pGeom->DrawLine(waveLoc, colorB, waveLoc+Vec3(0,0,2), colorB); // impulses //DrawImpulse(linearImp, Vec3(0,0,1), 3.f/deltaTime, ColorB(255,0,0,255)); //DrawImpulse(angularImp, Vec3(0,0,1), 2.f/deltaTime, ColorB(128,0,0,255)); //DrawImpulse(liftImp, Vec3(0,0,6), 2.f/deltaTime, ColorB(0,0,255,255)); } #endif }
//----------------------------------------------------------------------------- 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); } } }