void AZombieCharacter::Attack() { //This function is used only when it's permitted by the zombie's animation instance //It creates a raycast in a sphere shape and checks for possible hits //If the hits contain our player it makes sure it applies damage to him //Setting up the start and end location of the raycast FVector StartLocation = GetMesh()->GetSocketLocation(FName("MeleeStartSocket")); FVector EndLocation = GetMesh()->GetSocketLocation(FName("MeleeEndSocket")); //Raycasting in a sphere to detect collisions TArray<FHitResult> HitResults; //Setting up the shape of the raycast FCollisionShape CollisionShape; CollisionShape.ShapeType = ECollisionShape::Sphere; CollisionShape.SetSphere(AttackRaycastRadius); //Object query parameters FCollisionObjectQueryParams ObjectQueryParams; ObjectQueryParams.AllDynamicObjects; //Handling ignored actors FCollisionQueryParams QueryParams; QueryParams.AddIgnoredActor(this); UWorld* World = GetWorld(); if (World && ZAnimInstance->bEligibleForAttack) { //Raycasting... bool bHit = World->SweepMultiByObjectType(HitResults, StartLocation, EndLocation, FQuat::Identity, ObjectQueryParams, CollisionShape, QueryParams); //Raycast visualization /*FVector Center = ((EndLocation - StartLocation) / 2) + StartLocation; DrawDebugSphere(World, Center, AttackRaycastRadius, 20, FColor::Green, false, 2.f);*/ //Checking for possible hits if (bHit) { for (auto It = HitResults.CreateIterator(); It; It++) { ARoguelikeChar* Char = Cast<ARoguelikeChar>(It->GetActor()); if (Char && ZAnimInstance && GetCharacterMovement()) { //Calling the attack function from character Char->TakeDamageFromZombie(Damage); //Closing the flag which checks for the attack function ZAnimInstance->bEligibleForAttack = false; //Updating with new movement speed GetCharacterMovement()->MaxWalkSpeed = InitialMaxWalkSpeed; ZAnimInstance->Speed = InitialMaxWalkSpeed; break; } } } } }
AEyeXActorBase* AEyeXPlayerController::FindBySweep(FHitResult& OutHit, const FSceneView* const View, const FVector2D& GazePoint, const FCollisionObjectQueryParams& ObjectParams, const FCollisionQueryParams& TraceParams) { if (SweepIntervals <= 1) { UE_LOG(LogEyeX, Warning, TEXT("Invalid value for SweepIntervals: %i. Must be greater than 0."), SweepIntervals); return nullptr; } UWorld* World = GetWorld(); if (!World) return nullptr; FVector Start, Direction; View->DeprojectFVector2D(GazePoint, Start, Direction); const float TanFOVScaled = GetTanOfFOVAngleScaled(); // Perform sweeps const float DeltaDistance = MaxDistance / SweepIntervals; const FVector DeltaDirection = DeltaDistance * Direction; float CurrentDistance = DeltaDistance / 2; FCollisionShape Shape; AEyeXActorBase* EyeXActor = nullptr; for (int i = 0; i < SweepIntervals; ++i) { const FVector End = Start + DeltaDirection; const float Radius = (i == 0) ? 0.0f : TanFOVScaled * CurrentDistance; // Depends on the view frustrum, size of the screen and the distance. Shape.SetSphere(Radius); if (World->SweepSingleByObjectType(OutHit, Start, End, FQuat::Identity, ObjectParams, Shape, TraceParams)) { EyeXActor = Cast<AEyeXActorBase>(OutHit.GetActor()); break; } Start = End; CurrentDistance += DeltaDistance; } VisualizeHit(bVisualizeDetection, World, OutHit, Shape.GetSphereRadius()); VisualizeGazePoint(bVisualizeDetection, World, Start); return EyeXActor; }
/** Tests shape components more efficiently than the with-adjustment case, but does less-efficient ppr-poly collision for meshes. */ static bool ComponentEncroachesBlockingGeometry_NoAdjustment(UWorld const* World, AActor const* TestActor, UPrimitiveComponent const* PrimComp, FTransform const& TestWorldTransform) { float const Epsilon = CVarEncroachEpsilon.GetValueOnGameThread(); if (World && PrimComp) { bool bFoundBlockingHit = false; static FName NAME_ComponentEncroachesBlockingGeometry_NoAdjustment = FName(TEXT("ComponentEncroachesBlockingGeometry_NoAdjustment")); ECollisionChannel const BlockingChannel = PrimComp->GetCollisionObjectType(); FCollisionShape const CollisionShape = PrimComp->GetCollisionShape(-Epsilon); if (CollisionShape.IsBox() && (Cast<UBoxComponent>(PrimComp) == nullptr)) { // we have a bounding box not for a box component, which means this was the fallback aabb // since we don't need the penetration info, go ahead and test the component itself for overlaps, which is more accurate if (PrimComp->IsRegistered()) { // must be registered TArray<FOverlapResult> Overlaps; FComponentQueryParams Params(NAME_ComponentEncroachesBlockingGeometry_NoAdjustment, TestActor); return World->ComponentOverlapMultiByChannel(Overlaps, PrimComp, TestWorldTransform.GetLocation(), TestWorldTransform.GetRotation(), BlockingChannel, Params); } else { UE_LOG(LogPhysics, Log, TEXT("Components must be registered in order to be used in a ComponentOverlapMulti call. PriComp: %s TestActor: %s"), *PrimComp->GetName(), *TestActor->GetName()); return false; } } else { FCollisionQueryParams Params(NAME_ComponentEncroachesBlockingGeometry_NoAdjustment, false, TestActor); return World->OverlapAnyTestByChannel(TestWorldTransform.GetLocation(), TestWorldTransform.GetRotation(), BlockingChannel, CollisionShape, Params); } } return false; }
UCollision2PGeom::UCollision2PGeom(const FCollisionShape& CollisionShape) { switch (CollisionShape.ShapeType) { case ECollisionShape::Box: { new (Storage)PxBoxGeometry(U2PVector(CollisionShape.GetBox())); break; } case ECollisionShape::Sphere: { new (Storage)PxSphereGeometry(CollisionShape.GetSphereRadius()); break; } case ECollisionShape::Capsule: { new (Storage)PxCapsuleGeometry(CollisionShape.GetCapsuleRadius(), CollisionShape.GetCapsuleAxisHalfLength()); break; } default: // invalid point ensure(false); } }
bool UWorld::SweepMultiByChannel(TArray<struct FHitResult>& OutHits, const FVector& Start, const FVector& End, const FQuat& Rot, ECollisionChannel TraceChannel, const FCollisionShape& CollisionShape, const FCollisionQueryParams& Params /* = FCollisionQueryParams::DefaultQueryParam */, const FCollisionResponseParams& ResponseParam /* = FCollisionResponseParams::DefaultResponseParam */) const { if (CollisionShape.IsNearlyZero()) { return LineTraceMultiByChannel(OutHits, Start, End, TraceChannel, Params, ResponseParam); } else { #if UE_WITH_PHYSICS return GeomSweepMulti(this, CollisionShape, Rot, OutHits, Start, End, TraceChannel, Params, ResponseParam, FCollisionObjectQueryParams::DefaultObjectQueryParam); #else return false; #endif } }
float UAISense_Aquaphobia::Update() { AIPerception::FListenerMap& ListenersMap = *GetListeners(); //For each listener who has this sense we're going to perform a sweep to determine nearby aqua actors for (auto& Elem : ListenersMap) { //Get the listener FPerceptionListener Listener = Elem.Value; const AActor* ListenerBodyActor = Listener.GetBodyActor(); for (int32 DigestedPropertyIndex = 0; DigestedPropertyIndex < DigestedProperties.Num(); DigestedPropertyIndex++) { //Create the sphere for this sense and perform the sweep to determine nearby actors FCollisionShape CollisionSphere = FCollisionShape::MakeSphere(DigestedProperties[DigestedPropertyIndex].PhobiaRadius); TArray<FHitResult> HitResults; GetWorld()->SweepMultiByChannel(HitResults, ListenerBodyActor->GetActorLocation(), ListenerBodyActor->GetActorLocation() + FVector::UpVector*CollisionSphere.GetSphereRadius(), FQuat(), ECollisionChannel::ECC_WorldDynamic, CollisionSphere); //Draw debug sphere if we have activated it via the config if (DigestedProperties[DigestedPropertyIndex].bDisplayDebugSphere) { DrawDebugSphere(GetWorld(), ListenerBodyActor->GetActorLocation(), DigestedProperties[DigestedPropertyIndex].PhobiaRadius, 8, FColor::Blue, false, 30.f, 1, 2.f); } //Check hit results for aqua actors for (int32 i = 0; i < HitResults.Num(); i++) { FHitResult hit = HitResults[i]; //To simplify things, we're going to assume that "water resources" for this post are actors that have the following game tag if (hit.GetActor()->ActorHasTag(FName("AquaActor"))) { if ((hit.GetActor()->GetActorLocation() - ListenerBodyActor->GetActorLocation()).Size() <= DigestedProperties[DigestedPropertyIndex].PhobiaRadius) { Elem.Value.RegisterStimulus(hit.GetActor(), FAIStimulus(*this, 5.f, hit.GetActor()->GetActorLocation(), ListenerBodyActor->GetActorLocation())); GLog->Log("registered stimulus!"); } } } } } //Time until next update; in this case we're forcing the update to happen in each frame return 0.f; }
bool UWorld::SweepTestByChannel(const FVector& Start, const FVector& End, const FQuat& Rot, ECollisionChannel TraceChannel, const FCollisionShape& CollisionShape, const FCollisionQueryParams& Params /* = FCollisionQueryParams::DefaultQueryParam */, const FCollisionResponseParams& ResponseParam /* = FCollisionResponseParams::DefaultResponseParam */) const { if (CollisionShape.IsNearlyZero()) { // if extent is 0, we'll just do linetrace instead return LineTraceTestByChannel(Start, End, TraceChannel, Params, ResponseParam); } else { #if UE_WITH_PHYSICS return GeomSweepTest(this, CollisionShape, Rot, Start, End, TraceChannel, Params, ResponseParam, FCollisionObjectQueryParams::DefaultObjectQueryParam); #else return false; #endif } }
bool UWorld::SweepMultiByObjectType(TArray<struct FHitResult>& OutHits, const FVector& Start, const FVector& End, const FQuat& Rot, const FCollisionObjectQueryParams& ObjectQueryParams, const FCollisionShape& CollisionShape, const FCollisionQueryParams& Params /* = FCollisionQueryParams::DefaultQueryParam */) const { if (CollisionShape.IsNearlyZero()) { return LineTraceMultiByObjectType(OutHits, Start, End, ObjectQueryParams, Params); } else { #if UE_WITH_PHYSICS GeomSweepMulti(this, CollisionShape, Rot, OutHits, Start, End, DefaultCollisionChannel, Params, FCollisionResponseParams::DefaultResponseParam, ObjectQueryParams); // object query returns true if any hit is found, not only blocking hit return (OutHits.Num() > 0); #else return false; #endif } }
bool UWorld::SweepSingleByObjectType(struct FHitResult& OutHit, const FVector& Start, const FVector& End, const FQuat& Rot, const FCollisionObjectQueryParams& ObjectQueryParams, const FCollisionShape& CollisionShape, const FCollisionQueryParams& Params /* = FCollisionQueryParams::DefaultQueryParam */) const { if (CollisionShape.IsNearlyZero()) { return LineTraceSingleByObjectType(OutHit, Start, End, ObjectQueryParams, Params); } else { #if UE_WITH_PHYSICS return GeomSweepSingle(this, CollisionShape, Rot, OutHit, Start, End, DefaultCollisionChannel, Params, FCollisionResponseParams::DefaultResponseParam, ObjectQueryParams); #else OutHit.TraceStart = Start; OutHit.TraceEnd = End; return false; #endif } }
/** Tests shape components less efficiently than the no-adjustment case, but does quicker aabb collision for meshes. */ static bool ComponentEncroachesBlockingGeometry_WithAdjustment(UWorld const* World, AActor const* TestActor, UPrimitiveComponent const* PrimComp, FTransform const& TestWorldTransform, FVector& OutProposedAdjustment) { // init our output OutProposedAdjustment = FVector::ZeroVector; float const Epsilon = CVarEncroachEpsilon.GetValueOnGameThread(); if (World && PrimComp) { bool bFoundBlockingHit = false; bool bComputePenetrationAdjustment = true; TArray<FOverlapResult> Overlaps; static FName NAME_ComponentEncroachesBlockingGeometry_WithAdjustment = FName(TEXT("ComponentEncroachesBlockingGeometry_WithAdjustment")); ECollisionChannel const BlockingChannel = PrimComp->GetCollisionObjectType(); FCollisionShape const CollisionShape = PrimComp->GetCollisionShape(-Epsilon); if (CollisionShape.IsBox() && (Cast<UBoxComponent>(PrimComp) == nullptr)) { // we have a bounding box not for a box component, which means this was the fallback aabb // so lets test the actual component instead of it's aabb // note we won't get penetration adjustment but that's ok if (PrimComp->IsRegistered()) { // must be registered FComponentQueryParams Params(NAME_ComponentEncroachesBlockingGeometry_WithAdjustment, TestActor); bFoundBlockingHit = World->ComponentOverlapMultiByChannel(Overlaps, PrimComp, TestWorldTransform.GetLocation(), TestWorldTransform.GetRotation(), BlockingChannel, Params); bComputePenetrationAdjustment = false; } else { UE_LOG(LogPhysics, Log, TEXT("Components must be registered in order to be used in a ComponentOverlapMulti call. PriComp: %s TestActor: %s"), *PrimComp->GetName(), *TestActor->GetName()); } } else { // overlap our shape FCollisionQueryParams Params(NAME_ComponentEncroachesBlockingGeometry_WithAdjustment, false, TestActor); bFoundBlockingHit = World->OverlapMultiByChannel(Overlaps, TestWorldTransform.GetLocation(), TestWorldTransform.GetRotation(), BlockingChannel, CollisionShape, Params); } // compute adjustment if (bFoundBlockingHit && bComputePenetrationAdjustment) { // if encroaching, add up all the MTDs of overlapping shapes FMTDResult MTDResult; for (int32 HitIdx = 0; HitIdx < Overlaps.Num(); HitIdx++) { UPrimitiveComponent* const OverlapComponent = Overlaps[HitIdx].Component.Get(); // first determine closest impact point along each axis if (OverlapComponent && OverlapComponent->GetCollisionResponseToChannel(BlockingChannel) == ECR_Block) { FCollisionShape const NonShrunkenCollisionShape = PrimComp->GetCollisionShape(); bool bSuccess = OverlapComponent->ComputePenetration(MTDResult, NonShrunkenCollisionShape, TestWorldTransform.GetLocation(), TestWorldTransform.GetRotation()); if (bSuccess) { OutProposedAdjustment += MTDResult.Direction * MTDResult.Distance; } else { UE_LOG(LogPhysics, Log, TEXT("OverlapTest says we are overlapping, yet MTD says we're not. Something is wrong")); } // #hack: sometimes for boxes, physx returns a 0 MTD even though it reports a contact (returns true) // to get around this, let's go ahead and test again with the epsilon-shrunken collision shape to see if we're really in // the clear. if so, we'll say we have no contact (despite what OverlapMultiByChannel said -- it uses a different algorithm) if (FMath::IsNearlyZero(MTDResult.Distance)) { FCollisionShape const ShrunkenCollisionShape = PrimComp->GetCollisionShape(-Epsilon); bSuccess = OverlapComponent->ComputePenetration(MTDResult, ShrunkenCollisionShape, TestWorldTransform.GetLocation(), TestWorldTransform.GetRotation()); if (bSuccess) { OutProposedAdjustment += MTDResult.Direction * MTDResult.Distance; } else { // let's call this "no contact" and be done return false; } } } } } return bFoundBlockingHit; } return false; }
bool UDestructibleComponent::SweepComponent(FHitResult& OutHit, const FVector Start, const FVector End, const FCollisionShape &CollisionShape, bool bTraceComplex/*=false*/) { bool bHaveHit = false; #if WITH_APEX if (ApexDestructibleActor != NULL) { PxF32 HitTime = 0.0f; PxVec3 HitNormal; int32 ChunkIdx = ApexDestructibleActor->obbSweep(HitTime, HitNormal, U2PVector(Start), U2PVector(CollisionShape.GetExtent()), PxMat33::createIdentity(), U2PVector(End - Start), NxDestructibleActorRaycastFlags::AllChunks); if (ChunkIdx != NxModuleDestructibleConst::INVALID_CHUNK_INDEX && HitTime <= 1.0f) { PxRigidDynamic* PActor = ApexDestructibleActor->getChunkPhysXActor(ChunkIdx); if (PActor != NULL) { // Store body instance state FFakeBodyInstanceState PrevState; SetupFakeBodyInstance(PActor, ChunkIdx, &PrevState); bHaveHit = Super::SweepComponent(OutHit, Start, End, CollisionShape, bTraceComplex); // Reset original body instance ResetFakeBodyInstance(PrevState); } } } #endif return bHaveHit; }
/** Tick */ void UFluidSurfaceComponent::TickComponent( float DeltaTime, enum ELevelTick TickType, FActorComponentTickFunction *ThisTickFunction ) { Super::TickComponent( DeltaTime, TickType, ThisTickFunction ); LastDeltaTime = DeltaTime; float SimStep = 1.f / UpdateRate; static float Time = 0.0f; #if WITH_EDITOR /* Only update if checked */ if( !UpdateComponent ) return; #endif /* If this water hasn't been rendered for a while, stop updating */ if (LastRenderTime > 0 && GetWorld()->TimeSeconds - LastRenderTime > 1) return; Time += DeltaTime; if( Time > SimStep ) { Time = 0.0f; LatestVerts = !LatestVerts; /* Add ripples for actors in the water */ TArray<struct FOverlapResult> OverlappingActors; FCollisionShape CollisionShape; CollisionShape.SetBox( FluidBoundingBox.GetExtent( ) ); /* Find overlapping actors */ GetWorld()->OverlapMultiByChannel(OverlappingActors, GetComponentLocation(), GetComponentQuat(), ECC_WorldDynamic, CollisionShape, FCollisionQueryParams(false)); // @todo: handle better /* Iterate through found overlapping actors */ for( int i = 0; i < OverlappingActors.Num( ); i++ ) { TWeakObjectPtr<AActor> Actor = OverlappingActors[ i ].Actor; /* Dont care about self and modifiers */ if( Actor != NULL && !Actor->IsA( AFluidSurfaceActor::StaticClass( ) ) && !Actor->IsA( AFluidSurfaceModifier::StaticClass( ) ) ) { FVector LocalVel = GetWorldToComponent( ).TransformVector( Actor->GetVelocity( ) ); float HorizVelMag = LocalVel.Size( ); Pling( Actor->GetActorLocation( ), RippleVelocityFactor * HorizVelMag, Actor->GetSimpleCollisionRadius( ) ); } } /* Do test ripple (moving around in a circle) */ if( GIsEditor && TestRipple ) { TestRippleAng += SimStep * MyU2Rad * TestRippleSpeed; FVector WorldRipplePos, LocalRipplePos; float RippleRadius = 0.3f * ( FluidXSize - 1 ) * FluidGridSpacing; if( FluidGridType == EFluidGridType::FGT_Hexagonal ) RippleRadius = FMath::Max( RippleRadius, 0.3f * ( FluidYSize - 1 ) * FluidGridSpacing * ROOT3OVER2 ); else RippleRadius = FMath::Max( RippleRadius, 0.3f * ( FluidYSize - 1 ) * FluidGridSpacing ); LocalRipplePos.X = ( RippleRadius * FMath::Sin( TestRippleAng ) ); LocalRipplePos.Y = ( RippleRadius * FMath::Cos( TestRippleAng ) ); LocalRipplePos.Z = 0.f; WorldRipplePos = ComponentToWorld.TransformPosition( LocalRipplePos ); Pling( WorldRipplePos, TestRippleStrength, TestRippleRadius ); } /* Add modifier effects */ for( int i = 0; i < Modifiers.Num( ); i++ ) { if( Modifiers[ i ] && Modifiers[ i ]->Active ) Modifiers[ i ]->Update( DeltaTime ); } /* Need to send new dynamic data */ MarkRenderDynamicDataDirty( ); } }
EBTNodeResult::Type UBTTask_Escape::ExecuteTask(UBehaviorTreeComponent& OwnedTree, uint8* Node) { AWolfAIController* Controller = Cast<AWolfAIController>(OwnedTree.GetAIOwner()); if (!Controller) { GLog->Log("Controller fail"); return EBTNodeResult::Failed; } FName SensedTargetKey = "SensedTarget"; AMyCharacter_FirstTry* Caveman = Cast<AMyCharacter_FirstTry>(OwnedTree.GetBlackboardComponent()->GetValueAsObject(SensedTargetKey)); if (Caveman) { TArray<FHitResult> HitResults; //Start and End Location of the capsule FVector StartLocation = Caveman->GetActorLocation(); FVector EndLocation = StartLocation; EndLocation.Z += Caveman->GetCapsuleComponent()->GetUnscaledCapsuleHalfHeight() / 2; //Collision Channel ECollisionChannel ECC = ECollisionChannel::ECC_WorldDynamic; //Collision Shape FCollisionShape CollisionShape; //Making Collision in sphere CollisionShape.ShapeType = ECollisionShape::Sphere; CollisionShape.SetSphere(350); //Sweeping for possible escape nodes if (Caveman->GetWorld()->SweepMultiByChannel(HitResults, StartLocation, EndLocation, FQuat::FQuat(), ECC, CollisionShape)) { //DrawDebugSphere(Caveman->GetWorld(), ((EndLocation - StartLocation) / 2) + StartLocation, CollisionShape.GetSphereRadius(), 100, FColor::Green, true); TArray<AActor*> AllPathNodes; UGameplayStatics::GetAllActorsOfClass(Caveman->GetWorld(), APathNode::StaticClass(), AllPathNodes); APathNode* NextNode; NextNode = Cast<APathNode>(AllPathNodes[FMath::RandRange(0, AllPathNodes.Num() - 1)]); //Finding next possible node while (NextNode->bIsCurrentlyOccupied && AllPathNodes.Contains(NextNode)) { NextNode = Cast<APathNode>(AllPathNodes[FMath::RandRange(0, AllPathNodes.Num() - 1)]); GLog->Log("Fear success"); } //Occupy the node NextNode->bIsCurrentlyOccupied = true; //Set the new node in the blackboard OwnedTree.GetBlackboardComponent()->SetValue<UBlackboardKeyType_Object>(BlackboardKey.GetSelectedKeyID(), NextNode); //OwnedTree.GetBlackboardComponent()->SetValue<UBlackboardKeyType_Object>(Bl) GLog->Log("Success after while"); return EBTNodeResult::Succeeded; } } GLog->Log("General Fail"); return EBTNodeResult::Failed; }