void ASpawnEnemy::SpawnRandomEnemy() { TArray<FString> Parsed; TArray<FString> HowMuch; TArray<FString> TypeEnemy; const TCHAR* Delims[] = { TEXT(":"), TEXT(";") }; float RandomNumber = (float)rand() / (float)RAND_MAX; int SetNumber = RandomNumber * (Enemies.Num()); Enemies[SetNumber].ParseIntoArray(&Parsed, Delims, 2); int SizeOfArrayParsed = Parsed.Num() - 1; for (int x = 0; x <= SizeOfArrayParsed; x = x + 2) { HowMuch.Add(Parsed[x]); } for (int x = 1; x <= SizeOfArrayParsed; x = x + 2) { TypeEnemy.Add(Parsed[x]); } for (auto Itr(HowMuch.CreateIterator()); Itr; Itr++) { APawn* NewPawn = NULL; FVector BoxOnWorld = GetActorLocation(); FRotator RotatorBoxOnWorld = GetActorRotation(); FBox BoxInfo = GetComponentsBoundingBox(); FVector BoxSize = BoxInfo.GetSize(); if (TypeEnemy[Itr.GetIndex()] == "PegEnemyLight") { EnemyClass = PegLightEnemyClass; } else if (TypeEnemy[Itr.GetIndex()] == "PegDarkEnemy") { EnemyClass = PegDarkEnemyClass; } else if (TypeEnemy[Itr.GetIndex()] == "GarbageEnemy") { EnemyClass = GarbageEnemyClass; } else if (TypeEnemy[Itr.GetIndex()] == "MeleeBookEnemy") { EnemyClass = MeleeBookEnemyClass; } else if (TypeEnemy[Itr.GetIndex()] == "RangeBookEnemy") { EnemyClass = RangeBookEnemyClass; } else if (TypeEnemy[Itr.GetIndex()] == "PianoChargeEnemy") { EnemyClass = PianoEnemyClass; } else if (TypeEnemy[Itr.GetIndex()] == "BarrelChargeEnemy") { EnemyClass = BarrelEnemyClass; } else if (TypeEnemy[Itr.GetIndex()] == "FridgeChargeEnemy") { EnemyClass = FridgeEnemyClass; } if (GetWorld()) { int32 MyShinyNewInt = FCString::Atoi(*HowMuch[Itr.GetIndex()]); for (int x = 1; x <= MyShinyNewInt; x++) { float random = (float)rand() / (float)RAND_MAX; float randomy = (float)rand() / (float)RAND_MAX; int xValue = 1 + random * ((3) - (1)); int yValue = 1 + randomy * ((3) - (1)); float z, y; if (xValue == 1) z = random * (0 + (BoxSize[0] / 2)); else z = random * (0 - (BoxSize[0] / 2)); if (yValue == 1) y = random * (0 + (BoxSize[1] / 2)); else y = random * (0 - (BoxSize[1] / 2)); BoxOnWorld[0] += z; BoxOnWorld[1] += y; if (ShouldSpawnEnemies) { if (BoxInfo.IsInside(BoxOnWorld)) { NewPawn = GetWorld()->SpawnActor<AAI_BasicEnemy>(EnemyClass, BoxOnWorld, RotatorBoxOnWorld); FVector BoxOnWorld = GetActorLocation(); if (NewPawn != NULL) { if (NewPawn->Controller == NULL) { NewPawn->SpawnDefaultController(); } if (BehaviorTree != NULL) { AAIController* AIController = Cast<AAIController>(NewPawn->Controller); if (AIController != NULL) { AIController->RunBehaviorTree(BehaviorTree); } } } //AI Direct laten aanvallen wanneer die spawnt! AAI_BasicController* Controller = (AAI_BasicController*)NewPawn->GetController(); Controller->FoundPlayer(); Controller->AISetAttackState(); } } } } } EnemyClass = NULL; APawn* NewPawn = NULL; }
bool UBillboardComponent::ComponentIsTouchingSelectionBox(const FBox& InSelBBox, const FEngineShowFlags& ShowFlags, const bool bConsiderOnlyBSP, const bool bMustEncompassEntireComponent) const { AActor* Actor = GetOwner(); if (!bConsiderOnlyBSP && ShowFlags.BillboardSprites && Sprite != nullptr && Actor != nullptr) { const float Scale = ComponentToWorld.GetMaximumAxisScale(); // Construct a box representing the sprite const FBox SpriteBox( Actor->GetActorLocation() - Scale * FMath::Max(Sprite->GetSizeX(), Sprite->GetSizeY()) * FVector(0.5f, 0.5f, 0.5f), Actor->GetActorLocation() + Scale * FMath::Max(Sprite->GetSizeX(), Sprite->GetSizeY()) * FVector(0.5f, 0.5f, 0.5f)); // If the selection box doesn't have to encompass the entire component and it intersects with the box constructed for the sprite, then it is valid. // Additionally, if the selection box does have to encompass the entire component and both the min and max vectors of the sprite box are inside the selection box, // then it is valid. if ((!bMustEncompassEntireComponent && InSelBBox.Intersect(SpriteBox)) || (bMustEncompassEntireComponent && InSelBBox.IsInside(SpriteBox))) { return true; } } return false; }
void UParticleModuleCollision::Update(FParticleEmitterInstance* Owner, int32 Offset, float DeltaTime) { SCOPE_CYCLE_COUNTER(STAT_ParticleCollisionTime); check(Owner); check(Owner->Component); UWorld* World = Owner->Component->GetWorld(); if (Owner->ActiveParticles == 0 || (bDropDetail && World && World->bDropDetail)) { return; } //Gets the owning actor of the component. Can be NULL if the component is spawned with the World as an Outer, e.g. in UGameplayStatics::SpawnEmitterAtLocation(). AActor* Actor = Owner->Component->GetOwner(); UParticleLODLevel* LODLevel = Owner->SpriteTemplate->GetCurrentLODLevel(Owner); check(LODLevel); const int32 MeshRotationOffset = Owner->GetMeshRotationOffset(); const bool bMeshRotationActive = Owner->IsMeshRotationActive(); const FTransform& OwnerTM = Owner->Component->GetAsyncComponentToWorld(); const FVector ParentScale = OwnerTM.GetScale3D(); FParticleEventInstancePayload* EventPayload = NULL; if (LODLevel->EventGenerator) { EventPayload = (FParticleEventInstancePayload*)(Owner->GetModuleInstanceData(LODLevel->EventGenerator)); if (EventPayload && (EventPayload->bCollisionEventsPresent == false) && (EventPayload->bDeathEventsPresent == false)) { EventPayload = NULL; } } FParticleCollisionInstancePayload* CollisionInstPayload = (FParticleCollisionInstancePayload*)(Owner->GetModuleInstanceData(this)); const TArray<FVector>& PlayerLocations = Owner->Component->GetPlayerLocations(); TArray<float> PlayerLODDistanceFactor = Owner->Component->GetPlayerLODDistanceFactor(); //Make a copy because we need to square it later const int32 PlayerCount = PlayerLocations.Num(); if (World->IsGameWorld()) { bool bIgnoreAllCollision = false; // LOD collision based on visibility // This is at the 'emitter instance' level as it will be true or false for the whole instance... if (bCollideOnlyIfVisible && ((World->TimeSeconds - Owner->Component->LastRenderTime) > 0.1f)) { // no collision if not recently rendered bIgnoreAllCollision = true; } else { // If the MaxCollisionDistance is greater than WORLD_MAX, they obviously want the check disabled... if (MaxCollisionDistance < WORLD_MAX) { // If we have at least a few particles, do a simple check vs. the bounds if (Owner->ActiveParticles > 7) { if (CollisionInstPayload->CurrentLODBoundsCheckCount == 0) { FBox BoundingBox; BoundingBox.Init(); if (Owner->Component->Template && Owner->Component->Template->bUseFixedRelativeBoundingBox) { BoundingBox = Owner->Component->Template->FixedRelativeBoundingBox.TransformBy(OwnerTM); } else { // A frame behind, but shouldn't be an issue... BoundingBox = Owner->Component->GetAsyncBounds().GetBox(); } // see if any player is within the extended bounds... bIgnoreAllCollision = true; // Check for the system itself beyond beyond the bounds // LOD collision by distance bool bCloseEnough = false; for (int32 PlyrIdx = 0; PlyrIdx < PlayerCount; PlyrIdx++) { // Invert the LOD distance factor here because we are using it to *expand* the // bounds rather than shorten the distance checked as it is usually used for. float InvDistanceFactor = 1.0f / PlayerLODDistanceFactor[PlyrIdx]; FBox CheckBounds = BoundingBox; float BoxExpansionValue = MaxCollisionDistance * InvDistanceFactor; BoxExpansionValue += BoxExpansionValue * 0.075f; // Expand it by the max collision distance (and a little bit extra) CheckBounds = CheckBounds.ExpandBy(BoxExpansionValue); if (CheckBounds.IsInside(PlayerLocations[PlyrIdx])) { // If one is close enough, that's all it takes! bCloseEnough = true; break; } } if (bCloseEnough == true) { bIgnoreAllCollision = false; } } CollisionInstPayload->CurrentLODBoundsCheckCount++; // Every 30 frames recheck the overall bounds... if (CollisionInstPayload->CurrentLODBoundsCheckCount > 30) { CollisionInstPayload->CurrentLODBoundsCheckCount = 0; } } } } if (bIgnoreAllCollision == true) { // Turn off collision on *all* existing particles... // We don't want it to turn back on and have particles // already embedded start performing collision checks. BEGIN_UPDATE_LOOP; { Particle.Flags |= STATE_Particle_IgnoreCollisions; } END_UPDATE_LOOP; return; } // Square the LODDistanceFactor values now, so we don't have to do it // per particle in the update loop below... for (int32 SquareIdx = 0; SquareIdx < PlayerLocations.Num(); SquareIdx++) { PlayerLODDistanceFactor[SquareIdx] *= PlayerLODDistanceFactor[SquareIdx]; } } float SquaredMaxCollisionDistance = FMath::Square(MaxCollisionDistance); BEGIN_UPDATE_LOOP; { if ((Particle.Flags & STATE_Particle_CollisionIgnoreCheck) != 0) { CONTINUE_UPDATE_LOOP; } PARTICLE_ELEMENT(FParticleCollisionPayload, CollisionPayload); if ((Particle.Flags & STATE_Particle_DelayCollisions) != 0) { if (CollisionPayload.Delay > Particle.RelativeTime) { CONTINUE_UPDATE_LOOP; } Particle.Flags &= ~STATE_Particle_DelayCollisions; } FVector Location; FVector OldLocation; // Location won't be calculated till after tick so we need to calculate an intermediate one here. Location = Particle.Location + Particle.Velocity * DeltaTime; if (LODLevel->RequiredModule->bUseLocalSpace) { // Transform the location and old location into world space Location = OwnerTM.TransformPosition(Location); OldLocation = OwnerTM.TransformPosition(Particle.OldLocation); } else { OldLocation = Particle.OldLocation; } FVector Direction = (Location - OldLocation).GetSafeNormal(); // Determine the size FVector Size = Particle.Size * ParentScale; FVector Extent(0.0f); // Setup extent for mesh particles. UParticleModuleTypeDataMesh* MeshType = Cast<UParticleModuleTypeDataMesh>(LODLevel->TypeDataModule); if (MeshType && MeshType->Mesh) { Extent = MeshType->Mesh->GetBounds().BoxExtent; Extent = MeshType->bCollisionsConsiderPartilceSize ? Extent * Size : Extent; } FHitResult Hit; Hit.Normal.X = 0.0f; Hit.Normal.Y = 0.0f; Hit.Normal.Z = 0.0f; check( Owner->Component ); FVector End = Location + Direction * Size / DirScalar; if ((World->IsGameWorld() == true) && (MaxCollisionDistance < WORLD_MAX)) { // LOD collision by distance bool bCloseEnough = false; for (int32 CheckIdx = 0; CheckIdx < PlayerCount; CheckIdx++) { float CheckValue = (PlayerLocations[CheckIdx] - End).SizeSquared() * PlayerLODDistanceFactor[CheckIdx]; if (CheckValue < SquaredMaxCollisionDistance) { bCloseEnough = true; break; } } if (bCloseEnough == false) { Particle.Flags |= STATE_Particle_IgnoreCollisions; CONTINUE_UPDATE_LOOP; } } AActor* IgnoreActor = bIgnoreSourceActor ? Actor : NULL; if (PerformCollisionCheck(Owner, &Particle, Hit, IgnoreActor, End, OldLocation, Extent)) { bool bDecrementMaxCount = true; bool bIgnoreCollision = false; if (Hit.GetActor()) { bDecrementMaxCount = !bPawnsDoNotDecrementCount || !Cast<APawn>(Hit.GetActor()); bIgnoreCollision = bIgnoreTriggerVolumes && Hit.GetActor()->IsA(ATriggerBase::StaticClass()); //@todo.SAS. Allow for PSys to say what it wants to collide w/? } if (bIgnoreCollision == false) { if (bDecrementMaxCount && (bOnlyVerticalNormalsDecrementCount == true)) { if ((Hit.Normal.IsNearlyZero() == false) && (FMath::Abs(Hit.Normal.Z) + VerticalFudgeFactor) < 1.0f) { //UE_LOG(LogParticles, Log, TEXT("Particle from %s had a non-vertical hit!"), *(Owner->Component->Template->GetPathName())); bDecrementMaxCount = false; } } if (bDecrementMaxCount) { CollisionPayload.UsedCollisions--; } if (CollisionPayload.UsedCollisions > 0) { if (LODLevel->RequiredModule->bUseLocalSpace) { // Transform the particle velocity to world space FVector OldVelocity = OwnerTM.TransformVector(Particle.Velocity); FVector BaseVelocity = OwnerTM.TransformVector(Particle.BaseVelocity); BaseVelocity = BaseVelocity.MirrorByVector(Hit.Normal) * CollisionPayload.UsedDampingFactor; Particle.BaseVelocity = OwnerTM.InverseTransformVector(BaseVelocity); Particle.BaseRotationRate = Particle.BaseRotationRate * CollisionPayload.UsedDampingFactorRotation.X; if (bMeshRotationActive && MeshRotationOffset > 0) { FMeshRotationPayloadData* PayloadData = (FMeshRotationPayloadData*)((uint8*)&Particle + MeshRotationOffset); PayloadData->RotationRateBase *= CollisionPayload.UsedDampingFactorRotation; } // Reset the current velocity and manually adjust location to bounce off based on normal and time of collision. FVector NewVelocity = Direction.MirrorByVector(Hit.Normal) * (Location - OldLocation).Size() * CollisionPayload.UsedDampingFactor; Particle.Velocity = FVector::ZeroVector; // New location FVector NewLocation = Location + NewVelocity * (1.f - Hit.Time); Particle.Location = OwnerTM.InverseTransformPosition(NewLocation); if (bApplyPhysics) { check(IsInGameThread()); UPrimitiveComponent* PrimitiveComponent = Hit.Component.Get(); if(PrimitiveComponent && PrimitiveComponent->IsAnySimulatingPhysics()) { FVector vImpulse; vImpulse = -(NewVelocity - OldVelocity) * ParticleMass.GetValue(Particle.RelativeTime, Owner->Component); PrimitiveComponent->AddImpulseAtLocation(vImpulse, Hit.Location, Hit.BoneName); } } } else { FVector vOldVelocity = Particle.Velocity; // Reflect base velocity and apply damping factor. Particle.BaseVelocity = Particle.BaseVelocity.MirrorByVector(Hit.Normal) * CollisionPayload.UsedDampingFactor; Particle.BaseRotationRate = Particle.BaseRotationRate * CollisionPayload.UsedDampingFactorRotation.X; if (bMeshRotationActive && MeshRotationOffset > 0) { FMeshRotationPayloadData* PayloadData = (FMeshRotationPayloadData*)((uint8*)&Particle + MeshRotationOffset); PayloadData->RotationRateBase *= CollisionPayload.UsedDampingFactorRotation; } // Reset the current velocity and manually adjust location to bounce off based on normal and time of collision. FVector vNewVelocity = Direction.MirrorByVector(Hit.Normal) * (Location - OldLocation).Size() * CollisionPayload.UsedDampingFactor; Particle.Velocity = FVector::ZeroVector; Particle.Location += vNewVelocity * (1.f - Hit.Time); if (bApplyPhysics) { check(IsInGameThread()); UPrimitiveComponent* PrimitiveComponent = Hit.Component.Get(); if(PrimitiveComponent && PrimitiveComponent->IsAnySimulatingPhysics()) { FVector vImpulse; vImpulse = -(vNewVelocity - vOldVelocity) * ParticleMass.GetValue(Particle.RelativeTime, Owner->Component); PrimitiveComponent->AddImpulseAtLocation(vImpulse, Hit.Location, Hit.BoneName); } } } if (EventPayload && (EventPayload->bCollisionEventsPresent == true)) { LODLevel->EventGenerator->HandleParticleCollision(Owner, EventPayload, &CollisionPayload, &Hit, &Particle, Direction); } } else { if (LODLevel->RequiredModule->bUseLocalSpace == true) { Size = OwnerTM.TransformVector(Size); } Particle.Location = Hit.Location + (Size / 2.0f); if (LODLevel->RequiredModule->bUseLocalSpace == true) { // We need to transform the location back relative to the PSys. // NOTE: LocalSpace makes sense only for stationary emitters that use collision. Particle.Location = OwnerTM.InverseTransformPosition(Particle.Location); } switch (CollisionCompletionOption) { case EPCC_Kill: { if (EventPayload && (EventPayload->bDeathEventsPresent == true)) { LODLevel->EventGenerator->HandleParticleKilled(Owner, EventPayload, &Particle); } KILL_CURRENT_PARTICLE; } break; case EPCC_Freeze: { Particle.Flags |= STATE_Particle_Freeze; } break; case EPCC_HaltCollisions: { Particle.Flags |= STATE_Particle_IgnoreCollisions; } break; case EPCC_FreezeTranslation: { Particle.Flags |= STATE_Particle_FreezeTranslation; } break; case EPCC_FreezeRotation: { Particle.Flags |= STATE_Particle_FreezeRotation; } break; case EPCC_FreezeMovement: { Particle.Flags |= STATE_Particle_FreezeRotation; Particle.Flags |= STATE_Particle_FreezeTranslation; } break; } if (EventPayload && (EventPayload->bCollisionEventsPresent == true)) { LODLevel->EventGenerator->HandleParticleCollision(Owner, EventPayload, &CollisionPayload, &Hit, &Particle, Direction); } } Particle.Flags |= STATE_Particle_CollisionHasOccurred; } } } END_UPDATE_LOOP; }
/** * Returns an array of visibility data for the given view position, or NULL if none exists. * The data bits are indexed by VisibilityId of each primitive in the scene. * This method decompresses data if necessary and caches it based on the bucket and chunk index in the view state. */ const uint8* FSceneViewState::GetPrecomputedVisibilityData(FViewInfo& View, const FScene* Scene) { const uint8* PrecomputedVisibilityData = NULL; if (Scene->PrecomputedVisibilityHandler && GAllowPrecomputedVisibility && View.Family->EngineShowFlags.PrecomputedVisibility) { const FPrecomputedVisibilityHandler& Handler = *Scene->PrecomputedVisibilityHandler; FViewElementPDI VisibilityCellsPDI(&View, NULL); // Draw visibility cell bounds for debugging if enabled if ((GShowPrecomputedVisibilityCells || View.Family->EngineShowFlags.PrecomputedVisibilityCells) && !GShowRelevantPrecomputedVisibilityCells) { for (int32 BucketIndex = 0; BucketIndex < Handler.PrecomputedVisibilityCellBuckets.Num(); BucketIndex++) { for (int32 CellIndex = 0; CellIndex < Handler.PrecomputedVisibilityCellBuckets[BucketIndex].Cells.Num(); CellIndex++) { const FPrecomputedVisibilityCell& CurrentCell = Handler.PrecomputedVisibilityCellBuckets[BucketIndex].Cells[CellIndex]; // Construct the cell's bounds const FBox CellBounds(CurrentCell.Min, CurrentCell.Min + FVector(Handler.PrecomputedVisibilityCellSizeXY, Handler.PrecomputedVisibilityCellSizeXY, Handler.PrecomputedVisibilityCellSizeZ)); if (View.ViewFrustum.IntersectBox(CellBounds.GetCenter(), CellBounds.GetExtent())) { DrawWireBox(&VisibilityCellsPDI, CellBounds, FColor(50, 50, 255), SDPG_World); } } } } // Calculate the bucket that ViewOrigin falls into // Cells are hashed into buckets to reduce search time const float FloatOffsetX = (View.ViewMatrices.ViewOrigin.X - Handler.PrecomputedVisibilityCellBucketOriginXY.X) / Handler.PrecomputedVisibilityCellSizeXY; // FMath::TruncToInt rounds toward 0, we want to always round down const int32 BucketIndexX = FMath::Abs((FMath::TruncToInt(FloatOffsetX) - (FloatOffsetX < 0.0f ? 1 : 0)) / Handler.PrecomputedVisibilityCellBucketSizeXY % Handler.PrecomputedVisibilityNumCellBuckets); const float FloatOffsetY = (View.ViewMatrices.ViewOrigin.Y -Handler.PrecomputedVisibilityCellBucketOriginXY.Y) / Handler.PrecomputedVisibilityCellSizeXY; const int32 BucketIndexY = FMath::Abs((FMath::TruncToInt(FloatOffsetY) - (FloatOffsetY < 0.0f ? 1 : 0)) / Handler.PrecomputedVisibilityCellBucketSizeXY % Handler.PrecomputedVisibilityNumCellBuckets); const int32 PrecomputedVisibilityBucketIndex = BucketIndexY * Handler.PrecomputedVisibilityCellBucketSizeXY + BucketIndexX; check(PrecomputedVisibilityBucketIndex < Handler.PrecomputedVisibilityCellBuckets.Num()); const FPrecomputedVisibilityBucket& CurrentBucket = Handler.PrecomputedVisibilityCellBuckets[PrecomputedVisibilityBucketIndex]; for (int32 CellIndex = 0; CellIndex < CurrentBucket.Cells.Num(); CellIndex++) { const FPrecomputedVisibilityCell& CurrentCell = CurrentBucket.Cells[CellIndex]; // Construct the cell's bounds const FBox CellBounds(CurrentCell.Min, CurrentCell.Min + FVector(Handler.PrecomputedVisibilityCellSizeXY, Handler.PrecomputedVisibilityCellSizeXY, Handler.PrecomputedVisibilityCellSizeZ)); // Check if ViewOrigin is inside the current cell if (CellBounds.IsInside(View.ViewMatrices.ViewOrigin)) { // Reuse a cached decompressed chunk if possible if (CachedVisibilityChunk && CachedVisibilityHandlerId == Scene->PrecomputedVisibilityHandler->GetId() && CachedVisibilityBucketIndex == PrecomputedVisibilityBucketIndex && CachedVisibilityChunkIndex == CurrentCell.ChunkIndex) { checkSlow(CachedVisibilityChunk->Num() >= CurrentCell.DataOffset + CurrentBucket.CellDataSize); PrecomputedVisibilityData = &(*CachedVisibilityChunk)[CurrentCell.DataOffset]; } else { const FCompressedVisibilityChunk& CompressedChunk = Handler.PrecomputedVisibilityCellBuckets[PrecomputedVisibilityBucketIndex].CellDataChunks[CurrentCell.ChunkIndex]; CachedVisibilityBucketIndex = PrecomputedVisibilityBucketIndex; CachedVisibilityChunkIndex = CurrentCell.ChunkIndex; CachedVisibilityHandlerId = Scene->PrecomputedVisibilityHandler->GetId(); if (CompressedChunk.bCompressed) { // Decompress the needed visibility data chunk DecompressedVisibilityChunk.Reset(); DecompressedVisibilityChunk.AddUninitialized(CompressedChunk.UncompressedSize); verify(FCompression::UncompressMemory( COMPRESS_ZLIB, DecompressedVisibilityChunk.GetData(), CompressedChunk.UncompressedSize, CompressedChunk.Data.GetData(), CompressedChunk.Data.Num())); CachedVisibilityChunk = &DecompressedVisibilityChunk; } else { CachedVisibilityChunk = &CompressedChunk.Data; } checkSlow(CachedVisibilityChunk->Num() >= CurrentCell.DataOffset + CurrentBucket.CellDataSize); // Return a pointer to the cell containing ViewOrigin's decompressed visibility data PrecomputedVisibilityData = &(*CachedVisibilityChunk)[CurrentCell.DataOffset]; } if (GShowRelevantPrecomputedVisibilityCells) { // Draw the currently used visibility cell with green wireframe for debugging DrawWireBox(&VisibilityCellsPDI, CellBounds, FColor(50, 255, 50), SDPG_Foreground); } else { break; } } else if (GShowRelevantPrecomputedVisibilityCells) { // Draw all cells in the current visibility bucket as blue wireframe DrawWireBox(&VisibilityCellsPDI, CellBounds, FColor(50, 50, 255), SDPG_World); } } } return PrecomputedVisibilityData; }
FORCEINLINE_DEBUGGABLE bool FNavMeshPath::DoesPathIntersectBoxImplementation(const FBox& Box, const FVector& StartLocation, uint32 StartingIndex, int32* IntersectingSegmentIndex) const { bool bIntersects = false; const TArray<FNavigationPortalEdge>& CorridorEdges = GetPathCorridorEdges(); // note that it's a bit simplified. It works if (CorridorEdges.IsValidIndex(StartingIndex)) { FVector Start = StartLocation; for (int32 PortalIndex = StartingIndex; PortalIndex < CorridorEdges.Num(); ++PortalIndex) { const FNavigationPortalEdge& Edge = CorridorEdges[PortalIndex]; const FVector End = Edge.Right + (Edge.Left - Edge.Right) / 2; if (FVector::DistSquared(Start, End) > SMALL_NUMBER) { const FVector Direction = (End - Start); if (FMath::LineBoxIntersection(Box, Start, End, Direction)) { bIntersects = true; if (IntersectingSegmentIndex != NULL) { *IntersectingSegmentIndex = PortalIndex; } break; } } Start = End; } // test the last portal->path end line if (bIntersects == false) { ensure(PathPoints.Num() == 2); const FVector End = PathPoints.Last().Location; if (FVector::DistSquared(StartLocation, End) > SMALL_NUMBER) { const FVector Direction = (End - Start); if (FMath::LineBoxIntersection(Box, Start, End, Direction)) { bIntersects = true; if (IntersectingSegmentIndex != NULL) { *IntersectingSegmentIndex = CorridorEdges.Num(); } } } } } // just check if path's end is inside the tested box if (bIntersects == false && Box.IsInside(PathPoints.Last().Location)) { bIntersects = true; if (IntersectingSegmentIndex != NULL) { *IntersectingSegmentIndex = CorridorEdges.Num(); } } return bIntersects; }