void AAgent::CheckLoS() { AAgentController* Controller = Cast<AAgentController>(GetController()); if (Controller != NULL) { // Get the location of the agent FVector AgentLocation = GetActorLocation(); // Get the direction the agent is facing FVector Direction = GetActorForwardVector(); // Default trace params FCollisionQueryParams TraceParams(TEXT("LineOfSight_Trace"), false, this); TraceParams.bTraceAsyncScene = true; //=====Draw line trace from agent to player=====// FHitResult Hit(ForceInit); UWorld* World = GetWorld(); World->LineTraceSingleByChannel(Hit, AgentLocation + Direction, Controller->GetFocalPoint(), ECollisionChannel::ECC_Visibility, TraceParams, FCollisionResponseParams::DefaultResponseParam); //DrawDebugLine(World, AgentLocation + Direction, Controller->GetFocalPoint(), FColor::Yellow, false, -1, 0, 2.0f); //==============================================// AActor* HitActor = Hit.GetActor(); if (HitActor != NULL && HitActor->ActorHasTag("Player")) { } /* Otherwise we can assume the actor intersecting the line trace is blocking the line of sight from the agent to the player */ else if (HitActor != NULL) { /* The focal point is currently on the player actor. Set the PlayerLocation blackboard key to the location of this focal point, so that when the agent moves into the Search behaviour it will move to the actual location of the player when the agent lost LoS as opposed to the last location it sensed the player at. */ Controller->SetPlayerLocation(Controller->GetFocalPoint()); // LoS to player is blocked bPlayerSeen = false; // Reset the player has seen blackboard key so that the Agent can begin searching. Controller->SetPlayerFound(bPlayerSeen); // Clear the focus on the player Controller->ClearFocus(EAIFocusPriority::Gameplay); bCanSearch = true; Controller->SetCanSearch(bCanSearch); // Stop firing if still firing if (isFiring) StopFiring(); } } }
PyObject *py_ue_line_trace_single_by_channel(ue_PyUObject * self, PyObject * args) { ue_py_check(self); PyObject *py_obj_start; PyObject *py_obj_end; int channel; UWorld *world = ue_get_uworld(self); if (!world) return PyErr_Format(PyExc_Exception, "unable to retrieve UWorld from uobject"); if (!PyArg_ParseTuple(args, "OOi:line_trace_single_by_channel", &py_obj_start, &py_obj_end, &channel)) { return NULL; } ue_PyFVector *start = py_ue_is_fvector(py_obj_start); ue_PyFVector *end = py_ue_is_fvector(py_obj_end); if (!start || !end) return PyErr_Format(PyExc_Exception, "start and end location must be vectors"); FHitResult hit; bool got_hit = world->LineTraceSingleByChannel(hit, start->vec, end->vec, (ECollisionChannel)channel); if (got_hit) { return py_ue_new_fhitresult(hit); } Py_RETURN_NONE; }
/** * Perform LineTraceSingleByChannel tests. Does a ray trace from a given point to a given shape mesh and verifies blocking is correct. * Data for tests is in the [/Script/UnrealEd.CollisionAutomationTestConfigData] section of BaseEditor.ini * * @param Parameters - Unused for this test * @return TRUE if the test was successful, FALSE otherwise */ bool FLineTraceSingleByChannel::RunTest(const FString& Parameters) { // Create map UWorld* World = FAutomationEditorCommonUtils::CreateNewMap(); TestNotNull(TEXT("Failed to create world for Physics.Collision.Ray Test. Tests aborted."), World); CollisionAutomationTests::TestBase = this; static FName TraceIdent = FName(TEXT("TestTrace")); FVector StartPos; FVector EndPos; ECollisionChannel Channel = ECC_WorldStatic; UCollisionAutomationTestConfigData* Data = UCollisionAutomationTestConfigData::StaticClass()->GetDefaultObject<UCollisionAutomationTestConfigData>(); for (int32 iTest = 0; iTest < Data->LineTraceSingleByChannelTests.Num(); iTest++) { FCollisionTestEntry OneElement = Data->LineTraceSingleByChannelTests[iTest]; AStaticMeshActor* TestRayMeshActor = CollisionAutomationTests::CreateShapeMeshActor(*OneElement.RootShapeAsset, OneElement.HitResult.TraceEnd); if (TestRayMeshActor != nullptr) { // Create the Actor to check against TestRayMeshActor->GetStaticMeshComponent()->BodyInstance.SetCollisionProfileName(TEXT("BlockAll")); TestRayMeshActor->SetActorEnableCollision(true); TestRayMeshActor->GetStaticMeshComponent()->BodyInstance.bSimulatePhysics = true; // Setup trace start/end StartPos = OneElement.HitResult.TraceStart; EndPos = TestRayMeshActor->GetActorLocation(); // Do the trace FHitResult OutHit; bool WasBlocked = World->LineTraceSingleByChannel(OutHit,StartPos,EndPos,Channel); bool BlockedBySpecified = false; if (WasBlocked == true) { if (OutHit.GetActor() == TestRayMeshActor) { BlockedBySpecified = true; // This generates a snippet you can copy/paste into the ini file for test validation //UE_LOG(CollisionAutomationTestLog, Log, TEXT("%d:HitResult=(%s)"), iTest + 1, *(CollisionAutomationTests::HitToString(OutHit))); CollisionAutomationTests::CheckVector(OutHit.ImpactNormal, OneElement.HitResult.ImpactNormal, TEXT("LineTraceSingleByChannel"), TEXT("ImpactNormal"), iTest); CollisionAutomationTests::CheckVector(OutHit.Normal, OneElement.HitResult.Normal, TEXT("LineTraceSingleByChannel"), TEXT("Normal"), iTest); CollisionAutomationTests::CheckVector(OutHit.ImpactPoint, OneElement.HitResult.ImpactPoint, TEXT("LineTraceSingleByChannel"), TEXT("ImpactPoint"), iTest); CollisionAutomationTests::CheckFloat(OutHit.Time, OneElement.HitResult.Time, TEXT("LineTraceSingleByChannel"), TEXT("Time"), iTest); } } TestTrue(FString::Printf(TEXT("Test %d:LineTraceSingleByChannel to %s failed. Should return blocking hit"), iTest + 1, *TestRayMeshActor->GetName()), BlockedBySpecified); // Change the collision profile and ensure we dont get a blocking hit UShapeComponent* CollisionComponent = Cast<UShapeComponent>(TestRayMeshActor->GetRootComponent()); if (CollisionComponent != nullptr) { CollisionComponent->SetCollisionProfileName(TEXT("OverlapAll")); CollisionComponent->SetSimulatePhysics(true); } TestRayMeshActor->GetStaticMeshComponent()->BodyInstance.SetCollisionProfileName(TEXT("OverlapAll")); WasBlocked = World->LineTraceSingleByChannel(OutHit, StartPos, EndPos, Channel); TestFalse(FString::Printf(TEXT("Test %d:LineTraceSingleByChannel to %s failed. Should not return blocking hit"), iTest + 1, *TestRayMeshActor->GetName()), WasBlocked); } // Remove the actor TestRayMeshActor->Destroy(); } return true; }
void UAblRayCastQueryTask::OnTaskStart(const TWeakObjectPtr<const UAblAbilityContext>& Context) const { Super::OnTaskStart(Context); AActor* SourceActor = m_QueryLocation.GetSourceActor(*Context.Get()); check(SourceActor); UWorld* World = SourceActor->GetWorld(); FTransform QueryTransform; m_QueryLocation.GetTransform(*Context.Get(), QueryTransform); const FVector RayStart = QueryTransform.GetLocation(); const FVector RayEnd = RayStart + QueryTransform.GetRotation().GetForwardVector() * m_Length; if (m_UseAsyncQuery && UAbleSettings::IsAsyncEnabled()) { UAblRayCastQueryTaskScratchPad* ScratchPad = Cast<UAblRayCastQueryTaskScratchPad>(Context->GetScratchPadForTask(this)); check(ScratchPad); if (m_OnlyReturnBlockingHit) { ScratchPad->AsyncHandle = World->AsyncLineTraceByChannel(EAsyncTraceType::Single, RayStart, RayEnd, m_CollisionChannel); } else { ScratchPad->AsyncHandle = World->AsyncLineTraceByChannel(EAsyncTraceType::Multi, RayStart, RayEnd, m_CollisionChannel); } } else { TArray<FHitResult> HitResults; FHitResult TraceResult; if (m_OnlyReturnBlockingHit) { if (World->LineTraceSingleByChannel(TraceResult, RayStart, RayEnd, m_CollisionChannel)) { HitResults.Add(TraceResult); } } else { World->LineTraceMultiByChannel(HitResults, RayStart, RayEnd, m_CollisionChannel); } #if !(UE_BUILD_SHIPPING) if (IsVerbose()) { PrintVerbose(FString::Printf(TEXT("Raycast found %d results."), HitResults.Num())); } #endif if (HitResults.Num()) { #if !(UE_BUILD_SHIPPING) if (IsVerbose()) { // Quick distance print help to see if we hit ourselves. float DistanceToBlocker = HitResults[HitResults.Num() - 1].Distance; PrintVerbose(FString::Printf(TEXT("Raycast blocking hit distance: %4.2f."), DistanceToBlocker)); } #endif if (m_CopyResultsToContext) { #if !(UE_BUILD_SHIPPING) if (IsVerbose()) { PrintVerbose(FString::Printf(TEXT("Copying %d results into Context."), HitResults.Num())); } #endif CopyResultsToContext(HitResults, Context); } if (m_FireEvent) { #if !(UE_BUILD_SHIPPING) if (IsVerbose()) { PrintVerbose(FString::Printf(TEXT("Firing Raycast Event %s with %d results."), *m_Name.ToString(), HitResults.Num())); } #endif Context->GetAbility()->OnRaycastEvent(Context.Get(), m_Name, HitResults); } } } #if !UE_BUILD_SHIPPING if (FAblAbilityDebug::ShouldDrawQueries()) { FAblAbilityDebug::DrawRaycastQuery(World, QueryTransform, m_Length); } #endif }