예제 #1
0
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
}