FVector UTKMathFunctionLibrary::GetVelocityAtPoint(UPrimitiveComponent* Target, FVector Point, FName BoneName, bool DrawDebugInfo) { //FTransform Transform = Target->GetComponentTransform(); //FVector LocalLinearVelocity = Transform.InverseTransformVectorNoScale(Target->GetPhysicsLinearVelocity()); //FVector LocalAngularVelocity = Transform.InverseTransformVectorNoScale(Target->GetPhysicsAngularVelocity()); //FVector ResultPointVelocity = LocalLinearVelocity + FVector::CrossProduct(FVector::DegreesToRadians(LocalAngularVelocity), Transform.InverseTransformVectorNoScale(Point - Target->GetCenterOfMass())); if (!Target) return FVector::ZeroVector; //You can actually get it from the physx body instance instead. FBodyInstance* BI = Target->GetBodyInstance(BoneName); if (BI && BI->IsValidBodyInstance()) { FVector PointVelocity = BI->GetUnrealWorldVelocityAtPoint(Point); UWorld* TheWorld = Target->GetWorld(); if (DrawDebugInfo && TheWorld) { FColor DefaultColor(255,200,0); DrawDebugPoint(TheWorld, Point, 10, DefaultColor); DrawDebugString(TheWorld, Point, FString::SanitizeFloat(PointVelocity.Size()), NULL, FColor::White, 0.0f); } return PointVelocity; } return FVector::ZeroVector; }
void FSoundSource::DrawDebugInfo() { // Draw 3d Debug information about this source, if enabled FAudioDeviceManager* DeviceManager = GEngine->GetAudioDeviceManager(); if (DeviceManager && DeviceManager->IsVisualizeDebug3dEnabled()) { const uint32 AudioComponentID = WaveInstance->ActiveSound->GetAudioComponentID(); if (AudioComponentID > 0) { DECLARE_CYCLE_STAT(TEXT("FAudioThreadTask.DrawSourceDebugInfo"), STAT_AudioDrawSourceDebugInfo, STATGROUP_TaskGraphTasks); USoundBase* Sound = WaveInstance->ActiveSound->GetSound(); const FVector Location = WaveInstance->Location; const bool bSpatialized = Buffer->NumChannels == 2 && WaveInstance->bUseSpatialization; const FVector LeftChannelSourceLoc = LeftChannelSourceLocation; const FVector RightChannelSourceLoc = RightChannelSourceLocation; FAudioThread::RunCommandOnGameThread([AudioComponentID, Sound, bSpatialized, Location, LeftChannelSourceLoc, RightChannelSourceLoc]() { UAudioComponent* AudioComponent = UAudioComponent::GetAudioComponentFromID(AudioComponentID); if (AudioComponent) { UWorld* SoundWorld = AudioComponent->GetWorld(); if (SoundWorld) { FRotator SoundRotation = AudioComponent->GetComponentRotation(); DrawDebugCrosshairs(SoundWorld, Location, SoundRotation, 20.0f, FColor::White, false, -1.0f, SDPG_Foreground); if (bSpatialized) { DrawDebugCrosshairs(SoundWorld, LeftChannelSourceLoc, SoundRotation, 20.0f, FColor::Red, false, -1.0f, SDPG_Foreground); DrawDebugCrosshairs(SoundWorld, RightChannelSourceLoc, SoundRotation, 20.0f, FColor::Green, false, -1.0f, SDPG_Foreground); } const FString Name = Sound->GetName(); DrawDebugString(SoundWorld, AudioComponent->GetComponentLocation() + FVector(0, 0, 32), *Name, nullptr, FColor::White, 0.033, false); } } }, GET_STATID(STAT_AudioDrawSourceDebugInfo)); } } }
void UGameplayCueManager::HandleGameplayCue(AActor* TargetActor, FGameplayTag GameplayCueTag, EGameplayCueEvent::Type EventType, const FGameplayCueParameters& Parameters) { if (DisableGameplayCues) { return; } if (GameplayCueRunOnDedicatedServer == 0 && IsDedicatedServerForGameplayCue()) { return; } #if WITH_EDITOR if (GIsEditor && TargetActor == nullptr && UGameplayCueManager::PreviewComponent) { TargetActor = Cast<AActor>(AActor::StaticClass()->GetDefaultObject()); } #endif if (TargetActor == nullptr) { ABILITY_LOG(Warning, TEXT("UGameplayCueManager::HandleGameplayCue called on null TargetActor. GameplayCueTag: %s."), *GameplayCueTag.ToString()); return; } IGameplayCueInterface* GameplayCueInterface = Cast<IGameplayCueInterface>(TargetActor); bool bAcceptsCue = true; if (GameplayCueInterface) { bAcceptsCue = GameplayCueInterface->ShouldAcceptGameplayCue(TargetActor, GameplayCueTag, EventType, Parameters); } if (DisplayGameplayCues) { FString DebugStr = FString::Printf(TEXT("%s - %s"), *GameplayCueTag.ToString(), *EGameplayCueEventToString(EventType) ); FColor DebugColor = FColor::Green; DrawDebugString(TargetActor->GetWorld(), FVector(0.f, 0.f, 100.f), DebugStr, TargetActor, DebugColor, DisplayGameplayCueDuration); } CurrentWorld = TargetActor->GetWorld(); // Don't handle gameplay cues when world is tearing down if (!GetWorld() || GetWorld()->bIsTearingDown) { return; } // Give the global set a chance check(GlobalCueSet); if (bAcceptsCue) { GlobalCueSet->HandleGameplayCue(TargetActor, GameplayCueTag, EventType, Parameters); } // Use the interface even if it's not in the map if (GameplayCueInterface && bAcceptsCue) { GameplayCueInterface->HandleGameplayCue(TargetActor, GameplayCueTag, EventType, Parameters); } CurrentWorld = nullptr; }
// Runs calculations on friction component, applies friction force to effected component and returns reaction forces(forces that can effect track or a wheel) void UMMTFrictionComponent::ApplyFriction(const FVector& ContactPointLocation, const FVector& ContactPointNormal, const FVector& InducedVelocity, const FVector& PreNormalForceAtPoint, const EPhysicalSurface& PhysicalSurface, const float& NumberOfContactPoints, const float& DeltaTime, FVector& NormalizedReactionForce, FVector& RollingFrictionForce) { // Gather stats SCOPE_CYCLE_COUNTER(STAT_MMTFrictionApply); float NormalForceAtContactPoint = PreNormalForceAtPoint.ProjectOnTo(ContactPointNormal).Size(); // Check if Effected Component Mesh reference is valid and escape early otherwise if (!IsValid(EffectedComponentMesh)) { GEngine->AddOnScreenDebugMessage(-1, 15.0f, FColor::Red, FString::Printf(TEXT("%s->%s component's EffectedComponentMesh reference is invalid!"), *GetOwner()->GetName(), *GetName())); UE_LOG(LogTemp, Warning, TEXT("%s->%s component's EffectedComponentMesh reference is invalid!"), *GetOwner()->GetName(), *GetName()); NormalizedReactionForce = FVector::ZeroVector; RollingFrictionForce = FVector::ZeroVector; return; } //Find relative velocity of the friction surface and ground/another object at point FVector RelativeVelocityAtPoint = EffectedComponentMesh->GetPhysicsLinearVelocityAtPoint(ContactPointLocation) + InducedVelocity + FrictionSurfaceVelocity; RelativeVelocityAtPoint = RelativeVelocityAtPoint.VectorPlaneProject(RelativeVelocityAtPoint, ContactPointNormal); //filter out oscillations when vehicle is standing still but friction overshoots RelativeVelocityAtPoint = (PrevRelativeVelocityAtPoint + RelativeVelocityAtPoint) * 0.5; PrevRelativeVelocityAtPoint = RelativeVelocityAtPoint; // early exit if velocity is too low to consider as vehicle most likely standing still if (RelativeVelocityAtPoint.Size() < 1.0f) { NormalizedReactionForce = FVector::ZeroVector; RollingFrictionForce = FVector::ZeroVector; return; } //Calculate static and kinetic friction coefficients, taking into account velocity direction and friction ellipse float MuStatic; float MuKinetic; UMMTBPFunctionLibrary::GetMuFromFrictionElipse(RelativeVelocityAtPoint.GetSafeNormal(), ReferenceFrameTransform.TransformVector(FVector(1.0f, 1.0f, 1.0f)), MuXStatic, MuXKinetic, MuYStatic, MuYKinetic, MuStatic, MuKinetic); //Calculate "stopping force" which is amount of force necessary to completely remove velocity of the object FVector StoppingForce = ((RelativeVelocityAtPoint * (-1.0f) * EffectedComponentMesh->GetMass()) / DeltaTime) / NumberOfContactPoints; //Static friction threshold float MuStaticByLoad = NormalForceAtContactPoint * MuStatic; //Friction Force that will be applied to effected mesh component FVector ApplicationForce; if (StoppingForce.Size() >= MuStaticByLoad) { ApplicationForce = StoppingForce.GetClampedToSize(0.0f, NormalForceAtContactPoint * MuKinetic); if (IsDebugMode) { DrawDebugString(GetWorld(), ContactPointLocation, FString("Kinetic Friction"), nullptr, FColor::Magenta, 0.0f, false); } } else { ApplicationForce = StoppingForce.GetClampedToSize(0.0f, MuStaticByLoad); if (IsDebugMode) { DrawDebugString(GetWorld(), ContactPointLocation, FString("Static Friction"), nullptr, FColor::Red, 0.0f, false); } } //Apply friction force UMMTBPFunctionLibrary::MMTAddForceAtLocationComponent(EffectedComponentMesh, ApplicationForce, ContactPointLocation); //Calculate Reaction force NormalizedReactionForce = (ApplicationForce * (-1.0f)) / EffectedComponentMesh->GetMass(); //Calculate Rolling Friction float RollingFrictionCoefficient = FPhysicalSurfaceRollingFrictionCoefficient().RollingFrictionCoefficient; for (int32 i = 0; i < PhysicsSurfaceResponse.Num(); i++) { if (PhysicsSurfaceResponse[i].PhysicalSurface == PhysicalSurface) { RollingFrictionCoefficient = PhysicsSurfaceResponse[i].RollingFrictionCoefficient; break; } } RollingFrictionForce = RelativeVelocityAtPoint.GetSafeNormal() * NormalForceAtContactPoint * RollingFrictionCoefficient; if (IsDebugMode) { DrawDebugLine(GetWorld(), ContactPointLocation, ContactPointLocation + ApplicationForce * 0.005f, FColor::Yellow, false, 0.0f, 0, 3.0f); DrawDebugLine(GetWorld(), ContactPointLocation, ContactPointLocation + RollingFrictionForce * 0.005f, FColor::Green, false, 0.0f, 0, 3.0f); DrawDebugString(GetWorld(), ContactPointLocation+FVector(0.0f, 0.0f, 50.0f), (PhysicalSurfaceEnum ? PhysicalSurfaceEnum->GetEnumName(PhysicalSurface) : FString("<Invalid Enum>")), nullptr, FColor::Cyan, 0.0f, false); //DrawDebugString(GetWorld(), ContactPointLocation + FVector(0.0f, 0.0f, 25.0f), FString("Normal Force: ") + FString::SanitizeFloat(NormalForceAtContactPoint), nullptr, FColor::Turquoise, 0.0f, false); } }