bool UGripMotionControllerComponent::CheckComponentWithSweep(UPrimitiveComponent * ComponentToCheck, FVector Move, FRotator newOrientation, bool bSkipSimulatingComponents/*, bool &bHadBlockingHitOut*/) { TArray<FHitResult> Hits; // WARNING: HitResult is only partially initialized in some paths. All data is valid only if bFilledHitResult is true. FHitResult BlockingHit(NoInit); BlockingHit.bBlockingHit = false; BlockingHit.Time = 1.f; bool bFilledHitResult = false; bool bMoved = false; bool bIncludesOverlapsAtEnd = false; bool bRotationOnly = false; UPrimitiveComponent *root = ComponentToCheck; if (!root || !root->IsQueryCollisionEnabled()) return false; FVector start(root->GetComponentLocation()); const bool bCollisionEnabled = root->IsQueryCollisionEnabled(); if (bCollisionEnabled) { #if !(UE_BUILD_SHIPPING || UE_BUILD_TEST) if (!root->IsRegistered()) { UE_LOG(LogTemp, Warning, TEXT("MovedComponent %s not initialized in grip motion controller"), *root->GetFullName()); } #endif UWorld* const MyWorld = GetWorld(); FComponentQueryParams Params(TEXT("sweep_params"), root->GetOwner()); FCollisionResponseParams ResponseParam; root->InitSweepCollisionParams(Params, ResponseParam); bool const bHadBlockingHit = MyWorld->ComponentSweepMulti(Hits, root, start, start + Move, newOrientation, Params); if (bHadBlockingHit) { int32 BlockingHitIndex = INDEX_NONE; float BlockingHitNormalDotDelta = BIG_NUMBER; for (int32 HitIdx = 0; HitIdx < Hits.Num(); HitIdx++) { const FHitResult& TestHit = Hits[HitIdx]; // Ignore the owning actor to the motion controller if (TestHit.Actor == this->GetOwner() || (bSkipSimulatingComponents && TestHit.Component->IsSimulatingPhysics())) { if (Hits.Num() == 1) { //bHadBlockingHitOut = false; return false; } else continue; } if (TestHit.bBlockingHit && TestHit.IsValidBlockingHit()) { if (TestHit.Time == 0.f) { // We may have multiple initial hits, and want to choose the one with the normal most opposed to our movement. const float NormalDotDelta = (TestHit.ImpactNormal | Move); if (NormalDotDelta < BlockingHitNormalDotDelta) { BlockingHitNormalDotDelta = NormalDotDelta; BlockingHitIndex = HitIdx; } } else if (BlockingHitIndex == INDEX_NONE) { // First non-overlapping blocking hit should be used, if an overlapping hit was not. // This should be the only non-overlapping blocking hit, and last in the results. BlockingHitIndex = HitIdx; break; } //} } } // Update blocking hit, if there was a valid one. if (BlockingHitIndex >= 0) { BlockingHit = Hits[BlockingHitIndex]; bFilledHitResult = true; } } } // Handle blocking hit notifications. Avoid if pending kill (which could happen after overlaps). if (BlockingHit.bBlockingHit && !root->IsPendingKill()) { check(bFilledHitResult); if (root->IsDeferringMovementUpdates()) { FScopedMovementUpdate* ScopedUpdate = root->GetCurrentScopedMovement(); ScopedUpdate->AppendBlockingHitAfterMove(BlockingHit); } else { if(root->GetOwner()) root->DispatchBlockingHit(*root->GetOwner(), BlockingHit); } return true; } return false; }