void UBuoyancyComponent::InitializeComponent() { Super::InitializeComponent(); // If no OceanManager is defined auto-detect if (!OceanManager) { for (TActorIterator<AOceanManager> ActorItr(GetWorld()); ActorItr; ++ActorItr) { OceanManager = Cast<AOceanManager>(*ActorItr); break; } } ApplyUprightConstraint(); TestPointRadius = FMath::Abs(TestPointRadius); //Signed based on gravity, just in case we need an upside down world _SignedRadius = FMath::Sign(GetGravityZ()) * TestPointRadius; if (UpdatedPrimitive->IsValidLowLevel()) { _baseLinearDamping = UpdatedPrimitive->GetLinearDamping(); _baseAngularDamping = UpdatedPrimitive->GetAngularDamping(); } }
FVector UProjectileMovementComponent::ComputeAcceleration(const FVector& InVelocity, float DeltaTime) const { FVector Acceleration(FVector::ZeroVector); Acceleration.Z += GetGravityZ(); if (bIsHomingProjectile && HomingTargetComponent.IsValid()) { Acceleration += ComputeHomingAcceleration(InVelocity, DeltaTime); } return Acceleration; }
void UWorld::SetupPhysicsTickFunctions(float DeltaSeconds) { StartPhysicsTickFunction.bCanEverTick = true; StartPhysicsTickFunction.Target = this; EndPhysicsTickFunction.bCanEverTick = true; EndPhysicsTickFunction.Target = this; StartClothTickFunction.bCanEverTick = true; StartClothTickFunction.Target = this; EndClothTickFunction.bCanEverTick = true; EndClothTickFunction.Target = this; // see if we need to update tick registration bool bNeedToUpdateTickRegistration = (bShouldSimulatePhysics != StartPhysicsTickFunction.IsTickFunctionRegistered()) || (bShouldSimulatePhysics != EndPhysicsTickFunction.IsTickFunctionRegistered()) || (bShouldSimulatePhysics != StartClothTickFunction.IsTickFunctionRegistered()) || (bShouldSimulatePhysics != EndClothTickFunction.IsTickFunctionRegistered()); if (bNeedToUpdateTickRegistration && PersistentLevel) { if (bShouldSimulatePhysics && !StartPhysicsTickFunction.IsTickFunctionRegistered()) { StartPhysicsTickFunction.TickGroup = TG_StartPhysics; StartPhysicsTickFunction.RegisterTickFunction(PersistentLevel); } else if (!bShouldSimulatePhysics && StartPhysicsTickFunction.IsTickFunctionRegistered()) { StartPhysicsTickFunction.UnRegisterTickFunction(); } if (bShouldSimulatePhysics && !EndPhysicsTickFunction.IsTickFunctionRegistered()) { EndPhysicsTickFunction.TickGroup = TG_EndPhysics; EndPhysicsTickFunction.RegisterTickFunction(PersistentLevel); EndPhysicsTickFunction.AddPrerequisite(this, StartPhysicsTickFunction); } else if (!bShouldSimulatePhysics && EndPhysicsTickFunction.IsTickFunctionRegistered()) { EndPhysicsTickFunction.RemovePrerequisite(this, StartPhysicsTickFunction); EndPhysicsTickFunction.UnRegisterTickFunction(); } //cloth if (bShouldSimulatePhysics && !StartClothTickFunction.IsTickFunctionRegistered()) { StartClothTickFunction.TickGroup = TG_StartCloth; StartClothTickFunction.RegisterTickFunction(PersistentLevel); } else if (!bShouldSimulatePhysics && StartClothTickFunction.IsTickFunctionRegistered()) { StartClothTickFunction.UnRegisterTickFunction(); } if (bShouldSimulatePhysics && !EndClothTickFunction.IsTickFunctionRegistered()) { EndClothTickFunction.TickGroup = TG_EndCloth; EndClothTickFunction.RegisterTickFunction(PersistentLevel); EndClothTickFunction.AddPrerequisite(this, StartClothTickFunction); } else if (!bShouldSimulatePhysics && EndClothTickFunction.IsTickFunctionRegistered()) { EndClothTickFunction.RemovePrerequisite(this, StartClothTickFunction); EndClothTickFunction.UnRegisterTickFunction(); } } FPhysScene* PhysScene = GetPhysicsScene(); if (PhysicsScene == NULL) { return; } #if WITH_PHYSX // When ticking the main scene, clean up any physics engine resources (once a frame) DeferredPhysResourceCleanup(); #endif // Update gravity in case it changed FVector DefaultGravity( 0.f, 0.f, GetGravityZ() ); static const auto CVar_MaxPhysicsDeltaTime = IConsoleManager::Get().FindTConsoleVariableDataFloat(TEXT("p.MaxPhysicsDeltaTime")); PhysScene->SetUpForFrame(&DefaultGravity, DeltaSeconds, UPhysicsSettings::Get()->MaxPhysicsDeltaTime); }
float UProjectileMovementComponent::GetEffectiveGravityZ() const { // TODO: apply buoyancy if in water return ShouldApplyGravity() ? GetGravityZ() * ProjectileGravityScale : 0.f; }
void UBuoyancyComponent::TickComponent(float DeltaTime, enum ELevelTick TickType, FActorComponentTickFunction *ThisTickFunction) { if (!OceanManager || !UpdatedComponent || !UpdatedPrimitive) return; if (!UpdatedComponent->IsSimulatingPhysics()) { FVector waveHeight = OceanManager->GetWaveHeightValue(UpdatedComponent->GetComponentLocation()); UpdatedPrimitive->SetWorldLocation(FVector(UpdatedComponent->GetComponentLocation().X, UpdatedComponent->GetComponentLocation().Y, waveHeight.Z), true); return; } //ApplyUprightConstraint is apparently needed again at first tick for BP-updated components. //TODO: there has to be a better way than this(?), PostInitialize(?) if (!_hasTicked) { _hasTicked = true; ApplyUprightConstraint(); } float TotalPoints = TestPoints.Num(); if (TotalPoints < 1) return; int PointsUnderWater = 0; for (int pointIndex = 0; pointIndex < TotalPoints; pointIndex++) { if (!TestPoints.IsValidIndex(pointIndex)) return; //Array size changed during runtime bool isUnderwater = false; FVector testPoint = TestPoints[pointIndex]; FVector worldTestPoint = UpdatedComponent->GetComponentTransform().TransformPosition(testPoint); float waveHeight = OceanManager->GetWaveHeightValue(worldTestPoint).Z; //If test point radius is touching water add buoyancy force if (waveHeight > (worldTestPoint.Z + _SignedRadius)) { PointsUnderWater++; isUnderwater = true; float DepthMultiplier = (waveHeight - (worldTestPoint.Z + _SignedRadius)) / (TestPointRadius * 2); DepthMultiplier = FMath::Clamp(DepthMultiplier, 0.f, 1.f); //If we have a point density override, use the overriden value insted of MeshDensity float PointDensity = PointDensityOverride.IsValidIndex(pointIndex) ? PointDensityOverride[pointIndex] : MeshDensity; /** * -------- * Buoyancy force formula: (Volume(Mass / Density) * Fluid Density * -Gravity) / Total Points * Depth Multiplier * -------- */ float BuoyancyForceZ = UpdatedPrimitive->GetMass() / PointDensity * FluidDensity * -GetGravityZ() / TotalPoints * DepthMultiplier; //Experimental velocity damping using GetUnrealWorldVelocityAtPoint! FVector DampingForce = -GetVelocityAtPoint(UpdatedPrimitive, worldTestPoint) * VelocityDamper * UpdatedPrimitive->GetMass() * DepthMultiplier; //Wave push force if (EnableWaveForces) { float waveVelocity = FMath::Clamp(GetVelocityAtPoint(UpdatedPrimitive, worldTestPoint).Z, -20.f, 150.f) * (1 - DepthMultiplier); DampingForce += FVector(OceanManager->GlobalWaveDirection.X, OceanManager->GlobalWaveDirection.Y, 0) * UpdatedPrimitive->GetMass() * waveVelocity * WaveForceMultiplier / TotalPoints; } //Add force for this test point UpdatedPrimitive->AddForceAtLocation(FVector(DampingForce.X, DampingForce.Y, DampingForce.Z + BuoyancyForceZ), worldTestPoint); } if (DrawDebugPoints) { FColor DebugColor = FLinearColor(0.8, 0.7, 0.2, 0.8).ToRGBE(); if (isUnderwater) { DebugColor = FLinearColor(0, 0.2, 0.7, 0.8).ToRGBE(); } //Blue color underwater, yellow out of watter DrawDebugSphere(GetWorld(), worldTestPoint, TestPointRadius, 8, DebugColor); } } //Clamp the velocity to MaxUnderwaterVelocity if there is any point underwater if (ClampMaxVelocity && PointsUnderWater > 0 && UpdatedPrimitive->GetPhysicsLinearVelocity().Size() > MaxUnderwaterVelocity) { FVector Velocity = UpdatedPrimitive->GetPhysicsLinearVelocity().GetSafeNormal() * MaxUnderwaterVelocity; UpdatedPrimitive->SetPhysicsLinearVelocity(Velocity); } //Update damping based on number of underwater test points UpdatedPrimitive->SetLinearDamping(_baseLinearDamping + FluidLinearDamping / TotalPoints * PointsUnderWater); UpdatedPrimitive->SetAngularDamping(_baseAngularDamping + FluidAngularDamping / TotalPoints * PointsUnderWater); }
bool UProjectileMovementComponent::ShouldUseSubStepping() const { return bForceSubStepping || (GetGravityZ() != 0.f) || (bIsHomingProjectile && HomingTargetComponent.IsValid()); }
// Deprecated float UProjectileMovementComponent::GetEffectiveGravityZ() const { return GetGravityZ(); }