Download

MultiLineTraceForObjects in C++ ?

Hi,

I am rewriting my blueprint in C++, and right now I am stuck on an issue with line tracing. BP has MultiLineTraceForObjects node, which returns all hits along the line trace. Equivalent of this in C++ should be LineTraceMultiByChannel(), BUT unfortunately, LineTraceMultiByChannel() stops any further hit testing after initial blocking hit was encountered, whereas the blueprint version keeps testing all the subsequent hits, even if the first one was blocking.

Basically, what I am trying to do is to line trace a grid of points against one specific actor in the level. I am deriving start and end positions of the line traces by bounding box of the objects. However, some other scene actors can be present in the level and be withing the bounds of the actor I am tracing against. In BP, I would just trace through such occluding actor, and iterate the hits until I find one which equals to my desired actor. In C++ I am unable to do that since LineTraceMultiByChannel() will simply refuse to trace beyond first blocking hit.

Any other ideas to solve this are appreciated too, but I will be calling this a lot, so inefficient solutions such as gathering all actors in the scene except one I am tracing against and then using that array as an actor exclusion parameter for line trace by object type is not really an option.

Thanks in advance.

I’ve figured it out in case someone else needs this too. Looks like in C++, in a typical C++ DIY manner, we are required to do the recurring line trace ourselves:



TArray<FTracedPoint> AScatter::TracePoints(TArray<FGeneratedPoint> GeneratedPoints, AActor* Surface)
{
    TArray<FTracedPoint> TracedPoints;
    FCollisionQueryParams QueryParams;

    for (auto Point : GeneratedPoints)
    {
        //Start and end vector for LineTrace (with 100 unit offset)
        FVector Start = Point.Location + FVector(0.f, 0.f, 100.f);
        FVector End = Point.Location + FVector(0.f, 0.f, (Point.Depth - 100.f));

        //Performs the LineTrace
        FHitResult Hit;
        Hit.bBlockingHit = true;

        while (Hit.Actor != Surface && Hit.bBlockingHit == true)
        {
            QueryParams.AddIgnoredActor(Hit.Actor.Get());
            GetWorld()->LineTraceSingleByChannel(Hit, Start, End, ECollisionChannel::ECC_WorldStatic, QueryParams);
        }

        if ((FVector::DotProduct(Hit.Normal, FVector(0, 0, 1)) <= SlopeLimit) ^ SlopeLimitInvert)
        {
            FTracedPoint TracedPoint = FTracedPoint(Hit.ImpactPoint, Hit.Normal);            
            TracedPoints.Add(TracedPoint);
        }
    }
    return TracedPoints;
}


I am just rerunning the single line trace as long as I am not getting a hit on an actor I need, and add any actors I hit along the way to the ignored actors list, so I eventually get to the one I need. It’s a snippet from my project, so sorry for the project specific bloat :slight_smile: